/* Bitstream manipulation */
static int Ogg_ReadPage ( demux_t *, ogg_page * );
-static void Ogg_UpdatePCR ( logical_stream_t *, ogg_packet * );
+static void Ogg_UpdatePCR ( demux_t *, logical_stream_t *, ogg_packet * );
static void Ogg_DecodePacket ( demux_t *, logical_stream_t *, ogg_packet * );
static int Ogg_OpusPacketDuration( logical_stream_t *, ogg_packet * );
+static void Ogg_CreateES( demux_t *p_demux );
static int Ogg_BeginningOfStream( demux_t *p_demux );
static int Ogg_FindLogicalStreams( demux_t *p_demux );
static void Ogg_EndOfStream( demux_t *p_demux );
return VLC_ENOMEM;
p_sys->i_length = -1;
+ p_sys->b_preparsing_done = false;
/* Set exported functions */
p_demux->pf_demux = Demux;
/* */
TAB_INIT( p_sys->i_seekpoints, p_sys->pp_seekpoints );
+
+ while ( !p_sys->b_preparsing_done && p_demux->pf_demux( p_demux ) > 0 )
+ {}
+
return VLC_SUCCESS;
}
TAB_CLEAN( p_sys->i_streams, p_sys->pp_stream );
}
Ogg_EndOfStream( p_demux );
+ p_sys->b_chained_boundary = true;
}
if( Ogg_BeginningOfStream( p_demux ) != VLC_SUCCESS )
return 0;
- /* Find the real duration */
- stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
- if ( b_canseek )
- Oggseek_ProbeEnd( p_demux );
-
msg_Dbg( p_demux, "beginning of a group of logical streams" );
- es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 );
+
+ if ( !p_sys->b_chained_boundary )
+ {
+ /* Find the real duration */
+ stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
+ if ( b_canseek )
+ Oggseek_ProbeEnd( p_demux );
+ es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 );
+ }
+ else
+ {
+ es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
+ p_sys->b_chained_boundary = false;
+ }
+ }
+
+ if ( p_sys->b_preparsing_done )
+ {
+ for ( int i=0; i < p_sys->i_streams; i++ )
+ {
+ if ( !p_sys->pp_stream[i]->p_es )
+ {
+ Ogg_CreateES( p_demux );
+ break;
+ }
+ }
}
/*
{
/* If we delayed restarting encoders/SET_ES_FMT for more
* skeleton provided configuration */
- if ( p_sys->p_skelstream && p_sys->p_skelstream->i_serial_no == ogg_page_serialno(&p_sys->current_page) )
+ if ( p_sys->p_skelstream )
{
- msg_Dbg( p_demux, "End of Skeleton" );
- for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
+ if ( p_sys->p_skelstream->i_serial_no == ogg_page_serialno(&p_sys->current_page) )
{
- logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
- if ( p_stream->b_have_updated_format )
+ msg_Dbg( p_demux, "End of Skeleton" );
+ p_sys->b_preparsing_done = true;
+ for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
{
- p_stream->b_have_updated_format = false;
- if ( p_stream->p_skel ) Ogg_ApplySkeleton( p_stream );
- msg_Dbg( p_demux, "Resetting format for stream %d", i_stream );
- es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
- p_stream->p_es, &p_stream->fmt );
+ logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
+ Ogg_ApplySkeleton( p_stream );
}
}
}
DemuxDebug(
if ( p_stream->fmt.i_cat == VIDEO_ES )
- msg_Dbg(p_demux, "DEMUX READ pageno %ld g%"PRId64" (%d packets) cont %d %ld bytes eos %d ",
+ msg_Dbg(p_demux, "DEMUX READ pageno %ld g%"PRId64" (%d packets) cont %d %ld bytes",
ogg_page_pageno( &p_sys->current_page ),
ogg_page_granulepos( &p_sys->current_page ),
ogg_page_packets( &p_sys->current_page ),
ogg_page_continued(&p_sys->current_page),
- p_sys->current_page.body_len, p_sys->i_eos )
+ p_sys->current_page.body_len )
);
while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
{
/* If synchro is re-initialized we need to drop all the packets
* until we find a new dated one. */
- Ogg_UpdatePCR( p_stream, &oggpacket );
+ Ogg_UpdatePCR( p_demux, p_stream, &oggpacket );
}
if( p_stream->i_pcr >= 0 )
/* if a page was waiting, it's now processed */
p_sys->b_page_waiting = false;
+ if ( p_sys->p_skelstream && !p_sys->p_skelstream->b_finished )
+ p_sys->b_preparsing_done = false;
+ else
+ p_sys->b_preparsing_done = true;
+
p_sys->i_pcr = -1;
for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
{
logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
+ if ( p_sys->b_preparsing_done && p_stream->b_initializing )
+ {
+ /* We have 1 or more streams needing more than 1 page for preparsing */
+ p_sys->b_preparsing_done = false;
+ }
+
if( p_stream->fmt.i_cat == SPU_ES )
continue;
if( p_stream->i_interpolated_pcr < 0 )
* Ogg_UpdatePCR: update the PCR (90kHz program clock reference) for the
* current stream.
****************************************************************************/
-static void Ogg_UpdatePCR( logical_stream_t *p_stream,
+static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream,
ogg_packet *p_oggpacket )
{
+ demux_sys_t *p_ogg = p_demux->p_sys;
p_stream->i_end_trim = 0;
/* Convert the granulepos into a pcr */
p_stream->i_pcr = sample * CLOCK_FREQ / p_stream->f_rate;
}
- p_stream->i_pcr += VLC_TS_0;
+ if ( !p_ogg->i_pcr_offset )
+ p_stream->i_pcr += VLC_TS_0;
+ else
+ p_stream->i_pcr += p_ogg->i_pcr_offset;
p_stream->i_interpolated_pcr = p_stream->i_pcr;
}
else
sample = 0;
p_stream->i_interpolated_pcr =
VLC_TS_0 + sample * CLOCK_FREQ / p_stream->f_rate;
+ p_stream->i_interpolated_pcr += p_ogg->i_pcr_offset;
}
else if( p_stream->fmt.i_bitrate )
{
p_stream->i_interpolated_pcr +=
( p_oggpacket->bytes * CLOCK_FREQ /
p_stream->fmt.i_bitrate / 8 );
+ p_stream->i_interpolated_pcr += p_ogg->i_pcr_offset;
}
}
p_stream->i_previous_granulepos = p_oggpacket->granulepos;
p_oggpacket->packet[0] & PACKET_TYPE_BITS ) 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->p_es )
+ b_selected = true;
+ else
+ es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
+ p_stream->p_es, &b_selected );
if( p_stream->b_force_backup )
{
else
p_stream->fmt.i_extra = 0;
- if( Ogg_LogicalStreamResetEsFormat( p_demux, p_stream ) )
- {
- if ( p_ogg->p_skelstream )
- {
- /* We delay until eos is reached on skeleton.
- * There should only be headers, as no data page is
- * allowed before skeleton's eos.
- * Skeleton data is appended to fmt on skeleton eos.
- */
- p_stream->b_have_updated_format = true;
- }
- else
- {
- /* Otherwise we set config from first headers */
- es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
- p_stream->p_es, &p_stream->fmt );
- }
- }
if( p_stream->i_headers > 0 )
Ogg_ExtractMeta( p_demux, & p_stream->fmt,
p_stream->p_headers, p_stream->i_headers );
b_selected = false; /* Discard the header packet */
}
+ else
+ p_stream->b_initializing = false;
/* Convert the pcr into a pts */
if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
{
if( p_stream->i_pcr >= 0 )
{
- /* This is for streams where the granulepos of the header packets
- * doesn't match these of the data packets (eg. ogg web radios). */
- if( p_stream->i_previous_pcr == 0 &&
- p_stream->i_pcr > 3 * DEFAULT_PTS_DELAY )
- {
-
- /* Call the pace control */
- es_out_Control( p_demux->out, ES_OUT_SET_PCR,
- VLC_TS_0 + p_stream->i_pcr );
- }
-
p_stream->i_previous_pcr = p_stream->i_pcr;
-
/* The granulepos is the end date of the sample */
i_pts = p_stream->i_pcr;
}
/* Convert the granulepos into the next pcr */
i_interpolated_pts = p_stream->i_interpolated_pcr;
- Ogg_UpdatePCR( p_stream, p_oggpacket );
-
- /* SPU streams are typically discontinuous, do not mind large gaps */
- if( p_stream->fmt.i_cat != SPU_ES )
- {
- if( p_stream->i_pcr >= 0 )
- {
- /* This is for streams where the granulepos of the header packets
- * doesn't match these of the data packets (eg. ogg web radios). */
- if( p_stream->i_previous_pcr == 0 &&
- p_stream->i_pcr > 3 * DEFAULT_PTS_DELAY )
- {
-
- /* Call the pace control */
- es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_stream->i_pcr );
- }
- }
- }
+ Ogg_UpdatePCR( p_demux, p_stream, p_oggpacket );
if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS &&
p_stream->fmt.i_codec != VLC_CODEC_SPEEX &&
p_block->i_buffer = 0;
}
+
if( p_stream->fmt.i_codec == VLC_CODEC_TARKIN )
{
/* FIXME: the biggest hack I've ever done */
memcpy( p_block->p_buffer, p_oggpacket->packet + i_header_len,
p_oggpacket->bytes - i_header_len );
- es_out_Send( p_demux->out, p_stream->p_es, p_block );
+ if ( p_stream->p_es )
+ {
+ /* Because ES creation is delayed for preparsing */
+ if ( p_stream->p_preparse_block )
+ {
+ es_out_Send( p_demux->out, p_stream->p_es, p_stream->p_preparse_block );
+ p_stream->p_preparse_block = NULL;
+ }
+ es_out_Send( p_demux->out, p_stream->p_es, p_block );
+ }
+ else
+ block_ChainAppend( & p_stream->p_preparse_block, p_block );
}
/* Re-implemented to avoid linking against libopus from the demuxer. */
es_format_Init( &p_stream->fmt, 0, 0 );
es_format_Init( &p_stream->fmt_old, 0, 0 );
+ p_stream->b_initializing = true;
/* Setup the logical stream */
p_stream->i_serial_no = ogg_page_serialno( &p_ogg->current_page );
}
/* we'll need to get all headers */
- p_ogg->pp_stream[i_stream]->b_initializing |= p_ogg->pp_stream[i_stream]->b_force_backup;
+ p_ogg->pp_stream[i_stream]->b_initializing &= p_ogg->pp_stream[i_stream]->b_force_backup;
if( Ogg_ReadPage( p_demux, &p_ogg->current_page ) != VLC_SUCCESS )
return VLC_EGENERIC;
return VLC_EGENERIC;
}
+/****************************************************************************
+ * Ogg_CreateES: Creates all Elementary streams once headers are parsed
+ ****************************************************************************/
+static void Ogg_CreateES( demux_t *p_demux )
+{
+ demux_sys_t *p_ogg = p_demux->p_sys;
+ logical_stream_t *p_old_stream = p_ogg->p_old_stream;
+ int i_stream;
+
+ for( i_stream = 0 ; i_stream < p_ogg->i_streams; i_stream++ )
+ {
+ logical_stream_t *p_stream = p_ogg->pp_stream[i_stream];
+
+ if ( p_stream->p_es == NULL )
+ {
+ /* Better be safe than sorry when possible with ogm */
+ if( p_stream->fmt.i_codec == VLC_CODEC_MPGA ||
+ p_stream->fmt.i_codec == VLC_CODEC_A52 )
+ p_stream->fmt.b_packetized = false;
+
+ /* Try first to reuse an old ES */
+ if( p_old_stream &&
+ p_old_stream->fmt.i_cat == p_stream->fmt.i_cat &&
+ p_old_stream->fmt.i_codec == p_stream->fmt.i_codec )
+ {
+ msg_Dbg( p_demux, "will reuse old stream to avoid glitch" );
+
+ p_stream->p_es = p_old_stream->p_es;
+ p_stream->b_finished = false;
+ p_stream->b_reinit = false;
+ p_stream->b_initializing = false;
+ es_format_Copy( &p_stream->fmt_old, &p_old_stream->fmt );
+
+ p_old_stream->p_es = NULL;
+ p_old_stream = NULL;
+ es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
+ p_stream->p_es, &p_stream->fmt );
+ }
+ else
+ {
+ p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
+ }
+
+ // TODO: something to do here ?
+ if( p_stream->fmt.i_codec == VLC_CODEC_CMML )
+ {
+ /* Set the CMML stream active */
+ es_out_Control( p_demux->out, ES_OUT_SET_ES, p_stream->p_es );
+ }
+ }
+ }
+
+ if( p_ogg->p_old_stream )
+ {
+ if( p_ogg->p_old_stream->p_es )
+ msg_Dbg( p_demux, "old stream not reused" );
+ Ogg_LogicalStreamDelete( p_demux, p_ogg->p_old_stream );
+ p_ogg->p_old_stream = NULL;
+ }
+}
+
/****************************************************************************
* Ogg_BeginningOfStream: Look for Beginning of Stream ogg pages and add
* Elementary streams.
static int Ogg_BeginningOfStream( demux_t *p_demux )
{
demux_sys_t *p_ogg = p_demux->p_sys ;
- logical_stream_t *p_old_stream = p_ogg->p_old_stream;
int i_stream;
/* Find the logical streams embedded in the physical stream and
/* initialise kframe index */
p_stream->idx=NULL;
- /* Try first to reuse an old ES */
- if( p_old_stream &&
- p_old_stream->fmt.i_cat == p_stream->fmt.i_cat &&
- p_old_stream->fmt.i_codec == p_stream->fmt.i_codec )
- {
- msg_Dbg( p_demux, "will reuse old stream to avoid glitch" );
-
- p_stream->p_es = p_old_stream->p_es;
- es_format_Copy( &p_stream->fmt_old, &p_old_stream->fmt );
-
- p_old_stream->p_es = NULL;
- p_old_stream = NULL;
- }
-
- if( !p_stream->p_es )
- {
- /* Better be safe than sorry when possible with ogm */
- if( p_stream->fmt.i_codec == VLC_CODEC_MPGA ||
- p_stream->fmt.i_codec == VLC_CODEC_A52 )
- p_stream->fmt.b_packetized = false;
-
- p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
- }
-
- // TODO: something to do here ?
- if( p_stream->fmt.i_codec == VLC_CODEC_CMML )
- {
- /* Set the CMML stream active */
- es_out_Control( p_demux->out, ES_OUT_SET_ES, p_stream->p_es );
- }
-
if ( p_stream->fmt.i_bitrate == 0 &&
( p_stream->fmt.i_cat == VIDEO_ES ||
p_stream->fmt.i_cat == AUDIO_ES ) )
p_stream->b_reinit = false;
}
- if( p_ogg->p_old_stream )
- {
- if( p_ogg->p_old_stream->p_es )
- msg_Dbg( p_demux, "old stream not reused" );
- Ogg_LogicalStreamDelete( p_demux, p_ogg->p_old_stream );
- p_ogg->p_old_stream = NULL;
- }
-
-
/* get total frame count for video stream; we will need this for seeking */
p_ogg->i_total_frames = 0;
p_ogg->pp_stream = NULL;
p_ogg->skeleton.major = 0;
p_ogg->skeleton.minor = 0;
+ p_ogg->b_preparsing_done = false;
+ p_ogg->i_pcr_offset = p_ogg->i_pcr;
/* */
if( p_ogg->p_meta )
if ( p_demux->p_sys->p_skelstream == p_stream )
p_demux->p_sys->p_skelstream = NULL;
+ /* Shouldn't happen */
+ if ( unlikely( p_stream->p_preparse_block ) )
+ {
+ block_ChainRelease( p_stream->p_preparse_block );
+ p_stream->p_preparse_block = NULL;
+ }
+
free( p_stream );
}
/**