]> git.sesse.net Git - vlc/commitdiff
Modified the way xiph codecs headers are transported in VLC.
authorLaurent Aimar <fenrir@videolan.org>
Wed, 17 Feb 2010 00:30:45 +0000 (01:30 +0100)
committerLaurent Aimar <fenrir@videolan.org>
Wed, 17 Feb 2010 22:54:20 +0000 (23:54 +0100)
It makes VLC compatible with FFmpeg vorbis/theora decoder.
It fixes support of big headers (like comments with an art encoded
as a base64 string...).
It simplifies a bit.

modules/access/rtp/xiph.c
modules/codec/kate.c
modules/codec/speex.c
modules/codec/theora.c
modules/codec/vorbis.c
modules/demux/avi/avi.c
modules/demux/mkv/matroska_segment.cpp
modules/demux/ogg.c
modules/demux/xiph.h [new file with mode: 0644]
modules/mux/ogg.c

index 16aae1cc0116a8bc00dc204f10f8508296b73483..83b3eb592cf5fdf4ac4b87d785945616040a5b9d 100644 (file)
@@ -36,6 +36,7 @@
 #include <vlc_plugin.h>
 
 #include <vlc_codecs.h>
+#include "../../demux/xiph.h"
 
 #include "rtp.h"
 
@@ -112,28 +113,20 @@ static ssize_t vorbis_header (void **pextra, const uint8_t *buf, size_t len)
     setuplen = len - (idlen + cmtlen);
 
     /* Create the VLC extra format header */
-    uint8_t *extra = malloc ((size_t)6 + idlen + cmtlen + setuplen);
-    if (extra == NULL)
-        return -1;
-    uint8_t *ptr = *pextra = extra;
-    /* Identification header */
-    *ptr++ = idlen >> 8;
-    *ptr++ = idlen & 0xff;
-    memcpy (ptr, buf, idlen);
-    buf += idlen;
-    ptr += idlen;
-    /* Comments header */
-    *ptr++ = cmtlen >> 8;
-    *ptr++ = cmtlen & 0xff;
-    memcpy (ptr, buf, cmtlen);
-    buf += cmtlen;
-    ptr += cmtlen;
-    /* Setup header */
-    *ptr++ = setuplen >> 8;
-    *ptr++ = setuplen & 0xff;
-    memcpy (ptr, buf, setuplen);
-    ptr += setuplen;
-    return ptr - extra;
+    unsigned sizes[3] = {
+        idlen, cmtlen, setuplen
+    };
+    void *payloads[3] = {
+        buf + 0,
+        buf + idlen,
+        buf + cmtlen
+    };
+    void *extra;
+    int  extra_size;
+    if (xiph_PackHeaders (&extra_size, &extra, sizes, payloads, 3))
+        return -1;;
+    *pextra = extra;
+    return extra_size;
 }
 
 
index e912e035afb977dc30df003341ce3db050848846..4cd7e8993a5d15a34d61d17000c16f716257b6cc 100644 (file)
@@ -33,6 +33,7 @@
 #include <vlc_input.h>
 #include <vlc_codec.h>
 #include <vlc_osd.h>
+#include "../demux/xiph.h"
 
 #include <kate/kate.h>
 #ifdef HAVE_TIGER
@@ -73,8 +74,7 @@ struct decoder_sys_t
     /*
      * Input properties
      */
-    int i_num_headers;
-    int i_headers;
+    bool b_has_headers;
 
     /*
      * Kate properties
@@ -377,8 +377,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     kate_comment_init( &p_sys->kc );
     kate_info_init( &p_sys->ki );
 
-    p_sys->i_num_headers = 0;
-    p_sys->i_headers = 0;
+    p_sys->b_has_headers = false;
 
     /* retrieve options */
     p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
@@ -492,42 +491,14 @@ static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     /* Block to Kate packet */
     kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
 
-    if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
+    if( !p_sys->b_has_headers )
     {
-        /* Headers already available as extra data */
-        p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0];
-        p_sys->i_headers = p_sys->i_num_headers;
-    }
-    else if( kp.nbytes && (p_sys->i_headers==0 || p_sys->i_headers < p_sys->ki.num_headers ))
-    {
-        /* Backup headers as extra data */
-        uint8_t *p_extra;
-
-        p_dec->fmt_in.p_extra = xrealloc( p_dec->fmt_in.p_extra,
-                                      p_dec->fmt_in.i_extra + kp.nbytes + 2 );
-        p_extra = (void*)(((unsigned char*)p_dec->fmt_in.p_extra) + p_dec->fmt_in.i_extra);
-        *(p_extra++) = kp.nbytes >> 8;
-        *(p_extra++) = kp.nbytes & 0xFF;
-
-        memcpy( p_extra, kp.data, kp.nbytes );
-        p_dec->fmt_in.i_extra += kp.nbytes + 2;
-
-        block_Release( *pp_block );
-        p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0];
-        p_sys->i_headers++;
-        return NULL;
-    }
-
-    if( p_sys->i_headers == p_sys->i_num_headers && p_sys->i_num_headers>0 )
-    {
-        if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
+        if( ProcessHeaders( p_dec ) )
         {
-            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->b_has_headers = true;
     }
 
     return ProcessPacket( p_dec, &kp, pp_block );
@@ -540,37 +511,28 @@ static int ProcessHeaders( decoder_t *p_dec )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     kate_packet kp;
-    uint8_t *p_extra;
-    int i_extra;
-    int i_headeridx;
-    int i_ret;
-
-    if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
-
-    p_extra = p_dec->fmt_in.p_extra;
-    i_extra = p_dec->fmt_in.i_extra;
-
-    /* skip number of headers */
-    ++p_extra;
-    --i_extra;
 
-    /* Take care of the initial Kate header */
-    kp.nbytes = *(p_extra++) << 8;
-    kp.nbytes |= (*(p_extra++) & 0xFF);
-    kp.data = p_extra;
-    p_extra += kp.nbytes;
-    i_extra -= (kp.nbytes + 2);
-    if( i_extra < 0 )
-    {
-        msg_Err( p_dec, "header data corrupted");
+    unsigned pi_size[XIPH_MAX_HEADER_COUNT];
+    void     *pp_data[XIPH_MAX_HEADER_COUNT];
+    unsigned i_count;
+    if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
+                           p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
         return VLC_EGENERIC;
+    int i_ret = VLC_SUCCESS;
+    if( i_count < 1 )
+    {
+        i_ret = VLC_EGENERIC;
+        goto end;
     }
 
+    /* Take care of the initial Kate header */
+    kp.nbytes = pi_size[0];
+    kp.data   = pp_data[0];
     i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
     if( i_ret < 0 )
     {
         msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
-        return VLC_EGENERIC;
+        goto end;
     }
 
     msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
@@ -579,24 +541,15 @@ static int ProcessHeaders( decoder_t *p_dec )
              p_sys->ki.granule_shift);
 
     /* parse all remaining header packets */
-    for( i_headeridx = 1; i_headeridx < p_sys->ki.num_headers; ++i_headeridx )
+    for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
     {
-        kp.nbytes = *(p_extra++) << 8;
-        kp.nbytes |= (*(p_extra++) & 0xFF);
-        kp.data = p_extra;
-        p_extra += kp.nbytes;
-        i_extra -= (kp.nbytes + 2);
-        if( i_extra < 0 )
-        {
-            msg_Err( p_dec, "header %d data corrupted", i_headeridx );
-            return VLC_EGENERIC;
-        }
-
+        kp.nbytes = pi_size[i_headeridx];
+        kp.data   = pp_data[i_headeridx];
         i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
         if( i_ret < 0 )
         {
             msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
-            return VLC_EGENERIC;
+            goto end;
         }
 
         /* header 1 is comments */
@@ -631,7 +584,10 @@ static int ProcessHeaders( decoder_t *p_dec )
     }
 #endif
 
-    return VLC_SUCCESS;
+end:
+    for( unsigned i = 0; i < i_count; i++ )
+        free( pp_data[i] );
+    return i_ret < 0 ? VLC_EGENERIC : VLC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -668,12 +624,10 @@ static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
     else
 #endif
     {
-        if( p_sys->i_headers >= p_sys->i_num_headers && p_sys->i_num_headers > 0)
-            p_buf = DecodePacket( p_dec, p_kp, p_block );
-        else
-            p_buf = NULL;
+        p_buf = DecodePacket( p_dec, p_kp, p_block );
 
-        if( p_block ) block_Release( p_block );
+        if( p_block )
+            block_Release( p_block );
     }
 
     return p_buf;
index 7a171f510943ec13a5ee30072453899e78f522ee..b8a99a37815f99a837f24465f73286cc49215dec 100644 (file)
@@ -33,6 +33,7 @@
 #include <vlc_input.h>
 #include <vlc_codec.h>
 #include <vlc_aout.h>
+#include "../demux/xiph.h"
 
 #include <ogg/ogg.h>
 #include <speex/speex.h>
@@ -150,7 +151,7 @@ struct decoder_sys_t
     /*
      * Input properties
      */
-    int i_headers;
+    bool b_has_headers;
     int i_frame_in_packet;
 
     /*
@@ -214,6 +215,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->p_sys->bits.buf_size = 0;
     p_dec->p_sys->b_packetizer = false;
     p_dec->p_sys->rtp_rate = p_dec->fmt_in.audio.i_rate;
+    p_dec->p_sys->b_has_headers = false;
 
     date_Set( &p_sys->end_date, 0 );
 
@@ -242,7 +244,6 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
         DecodeBlock;
 
-    p_sys->i_headers = 0;
     p_sys->p_state = NULL;
     p_sys->p_header = NULL;
     p_sys->i_frame_in_packet = 0;
@@ -298,38 +299,14 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     oggpacket.packetno = 0;
 
     /* Check for headers */
-    if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
+    if( !p_sys->b_has_headers )
     {
-        p_sys->i_headers = 2;
-    }
-    else if( oggpacket.bytes && p_sys->i_headers < 2 )
-    {
-        uint8_t *p_extra;
-
-        p_dec->fmt_in.p_extra = xrealloc( p_dec->fmt_in.p_extra,
-                                p_dec->fmt_in.i_extra + oggpacket.bytes + 2 );
-        p_extra = ((uint8_t *)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 )
+        if( ProcessHeaders( p_dec ) )
         {
-            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->b_has_headers = true;
     }
 
     return ProcessPacket( p_dec, &oggpacket, pp_block );
@@ -342,50 +319,34 @@ 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;
+    unsigned pi_size[XIPH_MAX_HEADER_COUNT];
+    void     *pp_data[XIPH_MAX_HEADER_COUNT];
+    unsigned i_count;
+    if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
+                           p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
+        return VLC_EGENERIC;
+    if( i_count < 2 )
+        goto error;
 
     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;
-    }
-
-    /* Take care of the initial Speex header */
+    oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
+    oggpacket.bytes  = pi_size[0];
+    oggpacket.packet = pp_data[0];
     if( ProcessInitialHeader( p_dec, &oggpacket ) != VLC_SUCCESS )
     {
         msg_Err( p_dec, "initial Speex header is corrupted" );
-        return VLC_EGENERIC;
+        goto error;
     }
 
     /* 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;
-    }
-
+    oggpacket.bytes  = pi_size[1];
+    oggpacket.packet = pp_data[1];
     ParseSpeexComments( p_dec, &oggpacket );
 
     if( p_sys->b_packetizer )
@@ -397,7 +358,14 @@ static int ProcessHeaders( decoder_t *p_dec )
                 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
     }
 
+    for( unsigned i = 0; i < i_count; i++ )
+        free( pp_data[i] );
     return VLC_SUCCESS;
+
+error:
+    for( unsigned i = 0; i < i_count; i++ )
+        free( pp_data[i] );
+    return VLC_EGENERIC;
 }
 
 /*****************************************************************************
@@ -591,14 +559,10 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
     }
     else
     {
-        aout_buffer_t *p_aout_buffer;
-
-        if( p_sys->i_headers >= p_sys->p_header->extra_headers + 2 )
-            p_aout_buffer = DecodePacket( p_dec, p_oggpacket );
-        else
-            p_aout_buffer = NULL; /* Skip headers */
+        aout_buffer_t *p_aout_buffer = DecodePacket( p_dec, p_oggpacket );
 
-        if( p_block ) block_Release( p_block );
+        if( p_block )
+            block_Release( p_block );
         return p_aout_buffer;
     }
 }
@@ -796,15 +760,10 @@ static block_t *SendPacket( decoder_t *p_dec, block_t *p_block )
     /* Date management */
     p_block->i_dts = p_block->i_pts = date_Get( &p_sys->end_date );
 
-    if( p_sys->i_headers >= p_sys->p_header->extra_headers + 2 )
-    {
-        p_block->i_length =
-            date_Increment( &p_sys->end_date,
-                                p_sys->p_header->frame_size ) -
-            p_block->i_pts;
-    }
-    else
-        p_block->i_length = 0;
+    p_block->i_length =
+        date_Increment( &p_sys->end_date,
+                            p_sys->p_header->frame_size ) -
+        p_block->i_pts;
 
     return p_block;
 }
index d9345003ceb38d2441b7c0f55092ec450456db06..57d90d5e6abb7e0406c6cc6a707f0df4821c8f17 100644 (file)
@@ -33,6 +33,8 @@
 #include <vlc_codec.h>
 #include <vlc_sout.h>
 #include <vlc_input.h>
+#include "../demux/xiph.h"
+
 #include <ogg/ogg.h>
 
 #include <theora/theora.h>
@@ -48,7 +50,7 @@ struct decoder_sys_t
     /*
      * Input properties
      */
-    int i_headers;
+    bool b_has_headers;
 
     /*
      * Theora properties
@@ -143,7 +145,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
         return VLC_ENOMEM;
     p_dec->p_sys->b_packetizer = false;
-
+    p_sys->b_has_headers = false;
     p_sys->i_pts = VLC_TS_INVALID;
     p_sys->b_decoded_first_keyframe = false;
 
@@ -161,8 +163,6 @@ static int OpenDecoder( vlc_object_t *p_this )
     theora_comment_init( &p_sys->tc );
     theora_info_init( &p_sys->ti );
 
-    p_sys->i_headers = 0;
-
     return VLC_SUCCESS;
 }
 
@@ -205,40 +205,14 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     oggpacket.packetno = 0;
 
     /* Check for headers */
-    if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
-    {
-        /* Headers already available as extra data */
-        p_sys->i_headers = 3;
-    }
-    else if( oggpacket.bytes && p_sys->i_headers < 3 )
+    if( !p_sys->b_has_headers )
     {
-        /* Backup headers as extra data */
-        uint8_t *p_extra;
-
-        p_dec->fmt_in.p_extra = xrealloc( p_dec->fmt_in.p_extra,
-                                p_dec->fmt_in.i_extra + oggpacket.bytes + 2 );
-        p_extra = ((uint8_t *)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 == 3 )
-    {
-        if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
+        if( ProcessHeaders( p_dec ) )
         {
-            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->b_has_headers = true;
     }
 
     return ProcessPacket( p_dec, &oggpacket, pp_block );
@@ -251,34 +225,28 @@ 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;
+    unsigned pi_size[XIPH_MAX_HEADER_COUNT];
+    void     *pp_data[XIPH_MAX_HEADER_COUNT];
+    unsigned i_count;
+    if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
+                           p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
+        return VLC_EGENERIC;
+    if( i_count < 3 )
+        goto error;
 
     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;
-    }
-
+    oggpacket.b_o_s  = 1; /* yes this actually is a b_o_s packet :) */
+    oggpacket.bytes  = pi_size[0];
+    oggpacket.packet = pp_data[0];
     if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
     {
         msg_Err( p_dec, "this bitstream does not contain Theora video data" );
-        return VLC_EGENERIC;
+        goto error;
     }
 
     /* Set output properties */
@@ -351,23 +319,13 @@ static int ProcessHeaders( decoder_t *p_dec )
     }
 
     /* 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;
-    }
-
-    /* The next packet in order is the comments header */
+    oggpacket.b_o_s  = 0;
+    oggpacket.bytes  = pi_size[1];
+    oggpacket.packet = pp_data[1];
     if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
     {
         msg_Err( p_dec, "2nd Theora header is corrupted" );
-        return VLC_EGENERIC;
+        goto error;
     }
 
     ParseTheoraComments( p_dec );
@@ -375,23 +333,13 @@ static int ProcessHeaders( decoder_t *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;
-    }
-
-    /* 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.b_o_s  = 0;
+    oggpacket.bytes  = pi_size[2];
+    oggpacket.packet = pp_data[2];
     if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
     {
         msg_Err( p_dec, "3rd Theora header is corrupted" );
-        return VLC_EGENERIC;
+        goto error;
     }
 
     if( !p_sys->b_packetizer )
@@ -408,7 +356,14 @@ static int ProcessHeaders( decoder_t *p_dec )
                 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
     }
 
+    for( unsigned i = 0; i < i_count; i++ )
+        free( pp_data[i] );
     return VLC_SUCCESS;
+
+error:
+    for( unsigned i = 0; i < i_count; i++ )
+        free( pp_data[i] );
+    return VLC_EGENERIC;
 }
 
 /*****************************************************************************
@@ -442,21 +397,15 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
         /* Date management */
         p_block->i_dts = p_block->i_pts = p_sys->i_pts;
 
-        if( p_sys->i_headers >= 3 )
-            p_block->i_length = p_sys->i_pts - p_block->i_pts;
-        else
-            p_block->i_length = 0;
+        p_block->i_length = p_sys->i_pts - p_block->i_pts;
 
         p_buf = p_block;
     }
     else
     {
-        if( p_sys->i_headers >= 3 )
-            p_buf = DecodePacket( p_dec, p_oggpacket );
-        else
-            p_buf = NULL;
-
-        if( p_block ) block_Release( p_block );
+        p_buf = DecodePacket( p_dec, p_oggpacket );
+        if( p_block )
+            block_Release( p_block );
     }
 
     /* Date management */
index 3b8fba2d6900f6be685eef14a1babe6af902f0c9..4fe9b356b335b70f8362a4e52d82d46af60d43aa 100644 (file)
@@ -37,6 +37,7 @@
 #include <vlc_aout.h>
 #include <vlc_input.h>
 #include <vlc_sout.h>
+#include "../demux/xiph.h"
 
 #include <ogg/ogg.h>
 
@@ -60,10 +61,7 @@ struct decoder_sys_t
     /* Module mode */
     bool b_packetizer;
 
-    /*
-     * Input properties
-     */
-    int i_headers;
+    bool            b_has_headers;
 
     /*
      * Vorbis properties
@@ -236,7 +234,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     date_Set( &p_sys->end_date, 0 );
     p_sys->i_last_block_size = 0;
     p_sys->b_packetizer = false;
-    p_sys->i_headers = 0;
+    p_sys->b_has_headers = false;
 
     /* Take care of vorbis init */
     vorbis_info_init( &p_sys->vi );
@@ -307,41 +305,14 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     oggpacket.packetno = 0;
 
     /* Check for headers */
-    if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
-    {
-        /* Headers already available as extra data */
-        msg_Dbg( p_dec, "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 = xrealloc( p_dec->fmt_in.p_extra,
-                                p_dec->fmt_in.i_extra + oggpacket.bytes + 2 );
-        p_extra = (uint8_t *)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 == 3 )
+    if( !p_sys->b_has_headers )
     {
-        if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
+        if( ProcessHeaders( p_dec ) )
         {
-            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->b_has_headers = true;
     }
 
     return ProcessPacket( p_dec, &oggpacket, pp_block );
@@ -354,34 +325,28 @@ 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;
+    unsigned pi_size[XIPH_MAX_HEADER_COUNT];
+    void     *pp_data[XIPH_MAX_HEADER_COUNT];
+    unsigned i_count;
+    if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
+                           p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
+        return VLC_EGENERIC;
+    if( i_count < 3 )
+        goto error;
 
     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;
-    }
-
+    oggpacket.b_o_s  = 1; /* yes this actually is a b_o_s packet :) */
+    oggpacket.bytes  = pi_size[0];
+    oggpacket.packet = pp_data[0];
     if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
     {
         msg_Err( p_dec, "this bitstream does not contain Vorbis audio data");
-        return VLC_EGENERIC;
+        goto error;
     }
 
     /* Setup the format */
@@ -392,7 +357,7 @@ static int ProcessHeaders( decoder_t *p_dec )
     {
         msg_Err( p_dec, "invalid number of channels (not between 1 and 9): %i",
                  p_dec->fmt_out.audio.i_channels );
-        return VLC_EGENERIC;
+        goto error;
     }
 
     p_dec->fmt_out.audio.i_physical_channels =
@@ -406,38 +371,22 @@ static int ProcessHeaders( decoder_t *p_dec )
              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;
-    }
-
+    oggpacket.b_o_s  = 0;
+    oggpacket.bytes  = pi_size[1];
+    oggpacket.packet = pp_data[1];
     if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
     {
         msg_Err( p_dec, "2nd Vorbis header is corrupted" );
-        return VLC_EGENERIC;
+        goto error;
     }
     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;
-    }
-
+    oggpacket.b_o_s  = 0;
+    oggpacket.bytes  = pi_size[2];
+    oggpacket.packet = pp_data[2];
     if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
     {
         msg_Err( p_dec, "3rd Vorbis header is corrupted" );
@@ -454,7 +403,7 @@ static int ProcessHeaders( decoder_t *p_dec )
     {
         p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
         p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
-                                                  p_dec->fmt_out.i_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 );
     }
@@ -462,7 +411,14 @@ static int ProcessHeaders( decoder_t *p_dec )
     ConfigureChannelOrder(p_sys->pi_chan_table, p_sys->vi.channels,
             p_dec->fmt_out.audio.i_physical_channels, true);
 
+    for( unsigned i = 0; i < i_count; i++ )
+        free( pp_data[i] );
     return VLC_SUCCESS;
+
+error:
+    for( unsigned i = 0; i < i_count; i++ )
+        free( pp_data[i] );
+    return VLC_EGENERIC;
 }
 
 /*****************************************************************************
@@ -496,14 +452,9 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
     }
     else
     {
-        aout_buffer_t *p_aout_buffer;
-
-        if( p_sys->i_headers >= 3 )
-            p_aout_buffer = DecodePacket( p_dec, p_oggpacket );
-        else
-            p_aout_buffer = NULL;
-
-        if( p_block ) block_Release( p_block );
+        aout_buffer_t *p_aout_buffer = DecodePacket( p_dec, p_oggpacket );
+        if( p_block )
+            block_Release( p_block );
         return p_aout_buffer;
     }
 }
@@ -586,10 +537,7 @@ static block_t *SendPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
     /* Date management */
     p_block->i_dts = p_block->i_pts = date_Get( &p_sys->end_date );
 
-    if( p_sys->i_headers >= 3 )
-        p_block->i_length = date_Increment( &p_sys->end_date, i_samples ) - p_block->i_pts;
-    else
-        p_block->i_length = 0;
+    p_block->i_length = date_Increment( &p_sys->end_date, i_samples ) - p_block->i_pts;
 
     return p_block;
 }
@@ -730,7 +678,7 @@ static void CloseDecoder( vlc_object_t *p_this )
     decoder_t *p_dec = (decoder_t *)p_this;
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if( !p_sys->b_packetizer && p_sys->i_headers > 3 )
+    if( !p_sys->b_packetizer && p_sys->b_has_headers )
     {
         vorbis_block_clear( &p_sys->vb );
         vorbis_dsp_clear( &p_sys->vd );
index 523537624fc0e0dd94ce2583d87ee40adb2b0b0c..edc38fac902bba3d742f630906ea0ea6030089aa 100644 (file)
@@ -431,73 +431,6 @@ static int Open( vlc_object_t * p_this )
                 fmt.p_extra = malloc( fmt.i_extra );
                 if( !fmt.p_extra ) goto error;
                 memcpy( fmt.p_extra, &p_auds->p_wf[1], fmt.i_extra );
-
-                /* Rewrite the vorbis headers from Xiph-like format
-                 * to VLC internal format
-                 *
-                 * Xiph format:
-                 *  - 1st byte == N, is the number of packets - 1
-                 *  - Following bytes are the size of the N first packets:
-                 *      while( *p == 0xFF ) { size += 0xFF; p++ } size += *p;
-                 *      (the size of the last packet is the size of remaining
-                 *      data in the buffer)
-                 *  - Finally, all the packets concatenated
-                 *
-                 * VLC format:
-                 *  - Size of the packet on 16 bits (big endian) FIXME: should be 32 bits to be safe
-                 *  - The packet itself
-                 *  - Size of the next packet, and so on ...
-                 */
-
-                if( tk->i_codec == VLC_CODEC_VORBIS )
-                {
-                    uint8_t *p_extra = fmt.p_extra; 
-                    size_t i_extra = fmt.i_extra;
-
-                    if( i_extra <= 1 ) break;
-                    if( *p_extra++ != 2 ) break; /* 3 packets - 1 = 2 */
-                    i_extra--;
-
-                    size_t i_identifier_len = 0;
-                    while( *p_extra == 0xFF )
-                    {
-                        i_identifier_len += 0xFF;
-                        p_extra++;
-                        if( --i_extra <= 1 ) break;
-                    }
-                    i_identifier_len += *p_extra++;
-                    if( i_identifier_len > --i_extra ) break;
-
-                    size_t i_comment_len = 0;
-                    while( *p_extra == 0xFF )
-                    {
-                        i_comment_len += 0xFF;
-                        p_extra++;
-                        if( --i_extra <= 1 ) break;
-                    }
-                    i_comment_len += *p_extra++;
-                    if( i_comment_len > --i_extra ) break;
-                    size_t i_cookbook_len = i_extra;
-
-                    size_t i_headers_size = 3  * 2 + i_identifier_len +
-                                            i_comment_len + i_cookbook_len;
-                    uint8_t *p_out = malloc( i_headers_size );
-                    if( !p_out ) goto error;
-                    free( fmt.p_extra );
-                    fmt.p_extra = p_out;
-                    fmt.i_extra = i_headers_size;
-                    #define copy_packet( len ) \
-                        *p_out++ = len >> 8; \
-                        *p_out++ = len & 0xFF; \
-                        memcpy( p_out, p_extra, len ); \
-                        p_out += len; \
-                        p_extra += len;
-                    copy_packet( i_identifier_len );
-                    copy_packet( i_comment_len );
-                    copy_packet( i_cookbook_len );
-                    #undef copy_packet
-                    break;
-                }
                 break;
 
             case( AVIFOURCC_vids ):
index abb32c8b63fcba80619cc2b6936136cf8962b382..a9c0faf97895f5fda513d88bf37c01a6720459ca 100644 (file)
@@ -679,73 +679,10 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
         }
         else if( !strncmp( tracks[i_track]->psz_codec, "V_THEORA", 8 ) )
         {
-            uint8_t *p_data = tracks[i_track]->p_extra_data;
             tracks[i_track]->fmt.i_codec = VLC_CODEC_THEORA;
-            if( tracks[i_track]->i_extra_data >= 4 ) {
-                if( p_data[0] == 2 ) {
-                    int i = 1;
-                    int i_size1 = 0, i_size2 = 0;
-                    p_data++;
-                    /* read size of first header packet */
-                    while( *p_data == 0xFF &&
-                           i < tracks[i_track]->i_extra_data )
-                    {
-                        i_size1 += *p_data;
-                        p_data++;
-                        i++;
-                    }
-                    i_size1 += *p_data;
-                    p_data++;
-                    i++;
-                    msg_Dbg( &sys.demuxer, "first theora header size %d", i_size1 );
-                    /* read size of second header packet */
-                    while( *p_data == 0xFF &&
-                           i < tracks[i_track]->i_extra_data )
-                    {
-                        i_size2 += *p_data;
-                        p_data++;
-                        i++;
-                    }
-                    i_size2 += *p_data;
-                    p_data++;
-                    i++;
-                    int i_size3 = tracks[i_track]->i_extra_data - i - i_size1
-                        - i_size2;
-                    msg_Dbg( &sys.demuxer, "second theora header size %d", i_size2 );
-                    msg_Dbg( &sys.demuxer, "third theora header size %d", i_size3 );
-                    tracks[i_track]->fmt.i_extra = i_size1 + i_size2 + i_size3
-                        + 6;
-                    if( i_size1 > 0 && i_size2 > 0 && i_size3 > 0  ) {
-                        tracks[i_track]->fmt.p_extra =
-                            xmalloc( tracks[i_track]->fmt.i_extra );
-                        uint8_t *p_out = (uint8_t*)tracks[i_track]->fmt.p_extra;
-                        *p_out++ = (i_size1>>8) & 0xFF;
-                        *p_out++ = i_size1 & 0xFF;
-                        memcpy( p_out, p_data, i_size1 );
-                        p_data += i_size1;
-                        p_out += i_size1;
-                        *p_out++ = (i_size2>>8) & 0xFF;
-                        *p_out++ = i_size2 & 0xFF;
-                        memcpy( p_out, p_data, i_size2 );
-                        p_data += i_size2;
-                        p_out += i_size2;
-
-                        *p_out++ = (i_size3>>8) & 0xFF;
-                        *p_out++ = i_size3 & 0xFF;
-                        memcpy( p_out, p_data, i_size3 );
-                        p_data += i_size3;
-                        p_out += i_size3;
-                    }
-                    else
-                    {
-                        msg_Err( &sys.demuxer, "inconsistent theora extradata" );
-                    }
-                }
-                else {
-                    msg_Err( &sys.demuxer, "Wrong number of ogg packets with theora headers (%d)", p_data[0] + 1 );
-                }
-            }
+            tracks[i_track]->fmt.i_extra = tracks[i_track]->i_extra_data;
+            tracks[i_track]->fmt.p_extra = xmalloc( tracks[i_track]->i_extra_data );
+            memcpy( tracks[i_track]->fmt.p_extra,tracks[i_track]->p_extra_data, tracks[i_track]->i_extra_data );
         }
         else if( !strncmp( tracks[i_track]->psz_codec, "V_REAL/RV", 9 ) )
         {
@@ -879,41 +816,10 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
         }
         else if( !strcmp( tracks[i_track]->psz_codec, "A_VORBIS" ) )
         {
-            int i, i_offset = 1, i_size[3], i_extra;
-            uint8_t *p_extra;
-
             tracks[i_track]->fmt.i_codec = VLC_CODEC_VORBIS;
-
-            /* Split the 3 headers */
-            if( tracks[i_track]->p_extra_data[0] != 0x02 )
-                msg_Err( &sys.demuxer, "invalid vorbis header" );
-
-            for( i = 0; i < 2; i++ )
-            {
-                i_size[i] = 0;
-                while( i_offset < tracks[i_track]->i_extra_data )
-                {
-                    i_size[i] += tracks[i_track]->p_extra_data[i_offset];
-                    if( tracks[i_track]->p_extra_data[i_offset++] != 0xff ) break;
-                }
-            }
-
-            i_size[0] = __MIN(i_size[0], tracks[i_track]->i_extra_data - i_offset);
-            i_size[1] = __MIN(i_size[1], tracks[i_track]->i_extra_data -i_offset -i_size[0]);
-            i_size[2] = tracks[i_track]->i_extra_data - i_offset - i_size[0] - i_size[1];
-
-            tracks[i_track]->fmt.i_extra = 3 * 2 + i_size[0] + i_size[1] + i_size[2];
-            tracks[i_track]->fmt.p_extra = xmalloc( tracks[i_track]->fmt.i_extra );
-            p_extra = (uint8_t *)tracks[i_track]->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, tracks[i_track]->p_extra_data + i_offset + i_extra,
-                        i_size[i] );
-                p_extra += i_size[i];
-                i_extra += i_size[i];
-            }
+            tracks[i_track]->fmt.i_extra = tracks[i_track]->i_extra_data;
+            tracks[i_track]->fmt.p_extra = xmalloc( tracks[i_track]->i_extra_data );
+            memcpy( tracks[i_track]->fmt.p_extra,tracks[i_track]->p_extra_data, tracks[i_track]->i_extra_data );
         }
         else if( !strncmp( tracks[i_track]->psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
                  !strncmp( tracks[i_track]->psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
@@ -1035,47 +941,9 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
             tracks[i_track]->fmt.i_codec = VLC_CODEC_KATE;
             tracks[i_track]->fmt.subs.psz_encoding = strdup( "UTF-8" );
 
-            /* Recover the number of headers to expect */
-            num_headers = tracks[i_track]->p_extra_data[0]+1;
-            msg_Dbg( &sys.demuxer, "kate in mkv detected: %d headers in %u bytes",
-                num_headers, tracks[i_track]->i_extra_data);
-
-            /* this won't overflow the stack as is can allocate only 1020 bytes max */
-            uint16_t pi_size[num_headers];
-
-            /* Split the headers */
-            size_so_far = 0;
-            for( i = 0; i < num_headers-1; i++ )
-            {
-                pi_size[i] = 0;
-                while( i_offset < tracks[i_track]->i_extra_data )
-                {
-                    pi_size[i] += tracks[i_track]->p_extra_data[i_offset];
-                    if( tracks[i_track]->p_extra_data[i_offset++] != 0xff ) break;
-                }
-                msg_Dbg( &sys.demuxer, "kate header %d is %d bytes", i, pi_size[i]);
-                size_so_far += pi_size[i];
-            }
-            pi_size[num_headers-1] = tracks[i_track]->i_extra_data - (size_so_far+i_offset);
-            msg_Dbg( &sys.demuxer, "kate last header (%d) is %d bytes", num_headers-1, pi_size[num_headers-1]);
-
-            tracks[i_track]->fmt.i_extra = 1 + num_headers * 2 + size_so_far + pi_size[num_headers-1];
-            tracks[i_track]->fmt.p_extra = xmalloc( tracks[i_track]->fmt.i_extra );
-
-            p_extra = (uint8_t *)tracks[i_track]->fmt.p_extra;
-            i_extra = 0;
-            *(p_extra++) = num_headers;
-            ++i_extra;
-            for( i = 0; i < num_headers; i++ )
-            {
-                *(p_extra++) = pi_size[i] >> 8;
-                *(p_extra++) = pi_size[i] & 0xFF;
-                memcpy( p_extra, tracks[i_track]->p_extra_data + i_offset + i_extra-1,
-                        pi_size[i] );
-
-                p_extra += pi_size[i];
-                i_extra += pi_size[i];
-            }
+            tracks[i_track]->fmt.i_extra = tracks[i_track]->i_extra_data;
+            tracks[i_track]->fmt.p_extra = xmalloc( tracks[i_track]->i_extra_data );
+            memcpy( tracks[i_track]->fmt.p_extra,tracks[i_track]->p_extra_data, tracks[i_track]->i_extra_data );
         }
         else if( !strcmp( tracks[i_track]->psz_codec, "S_TEXT/ASCII" ) )
         {
index b92ed954c9fcf54f54c10dfc5d60b6620e064be2..4ccc546210484424532fbe560eb9e8e4ac1fcaaf 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <vlc_codecs.h>
 #include <vlc_bits.h>
+#include "xiph.h"
 #include "vorbis.h"
 #include "kate_categories.h"
 
@@ -78,7 +79,7 @@ typedef struct logical_stream_s
      * them to the decoder. */
     int              b_force_backup;
     int              i_packets_backup;
-    uint8_t          *p_headers;
+    void             *p_headers;
     int              i_headers;
 
     /* program clock reference (in units of 90kHz) derived from the previous
@@ -624,10 +625,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
 
     if( p_stream->b_force_backup )
     {
-        uint8_t *p_sav;
-        bool b_store_size = true;
-        bool b_store_num_headers = false;
-
+        bool b_xiph;
         p_stream->i_packets_backup++;
         switch( p_stream->fmt.i_codec )
         {
@@ -635,6 +633,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
         case VLC_CODEC_SPEEX:
         case VLC_CODEC_THEORA:
             if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0;
+            b_xiph = true;
             break;
 
         case VLC_CODEC_FLAC:
@@ -652,44 +651,45 @@ static void Ogg_DecodePacket( demux_t *p_demux,
                     p_oggpacket->bytes -= 9;
                 }
             }
-            b_store_size = false;
+            b_xiph = false;
             break;
 
         case VLC_CODEC_KATE:
-            if( p_stream->i_packets_backup == 1)
-                b_store_num_headers = true;
             if( p_stream->i_packets_backup == p_stream->i_kate_num_headers ) p_stream->b_force_backup = 0;
+            b_xiph = true;
             break;
 
         default:
             p_stream->b_force_backup = 0;
+            b_xiph = false;
             break;
         }
 
         /* Backup the ogg packet (likely an header packet) */
-        p_stream->p_headers =
-            realloc( p_sav = p_stream->p_headers, p_stream->i_headers +
-                     p_oggpacket->bytes + (b_store_size ? 2 : 0) + (b_store_num_headers ? 1 : 0) );
-        if( !p_stream->p_headers )
-            p_stream->p_headers = p_sav;
-        else
+        if( !b_xiph )
         {
-            uint8_t *p_extra = p_stream->p_headers + p_stream->i_headers;
-
-            if( b_store_num_headers )
+            void *p_org = p_stream->p_headers;
+            p_stream->i_headers += p_oggpacket->bytes;
+            p_stream->p_headers = realloc( p_stream->p_headers, p_stream->i_headers );
+            if( p_stream->p_headers )
             {
-                /* Kate streams store the number of headers in the first header,
-                   so we can't just test for 3 as Vorbis/Theora */
-                *(p_extra++) = p_stream->i_kate_num_headers;
+                memcpy( p_stream->p_headers, p_oggpacket->packet, p_stream->i_headers );
             }
-            if( b_store_size )
+            else
             {
-                *(p_extra++) = p_oggpacket->bytes >> 8;
-                *(p_extra++) = p_oggpacket->bytes & 0xFF;
+                p_stream->i_headers = 0;
+                p_stream->p_headers = NULL;
+                free( p_org );
             }
-            memcpy( p_extra, p_oggpacket->packet, p_oggpacket->bytes );
-            p_stream->i_headers += p_oggpacket->bytes + (b_store_size ? 2 : 0) + (b_store_num_headers ? 1 : 0);
-
+        }
+        else if( xiph_AppendHeaders( &p_stream->i_headers, &p_stream->p_headers,
+                                     p_oggpacket->bytes, p_oggpacket->packet ) )
+        {
+            p_stream->i_headers = 0;
+            p_stream->p_headers = NULL;
+        }
+        if( p_stream->i_headers > 0 )
+        {
             if( !p_stream->b_force_backup )
             {
                 /* Last header received, commit changes */
@@ -1464,33 +1464,34 @@ static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_strea
  */
 static bool Ogg_IsVorbisFormatCompatible( const es_format_t *p_new, const es_format_t *p_old )
 {
-    int i_new = 0;
-    int i_old = 0;
-    int i;
-
-    for( i = 0; i < 3; i++ )
+    unsigned pi_new_size[XIPH_MAX_HEADER_COUNT];
+    void     *pp_new_data[XIPH_MAX_HEADER_COUNT];
+    unsigned i_new_count;
+    if( xiph_SplitHeaders(pi_new_size, pp_new_data, &i_new_count, p_new->i_extra, p_new->p_extra ) )
+        i_new_count = 0;
+
+    unsigned pi_old_size[XIPH_MAX_HEADER_COUNT];
+    void     *pp_old_data[XIPH_MAX_HEADER_COUNT];
+    unsigned i_old_count;
+    if( xiph_SplitHeaders(pi_old_size, pp_old_data, &i_old_count, p_old->i_extra, p_old->p_extra ) )
+        i_old_count = 0;
+
+    bool b_match = i_new_count == i_old_count;
+    for( unsigned i = 0; i < i_new_count && b_match; i++ )
     {
-        const uint8_t *p_new_extra = ( const uint8_t*)p_new->p_extra + i_new;
-        const uint8_t *p_old_extra = ( const uint8_t*)p_old->p_extra + i_old;
-
-        if( p_new->i_extra < i_new+2 || p_old->i_extra < i_old+2 )
-            return false;
-
-        const int i_new_size = GetWBE( &p_new_extra[0] );
-        const int i_old_size = GetWBE( &p_old_extra[0] );
-
-        if( i != 1 ) /* Ignore vorbis comment */
-        {
-            if( i_new_size != i_old_size )
-                return false;
-            if( memcmp( &p_new_extra[2], &p_old_extra[2], i_new_size ) )
-                return false;
-        }
-
-        i_new += 2 + i_new_size;
-        i_old += 2 + i_old_size;
+        /* Ignore vorbis comment */
+        if( i == 1 )
+            continue;
+        if( pi_new_size[i] != pi_old_size[i] ||
+            memcmp( pp_new_data[i], pp_old_data[i], pi_new_size[i] ) )
+            b_match = false;
     }
-    return true;
+
+    for( unsigned i = 0; i < i_new_count; i++ )
+        free( pp_new_data[i] );
+    for( unsigned i = 0; i < i_old_count; i++ )
+        free( pp_old_data[i] );
+    return b_match;
 }
 static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *p_stream )
 {
@@ -1507,44 +1508,22 @@ static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *
 
     return !b_compatible;
 }
-static void Ogg_ExtractXiphMeta( demux_t *p_demux, const uint8_t *p_headers, int i_headers, int i_skip, bool b_has_num_headers )
+static void Ogg_ExtractXiphMeta( demux_t *p_demux, const void *p_headers, unsigned i_headers, unsigned i_skip )
 {
     demux_sys_t *p_ogg = p_demux->p_sys;
 
-    if (b_has_num_headers)
-    {
-        if (i_headers <= 0)
-            return;
-        /* number of headers on a byte, we're interested in the second header, so should be at least 2 to go on */
-        if (*p_headers++ < 2)
-            return;
-        --i_headers;
-    }
-
-    if( i_headers <= 2 )
-        return;
-
-    /* Skip first packet */
-    const int i_tmp = GetWBE( &p_headers[0] );
-    if( i_tmp > i_headers-2 )
-        return;
-    p_headers += 2 + i_tmp;
-    i_headers -= 2 + i_tmp;
-
-    if( i_headers <= 2 )
-        return;
-
-    /* */
-    int i_comment = GetWBE( &p_headers[0] );
-    const uint8_t *p_comment = &p_headers[2];
-    if( i_comment > i_headers - 2 )
-        return;
-
-    if( i_comment <= i_skip )
+    unsigned pi_size[XIPH_MAX_HEADER_COUNT];
+    void     *pp_data[XIPH_MAX_HEADER_COUNT];
+    unsigned i_count;
+    if( xiph_SplitHeaders( pi_size, pp_data, &i_count, i_headers, p_headers ) )
         return;
 
     /* TODO how to handle multiple comments properly ? */
-    vorbis_ParseComment( &p_ogg->p_meta, &p_comment[i_skip], i_comment - i_skip );
+    if( i_count >= 2 && pi_size[1] > i_skip )
+        vorbis_ParseComment( &p_ogg->p_meta, (uint8_t*)pp_data[1] + i_skip, pi_size[1] - i_skip );
+
+    for( unsigned i = 0; i < i_count; i++ )
+        free( pp_data[i] );
 }
 static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8_t *p_headers, int i_headers )
 {
@@ -1554,19 +1533,19 @@ static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8
     {
     /* 3 headers with the 2° one being the comments */
     case VLC_CODEC_VORBIS:
-        Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6, false );
+        Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6 );
         break;
     case VLC_CODEC_THEORA:
-        Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6, false );
+        Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6 );
         break;
     case VLC_CODEC_SPEEX:
-        Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 0, false );
+        Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 0 );
         break;
 
     /* N headers with the 2° one being the comments */
     case VLC_CODEC_KATE:
-        /* 1 byte for header type, 7 bit for magic, 1 reserved zero byte */
-        Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+7+1, true );
+        /* 1 byte for header type, 7 bytes for magic, 1 reserved zero byte */
+        Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+7+1 );
         break;
 
     /* TODO */
diff --git a/modules/demux/xiph.h b/modules/demux/xiph.h
new file mode 100644 (file)
index 0000000..dc1df97
--- /dev/null
@@ -0,0 +1,149 @@
+/*****************************************************************************
+ * xiph.h: Xiph helpers
+ *****************************************************************************
+ * Copyright (C) 2010 Laurent Aimar
+ * $Id$
+ *
+ * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include <assert.h>
+#define XIPH_MAX_HEADER_COUNT (256)
+
+static inline int xiph_SplitHeaders(unsigned packet_size[], void *packet[], unsigned *packet_count,
+                                    unsigned extra_size, const void *extra)
+{
+    const uint8_t *current = (const uint8_t*)extra;
+    const uint8_t *end = &current[extra_size];
+    if (extra_size < 1)
+        return VLC_EGENERIC;
+
+    /* Parse the packet count and their sizes */
+    const unsigned count = 1 + *current++;
+    if (packet_count)
+        *packet_count = count;
+    unsigned size = 0;
+    for (unsigned i = 0; i < count - 1; i++) {
+        packet_size[i] = 0;
+        for (;;) {
+            if (current >= end)
+                return VLC_EGENERIC;
+            packet_size[i] += *current;
+            if (*current++ != 255)
+                break;
+        }
+        size += packet_size[i];
+    }
+    if (end - current < size)
+        return VLC_EGENERIC;
+    packet_size[count - 1] = end - current - size;
+
+    /* Copy the payloads */
+    for (unsigned i = 0; i < count; i++) {
+        packet[i] = malloc(packet_size[i]);
+        if (!packet[i]) {
+            for (unsigned j = 0; j < i; j++)
+                free(packet[j]);
+            return VLC_ENOMEM;
+        }
+        if (packet_size[i] > 0) {
+            memcpy(packet[i], current, packet_size[i]);
+            current += packet_size[i];
+        }
+    }
+    return VLC_SUCCESS;
+}
+
+static inline int xiph_PackHeaders(int *extra_size, void **extra,
+                                   unsigned packet_size[], void *packet[], unsigned packet_count )
+{
+    if (packet_count <= 0 || packet_count > XIPH_MAX_HEADER_COUNT)
+        return VLC_EGENERIC;
+
+    /* Compute the size needed for the whole extra data */
+    unsigned payload_size = 0;
+    unsigned header_size = 1;
+    for (unsigned i = 0; i < packet_count; i++) {
+        payload_size += packet_size[i];
+        if (i < packet_count - 1)
+            header_size += 1 + packet_size[i] / 255;
+    }
+
+    /* */
+    *extra_size = header_size + payload_size;
+    *extra = malloc(*extra_size);
+    if (*extra == NULL)
+        return VLC_ENOMEM;
+
+    /* Write the header */
+    uint8_t *current = (uint8_t*)*extra;
+    *current++ = packet_count - 1;
+    for (unsigned i = 0; i < packet_count - 1; i++) {
+        unsigned t = packet_size[i];
+        for (;;) {
+            if (t >= 255) {
+                *current++ = 255;
+                t -= 255;
+            } else {
+                *current++ = t;
+                break;
+            }
+        }
+    }
+
+    /* Copy the payloads */
+    for (unsigned i = 0; i < packet_count; i++) {
+        if (packet_size[i] > 0) {
+            memcpy(current, packet[i], packet_size[i]);
+            current += packet_size[i];
+        }
+    }
+    assert(current == (uint8_t*)*extra + *extra_size);
+    return VLC_SUCCESS;
+}
+
+static inline int xiph_AppendHeaders(int *extra_size, void **extra,
+                                     unsigned size, const void *data)
+{
+    unsigned packet_size[XIPH_MAX_HEADER_COUNT];
+    void *packet[XIPH_MAX_HEADER_COUNT];
+    unsigned count;
+    if (*extra_size > 0 && *extra) {
+        if (xiph_SplitHeaders(packet_size, packet, &count, *extra_size, *extra))
+            return VLC_EGENERIC;
+    } else {
+        count = 0;
+    }
+    if (count >= XIPH_MAX_HEADER_COUNT)
+        return VLC_EGENERIC;
+
+    free(*extra);
+
+    packet_size[count] = size;
+    packet[count]      = (void*)data;
+    if (xiph_PackHeaders(extra_size, extra, packet_size, packet, count + 1)) {
+        *extra_size = 0;
+        *extra      = NULL;
+    }
+    for (unsigned i = 0; i < count; i++)
+        free(packet[i]);
+
+    if (*extra_size <= 0)
+        return VLC_EGENERIC;
+    return VLC_SUCCESS;
+}
+
index 2aaa3693bff52d7ed0fbe8b6d3a8f3006baa6842..7e319849887ca771f2c796fb8b26d1d637e2b320 100644 (file)
@@ -35,6 +35,7 @@
 #include <vlc_sout.h>
 #include <vlc_block.h>
 #include <vlc_codecs.h>
+#include "../demux/xiph.h"
 
 #include <ogg/ogg.h>
 
@@ -562,8 +563,7 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux )
     block_t *p_hdr = NULL;
     block_t *p_og = NULL;
     ogg_packet op;
-    uint8_t *p_extra;
-    int i, i_extra;
+    int i;
 
     /* 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. */
@@ -590,19 +590,22 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux )
                 p_stream->i_fourcc == VLC_CODEC_THEORA )
             {
                 /* 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 )
+                unsigned pi_size[XIPH_MAX_HEADER_COUNT];
+                void     *pp_data[XIPH_MAX_HEADER_COUNT];
+                unsigned i_count;
+                if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
+                                       p_input->p_fmt->i_extra, p_input->p_fmt->p_extra ) )
                 {
-                    msg_Err( p_mux, "header data corrupted");
-                    op.bytes += i_extra;
+                    i_count = 0;
+                    pi_size[0] = 0;
+                    pp_data[0] = NULL;
                 }
 
+                op.bytes  = pi_size[0];
+                op.packet = pp_data[0];
+                if( pi_size[0] <= 0 )
+                    msg_Err( p_mux, "header data corrupted");
+
                 op.b_o_s  = 1;
                 op.e_o_s  = 0;
                 op.granulepos = 0;
@@ -616,6 +619,9 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux )
                     p_stream->i_keyframe_granule_shift =
                         ( (op.packet[40] & 0x03) << 3 ) | ( (op.packet[41] & 0xe0) >> 5 );
                 }
+
+                for( unsigned i = 0; i < i_count; i++ )
+                    free( pp_data[i] );
             }
             else if( p_stream->i_fourcc == VLC_CODEC_DIRAC )
             {
@@ -667,34 +673,21 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux )
             p_stream->i_fourcc == VLC_CODEC_SPEEX ||
             p_stream->i_fourcc == VLC_CODEC_THEORA )
         {
+            unsigned pi_size[XIPH_MAX_HEADER_COUNT];
+            void     *pp_data[XIPH_MAX_HEADER_COUNT];
+            unsigned i_count;
+            if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
+                                   p_input->p_fmt->i_extra, p_input->p_fmt->p_extra ) )
+                i_count = 0;
+
             /* Special case, headers are already there in the incoming stream.
              * We need to gather them an mark them as headers. */
-            int j = 2;
-
-            if( p_stream->i_fourcc == VLC_CODEC_SPEEX ) 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-- )
+            for( unsigned i = 1; i < i_count; i++ )
             {
-                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 )
-                {
+                op.bytes  = pi_size[i];
+                op.packet = pp_data[i];
+                if( pi_size[i] <= 0 )
                     msg_Err( p_mux, "header data corrupted");
-                    op.bytes += i_extra;
-                }
 
                 op.b_o_s  = 0;
                 op.e_o_s  = 0;
@@ -702,13 +695,15 @@ static block_t *OggCreateHeader( sout_mux_t *p_mux )
                 op.packetno = p_stream->i_packet_no++;
                 ogg_stream_packetin( &p_stream->os, &op );
 
-                if( j == 0 )
+                if( i == i_count - 1 )
                     p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
                 else
                     p_og = OggStreamPageOut( p_mux, &p_stream->os, 0 );
                 if( p_og )
                     block_ChainAppend( &p_hdr, p_og );
             }
+            for( unsigned i = 0; i < i_count; i++ )
+                free( pp_data[i] );
         }
         else if( p_stream->i_fourcc != VLC_CODEC_FLAC &&
                  p_stream->i_fourcc != VLC_CODEC_DIRAC )