]> git.sesse.net Git - vlc/commitdiff
* include/vlc_es_out.h, src/input/es_out.c: added an ES_OUT_SET_FMT control.
authorGildas Bazin <gbazin@videolan.org>
Sat, 28 Aug 2004 11:02:51 +0000 (11:02 +0000)
committerGildas Bazin <gbazin@videolan.org>
Sat, 28 Aug 2004 11:02:51 +0000 (11:02 +0000)
* modules/demux/ogg.c, modules/demux/mkv.cpp:
  - store the vorbis/theora/speex headers in fmt.p_extra.
  - this change simplifies the code quite a bit and is a lot cleaner.
* modules/codec/vorbis.c, theora.c, speex.c, flac.c:
  - get the headers from fmt_in.p_extra or from the bitstream if empty.
* modules/mux/ogg.c:
  - recontstruct the headers from fmt.p_extra.

include/vlc_es_out.h
modules/codec/flac.c
modules/codec/speex.c
modules/codec/theora.c
modules/codec/vorbis.c
modules/demux/mkv.cpp
modules/demux/ogg.c
modules/mux/ogg.c
src/input/es_out.c

index d1970874e6c47f868427bcd546daf8aa588bb5c3..01bc37f3d84565ec83e9679b56c7d2eea0e7fce3 100644 (file)
@@ -2,7 +2,7 @@
  * vlc_es_out.h
  *****************************************************************************
  * Copyright (C) 1999-2004 VideoLAN
- * $Id: ninput.h 7930 2004-06-07 18:23:15Z fenrir $
+ * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -62,6 +62,9 @@ enum es_out_query_e
     ES_OUT_SET_PCR,             /* arg1=int64_t i_pcr(microsecond!) (using default group 0)*/
     ES_OUT_SET_GROUP_PCR,       /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/
     ES_OUT_RESET_PCR,           /* no arg */
+
+    /* Try not to use this one as it is a bit hacky */
+    ES_OUT_SET_FMT      /* arg1= es_out_id_t* arg2=es_format_t* */
 };
 
 struct es_out_t
index 194edb4559324e05b7ca8dcf5c6824581378911b..f63c7eedb52f24142d638555a6fcdba54dbf2f34 100644 (file)
@@ -215,14 +215,6 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->pf_decode_audio = DecodeBlock;
     p_dec->pf_packetize    = PacketizeBlock;
 
-    /* Decode STREAMINFO */
-    msg_Dbg( p_dec, "decode STREAMINFO" );
-    p_sys->p_block = block_New( p_dec, p_dec->fmt_in.i_extra );
-    memcpy( p_sys->p_block->p_buffer, p_dec->fmt_in.p_extra,
-            p_dec->fmt_in.i_extra );
-    FLAC__stream_decoder_process_until_end_of_metadata( p_sys->p_flac );
-    msg_Dbg( p_dec, "STREAMINFO decoded" );
-
     return VLC_SUCCESS;
 }
 
@@ -236,11 +228,43 @@ static int OpenPacketizer( vlc_object_t *p_this )
 
     i_ret = OpenDecoder( p_this );
 
+    /* Set output properties */
+    p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','a','c');
+
     if( i_ret != VLC_SUCCESS ) return i_ret;
 
     return i_ret;
 }
 
+/*****************************************************************************
+ * ProcessHeader: processe Flac header.
+ *****************************************************************************/
+static void ProcessHeader( decoder_t *p_dec )
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    if( !p_dec->fmt_in.i_extra ) return;
+
+    /* Decode STREAMINFO */
+    msg_Dbg( p_dec, "decode STREAMINFO" );
+    p_sys->p_block = block_New( p_dec, p_dec->fmt_in.i_extra );
+    memcpy( p_sys->p_block->p_buffer, p_dec->fmt_in.p_extra,
+            p_dec->fmt_in.i_extra );
+    FLAC__stream_decoder_process_until_end_of_metadata( p_sys->p_flac );
+    msg_Dbg( p_dec, "STREAMINFO decoded" );
+
+    if( !p_sys->b_stream_info ) return;
+
+    if( p_dec->fmt_out.i_codec == VLC_FOURCC('f','l','a','c') )
+    {
+        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 );
+    }
+}
+
 /****************************************************************************
  * PacketizeBlock: the whole thing
  ****************************************************************************
@@ -254,6 +278,8 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
 
     if( !pp_block || !*pp_block ) return NULL;
 
+    if( !p_sys->b_stream_info ) ProcessHeader( p_dec );
+
     if( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts )
     {
         /* We've just started the stream, wait for the first PTS. */
index 0cba6456db3bf784780399b69b15c907bb20895f..666a2c9233373efaa470708dbd04fa67cddfcaf9 100755 (executable)
@@ -82,7 +82,8 @@ static int  OpenPacketizer( vlc_object_t * );
 static void CloseDecoder  ( vlc_object_t * );
 
 static void *DecodeBlock  ( decoder_t *, block_t ** );
-static int  ProcessHeader ( decoder_t *, ogg_packet * );
+static int  ProcessHeaders( decoder_t * );
+static int  ProcessInitialHeader ( decoder_t *, ogg_packet * );
 static void *ProcessPacket( decoder_t *, ogg_packet *, block_t ** );
 
 static aout_buffer_t *DecodePacket( decoder_t *, ogg_packet * );
@@ -202,37 +203,116 @@ 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 Speex header */
-        if( ProcessHeader( p_dec, &oggpacket ) != VLC_SUCCESS )
+        /* Headers already available as extra data */
+        p_sys->i_headers = 2;
+    }
+    else if( oggpacket.bytes && p_sys->i_headers < 2 )
+    {
+        /* 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;
+
+        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 == 2 )
+    {
+        if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
         {
-            msg_Err( p_dec, "initial Speex header is corrupted" );
+            p_sys->i_headers = 0;
+            p_dec->fmt_in.i_extra = 0;
             block_Release( *pp_block );
             return NULL;
         }
+        else p_sys->i_headers++;
+    }
 
-        p_sys->i_headers++;
+    return ProcessPacket( p_dec, &oggpacket, pp_block );
+}
+
+/*****************************************************************************
+ * ProcessHeaders: process Speex 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;
+
+    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 )
+    /* Take care of the initial Speex header */
+    if( ProcessInitialHeader( p_dec, &oggpacket ) != VLC_SUCCESS )
     {
-        /* The next packet in order is the comments header */
-        ParseSpeexComments( p_dec, &oggpacket );
-        p_sys->i_headers++;
+        msg_Err( p_dec, "initial Speex header is corrupted" );
+        return VLC_EGENERIC;
+    }
+
+    /* 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;
+    }
+
+    ParseSpeexComments( p_dec, &oggpacket );
 
-        return ProcessPacket( p_dec, &oggpacket, pp_block );
+    if( p_sys->b_packetizer )
+    {
+        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;
 }
 
 /*****************************************************************************
- * ProcessHeader: processes the inital Speex header packet.
+ * ProcessInitialHeader: processes the inital Speex header packet.
  *****************************************************************************/
-static int ProcessHeader( decoder_t *p_dec, ogg_packet *p_oggpacket )
+static int ProcessInitialHeader( decoder_t *p_dec, ogg_packet *p_oggpacket )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
@@ -350,10 +430,7 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
         else
             p_aout_buffer = NULL; /* Skip headers */
 
-        if( p_block )
-        {
-            block_Release( p_block );
-        }
+        if( p_block ) block_Release( p_block );
         return p_aout_buffer;
     }
 }
@@ -463,6 +540,8 @@ static void ParseSpeexComments( decoder_t *p_dec, ogg_packet *p_oggpacket )
     const SpeexMode *p_mode;
     int i_len;
 
+    if( p_input->i_object_type != VLC_OBJECT_INPUT ) return;
+
     p_mode = speex_mode_list[p_sys->p_header->mode];
 
     input_Control( p_input, INPUT_ADD_INFO, _("Speex comment"), _("Mode"),
@@ -603,9 +682,8 @@ static int OpenEncoder( vlc_object_t *p_this )
     pp_header[1] = "ENCODER=VLC media player";
     pi_header[1] = sizeof("ENCODER=VLC media player");
 
-    p_enc->fmt_out.i_extra = 1 + 3 * 2 + pi_header[0] + pi_header[1];
+    p_enc->fmt_out.i_extra = 3 * 2 + pi_header[0] + pi_header[1];
     p_extra = p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra );
-    *(p_extra++) = 2; /* number of headers */
     for( i = 0; i < 2; i++ )
     {
         *(p_extra++) = pi_header[i] >> 8;
index 669f77b098fe7eeac3f228f6fd8d9690df2bf104..ae8ab3bc8ebb4bc33b2f33900543dad01abfb49a 100644 (file)
@@ -67,6 +67,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 picture_t *DecodePacket( decoder_t *, ogg_packet * );
@@ -194,83 +195,166 @@ 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 Theora 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;
+
+        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;
+    }
 
-        oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
-        if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
+    if( p_sys->i_headers == 3 )
+    {
+        if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
         {
-            msg_Err( p_dec, "This bitstream does not contain Theora "
-                     "video data." );
-            block_Release( p_block );
+            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++;
+    }
 
-        /* Set output properties */
-        p_dec->fmt_out.video.i_width = p_sys->ti.width;
-        p_dec->fmt_out.video.i_height = p_sys->ti.height;
+    return ProcessPacket( p_dec, &oggpacket, pp_block );
+}
 
-        if( p_sys->ti.aspect_denominator && p_sys->ti.aspect_numerator )
-        {
-            p_dec->fmt_out.video.i_aspect = ((int64_t)VOUT_ASPECT_FACTOR) *
-                ( p_sys->ti.aspect_numerator * p_sys->ti.width ) /
-                ( p_sys->ti.aspect_denominator * p_sys->ti.height );
-        }
-        else
-        {
-            p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *
-                p_sys->ti.frame_width / p_sys->ti.frame_height;
-        }
+/*****************************************************************************
+ * ProcessHeaders: process Theora 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, "%dx%d %.02f fps video, frame content "
-                 "is %dx%d with offset (%d,%d).",
-                 p_sys->ti.width, p_sys->ti.height,
-                 (double)p_sys->ti.fps_numerator/p_sys->ti.fps_denominator,
-                 p_sys->ti.frame_width, p_sys->ti.frame_height,
-                 p_sys->ti.offset_x, p_sys->ti.offset_y );
+    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( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
     {
-        /* The next packet in order is the comments header */
-        if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
-        {
-            msg_Err( p_dec, "2nd Theora header is corrupted." );
-            return NULL;
-        }
-        p_sys->i_headers++;
+        msg_Err( p_dec, "This bitstream does not contain Theora video data" );
+        return VLC_EGENERIC;
+    }
+
+    /* Set output properties */
+    p_dec->fmt_out.video.i_width = p_sys->ti.width;
+    p_dec->fmt_out.video.i_height = p_sys->ti.height;
+
+    if( p_sys->ti.aspect_denominator && p_sys->ti.aspect_numerator )
+    {
+        p_dec->fmt_out.video.i_aspect = ((int64_t)VOUT_ASPECT_FACTOR) *
+            ( p_sys->ti.aspect_numerator * p_sys->ti.width ) /
+            ( p_sys->ti.aspect_denominator * p_sys->ti.height );
+    }
+    else
+    {
+        p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *
+            p_sys->ti.frame_width / p_sys->ti.frame_height;
+    }
 
-        ParseTheoraComments( p_dec );
+    msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content "
+             "is %dx%d with offset (%d,%d)",
+             p_sys->ti.width, p_sys->ti.height,
+             (double)p_sys->ti.fps_numerator/p_sys->ti.fps_denominator,
+             p_sys->ti.frame_width, p_sys->ti.frame_height,
+             p_sys->ti.offset_x, p_sys->ti.offset_y );
 
-        return ProcessPacket( p_dec, &oggpacket, pp_block );
+    /* 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 )
+    /* The next packet in order is the comments header */
+    if( theora_decode_header( &p_sys->ti, &p_sys->tc, &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( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
-        {
-            msg_Err( p_dec, "3rd Theora header is corrupted." );
-            return NULL;
-        }
-        p_sys->i_headers++;
+        msg_Err( p_dec, "2nd Theora header is corrupted" );
+        return VLC_EGENERIC;
+    }
 
-        if( !p_sys->b_packetizer )
-        {
-            /* We have all the headers, initialize decoder */
-            theora_decode_init( &p_sys->td, &p_sys->ti );
-        }
+    ParseTheoraComments( p_dec );
 
-        return ProcessPacket( p_dec, &oggpacket, pp_block );
+    /* 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;
     }
 
-    return ProcessPacket( p_dec, &oggpacket, pp_block );
+    /* 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( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
+    {
+        msg_Err( p_dec, "3rd Theora header is corrupted" );
+        return VLC_EGENERIC;
+    }
+
+    if( !p_sys->b_packetizer )
+    {
+        /* We have all the headers, initialize decoder */
+        theora_decode_init( &p_sys->td, &p_sys->ti );
+    }
+    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 VLC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -289,6 +373,8 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
         p_sys->i_pts = p_block->i_pts;
     }
 
+    *pp_block = NULL; /* To avoid being fed the same packet again */
+
     if( p_sys->b_packetizer )
     {
         /* Date management */
@@ -308,11 +394,7 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
         else
             p_buf = NULL;
 
-        if( p_block )
-        {
-            block_Release( p_block );
-            *pp_block = NULL;
-        }
+        if( p_block ) block_Release( p_block );
     }
 
     /* Date management */
@@ -353,9 +435,11 @@ static picture_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
 static void ParseTheoraComments( 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;
+    int i = 0;
+
+    if( p_input->i_object_type != VLC_OBJECT_INPUT ) return;
+
     while ( i < p_dec->p_sys->tc.comments )
     {
         psz_comment = strdup( p_dec->p_sys->tc.user_comments[i] );
@@ -459,7 +543,7 @@ static int OpenEncoder( vlc_object_t *p_this )
 {
     encoder_t *p_enc = (encoder_t *)p_this;
     encoder_sys_t *p_sys = p_enc->p_sys;
-    ogg_packet header[3];
+    ogg_packet header;
     uint8_t *p_extra;
     vlc_value_t val;
     int i_quality, i;
@@ -549,19 +633,24 @@ static int OpenEncoder( vlc_object_t *p_this )
     theora_comment_init( &p_sys->tc );
 
     /* Create and store headers */
-    theora_encode_header( &p_sys->td, &header[0] );
-    theora_encode_comment( &p_sys->tc, &header[1] );
-    theora_encode_tables( &p_sys->td, &header[2] );
-    p_enc->fmt_out.i_extra = 1 + 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 */
+    p_enc->fmt_out.i_extra = 3 * 2;
     for( i = 0; i < 3; i++ )
     {
-        *(p_extra++) = header[i].bytes >> 8;
-        *(p_extra++) = header[i].bytes & 0xFF;
-        memcpy( p_extra, header[i].packet, header[i].bytes );
-        p_extra += header[i].bytes;
+        if( i == 0 ) theora_encode_header( &p_sys->td, &header );
+        else if( i == 1 ) theora_encode_comment( &p_sys->tc, &header );
+        else if( i == 2 ) theora_encode_tables( &p_sys->td, &header );
+
+        p_enc->fmt_out.p_extra =
+            realloc( p_enc->fmt_out.p_extra,
+                     p_enc->fmt_out.i_extra + header.bytes );
+        p_extra = p_enc->fmt_out.p_extra;
+        p_extra += p_enc->fmt_out.i_extra + (i-3)*2;
+        p_enc->fmt_out.i_extra += header.bytes;
+
+        *(p_extra++) = header.bytes >> 8;
+        *(p_extra++) = header.bytes & 0xFF;
+
+        memcpy( p_extra, header.packet, header.bytes );
     }
 
     return VLC_SUCCESS;
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;
index e1b47756453f746b864e80cf56d9e3d40067cb06..c2c3f68deab7a7e6a6c6a16cdf800b39fd213f5a 100644 (file)
@@ -535,9 +535,41 @@ static int Open( vlc_object_t * p_this )
         }
         else if( !strcmp( tk.psz_codec, "A_VORBIS" ) )
         {
+            int i, i_offset = 1, i_size[3], i_extra;
+            uint8_t *p_extra;
+
             tk.fmt.i_codec = VLC_FOURCC( 'v', 'o', 'r', 'b' );
-            tk.i_data_init = tk.i_extra_data;
-            tk.p_data_init = tk.p_extra_data;
+
+            /* Split the 3 headers */
+            if( tk.p_extra_data[0] != 0x02 )
+                msg_Err( p_demux, "invalid vorbis header" );
+
+            for( i = 0; i < 2; i++ )
+            {
+                i_size[i] = 0;
+                while( i_offset < tk.i_extra_data )
+                {
+                    i_size[i] += tk.p_extra_data[i_offset];
+                    if( tk.p_extra_data[i_offset++] != 0xff ) break;
+                }
+            }
+
+            i_size[0] = __MIN(i_size[0], tk.i_extra_data - i_offset);
+            i_size[1] = __MIN(i_size[1], tk.i_extra_data -i_offset -i_size[0]);
+            i_size[2] = tk.i_extra_data - i_offset - i_size[0] - i_size[1];
+
+            tk.fmt.i_extra = 3 * 2 + i_size[0] + i_size[1] + i_size[2];
+            tk.fmt.p_extra = malloc( tk.fmt.i_extra );
+            p_extra = (uint8_t *)tk.fmt.p_extra; i_extra = 0;
+            for( i = 0; i < 3; i++ )
+            {
+                *(p_extra++) = i_size[i] >> 8;
+                *(p_extra++) = i_size[i] & 0xFF;
+                memcpy( p_extra, tk.p_extra_data + i_offset + i_extra,
+                        i_size[i] );
+                p_extra += i_size[i];
+                i_extra += i_size[i];
+            }
         }
         else if( !strncmp( tk.psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
                  !strncmp( tk.psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
@@ -915,7 +947,8 @@ static block_t *MemToBlock( demux_t *p_demux, uint8_t *p_mem, int i_mem)
     return p_block;
 }
 
-static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts, mtime_t i_duration )
+static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
+                         mtime_t i_duration )
 {
     demux_sys_t *p_sys = p_demux->p_sys;
 
@@ -951,59 +984,8 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts, mtime
         block_t *p_init;
 
         msg_Dbg( p_demux, "sending header (%d bytes)", tk.i_data_init );
-
-        if( tk.fmt.i_codec == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
-        {
-            int i;
-            int i_offset = 1;
-            int i_size[3];
-
-            /* XXX hack split the 3 headers */
-            if( tk.p_data_init[0] != 0x02 )
-            {
-                msg_Err( p_demux, "invalid vorbis header" );
-            }
-
-            for( i = 0; i < 2; i++ )
-            {
-                i_size[i] = 0;
-                while( i_offset < tk.i_data_init )
-                {
-                    i_size[i] += tk.p_data_init[i_offset];
-                    if( tk.p_data_init[i_offset++] != 0xff )
-                    {
-                        break;
-                    }
-                }
-            }
-            i_size[0] = __MIN( i_size[0], tk.i_data_init - i_offset );
-            i_size[1] = __MIN( i_size[1], tk.i_data_init - i_offset - i_size[0] );
-            i_size[2] = tk.i_data_init - i_offset - i_size[0] - i_size[1];
-
-            p_init = MemToBlock( p_demux, &tk.p_data_init[i_offset], i_size[0] );
-            if( p_init )
-            {
-                es_out_Send( p_demux->out, tk.p_es, p_init );
-            }
-            p_init = MemToBlock( p_demux, &tk.p_data_init[i_offset+i_size[0]], i_size[1] );
-            if( p_init )
-            {
-                es_out_Send( p_demux->out, tk.p_es, p_init );
-            }
-            p_init = MemToBlock( p_demux, &tk.p_data_init[i_offset+i_size[0]+i_size[1]], i_size[2] );
-            if( p_init )
-            {
-                es_out_Send( p_demux->out, tk.p_es, p_init );
-            }
-        }
-        else
-        {
-            p_init = MemToBlock( p_demux, tk.p_data_init, tk.i_data_init );
-            if( p_init )
-            {
-                es_out_Send( p_demux->out, tk.p_es, p_init );
-            }
-        }
+        p_init = MemToBlock( p_demux, tk.p_data_init, tk.i_data_init );
+        if( p_init ) es_out_Send( p_demux->out, tk.p_es, p_init );
     }
     tk.b_inited = VLC_TRUE;
 
index bb7a1837458bd3ed9f2a2de86fd272fbd83cd6c6..187fbc2217f58a450b8d8f58b76c693830da319d 100644 (file)
@@ -59,14 +59,14 @@ typedef struct logical_stream_s
     double           f_rate;
 
     int              i_serial_no;
-    int              b_activated;
 
     /* the header of some logical streams (eg vorbis) contain essential
      * data for the decoder. We back them up here in case we need to re-feed
      * them to the decoder. */
     int              b_force_backup;
     int              i_packets_backup;
-    ogg_packet       *p_packets_backup;
+    uint8_t          *p_headers;
+    int              i_headers;
 
     /* program clock reference (in units of 90kHz) derived from the previous
      * granulepos */
@@ -163,12 +163,11 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux );
 static void Ogg_EndOfStream( demux_t *p_demux );
 
 /* Logical bitstream headers */
-static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream,
-                                  ogg_packet *p_oggpacket );
-static void Ogg_ReadVorbisHeader( logical_stream_t *p_stream,
-                                  ogg_packet *p_oggpacket );
-static void Ogg_ReadAnnodexHeader( vlc_object_t *, logical_stream_t *p_stream,
-                                   ogg_packet *p_oggpacket );
+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_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * );
+static void Ogg_ReadAnnodexHeader( vlc_object_t *, logical_stream_t *, ogg_packet * );
 
 /*****************************************************************************
  * Open: initializes ogg demux structures
@@ -502,9 +501,15 @@ static void Ogg_DecodePacket( demux_t *p_demux,
         return; 
     }
 
+    /* Check the ES is selected */
+    es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
+                    p_stream->p_es, &b_selected );
+
     if( p_stream->b_force_backup )
     {
-        ogg_packet *p_packet_backup;
+        uint8_t *p_extra;
+       vlc_bool_t b_store_size = VLC_TRUE;
+
         p_stream->i_packets_backup++;
         switch( p_stream->fmt.i_codec )
         {
@@ -515,59 +520,12 @@ static void Ogg_DecodePacket( demux_t *p_demux,
           break;
 
         case VLC_FOURCC( 'f','l','a','c' ):
-          if( p_stream->i_packets_backup == 1 ) return;
-          else if( p_stream->i_packets_backup == 2 )
+          if( p_stream->i_packets_backup == 2 )
           {
-              /* Parse the STREAMINFO metadata */
-              bs_t s;
-              bs_init( &s, p_oggpacket->packet, p_oggpacket->bytes );
-              bs_read( &s, 1 );
-              if( bs_read( &s, 7 ) == 0 )
-              {
-                  if( bs_read( &s, 24 ) >= 34 /*size STREAMINFO*/ )
-                  {
-                      bs_skip( &s, 80 );
-                      p_stream->f_rate = p_stream->fmt.audio.i_rate =
-                          bs_read( &s, 20 );
-                      p_stream->fmt.audio.i_channels =
-                          bs_read( &s, 3 ) + 1;
-
-                      msg_Dbg( p_demux, "FLAC header, channels: %i, rate: %i",
-                               p_stream->fmt.audio.i_channels,
-                               (int)p_stream->f_rate );
-                  }
-                  else
-                  {
-                      msg_Dbg( p_demux, "FLAC STREAMINFO metadata too short" );
-                  }
-
-                  /* Store STREAMINFO for the decoder and packetizer */
-                  p_stream->fmt.i_extra = p_oggpacket->bytes + 4;
-                  p_stream->fmt.p_extra = malloc( p_stream->fmt.i_extra );
-                  memcpy( p_stream->fmt.p_extra, "fLaC", 4);
-                  memcpy( ((uint8_t *)p_stream->fmt.p_extra) + 4,
-                          p_oggpacket->packet, p_oggpacket->bytes );
-
-                  /* Fake this as the last metadata block */
-                  ((uint8_t*)p_stream->fmt.p_extra)[4] |= 0x80;
-
-                  p_stream->p_es = es_out_Add( p_demux->out,
-                                               &p_stream->fmt );
-              }
-              else
-              {
-                  /* This ain't a STREAMINFO metadata */
-                  msg_Dbg( p_demux, "Invalid FLAC STREAMINFO metadata" );
-              }
+             Ogg_ReadFlacHeader( p_demux, p_stream, p_oggpacket );
               p_stream->b_force_backup = 0;
-              p_stream->i_packets_backup = 0;
-
-              if( p_oggpacket->granulepos >= 0 )
-                  Ogg_UpdatePCR( p_stream, p_oggpacket );
-
-              p_stream->i_previous_pcr = 0;
-              return;
           }
+          b_store_size = VLC_FALSE;
           break;
 
         default:
@@ -576,53 +534,31 @@ static void Ogg_DecodePacket( demux_t *p_demux,
         }
 
         /* Backup the ogg packet (likely an header packet) */
-        p_stream->p_packets_backup =
-            realloc( p_stream->p_packets_backup, p_stream->i_packets_backup *
-                     sizeof(ogg_packet) );
-
-        p_packet_backup =
-            &p_stream->p_packets_backup[p_stream->i_packets_backup - 1];
-
-        p_packet_backup->bytes = p_oggpacket->bytes;
-        p_packet_backup->granulepos = p_oggpacket->granulepos;
-
-        if( p_oggpacket->granulepos >= 0 )
+        p_stream->p_headers =
+            realloc( p_stream->p_headers, p_stream->i_headers +
+                     p_oggpacket->bytes + (b_store_size ? 2 : 0) );
+        p_extra = p_stream->p_headers + p_stream->i_headers;
+        if( b_store_size )
         {
-            /* Because of vorbis granulepos scheme we must set the pcr for the
-             * 1st header packet so it doesn't get discarded in the
-             * packetizer */
-            Ogg_UpdatePCR( p_stream, p_oggpacket );
+            *(p_extra++) = p_oggpacket->bytes >> 8;
+            *(p_extra++) = p_oggpacket->bytes & 0xFF;
         }
+        memcpy( p_extra, p_oggpacket->packet, p_oggpacket->bytes );
+        p_stream->i_headers += p_oggpacket->bytes + (b_store_size ? 2 : 0);
 
-        p_packet_backup->packet = malloc( p_oggpacket->bytes );
-        if( !p_packet_backup->packet ) return;
-        memcpy( p_packet_backup->packet, p_oggpacket->packet,
-                p_oggpacket->bytes );
-    }
-
-    /* Check the ES is selected */
-    es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
-                    p_stream->p_es, &b_selected );
-
-    if( b_selected && !p_stream->b_activated )
-    {
-        p_stream->b_activated = VLC_TRUE;
-
-        /* Newly activated stream, feed the backup headers to the decoder */
         if( !p_stream->b_force_backup )
         {
-            int i;
-            for( i = 0; i < p_stream->i_packets_backup; i++ )
-            {
-                /* Set correct starting date in header packets */
-                p_stream->p_packets_backup[i].granulepos =
-                    p_stream->i_interpolated_pcr * p_stream->f_rate /
-                    I64C(1000000);
-
-                Ogg_DecodePacket( p_demux, p_stream,
-                                  &p_stream->p_packets_backup[i] );
-            }
+            /* Last header received, commit changes */
+            p_stream->fmt.i_extra = p_stream->i_headers;
+            p_stream->fmt.p_extra =
+                realloc( p_stream->fmt.p_extra, p_stream->i_headers );
+           memcpy( p_stream->fmt.p_extra, p_stream->p_headers,
+                   p_stream->i_headers );
+            es_out_Control( p_demux->out, ES_OUT_SET_FMT,
+                            p_stream->p_es, &p_stream->fmt );
         }
+
+        b_selected = VLC_FALSE; /* Discard the header packet */
     }
 
     /* Convert the pcr into a pts */
@@ -683,7 +619,6 @@ static void Ogg_DecodePacket( demux_t *p_demux,
     {
         /* This stream isn't currently selected so we don't need to decode it,
          * but we did need to store its pcr as it might be selected later on */
-        p_stream->b_activated = VLC_FALSE;
         return;
     }
 
@@ -791,9 +726,9 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
 
                 p_stream = malloc( sizeof(logical_stream_t) );
                 memset( p_stream, 0, sizeof(logical_stream_t) );
+                p_stream->p_headers = 0;
 
                 es_format_Init( &p_stream->fmt, 0, 0 );
-                p_stream->b_activated = VLC_TRUE;
 
                 /* Setup the logical stream */
                 p_stream->i_serial_no = ogg_page_serialno( &oggpage );
@@ -823,28 +758,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
                 else if( oggpacket.bytes >= 7 &&
                     ! strncmp( &oggpacket.packet[0], "Speex", 5 ) )
                 {
-                    oggpack_buffer opb;
-
-                    p_stream->fmt.i_cat = AUDIO_ES;
-                    p_stream->fmt.i_codec = VLC_FOURCC( 's','p','x',' ' );
-
-                    /* Signal that we want to keep a backup of the vorbis
-                     * stream headers. They will be used when switching between
-                     * audio streams. */
-                    p_stream->b_force_backup = 1;
-
-                    /* Cheat and get additionnal info ;) */
-                    oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
-                    oggpack_adv( &opb, 224 );
-                    oggpack_adv( &opb, 32 ); /* speex_version_id */
-                    oggpack_adv( &opb, 32 ); /* header_size */
-                    p_stream->f_rate = p_stream->fmt.audio.i_rate =
-                        oggpack_read( &opb, 32 );
-                    oggpack_adv( &opb, 32 ); /* mode */
-                    oggpack_adv( &opb, 32 ); /* mode_bitstream_version */
-                    p_stream->fmt.audio.i_channels = oggpack_read( &opb, 32 );
-                    p_stream->fmt.i_bitrate = oggpack_read( &opb, 32 );
-
+                    Ogg_ReadSpeexHeader( p_stream, &oggpacket );
                     msg_Dbg( p_demux, "found speex header, channels: %i, "
                              "rate: %i,  bitrate: %i",
                              p_stream->fmt.audio.i_channels,
@@ -1174,14 +1088,12 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
     for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
     {
 #define p_stream p_ogg->pp_stream[i_stream]
-        if( p_stream->fmt.i_codec != VLC_FOURCC('f','l','a','c') )
-            p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
+        p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
 
         if( p_stream->fmt.i_codec == VLC_FOURCC('c','m','m','l') )
         {
             /* Set the CMML stream active */
-            es_out_Control( p_demux->out, ES_OUT_SET_ES,
-                            p_stream->p_es );
+            es_out_Control( p_demux->out, ES_OUT_SET_ES, p_stream->p_es );
         }
 
         p_ogg->i_bitrate += p_stream->fmt.i_bitrate;
@@ -1201,7 +1113,7 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
 static void Ogg_EndOfStream( demux_t *p_demux )
 {
     demux_sys_t *p_ogg = p_demux->p_sys  ;
-    int i_stream, j;
+    int i_stream;
 
 #define p_stream p_ogg->pp_stream[i_stream]
     for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
@@ -1212,12 +1124,8 @@ static void Ogg_EndOfStream( demux_t *p_demux )
         p_ogg->i_bitrate -= p_stream->fmt.i_bitrate;
 
         ogg_stream_clear( &p_ogg->pp_stream[i_stream]->os );
-        for( j = 0; j < p_ogg->pp_stream[i_stream]->i_packets_backup; j++ )
-        {
-            free( p_ogg->pp_stream[i_stream]->p_packets_backup[j].packet );
-        }
-        if( p_ogg->pp_stream[i_stream]->p_packets_backup)
-            free( p_ogg->pp_stream[i_stream]->p_packets_backup );
+        if( p_ogg->pp_stream[i_stream]->p_headers)
+            free( p_ogg->pp_stream[i_stream]->p_headers );
 
         es_format_Clean( &p_stream->fmt );
 
@@ -1242,7 +1150,7 @@ static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream,
     p_stream->fmt.i_cat = VIDEO_ES;
     p_stream->fmt.i_codec = VLC_FOURCC( 't','h','e','o' );
 
-    /* Signal that we want to keep a backup of the vorbis
+    /* Signal that we want to keep a backup of the theora
      * stream headers. They will be used when switching between
      * audio streams. */
     p_stream->b_force_backup = 1;
@@ -1281,12 +1189,6 @@ static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream,
     }
 
     p_stream->f_rate = ((float)i_fps_numerator) / i_fps_denominator;
-
-    /* Save this data in p_extra for ffmpeg */
-    p_stream->fmt.i_extra = p_oggpacket->bytes;
-    p_stream->fmt.p_extra = malloc( p_oggpacket->bytes );
-    memcpy( p_stream->fmt.p_extra, p_oggpacket->packet, p_oggpacket->bytes );
-
 }
 
 static void Ogg_ReadVorbisHeader( logical_stream_t *p_stream,
@@ -1312,6 +1214,62 @@ static void Ogg_ReadVorbisHeader( logical_stream_t *p_stream,
     p_stream->fmt.i_bitrate = oggpack_read( &opb, 32 );
 }
 
+static void Ogg_ReadSpeexHeader( 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_FOURCC( 's','p','x',' ' );
+
+    /* Signal that we want to keep a backup of the speex
+     * stream headers. They will be used when switching between
+     * audio streams. */
+    p_stream->b_force_backup = 1;
+
+    /* Cheat and get additionnal info ;) */
+    oggpack_readinit( &opb, p_oggpacket->packet, p_oggpacket->bytes);
+    oggpack_adv( &opb, 224 );
+    oggpack_adv( &opb, 32 ); /* speex_version_id */
+    oggpack_adv( &opb, 32 ); /* header_size */
+    p_stream->f_rate = p_stream->fmt.audio.i_rate = oggpack_read( &opb, 32 );
+    oggpack_adv( &opb, 32 ); /* mode */
+    oggpack_adv( &opb, 32 ); /* mode_bitstream_version */
+    p_stream->fmt.audio.i_channels = oggpack_read( &opb, 32 );
+    p_stream->fmt.i_bitrate = oggpack_read( &opb, 32 );
+}
+
+static void Ogg_ReadFlacHeader( demux_t *p_demux, logical_stream_t *p_stream,
+                                ogg_packet *p_oggpacket )
+{
+    /* Parse the STREAMINFO metadata */
+    bs_t s;
+
+    bs_init( &s, p_oggpacket->packet, p_oggpacket->bytes );
+    bs_read( &s, 1 );
+    if( bs_read( &s, 7 ) == 0 )
+    {
+        if( bs_read( &s, 24 ) >= 34 /*size STREAMINFO*/ )
+       {
+           bs_skip( &s, 80 );
+           p_stream->f_rate = p_stream->fmt.audio.i_rate = bs_read( &s, 20 );
+           p_stream->fmt.audio.i_channels = bs_read( &s, 3 ) + 1;
+
+           msg_Dbg( p_demux, "FLAC header, channels: %i, rate: %i",
+                    p_stream->fmt.audio.i_channels, (int)p_stream->f_rate );
+       }
+       else msg_Dbg( p_demux, "FLAC STREAMINFO metadata too short" );
+
+       /* Fake this as the last metadata block */
+       *((uint8_t*)p_oggpacket->packet) |= 0x80;
+    }
+    else
+    {
+        /* This ain't a STREAMINFO metadata */
+        msg_Dbg( p_demux, "Invalid FLAC STREAMINFO metadata" );
+    }
+}
+
 static void Ogg_ReadAnnodexHeader( vlc_object_t *p_this,
                                    logical_stream_t *p_stream,
                                    ogg_packet *p_oggpacket )
index 348790f65e635d522f4bb5c3b789e75512e631c6..44d0ff62d640ea8c2f5b1b96225bf75df95844d9 100644 (file)
@@ -5,7 +5,7 @@
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- *          Gildas Bazin <gbazin@netcourrier.com>
+ *          Gildas Bazin <gbazin@videolan.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -146,10 +146,7 @@ static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
         if( p_mux->pp_inputs[i]->p_fmt->i_cat == SPU_ES &&
             p_fifo->i_depth == 0 ) continue;
 
-        if( p_fifo->i_depth > 2 ||
-            /* Special case for SPUs */
-            ( p_mux->pp_inputs[i]->p_fmt->i_cat == SPU_ES &&
-              p_fifo->i_depth > 0 ) )
+        if( p_fifo->i_depth )
         {
             block_t *p_buf;
 
@@ -160,11 +157,8 @@ static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
                 i_stream = i;
             }
         }
-        else
-        {
-            // wait that all fifo have at least 3 packets (3 vorbis headers)
-            return -1;
-        }
+        else return -1;
+
     }
     if( pi_stream )
     {
@@ -196,9 +190,6 @@ typedef struct
 
     oggds_header_t *p_oggds_header;
 
-    block_t *pp_sout_headers[3];
-    int           i_sout_headers;
-
 } ogg_stream_t;
 
 struct sout_mux_sys_t
@@ -336,7 +327,6 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     p_stream->i_serial_no = p_sys->i_next_serial_no++;
     p_stream->i_packet_no = 0;
 
-    p_stream->i_sout_headers = 0;
     p_stream->p_oggds_header = 0;
 
     switch( p_input->p_fmt->i_cat )
@@ -437,7 +427,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
             if( p_input->p_fmt->i_extra )
             {
                 memcpy( &p_stream->p_oggds_header[1],
-                       p_input->p_fmt->p_extra, p_input->p_fmt->i_extra );
+                        p_input->p_fmt->p_extra, p_input->p_fmt->i_extra );
             }
 
             memcpy( p_stream->p_oggds_header->stream_type, "audio", 5 );
@@ -506,8 +496,6 @@ static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
     /* flush all remaining data */
     if( p_input->p_sys )
     {
-        int i;
-
         if( !p_stream->b_new &&
             ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
         {
@@ -515,12 +503,6 @@ static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
             sout_AccessOutWrite( p_mux->p_access, p_og );
         }
 
-        for( i = 0; i < p_stream->i_sout_headers; i++ )
-        {
-            block_Release( p_stream->pp_sout_headers[i] );
-            p_stream->i_sout_headers = 0;
-        }
-
         /* move input in delete queue */
         if( !p_stream->b_new )
         {
@@ -601,13 +583,15 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
     block_t *p_hdr = NULL;
     block_t *p_og = NULL;
     ogg_packet op;
-    int i;
+    uint8_t *p_extra;
+    int i, i_extra;
 
     /* Write header for each stream. All b_o_s (beginning of stream) packets
      * must appear first in the ogg stream so we take care of them first. */
     for( i = 0; i < p_mux->i_nb_inputs; i++ )
     {
-        ogg_stream_t *p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
+        sout_input_t *p_input = p_mux->pp_inputs[i];
+        ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
         p_stream->b_new = VLC_FALSE;
 
         msg_Dbg( p_mux, "creating header for %4.4s",
@@ -620,25 +604,26 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
             p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) ||
             p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
         {
-            /* Special case, headers are already there in the
-             * incoming stream or we backed them up earlier */
-
-            /* first packet in order: vorbis/speex/theora info */
-            if( !p_stream->i_sout_headers )
+            /* First packet in order: vorbis/speex/theora info */
+            p_extra = p_input->p_fmt->p_extra;
+            i_extra = p_input->p_fmt->i_extra;
+
+            op.bytes = *(p_extra++) << 8;
+            op.bytes |= (*(p_extra++) & 0xFF);
+            op.packet = p_extra;
+            i_extra -= (op.bytes + 2);
+            if( i_extra < 0 )
             {
-                p_og = block_FifoGet( p_mux->pp_inputs[i]->p_fifo );
-                op.packet = p_og->p_buffer;
-                op.bytes  = p_og->i_buffer;
-                op.b_o_s  = 1;
-                op.e_o_s  = 0;
-                op.granulepos = 0;
-                op.packetno = p_stream->i_packet_no++;
-                ogg_stream_packetin( &p_stream->os, &op );
-                p_stream->pp_sout_headers[0] =
-                    OggStreamFlush( p_mux, &p_stream->os, 0 );
-                p_stream->i_sout_headers++;
+                msg_Err( p_mux, "header data corrupted");
+                op.bytes += i_extra;
             }
-            p_og = block_Duplicate( p_stream->pp_sout_headers[0] );
+
+            op.b_o_s  = 1;
+            op.e_o_s  = 0;
+            op.granulepos = 0;
+            op.packetno = p_stream->i_packet_no++;
+            ogg_stream_packetin( &p_stream->os, &op );
+            p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
 
             /* Get keyframe_granule_shift for theora granulepos calculation */
             if( p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
@@ -687,7 +672,8 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
     /* Take care of the non b_o_s headers */
     for( i = 0; i < p_mux->i_nb_inputs; i++ )
     {
-        ogg_stream_t *p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
+        sout_input_t *p_input = p_mux->pp_inputs[i];
+        ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
 
         if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
             p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) ||
@@ -695,26 +681,40 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
         {
             /* Special case, headers are already there in the incoming stream.
              * We need to gather them an mark them as headers. */
-            int j;
-            for( j = 0; j < 2; j++ )
+            int j = 2;
+
+            if( p_stream->i_fourcc == VLC_FOURCC( 's', 'p', 'x', ' ' ) ) j = 1;
+
+            p_extra = p_input->p_fmt->p_extra;
+            i_extra = p_input->p_fmt->i_extra;
+
+            /* Skip 1 header */
+            op.bytes = *(p_extra++) << 8;
+            op.bytes |= (*(p_extra++) & 0xFF);
+            op.packet = p_extra;
+            p_extra += op.bytes;
+            i_extra -= (op.bytes + 2);
+
+            while( j-- )
             {
-                if( p_stream->i_sout_headers < j + 2 )
+                op.bytes = *(p_extra++) << 8;
+                op.bytes |= (*(p_extra++) & 0xFF);
+                op.packet = p_extra;
+                p_extra += op.bytes;
+                i_extra -= (op.bytes + 2);
+                if( i_extra < 0 )
                 {
-                    /* next packets in order: comments and codebooks */
-                    p_og = block_FifoGet( p_mux->pp_inputs[i]->p_fifo );
-                    op.packet = p_og->p_buffer;
-                    op.bytes  = p_og->i_buffer;
-                    op.b_o_s  = 0;
-                    op.e_o_s  = 0;
-                    op.granulepos = 0;
-                    op.packetno = p_stream->i_packet_no++;
-                    ogg_stream_packetin( &p_stream->os, &op );
-                    p_stream->pp_sout_headers[j+1] =
-                        OggStreamFlush( p_mux, &p_stream->os, 0 );
-                    p_stream->i_sout_headers++;
+                    msg_Err( p_mux, "header data corrupted");
+                    op.bytes += i_extra;
                 }
 
-                p_og = block_Duplicate( p_stream->pp_sout_headers[j+1] );
+                op.b_o_s  = 0;
+                op.e_o_s  = 0;
+                op.granulepos = 0;
+                op.packetno = p_stream->i_packet_no++;
+                ogg_stream_packetin( &p_stream->os, &op );
+
+                p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
                 block_ChainAppend( &p_hdr, p_og );
             }
         }
@@ -741,13 +741,13 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
         /* Special case for mp4v and flac */
         if( ( p_stream->i_fourcc == VLC_FOURCC( 'm', 'p', '4', 'v' ) ||
               p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) ) &&
-            p_mux->pp_inputs[i]->p_fmt->i_extra )
+            p_input->p_fmt->i_extra )
         {
             /* Send a packet with the VOL data for mp4v
              * or STREAMINFO for flac */
             msg_Dbg( p_mux, "writing extra data" );
-            op.bytes  = p_mux->pp_inputs[i]->p_fmt->i_extra;
-            op.packet = p_mux->pp_inputs[i]->p_fmt->p_extra;
+            op.bytes  = p_input->p_fmt->i_extra;
+            op.packet = p_input->p_fmt->p_extra;
             if( p_stream->i_fourcc == VLC_FOURCC( 'f', 'l', 'a', 'c' ) )
             {
                 /* Skip the flac stream marker */
index 710045394ec2530a2c1613db0754cc263c416a13..29e9ed6ab470a766b1cb4783245f541c64801509 100644 (file)
@@ -991,6 +991,30 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
             return VLC_EGENERIC;
         }
 
+        case ES_OUT_SET_FMT:
+        {
+            /* This ain't pretty but is need by some demuxers (eg. Ogg )
+             * to update the p_extra data */
+            es = (es_out_id_t*) va_arg( args, es_out_id_t * );
+            es_format_t *p_fmt = (es_format_t*) va_arg( args, es_format_t * );
+            if( es == NULL || !es->p_dec ) return VLC_EGENERIC;
+
+            if( p_fmt->i_extra )
+            {
+                es->fmt.i_extra = p_fmt->i_extra;
+                es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
+                memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
+
+                es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
+                es->p_dec->fmt_in.p_extra =
+                    realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
+                memcpy( es->p_dec->fmt_in.p_extra,
+                        p_fmt->p_extra, p_fmt->i_extra );
+            }
+
+            return VLC_SUCCESS;
+        }
+
         default:
             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
             return VLC_EGENERIC;