]> git.sesse.net Git - vlc/blobdiff - modules/codec/vorbis.c
* include/vlc_es_out.h, src/input/es_out.c: added an ES_OUT_SET_FMT control.
[vlc] / modules / codec / vorbis.c
index d3fa8a03dc16ab45100518ab98168f7052e51116..3333b05a4ad41854edab0fa5a6dc9315ec2bd528 100644 (file)
@@ -101,6 +101,7 @@ static int  OpenPacketizer( vlc_object_t * );
 static void CloseDecoder  ( vlc_object_t * );
 static void *DecodeBlock  ( decoder_t *, block_t ** );
 
+static int  ProcessHeaders( decoder_t * );
 static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
 
 static aout_buffer_t *DecodePacket  ( decoder_t *, ogg_packet * );
@@ -268,80 +269,153 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     oggpacket.e_o_s = 0;
     oggpacket.packetno = 0;
 
-    if( p_sys->i_headers == 0 )
+    /* Check for headers */
+    if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
     {
-        /* Take care of the initial Vorbis header */
+        /* Headers already available as extra data */
+        p_sys->i_headers = 3;
+    }
+    else if( oggpacket.bytes && p_sys->i_headers < 3 )
+    {
+        /* Backup headers as extra data */
+        uint8_t *p_extra;
+
+        p_dec->fmt_in.p_extra =
+            realloc( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra +
+                     oggpacket.bytes + 2 );
+        p_extra = p_dec->fmt_in.p_extra + p_dec->fmt_in.i_extra;
+        *(p_extra++) = oggpacket.bytes >> 8;
+        *(p_extra++) = oggpacket.bytes & 0xFF;
 
-        oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
-        if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc,
-                                       &oggpacket ) < 0 )
+        memcpy( p_extra, oggpacket.packet, oggpacket.bytes );
+        p_dec->fmt_in.i_extra += oggpacket.bytes + 2;
+
+        block_Release( *pp_block );
+        p_sys->i_headers++;
+        return NULL;
+    }
+
+    if( p_sys->i_headers == 3 )
+    {
+        if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
         {
-            msg_Err( p_dec, "this bitstream does not contain Vorbis "
-                     "audio data.");
+            p_sys->i_headers = 0;
+            p_dec->fmt_in.i_extra = 0;
             block_Release( *pp_block );
             return NULL;
         }
-        p_sys->i_headers++;
+        else p_sys->i_headers++;
+    }
 
-        /* Setup the format */
-        p_dec->fmt_out.audio.i_rate     = p_sys->vi.rate;
-        p_dec->fmt_out.audio.i_channels = p_sys->vi.channels;
-        p_dec->fmt_out.audio.i_physical_channels =
-            p_dec->fmt_out.audio.i_original_channels =
-                pi_channels_maps[p_sys->vi.channels];
-        p_dec->fmt_out.i_bitrate = p_sys->vi.bitrate_nominal;
+    return ProcessPacket( p_dec, &oggpacket, pp_block );
+}
 
-        aout_DateInit( &p_sys->end_date, p_sys->vi.rate );
+/*****************************************************************************
+ * ProcessHeaders: process Vorbis headers.
+ *****************************************************************************/
+static int ProcessHeaders( decoder_t *p_dec )
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    ogg_packet oggpacket;
+    uint8_t *p_extra;
+    int i_extra;
 
-        msg_Dbg( p_dec, "channels:%d samplerate:%ld bitrate:%ld",
-                 p_sys->vi.channels, p_sys->vi.rate,
-                 p_sys->vi.bitrate_nominal );
+    if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
 
-        return ProcessPacket( p_dec, &oggpacket, pp_block );
+    oggpacket.granulepos = -1;
+    oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
+    oggpacket.e_o_s = 0;
+    oggpacket.packetno = 0;
+    p_extra = p_dec->fmt_in.p_extra;
+    i_extra = p_dec->fmt_in.i_extra;
+
+    /* Take care of the initial Vorbis header */
+    oggpacket.bytes = *(p_extra++) << 8;
+    oggpacket.bytes |= (*(p_extra++) & 0xFF);
+    oggpacket.packet = p_extra;
+    p_extra += oggpacket.bytes;
+    i_extra -= (oggpacket.bytes + 2);
+    if( i_extra < 0 )
+    {
+        msg_Err( p_dec, "header data corrupted");
+        return VLC_EGENERIC;
     }
 
-    if( p_sys->i_headers == 1 )
+    if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
     {
-        /* The next packet in order is the comments header */
-        if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket )
-            < 0 )
-        {
-            msg_Err( p_dec, "2nd Vorbis header is corrupted" );
-            block_Release( *pp_block );
-            return NULL;
-        }
-        p_sys->i_headers++;
+        msg_Err( p_dec, "this bitstream does not contain Vorbis audio data");
+        return VLC_EGENERIC;
+    }
 
-        ParseVorbisComments( p_dec );
+    /* Setup the format */
+    p_dec->fmt_out.audio.i_rate     = p_sys->vi.rate;
+    p_dec->fmt_out.audio.i_channels = p_sys->vi.channels;
+    p_dec->fmt_out.audio.i_physical_channels =
+        p_dec->fmt_out.audio.i_original_channels =
+            pi_channels_maps[p_sys->vi.channels];
+    p_dec->fmt_out.i_bitrate = p_sys->vi.bitrate_nominal;
+
+    aout_DateInit( &p_sys->end_date, p_sys->vi.rate );
+    aout_DateSet( &p_sys->end_date, 0 );
 
-        return ProcessPacket( p_dec, &oggpacket, pp_block );
+    msg_Dbg( p_dec, "channels:%d samplerate:%ld bitrate:%ld",
+             p_sys->vi.channels, p_sys->vi.rate, p_sys->vi.bitrate_nominal );
+
+    /* The next packet in order is the comments header */
+    oggpacket.b_o_s = 0;
+    oggpacket.bytes = *(p_extra++) << 8;
+    oggpacket.bytes |= (*(p_extra++) & 0xFF);
+    oggpacket.packet = p_extra;
+    p_extra += oggpacket.bytes;
+    i_extra -= (oggpacket.bytes + 2);
+    if( i_extra < 0 )
+    {
+        msg_Err( p_dec, "header data corrupted");
+        return VLC_EGENERIC;
     }
 
-    if( p_sys->i_headers == 2 )
+    if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
     {
-        /* The next packet in order is the codebooks header
-           We need to watch out that this packet is not missing as a
-           missing or corrupted header is fatal. */
-        if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket )
-            < 0 )
-        {
-            msg_Err( p_dec, "3rd Vorbis header is corrupted" );
-            block_Release( *pp_block );
-            return NULL;
-        }
-        p_sys->i_headers++;
+        msg_Err( p_dec, "2nd Vorbis header is corrupted" );
+        return VLC_EGENERIC;
+    }
+    ParseVorbisComments( p_dec );
+
+    /* The next packet in order is the codebooks header
+     * We need to watch out that this packet is not missing as a
+     * missing or corrupted header is fatal. */
+    oggpacket.bytes = *(p_extra++) << 8;
+    oggpacket.bytes |= (*(p_extra++) & 0xFF);
+    oggpacket.packet = p_extra;
+    i_extra -= (oggpacket.bytes + 2);
+    if( i_extra < 0 )
+    {
+        msg_Err( p_dec, "header data corrupted");
+        return VLC_EGENERIC;
+    }
 
-        if( !p_sys->b_packetizer )
-        {
-            /* Initialize the Vorbis packet->PCM decoder */
-            vorbis_synthesis_init( &p_sys->vd, &p_sys->vi );
-            vorbis_block_init( &p_sys->vd, &p_sys->vb );
-        }
+    if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
+    {
+        msg_Err( p_dec, "3rd Vorbis header is corrupted" );
+        return VLC_EGENERIC;
+    }
 
-        return ProcessPacket( p_dec, &oggpacket, pp_block );
+    if( !p_sys->b_packetizer )
+    {
+        /* Initialize the Vorbis packet->PCM decoder */
+        vorbis_synthesis_init( &p_sys->vd, &p_sys->vi );
+        vorbis_block_init( &p_sys->vd, &p_sys->vb );
+    }
+    else
+    {
+        p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
+        p_dec->fmt_out.p_extra =
+            realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
+        memcpy( p_dec->fmt_out.p_extra,
+                p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
     }
 
-    return ProcessPacket( p_dec, &oggpacket, pp_block );
+    return VLC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -382,10 +456,7 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
         else
             p_aout_buffer = NULL;
 
-        if( p_block )
-        {
-            block_Release( p_block );
-        }
+        if( p_block ) block_Release( p_block );
         return p_aout_buffer;
     }
 }
@@ -479,9 +550,12 @@ static block_t *SendPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
 static void ParseVorbisComments( decoder_t *p_dec )
 {
     input_thread_t *p_input = (input_thread_t *)p_dec->p_parent;
-    int i = 0;
     char *psz_name, *psz_value, *psz_comment;
-    while ( i < p_dec->p_sys->vc.comments )
+    int i = 0;
+
+    if( p_input->i_object_type != VLC_OBJECT_INPUT ) return;
+
+    while( i < p_dec->p_sys->vc.comments )
     {
         psz_comment = strdup( p_dec->p_sys->vc.user_comments[i] );
         if( !psz_comment )
@@ -600,7 +674,7 @@ static int OpenEncoder( vlc_object_t *p_this )
     p_enc->p_sys = p_sys;
 
     p_enc->pf_encode_audio = Encode;
-    p_enc->fmt_in.i_codec = VLC_FOURCC('f','l','3','2');
+    p_enc->fmt_in.i_codec = AUDIO_FMT_S16_NE;
     p_enc->fmt_out.i_codec = VLC_FOURCC('v','o','r','b');
 
     sout_CfgParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
@@ -677,10 +751,9 @@ static int OpenEncoder( vlc_object_t *p_this )
     /* Create and store headers */
     vorbis_analysis_headerout( &p_sys->vd, &p_sys->vc,
                                &header[0], &header[1], &header[2]);
-    p_enc->fmt_out.i_extra = 1 + 3 * 2 + header[0].bytes +
+    p_enc->fmt_out.i_extra = 3 * 2 + header[0].bytes +
        header[1].bytes + header[2].bytes;
     p_extra = p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra );
-    *(p_extra++) = 3; /* number of headers */
     for( i = 0; i < 3; i++ )
     {
         *(p_extra++) = header[i].bytes >> 8;