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.
#include <vlc_plugin.h>
#include <vlc_codecs.h>
+#include "../../demux/xiph.h"
#include "rtp.h"
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;
}
#include <vlc_input.h>
#include <vlc_codec.h>
#include <vlc_osd.h>
+#include "../demux/xiph.h"
#include <kate/kate.h>
#ifdef HAVE_TIGER
/*
* Input properties
*/
- int i_num_headers;
- int i_headers;
+ bool b_has_headers;
/*
* Kate properties
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" );
/* 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 );
{
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",
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 */
}
#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;
}
/*****************************************************************************
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;
#include <vlc_input.h>
#include <vlc_codec.h>
#include <vlc_aout.h>
+#include "../demux/xiph.h"
#include <ogg/ogg.h>
#include <speex/speex.h>
/*
* Input properties
*/
- int i_headers;
+ bool b_has_headers;
int i_frame_in_packet;
/*
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 );
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;
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 );
{
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 )
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;
}
/*****************************************************************************
}
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;
}
}
/* 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;
}
#include <vlc_codec.h>
#include <vlc_sout.h>
#include <vlc_input.h>
+#include "../demux/xiph.h"
+
#include <ogg/ogg.h>
#include <theora/theora.h>
/*
* Input properties
*/
- int i_headers;
+ bool b_has_headers;
/*
* Theora properties
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;
theora_comment_init( &p_sys->tc );
theora_info_init( &p_sys->ti );
- p_sys->i_headers = 0;
-
return VLC_SUCCESS;
}
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 );
{
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 */
}
/* 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 );
/* 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 )
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;
}
/*****************************************************************************
/* 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 */
#include <vlc_aout.h>
#include <vlc_input.h>
#include <vlc_sout.h>
+#include "../demux/xiph.h"
#include <ogg/ogg.h>
/* Module mode */
bool b_packetizer;
- /*
- * Input properties
- */
- int i_headers;
+ bool b_has_headers;
/*
* Vorbis properties
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 );
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 );
{
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 */
{
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 =
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" );
{
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 );
}
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;
}
/*****************************************************************************
}
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;
}
}
/* 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;
}
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 );
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 ):
}
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 ) )
{
}
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/" ) ) )
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" ) )
{
#include <vlc_codecs.h>
#include <vlc_bits.h>
+#include "xiph.h"
#include "vorbis.h"
#include "kate_categories.h"
* 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
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 )
{
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:
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 */
*/
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 )
{
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 )
{
{
/* 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 */
--- /dev/null
+/*****************************************************************************
+ * 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 = ¤t[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;
+}
+
#include <vlc_sout.h>
#include <vlc_block.h>
#include <vlc_codecs.h>
+#include "../demux/xiph.h"
#include <ogg/ogg.h>
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. */
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;
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 )
{
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;
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 )