[vlc-devel] [PATCH v1 2/3] ogg: Add OggSpots video codec support

Michael Tänzer neo at nhng.de
Thu Mar 3 20:02:48 CET 2016


---
 include/vlc_fourcc.h    |  1 +
 modules/demux/ogg.c     | 88 ++++++++++++++++++++++++++++++++++++++++++++++++-
 modules/demux/oggseek.c |  7 ++++
 3 files changed, 95 insertions(+), 1 deletion(-)

diff --git a/include/vlc_fourcc.h b/include/vlc_fourcc.h
index 656ec4f..3d14a51 100644
--- a/include/vlc_fourcc.h
+++ b/include/vlc_fourcc.h
@@ -52,6 +52,7 @@
 #define VLC_CODEC_THEORA          VLC_FOURCC('t','h','e','o')
 #define VLC_CODEC_TARKIN          VLC_FOURCC('t','a','r','k')
 #define VLC_CODEC_DIRAC           VLC_FOURCC('d','r','a','c')
+#define VLC_CODEC_OGGSPOTS        VLC_FOURCC('S','P','O','T')
 #define VLC_CODEC_CAVS            VLC_FOURCC('C','A','V','S')
 #define VLC_CODEC_NUV             VLC_FOURCC('N','J','P','G')
 #define VLC_CODEC_RV10            VLC_FOURCC('R','V','1','0')
diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c
index 1f5456a..1175f5b 100644
--- a/modules/demux/ogg.c
+++ b/modules/demux/ogg.c
@@ -38,6 +38,8 @@
 
 #include <ogg/ogg.h>
 
+#include <limits.h>
+
 #include <vlc_codecs.h>
 #include <vlc_bits.h>
 #include "xiph.h"
@@ -151,6 +153,7 @@ static void Ogg_ReadAnnodexHeader( demux_t *, logical_stream_t *, ogg_packet * )
 static bool Ogg_ReadDiracHeader( logical_stream_t *, ogg_packet * );
 static bool Ogg_ReadVP8Header( demux_t *, logical_stream_t *, ogg_packet * );
 static void Ogg_ReadSkeletonHeader( demux_t *, logical_stream_t *, ogg_packet * );
+static bool Ogg_ReadOggSpotsHeader( logical_stream_t *, ogg_packet * );
 
 /* Skeleton */
 static void Ogg_ReadSkeletonBones( demux_t *, ogg_packet * );
@@ -639,6 +642,8 @@ static int Demux( demux_t * p_demux )
 
         if( p_stream->fmt.i_cat == SPU_ES )
             continue;
+        if( p_stream->fmt.i_codec == VLC_CODEC_OGGSPOTS )
+            continue;
         if( p_stream->i_pcr < VLC_TS_0 )
             continue;
         if ( p_stream->b_finished || p_stream->b_initializing )
@@ -983,6 +988,7 @@ static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream,
             p_stream->fmt.i_codec == VLC_CODEC_VP8 ||
             p_stream->fmt.i_codec == VLC_CODEC_DIRAC ||
             p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
+            p_stream->fmt.i_codec == VLC_CODEC_OGGSPOTS ||
             (p_stream->b_oggds && p_stream->fmt.i_cat == VIDEO_ES) )
         {
             p_stream->i_pcr = VLC_TS_0 + Oggseek_GranuleToAbsTimestamp( p_stream,
@@ -1413,7 +1419,8 @@ static void Ogg_DecodePacket( demux_t *p_demux,
         p_stream->fmt.i_codec != VLC_CODEC_DAALA &&
         p_stream->fmt.i_codec != VLC_CODEC_CMML &&
         p_stream->fmt.i_codec != VLC_CODEC_DIRAC &&
-        p_stream->fmt.i_codec != VLC_CODEC_KATE )
+        p_stream->fmt.i_codec != VLC_CODEC_KATE &&
+        p_stream->fmt.i_codec != VLC_CODEC_OGGSPOTS )
     {
         if( p_oggpacket->bytes <= 0 )
         {
@@ -2013,6 +2020,22 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
                                 p_ogg->i_streams-1 );
                     Ogg_ReadSkeletonHeader( p_demux, p_stream, &oggpacket );
                 }
+                /* Check for OggSpots header */
+                else if( oggpacket.bytes >= 8 &&
+                         ! memcmp( oggpacket.packet, "SPOTS\0\0", 8 ) )
+                {
+                    if ( Ogg_ReadOggSpotsHeader( p_stream, &oggpacket ) )
+                        msg_Dbg( p_demux,
+                                 "found OggSpots header, time resolution: %f",
+                                 p_stream->f_rate );
+                    else
+                    {
+                        msg_Err( p_demux, "found invalid OggSpots header" );
+                        Ogg_LogicalStreamDelete( p_demux, p_stream );
+                        p_stream = NULL;
+                        p_ogg->i_streams--;
+                    }
+                }
                 else
                 {
                     msg_Dbg( p_demux, "stream %d is of unknown type",
@@ -3384,3 +3407,66 @@ static bool Ogg_ReadDiracHeader( logical_stream_t *p_stream,
 
     return true;
 }
+
+static bool Ogg_ReadOggSpotsHeader( logical_stream_t *p_stream,
+                                    ogg_packet *p_oggpacket )
+{
+    uint64_t i_granulerate_numerator;
+    uint64_t i_granulerate_denominator;
+    int i_major;
+    int i_minor;
+
+    p_stream->fmt.i_cat = VIDEO_ES;
+    p_stream->fmt.i_codec = VLC_CODEC_OGGSPOTS;
+
+    /* Signal that we want to keep a backup of the OggSpots
+     * stream headers. They will be used when switching between
+     * audio streams. */
+    p_stream->b_force_backup = true;
+
+    /* Cheat and get additionnal info ;) */
+    if ( p_oggpacket->bytes != 52 )
+    {
+        /* The OggSpots header is always 52 bytes */
+        return false;
+    }
+
+    i_major = GetWLE( &p_oggpacket->packet[ 8] ); /* major version num */
+    i_minor = GetWLE( &p_oggpacket->packet[10] ); /* minor version num */
+    if ( i_major != 0 || i_minor != 1 )
+    {
+        return false;
+    }
+
+    /* Granule rate */
+    i_granulerate_numerator   = GetQWLE( &p_oggpacket->packet[12] );
+    i_granulerate_denominator = GetQWLE( &p_oggpacket->packet[20] );
+    if ( i_granulerate_numerator == 0 || i_granulerate_denominator == 0 )
+    {
+        return false;
+    }
+
+    /* The OggSpots spec contained an error and there are implementations out
+     * there that used the wrong value. So we detect that case and switch
+     * numerator and denominator in that case */
+    if ( i_granulerate_numerator == 1 && i_granulerate_denominator == 30 )
+    {
+        i_granulerate_numerator   = 30;
+        i_granulerate_denominator = 1;
+    }
+
+    p_stream->f_rate = ((double)i_granulerate_numerator) / i_granulerate_denominator;
+    if ( p_stream->f_rate == 0 )
+    {
+        return false;
+    }
+
+    /* Normalize granulerate */
+    vlc_ureduce(&p_stream->fmt.video.i_frame_rate,
+                &p_stream->fmt.video.i_frame_rate_base,
+                i_granulerate_numerator, i_granulerate_denominator, 0);
+
+    p_stream->i_granule_shift = p_oggpacket->packet[28];
+
+    return true;
+}
diff --git a/modules/demux/oggseek.c b/modules/demux/oggseek.c
index ce9d884..3376aea 100644
--- a/modules/demux/oggseek.c
+++ b/modules/demux/oggseek.c
@@ -738,6 +738,13 @@ int64_t Oggseek_GranuleToAbsTimestamp( logical_stream_t *p_stream,
         i_timestamp = i_granule * CLOCK_FREQ / p_stream->f_rate;
         break;
     }
+    case VLC_CODEC_OGGSPOTS:
+    {
+        if ( b_presentation ) return VLC_TS_INVALID;
+        i_timestamp = ( i_granule >> p_stream->i_granule_shift )
+                * CLOCK_FREQ / p_stream->f_rate;
+        break;
+    }
     }
 
     return i_timestamp;
-- 
2.5.0



More information about the vlc-devel mailing list