Commit 535be4f6 authored by Gildas Bazin's avatar Gildas Bazin

* include/vlc_es_out.h, src/input/es_out.c: added an ES_OUT_SET_FMT control.

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