[vlc-commits] Ogg demux: add Opus support

Gregory Maxwell git at videolan.org
Tue Sep 4 00:04:08 CEST 2012


vlc/vlc-2.0 | branch: master | Gregory Maxwell <greg at xiph.org> | Tue Aug  7 15:42:05 2012 +0200| [832c7b27da19ff98ad01bcca94f2b8fbf9c3ed33] | committer: Jean-Baptiste Kempf

Ogg demux: add Opus support

Modified-by: Rafaël Carré <funman at videolan.org>
Signed-off-by: Rafaël Carré <funman at videolan.org>
(cherry picked from commit 7258c97afdf6e8209a1be5c8ce707e6040c38454)

Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>

> http://git.videolan.org/gitweb.cgi/vlc/vlc-2.0.git/?a=commit;h=832c7b27da19ff98ad01bcca94f2b8fbf9c3ed33
---

 modules/demux/ogg.c |   73 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 modules/demux/ogg.h |    2 ++
 2 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c
index da6dab3..96c965a 100644
--- a/modules/demux/ogg.c
+++ b/modules/demux/ogg.c
@@ -139,6 +139,7 @@ static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8
 static void Ogg_ReadTheoraHeader( logical_stream_t *, ogg_packet * );
 static void Ogg_ReadVorbisHeader( logical_stream_t *, ogg_packet * );
 static void Ogg_ReadSpeexHeader( logical_stream_t *, ogg_packet * );
+static void Ogg_ReadOpusHeader( logical_stream_t *, ogg_packet * );
 static void Ogg_ReadKateHeader( logical_stream_t *, ogg_packet * );
 static void Ogg_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * );
 static void Ogg_ReadAnnodexHeader( vlc_object_t *, logical_stream_t *, ogg_packet * );
@@ -349,6 +350,7 @@ static int Demux( demux_t * p_demux )
                 /* An Ogg/vorbis packet contains an end date granulepos */
                 if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
                     p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
+                    p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
                     p_stream->fmt.i_codec == VLC_CODEC_FLAC )
                 {
                     if( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
@@ -586,6 +588,11 @@ static void Ogg_DecodePacket( demux_t *p_demux,
             b_xiph = true;
             break;
 
+        case VLC_CODEC_OPUS:
+            if( p_stream->i_packets_backup == 2 ) p_stream->b_force_backup = 0;
+            b_xiph = true;
+            break;
+
         case VLC_CODEC_FLAC:
             if( !p_stream->fmt.audio.i_rate && p_stream->i_packets_backup == 2 )
             {
@@ -674,7 +681,19 @@ static void Ogg_DecodePacket( demux_t *p_demux,
     /* Convert the pcr into a pts */
     if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
         p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
+        p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
         p_stream->fmt.i_codec == VLC_CODEC_FLAC )
+        if (p_stream->i_pre_skip)
+        {
+            if( i_pts > p_stream->i_pre_skip )
+            {
+                i_pts -= - p_stream->i_pre_skip;
+            }
+            else
+            {
+                i_pts = 0;
+            }
+        }
     {
         if( p_stream->i_pcr >= 0 )
         {
@@ -693,7 +712,18 @@ static void Ogg_DecodePacket( demux_t *p_demux,
             p_stream->i_previous_pcr = p_stream->i_pcr;
 
             /* The granulepos is the end date of the sample */
-            i_pts =  p_stream->i_pcr;
+            i_pts = p_stream->i_pcr;
+            if (p_stream->i_pre_skip)
+            {
+                if( i_pts > p_stream->i_pre_skip )
+                {
+                    i_pts -= - p_stream->i_pre_skip;
+                }
+                else
+                {
+                    i_pts = 0;
+                }
+            }
         }
     }
 
@@ -721,6 +751,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
 
     if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS &&
         p_stream->fmt.i_codec != VLC_CODEC_SPEEX &&
+        p_stream->fmt.i_codec != VLC_CODEC_OPUS &&
         p_stream->fmt.i_codec != VLC_CODEC_FLAC &&
         p_stream->i_pcr >= 0 )
     {
@@ -794,6 +825,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
 
     if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS &&
         p_stream->fmt.i_codec != VLC_CODEC_SPEEX &&
+        p_stream->fmt.i_codec != VLC_CODEC_OPUS &&
         p_stream->fmt.i_codec != VLC_CODEC_FLAC &&
         p_stream->fmt.i_codec != VLC_CODEC_TARKIN &&
         p_stream->fmt.i_codec != VLC_CODEC_THEORA &&
@@ -933,6 +965,16 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
                              p_stream->fmt.audio.i_channels,
                              (int)p_stream->f_rate, p_stream->fmt.i_bitrate );
                 }
+                /* Check for Opus header */
+                else if( oggpacket.bytes >= 8 &&
+                    ! memcmp( oggpacket.packet, "OpusHead", 8 ) )
+                {
+                    Ogg_ReadOpusHeader( p_stream, &oggpacket );
+                    msg_Dbg( p_demux, "found opus header, channels: %i, "
+                             "pre-skip: %i",
+                             p_stream->fmt.audio.i_channels,
+                             (int)p_stream->i_pre_skip);
+                }
                 /* Check for Flac header (< version 1.1.1) */
                 else if( oggpacket.bytes >= 4 &&
                     ! memcmp( oggpacket.packet, "fLaC", 4 ) )
@@ -1530,6 +1572,9 @@ static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8
     case VLC_CODEC_SPEEX:
         Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 0 );
         break;
+    case VLC_CODEC_OPUS:
+        Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 0 );
+        break;
 
     /* N headers with the 2° one being the comments */
     case VLC_CODEC_KATE:
@@ -1669,6 +1714,32 @@ static void Ogg_ReadSpeexHeader( logical_stream_t *p_stream,
     p_stream->fmt.i_bitrate = oggpack_read( &opb, 32 );
 }
 
+static void Ogg_ReadOpusHeader( logical_stream_t *p_stream,
+                                 ogg_packet *p_oggpacket )
+{
+    oggpack_buffer opb;
+
+    p_stream->fmt.i_cat = AUDIO_ES;
+    p_stream->fmt.i_codec = VLC_CODEC_OPUS;
+
+    /* Signal that we want to keep a backup of the opus
+     * stream headers. They will be used when switching between
+     * audio streams. */
+    p_stream->b_force_backup = 1;
+
+    /* All OggOpus streams are timestamped at 48kHz and
+     * can be played at 48kHz. */
+    p_stream->f_rate = p_stream->fmt.audio.i_rate = 48000;
+    p_stream->fmt.i_bitrate = 0;
+
+    /* Cheat and get additionnal info ;) */
+    oggpack_readinit( &opb, p_oggpacket->packet, p_oggpacket->bytes);
+    oggpack_adv( &opb, 64 );
+    oggpack_adv( &opb, 8 ); /* version_id */
+    p_stream->fmt.audio.i_channels = oggpack_read( &opb, 8 );
+    p_stream->i_pre_skip = oggpack_read( &opb, 16 );
+}
+
 static void Ogg_ReadFlacHeader( demux_t *p_demux, logical_stream_t *p_stream,
                                 ogg_packet *p_oggpacket )
 {
diff --git a/modules/demux/ogg.h b/modules/demux/ogg.h
index 60fbfce..03f2ef5 100644
--- a/modules/demux/ogg.h
+++ b/modules/demux/ogg.h
@@ -65,6 +65,8 @@ typedef struct logical_stream_s
     /* Misc */
     bool b_reinit;
     int i_granule_shift;
+    /* Opus has a starting offset in the headers. */
+    int i_pre_skip;
 
     /* offset of first keyframe for theora; can be 0 or 1 depending on version number */
     int64_t i_keyframe_offset;



More information about the vlc-commits mailing list