vlc | branch: master | Francois Cartegnie <[email protected]> | Thu May 31 11:54:03 2018 +0200| [4c79ba453ca89099c6e74c4085acf79291aec687] | committer: Francois Cartegnie
demux: ogg: rework block/queuing/pcr and lots of fixes part 2 of the cleanup/simplification > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=4c79ba453ca89099c6e74c4085acf79291aec687 --- modules/demux/ogg.c | 514 ++++++++++++++++++++------------------------ modules/demux/ogg.h | 14 +- modules/demux/ogg_granule.c | 17 +- 3 files changed, 249 insertions(+), 296 deletions(-) diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c index cfeb239974..ebca534026 100644 --- a/modules/demux/ogg.c +++ b/modules/demux/ogg.c @@ -128,7 +128,8 @@ static int Control( demux_t *, int, va_list ); static int Ogg_ReadPage ( demux_t *, ogg_page * ); static void Ogg_DecodePacket ( demux_t *, logical_stream_t *, ogg_packet * ); static unsigned Ogg_OpusPacketDuration( ogg_packet * ); -static void Ogg_SendOrQueueBlocks( demux_t *, logical_stream_t *, block_t * ); +static void Ogg_QueueBlocks( demux_t *, logical_stream_t *, block_t * ); +static void Ogg_SendQueuedBlocks( demux_t *, logical_stream_t * ); static void Ogg_CreateES( demux_t *p_demux ); static int Ogg_BeginningOfStream( demux_t *p_demux ); @@ -136,6 +137,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ); static void Ogg_EndOfStream( demux_t *p_demux ); /* */ +static void Ogg_LogicalStreamInit( logical_stream_t *p_stream ); static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_stream ); static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *p_stream ); static void Ogg_ResetStream( logical_stream_t *p_stream ); @@ -196,10 +198,6 @@ static void fill_channels_info(audio_format_t *audio) audio->i_physical_channels = pi_channels_map[chans]; } -/* Special TS value: don't send or derive any pts/pcr from it. - Represents TS state prior first known valid timestamp */ -#define VLC_TS_UNKNOWN (VLC_TS_INVALID + 1) - /***************************************************************************** * Open: initializes ogg demux structures *****************************************************************************/ @@ -236,9 +234,6 @@ static int Open( vlc_object_t * p_this ) p_sys->i_length = -1; p_sys->b_preparsing_done = false; - vlc_stream_Control( p_demux->s, STREAM_GET_PTS_DELAY, - &p_sys->i_access_delay ); - /* Set exported functions */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; @@ -278,7 +273,7 @@ static void Close( vlc_object_t *p_this ) } -static void Ogg_GeneratePCR( demux_t * p_demux ) +static mtime_t Ogg_GeneratePCR( demux_t * p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; /* We will consider the lowest PCR among tracks, because the audio core badly @@ -293,12 +288,10 @@ static void Ogg_GeneratePCR( demux_t * p_demux ) continue; if( p_stream->fmt.i_codec == VLC_CODEC_OGGSPOTS ) continue; - if( p_stream->i_pcr <= VLC_TS_UNKNOWN ) + if( p_stream->i_pcr == VLC_TS_INVALID ) continue; if ( p_stream->b_finished || p_stream->b_initializing ) continue; - if ( p_stream->p_preparse_block ) - continue; if( i_pcr_candidate == VLC_TS_INVALID || p_stream->i_pcr <= i_pcr_candidate ) { @@ -306,24 +299,7 @@ static void Ogg_GeneratePCR( demux_t * p_demux ) } } - if ( i_pcr_candidate != VLC_TS_INVALID && p_sys->i_pcr != i_pcr_candidate ) - { - if ( p_sys->i_streams == 1 && p_sys->i_access_delay ) - { - int64_t i_pcr_jitter = i_pcr_candidate - p_sys->i_pcr; - if ( i_pcr_jitter > p_sys->i_pcr_jitter ) - { - p_sys->i_pcr_jitter = i_pcr_jitter; - if ( p_sys->i_access_delay < i_pcr_jitter ) - msg_Warn( p_demux, "Consider increasing access caching variable from %"PRId64" to >%"PRId64, - p_sys->i_access_delay / 1000, i_pcr_jitter / 1000 ); - } - } - - p_sys->i_pcr = i_pcr_candidate; - if( likely( !p_sys->b_slave ) ) - es_out_SetPCR( p_demux->out, p_sys->i_pcr ); - } + return i_pcr_candidate; } /***************************************************************************** @@ -336,7 +312,6 @@ static int Demux( demux_t * p_demux ) demux_sys_t *p_sys = p_demux->p_sys; ogg_packet oggpacket; int i_stream; - bool b_skipping = false; bool b_canseek; int i_active_streams = p_sys->i_streams; @@ -454,12 +429,6 @@ static int Demux( demux_t * p_demux ) } } - b_skipping = false; - for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ ) - { - b_skipping |= p_sys->pp_stream[i_stream]->i_skip_frames; - } - for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ ) { logical_stream_t *p_stream = p_sys->pp_stream[i_stream]; @@ -498,43 +467,8 @@ static int Demux( demux_t * p_demux ) p_sys->current_page.body_len ) ); - const int i_page_packets = ogg_page_packets( &p_sys->current_page ); - bool b_doprepcr = false; - - if ( p_stream->i_pcr < VLC_TS_0 && ogg_page_granulepos( &p_sys->current_page ) > 0 ) - { - // PASS 0 - if ( p_stream->fmt.i_codec == VLC_CODEC_OPUS || - p_stream->fmt.i_codec == VLC_CODEC_VORBIS || - p_stream->fmt.i_codec == VLC_CODEC_SPEEX || - p_stream->fmt.i_cat == VIDEO_ES ) - { - assert( p_stream->prepcr.pp_blocks == NULL ); - b_doprepcr = true; - } - } - - int i_real_page_packets = 0; while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 ) { - i_real_page_packets++; - int i_max_packets = __MAX(i_page_packets, i_real_page_packets); - if ( b_doprepcr && p_stream->prepcr.i_size < i_max_packets ) - { - /* always double alloc for performance */ - i_max_packets = __MAX( i_max_packets << 1, 255 ); - /* alloc or realloc */ - block_t **pp_realloc = realloc( p_stream->prepcr.pp_blocks, - sizeof(block_t *) * i_max_packets ); - if ( !pp_realloc ) - { - /* drop it then */ - continue; - } - p_stream->prepcr.i_size = i_max_packets; - p_stream->prepcr.pp_blocks = pp_realloc; - } - /* Read info from any secondary header packets, if there are any */ if( p_stream->i_secondary_header_packets > 0 ) { @@ -565,11 +499,6 @@ static int Demux( demux_t * p_demux ) p_stream->i_data_start = vlc_stream_Tell( p_demux->s ); } - /* If any streams have i_skip_frames, only decode (pre-roll) - * for those streams, but don't skip headers */ - if ( b_skipping && p_stream->i_skip_frames == 0 - && p_stream->i_secondary_header_packets ) continue; - if( p_stream->b_reinit ) { p_stream->b_reinit = false; @@ -582,109 +511,6 @@ static int Demux( demux_t * p_demux ) Ogg_DecodePacket( p_demux, p_stream, &oggpacket ); } - if ( p_stream->prepcr.pp_blocks ) - { - mtime_t i_end = Ogg_GranuleToTime( p_stream, - ogg_page_granulepos( &p_sys->current_page ), - false, false ); - mtime_t i_end_backup = i_end; - -#ifdef HAVE_LIBVORBIS - int i_prev_blocksize = 0; -#endif - // PASS 1 - for( int i=0; i<p_stream->prepcr.i_used; i++ ) - { - block_t *p_block = p_stream->prepcr.pp_blocks[i]; - ogg_packet dumb_packet; - dumb_packet.bytes = p_block->i_buffer; - dumb_packet.packet = p_block->p_buffer; - - switch( p_stream->fmt.i_codec ) - { - case VLC_CODEC_SPEEX: - p_block->i_nb_samples = p_stream->special.speex.i_framesize * - p_stream->special.speex.i_framesperpacket; - break; - case VLC_CODEC_OPUS: - p_block->i_nb_samples = Ogg_OpusPacketDuration( &dumb_packet ); - break; -#ifdef HAVE_LIBVORBIS - case VLC_CODEC_VORBIS: - { - if( !VORBIS_HEADERS_VALID(p_stream) ) - { - msg_Err( p_demux, "missing vorbis headers, can't compute block size" ); - break; - } - long i_blocksize = vorbis_packet_blocksize( - p_stream->special.vorbis.p_info, &dumb_packet ); - if ( i_prev_blocksize ) - p_block->i_nb_samples = ( i_blocksize + i_prev_blocksize ) / 4; - else - p_block->i_nb_samples = i_blocksize / 2; - i_prev_blocksize = i_blocksize; - } -#endif - } - } - - // PASS 2 - bool b_fixed = false; - date_t d = p_stream->dts; - date_Set( &d, p_sys->i_nzpcr_offset + i_end - VLC_TS_0 ); - for( int i=p_stream->prepcr.i_used - 1; i>=0; i-- ) - { - block_t *p_block = p_stream->prepcr.pp_blocks[i]; - switch( p_stream->fmt.i_codec ) - { - case VLC_CODEC_SPEEX: - case VLC_CODEC_OPUS: - case VLC_CODEC_VORBIS: - if( i_end != VLC_TS_INVALID ) - { - date_Decrement( &d, p_block->i_nb_samples ); - p_block->i_pts = date_Get( &d ) + VLC_TS_0; - } - else - { - p_block->i_pts = VLC_TS_INVALID; - if( p_sys->i_nzpcr_offset == 0 ) /* not on chained streams */ - p_block->i_flags |= BLOCK_FLAG_PREROLL; - } - b_fixed = true; - break; - default: - if ( p_stream->fmt.i_cat == VIDEO_ES ) - { - if( i_end != VLC_TS_INVALID ) - { - date_Decrement( &d, 1 ); - p_block->i_pts = date_Get( &d ) + VLC_TS_0; - } - b_fixed = true; - } - } - } - - if ( b_fixed ) - { - i_end = i_end_backup; /* as set above */ - if( i_end != VLC_TS_INVALID ) - p_stream->i_pcr = i_end + p_sys->i_nzpcr_offset; - } - - FREENULL(p_stream->prepcr.pp_blocks); - p_stream->prepcr.i_used = 0; - - Ogg_SendOrQueueBlocks( p_demux, p_stream, NULL ); - } - - mtime_t i_pcr = Ogg_GranuleToTime( p_stream, - ogg_page_granulepos( &p_sys->current_page ), - !p_stream->b_contiguous, false ); - if ( i_pcr != VLC_TS_INVALID ) - p_stream->i_pcr = p_sys->i_nzpcr_offset + i_pcr; if( !p_sys->b_page_waiting ) break; @@ -712,8 +538,37 @@ static int Demux( demux_t * p_demux ) } } - if( !b_skipping && p_sys->b_preparsing_done ) - Ogg_GeneratePCR( p_demux ); + if( p_sys->b_preparsing_done ) + { + mtime_t i_pcr; + + /* Generate First PCR */ + if( p_sys->i_pcr == VLC_TS_INVALID ) + { + i_pcr = Ogg_GeneratePCR( p_demux ); + if( i_pcr != VLC_TS_INVALID && i_pcr != p_sys->i_pcr ) + { + p_sys->i_pcr = i_pcr; + if( likely( !p_sys->b_slave ) ) + es_out_SetPCR( p_demux->out, p_sys->i_pcr ); + } + } + + if( p_sys->i_pcr != VLC_TS_INVALID ) + { + for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ ) + Ogg_SendQueuedBlocks( p_demux, p_sys->pp_stream[i_stream] ); + + /* Generate Current PCR */ + i_pcr = Ogg_GeneratePCR( p_demux ); + if( i_pcr != VLC_TS_INVALID && i_pcr != p_sys->i_pcr ) + { + p_sys->i_pcr = i_pcr; + if( likely( !p_sys->b_slave ) ) + es_out_SetPCR( p_demux->out, p_sys->i_pcr ); + } + } + } return VLC_DEMUXER_SUCCESS; } @@ -728,21 +583,25 @@ static void Ogg_ResetStream( logical_stream_t *p_stream ) #endif /* we'll trash all the data until we find the next pcr */ p_stream->b_reinit = true; - p_stream->i_pcr = VLC_TS_UNKNOWN; + p_stream->i_pcr = VLC_TS_INVALID; + p_stream->i_next_block_flags = 0; date_Set( &p_stream->dts, VLC_TS_INVALID ); ogg_stream_reset( &p_stream->os ); - FREENULL( p_stream->prepcr.pp_blocks ); - p_stream->prepcr.i_size = 0; - p_stream->prepcr.i_used = 0; + block_ChainRelease( p_stream->queue.p_blocks ); + p_stream->queue.p_blocks = NULL; + p_stream->queue.pp_append = &p_stream->queue.p_blocks; } -static void Ogg_ResetStreamsHelper( demux_sys_t *p_sys ) +static void Ogg_PreparePostSeek( demux_sys_t *p_sys ) { for( int i = 0; i < p_sys->i_streams; i++ ) + { Ogg_ResetStream( p_sys->pp_stream[i] ); + p_sys->pp_stream[i]->i_next_block_flags = BLOCK_FLAG_DISCONTINUITY; + } ogg_sync_reset( &p_sys->oy ); - p_sys->i_pcr = VLC_TS_UNKNOWN; + p_sys->i_pcr = VLC_TS_INVALID; } static logical_stream_t * Ogg_GetSelectedStream( demux_t *p_demux ) @@ -826,7 +685,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b ); if ( Oggseek_BlindSeektoAbsoluteTime( p_demux, p_stream, VLC_TS_0 + i64, b ) ) { - Ogg_ResetStreamsHelper( p_sys ); + Ogg_PreparePostSeek( p_sys ); if( acc ) es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, VLC_TS_0 + i64 ); @@ -891,13 +750,13 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) acc = va_arg( args, int ); if ( p_sys->i_length <= 0 || !b /* || ! STREAM_CAN_FASTSEEK */ ) { - Ogg_ResetStreamsHelper( p_sys ); + Ogg_PreparePostSeek( p_sys ); return Oggseek_BlindSeektoPosition( p_demux, p_stream, f, b ); } assert( p_sys->i_length > 0 ); i64 = CLOCK_FREQ * p_sys->i_length * f; - Ogg_ResetStreamsHelper( p_sys ); + Ogg_PreparePostSeek( p_sys ); if ( Oggseek_SeektoAbsolutetime( p_demux, p_stream, VLC_TS_0 + i64 ) >= 0 ) { if( acc ) @@ -971,7 +830,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b ); if ( Oggseek_BlindSeektoAbsoluteTime( p_demux, p_stream, VLC_TS_0 + i64, b ) ) { - Ogg_ResetStreamsHelper( p_sys ); + Ogg_PreparePostSeek( p_sys ); es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, VLC_TS_0 + i64 ); p_sys->updates |= INPUT_UPDATE_SEEKPOINT; @@ -1092,72 +951,170 @@ static void Ogg_SetNextFrame( demux_t *p_demux, logical_stream_t *p_stream, } } -static void Ogg_SendOrQueueBlocks( demux_t *p_demux, logical_stream_t *p_stream, - block_t *p_block ) +static mtime_t Ogg_FixupOutputQueue( demux_t *p_demux, logical_stream_t *p_stream ) { - demux_sys_t *p_ogg = p_demux->p_sys; - if ( (!p_stream->p_es || p_stream->prepcr.pp_blocks || p_stream->i_pcr == VLC_TS_UNKNOWN) && - p_ogg->i_nzpcr_offset == 0 /* Not on chained streams */ ) + mtime_t i_enddts = VLC_TS_INVALID; + +#ifdef HAVE_LIBVORBIS + long i_prev_blocksize = 0; +#else + VLC_UNUSED(p_demux); +#endif + // PASS 1, set number of samples + unsigned i_total_samples = 0; + for( block_t *p_block = p_stream->queue.p_blocks; p_block; p_block = p_block->p_next ) { - if ( !p_block ) return; - if ( p_stream->prepcr.pp_blocks ) + if( p_block->i_dts != VLC_TS_INVALID ) { - assert( p_stream->prepcr.i_size ); - p_stream->prepcr.pp_blocks[p_stream->prepcr.i_used++] = p_block; + i_enddts = p_block->i_dts; + break; } - DemuxDebug( msg_Dbg( p_demux, "block prepcr append > pts %"PRId64" spcr %"PRId64" pcr %"PRId64, - p_block->i_pts, p_stream->i_pcr, p_ogg->i_pcr ); ) - block_ChainAppend( & p_stream->p_preparse_block, p_block ); - } - else - { - /* Because ES creation is delayed for preparsing */ - if ( p_stream->p_preparse_block ) + + if( p_block->i_flags & BLOCK_FLAG_HEADER ) + continue; + + ogg_packet dumb_packet; + dumb_packet.bytes = p_block->i_buffer; + dumb_packet.packet = p_block->p_buffer; + + switch( p_stream->fmt.i_codec ) { - block_t *temp = p_stream->p_preparse_block; - while ( temp ) + case VLC_CODEC_SPEEX: + p_block->i_nb_samples = p_stream->special.speex.i_framesize * + p_stream->special.speex.i_framesperpacket; + break; + case VLC_CODEC_OPUS: + p_block->i_nb_samples = Ogg_OpusPacketDuration( &dumb_packet ); + break; +#ifdef HAVE_LIBVORBIS + case VLC_CODEC_VORBIS: { - block_t *tosend = temp; - temp = temp->p_next; - tosend->p_next = NULL; - - if( tosend->i_dts == VLC_TS_INVALID ) + if( !VORBIS_HEADERS_VALID(p_stream) ) { - tosend->i_dts = tosend->i_pts; + msg_Err( p_demux, "missing vorbis headers, can't compute block size" ); + break; } + long i_blocksize = vorbis_packet_blocksize( p_stream->special.vorbis.p_info, + &dumb_packet ); + if ( i_prev_blocksize ) + p_block->i_nb_samples = ( i_blocksize + i_prev_blocksize ) / 4; + else + p_block->i_nb_samples = i_blocksize / 2; + i_prev_blocksize = i_blocksize; + break; + } +#endif + default: + break; + } + i_total_samples += p_block->i_nb_samples; + } - if( tosend->i_dts == VLC_TS_INVALID ) - { - /* Don't send metadata from chained streams */ - block_Release( tosend ); - continue; - } + // PASS 2 + if( i_enddts != VLC_TS_INVALID ) + { + date_t d = p_stream->dts; + date_Set( &d, i_enddts ); + i_enddts = date_Decrement( &d, i_total_samples ); + for( block_t *p_block = p_stream->queue.p_blocks; p_block; p_block = p_block->p_next ) + { + if( p_block->i_dts != VLC_TS_INVALID ) + break; + if( p_block->i_flags & BLOCK_FLAG_HEADER ) + continue; + p_block->i_dts = date_Get( &d ); + date_Increment( &d, p_block->i_nb_samples ); + } + } /* else can't do anything, no timestamped blocks in stream */ - DemuxDebug( msg_Dbg( p_demux, "block sent from preparse > dts %"PRId64" pts %"PRId64" spcr %"PRId64" pcr %"PRId64, - tosend->i_dts, tosend->i_pts, p_stream->i_pcr, p_ogg->i_pcr ); ) + return i_enddts; +} - if ( p_ogg->i_pcr == VLC_TS_INVALID && tosend->i_dts != VLC_TS_INVALID ) - { - p_ogg->i_pcr = tosend->i_dts; - if( likely( !p_ogg->b_slave ) ) - es_out_SetPCR( p_demux->out, p_ogg->i_pcr ); - } +static void Ogg_QueueBlocks( demux_t *p_demux, logical_stream_t *p_stream, block_t *p_block ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + VLC_UNUSED(p_sys); + + if( p_block == NULL ) + { + assert( p_block != NULL ); + return; + } + + block_ChainLastAppend( &p_stream->queue.pp_append, p_block ); + + if( p_stream->i_pcr == VLC_TS_INVALID && p_block->i_dts != VLC_TS_INVALID ) + { + /* fixup queue */ + p_stream->i_pcr = Ogg_FixupOutputQueue( p_demux, p_stream ); + } + + DemuxDebug( msg_Dbg( p_demux, "%4.4s block queued > dts %"PRId64" spcr %"PRId64" pcr %"PRId64, + (char*)&p_stream->fmt.i_codec, p_block->i_dts, p_stream->i_pcr, p_sys->i_pcr ); ) +} + +static void Ogg_SendQueuedBlocks( demux_t *p_demux, logical_stream_t *p_stream ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + + while( p_stream->queue.p_blocks ) + { + block_t *p_queued = p_stream->queue.p_blocks; + p_stream->queue.p_blocks = p_queued->p_next; + p_queued->p_next = NULL; + + if( p_queued->i_dts == VLC_TS_INVALID ) + p_queued->i_dts = p_queued->i_pts; - es_out_Send( p_demux->out, p_stream->p_es, tosend ); + if( p_queued->i_flags & BLOCK_FLAG_HEADER ) + { + if( p_sys->i_nzpcr_offset > 0 || /* Don't send metadata from chained streams */ + p_stream->fmt.i_extra > 0 ) /* Don't send metadata if configured by extradata */ + { + block_Release( p_queued ); + continue; } - p_stream->p_preparse_block = NULL; + p_queued->i_flags &= ~BLOCK_FLAG_HEADER; } - if ( p_block ) + unsigned i_toskip = 0; + if( p_stream->i_skip_frames > 0 ) { - DemuxDebug( msg_Dbg( p_demux, "block sent directly > pts %"PRId64" spcr %"PRId64" pcr %"PRId64, - p_block->i_pts, p_stream->i_pcr, p_ogg->i_pcr ) ); - if ( p_stream->p_es ) - es_out_Send( p_demux->out, p_stream->p_es, p_block ); + if( p_sys->i_nzpcr_offset > 0 ) + { + /* not preskip handling on chained streams */ + p_stream->i_skip_frames = 0; + } else - block_Release( p_block ); + { + i_toskip = __MIN( p_stream->i_skip_frames, p_queued->i_nb_samples ); + p_stream->i_skip_frames -= i_toskip; + p_queued->i_nb_samples -= i_toskip; + if( p_queued->i_nb_samples == 0 ) + p_queued->i_flags |= BLOCK_FLAG_PREROLL; + } } + + p_queued->i_flags |= p_stream->i_next_block_flags; + p_stream->i_next_block_flags = 0; + p_stream->i_pcr = p_queued->i_dts; + + DemuxDebug( msg_Dbg( p_demux, "%4.4s block sent > dts %"PRId64" pts %"PRId64" spcr %"PRId64" pcr %"PRId64 + " samples (%d/%d)", + (char*)&p_stream->fmt.i_codec, p_queued->i_dts, + p_queued->i_pts, p_stream->i_pcr, p_sys->i_pcr, + p_queued->i_nb_samples, i_toskip ); ); + + assert( p_sys->i_pcr != VLC_TS_INVALID ); + + if( p_stream->p_es ) + es_out_Send( p_demux->out, p_stream->p_es, p_queued ); + else + block_Release( p_queued ); } + + assert( p_stream->queue.p_blocks == NULL ); + p_stream->queue.pp_append = &p_stream->queue.p_blocks; } static bool Ogg_IsHeaderPacket( const logical_stream_t *p_stream, @@ -1354,13 +1311,20 @@ static void Ogg_DecodePacket( demux_t *p_demux, date_Set( &p_stream->dts, i_dts ); /* Write end granule as next start, or do interpolation */ - if( !Ogg_IsHeaderPacket( p_stream, p_oggpacket ) ) + bool b_header = Ogg_IsHeaderPacket( p_stream, p_oggpacket ); + if( !b_header ) Ogg_SetNextFrame( p_demux, p_stream, p_oggpacket ); if( !b_selected ) { /* 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 */ + if( !b_header && !p_stream->b_initializing ) + { + mtime_t i_pcr = date_Get( &p_stream->dts ); + if( i_pcr != VLC_TS_INVALID ) + p_stream->i_pcr = p_sys->i_nzpcr_offset + i_pcr; + } return; } @@ -1385,34 +1349,11 @@ static void Ogg_DecodePacket( demux_t *p_demux, if( p_stream->fmt.i_codec == VLC_CODEC_OPUS ) /* also required for trimming */ p_block->i_nb_samples = Ogg_OpusPacketDuration( p_oggpacket ); - DemuxDebug( msg_Dbg(p_demux, "block set from granule %"PRId64" to pts/pcr %"PRId64" skip %d", - p_oggpacket->granulepos, p_block->i_dts, p_stream->i_skip_frames); ) + DemuxDebug( msg_Dbg(p_demux, "%4.4s block set from granule %"PRId64" to pts/pcr %"PRId64" skip %d", + (char *) &p_stream->fmt.i_codec, p_oggpacket->granulepos, + p_block->i_dts, p_stream->i_skip_frames); ) /* may need to preroll after a seek or in case of preskip */ - if ( p_stream->i_skip_frames > 0 ) - { - if( p_stream->fmt.i_codec == VLC_CODEC_OPUS ) - { - if( p_stream->i_skip_frames >= p_block->i_nb_samples ) - { - if( p_sys->i_nzpcr_offset == 0 ) /* not on chained streams */ - p_block->i_flags |= BLOCK_FLAG_PREROLL; - p_stream->i_skip_frames -= p_block->i_nb_samples; - p_block->i_nb_samples = 0; - } - else - { - p_block->i_nb_samples -= p_stream->i_skip_frames; - p_stream->i_skip_frames = 0; - } - } - else - { - if( p_sys->i_nzpcr_offset == 0 ) /* not on chained streams */ - p_block->i_flags |= BLOCK_FLAG_PREROLL; - p_stream->i_skip_frames--; - } - } /* Conditional block fixes */ if ( p_stream->fmt.i_cat == VIDEO_ES ) @@ -1489,10 +1430,13 @@ static void Ogg_DecodePacket( demux_t *p_demux, p_block->i_buffer = 0; } + if( b_header ) + p_block->i_flags |= BLOCK_FLAG_HEADER; + memcpy( p_block->p_buffer, p_oggpacket->packet + i_header_len, p_oggpacket->bytes - i_header_len ); - Ogg_SendOrQueueBlocks( p_demux, p_stream, p_block ); + Ogg_QueueBlocks( p_demux, p_stream, p_block ); } static unsigned Ogg_OpusPacketDuration( ogg_packet *p_oggpacket ) @@ -1529,21 +1473,18 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) * We found the beginning of our first logical stream. */ while( ogg_page_bos( &p_ogg->current_page ) ) { - logical_stream_t *p_stream = calloc( 1, sizeof(logical_stream_t) ); + logical_stream_t *p_stream = malloc( sizeof(logical_stream_t) ); if( unlikely( !p_stream ) ) return VLC_ENOMEM; - TAB_APPEND( p_ogg->i_streams, p_ogg->pp_stream, p_stream ); - - es_format_Init( &p_stream->fmt, UNKNOWN_ES, 0 ); - es_format_Init( &p_stream->fmt_old, UNKNOWN_ES, 0 ); - p_stream->b_initializing = true; - p_stream->b_contiguous = true; /* default */ + Ogg_LogicalStreamInit( p_stream ); /* Setup the logical stream */ p_stream->i_serial_no = ogg_page_serialno( &p_ogg->current_page ); ogg_stream_init( &p_stream->os, p_stream->i_serial_no ); + TAB_APPEND( p_ogg->i_streams, p_ogg->pp_stream, p_stream ); + /* Extract the initial header from the first page and verify * the codec type of this Ogg bitstream */ if( ogg_stream_pagein( &p_stream->os, &p_ogg->current_page ) < 0 ) @@ -2190,7 +2131,7 @@ static int Ogg_BeginningOfStream( demux_t *p_demux ) else p_ogg->i_bitrate += p_stream->fmt.i_bitrate; - p_stream->i_pcr = VLC_TS_UNKNOWN; + p_stream->i_pcr = VLC_TS_INVALID; p_stream->b_reinit = false; } @@ -2256,6 +2197,18 @@ static void Ogg_CleanSpecificData( logical_stream_t *p_stream ) #endif } +static void Ogg_LogicalStreamInit( logical_stream_t *p_stream ) +{ + memset( p_stream, 0, sizeof(logical_stream_t) ); + es_format_Init( &p_stream->fmt, UNKNOWN_ES, 0 ); + es_format_Init( &p_stream->fmt_old, UNKNOWN_ES, 0 ); + p_stream->i_pcr = VLC_TS_INVALID; + date_Set( &p_stream->dts, VLC_TS_INVALID ); + p_stream->b_initializing = true; + p_stream->b_contiguous = true; /* default */ + p_stream->queue.pp_append = &p_stream->queue.p_blocks; +} + /** * This function delete and release all data associated to a logical_stream_t */ @@ -2285,12 +2238,7 @@ static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_strea 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->prepcr.pp_blocks ); + block_ChainRelease( p_stream->queue.p_blocks ); free( p_stream ); } @@ -3331,6 +3279,8 @@ static int dirac_bool( bs_t *p_bs ) static bool Ogg_ReadDiracHeader( logical_stream_t *p_stream, ogg_packet *p_oggpacket ) { + p_stream->special.dirac.b_old = (p_oggpacket->packet[0] == 'K'); + static const struct { uint32_t u_n /* numerator */, u_d /* denominator */; } p_dirac_frate_tbl[] = { /* table 10.3 */ @@ -3347,8 +3297,6 @@ static bool Ogg_ReadDiracHeader( logical_stream_t *p_stream, bs_t bs; - p_stream->i_granule_shift = 22; /* not 32 */ - /* Backing up stream headers is not required -- seqhdrs are repeated * thoughout the stream at suitable decoding start points */ p_stream->b_force_backup = false; diff --git a/modules/demux/ogg.h b/modules/demux/ogg.h index 1914762e41..4517eabb17 100644 --- a/modules/demux/ogg.h +++ b/modules/demux/ogg.h @@ -83,6 +83,7 @@ typedef struct logical_stream_s bool b_reinit; bool b_oggds; int i_granule_shift; + int i_next_block_flags; /* Opus has a starting offset in the headers. */ int i_pre_skip; @@ -108,12 +109,9 @@ typedef struct logical_stream_s /* All blocks which can't be sent because track PCR isn't known yet */ struct { - block_t **pp_blocks; - uint8_t i_size; /* max 255 */ - uint8_t i_used; - } prepcr; - /* All blocks that are queued because ES isn't created yet */ - block_t *p_preparse_block; + block_t *p_blocks; + block_t **pp_append; + } queue; union { @@ -134,6 +132,7 @@ typedef struct logical_stream_s struct { bool b_interlaced; + bool b_old; } dirac; struct { @@ -174,9 +173,6 @@ typedef struct * the sub-streams */ mtime_t i_pcr; mtime_t i_nzpcr_offset; - /* informative only */ - mtime_t i_pcr_jitter; - int64_t i_access_delay; /* new stream or starting from a chain */ bool b_chained_boundary; diff --git a/modules/demux/ogg_granule.c b/modules/demux/ogg_granule.c index 524533dd87..e29dcfed42 100644 --- a/modules/demux/ogg_granule.c +++ b/modules/demux/ogg_granule.c @@ -56,7 +56,10 @@ bool Ogg_IsKeyFrame( const logical_stream_t *p_stream, const ogg_packet *p_packe case VLC_CODEC_VP8: return ( ( ( p_packet->granulepos >> 3 ) & 0x07FFFFFF ) == 0 ); case VLC_CODEC_DIRAC: - return ( p_packet->granulepos & 0xFF8000FF ); + if( p_stream->special.dirac.b_old ) + return (p_packet->granulepos & 0x3FFFFFFF) == 0; + else + return (p_packet->granulepos & 0xFF8000FF) == 0; default: return true; } @@ -74,7 +77,10 @@ int64_t Ogg_GetKeyframeGranule( const logical_stream_t *p_stream, int64_t i_gran case VLC_CODEC_DAALA: return ( i_granule >> p_stream->i_granule_shift ) << p_stream->i_granule_shift; case VLC_CODEC_DIRAC: - return ( i_granule >> 31 ) << 31; + if( p_stream->special.dirac.b_old ) + return ( i_granule >> 30 ) << 30; + else + return ( i_granule >> 31 ) << 31; default: /* No change, that's keyframe */ return i_granule; @@ -83,7 +89,7 @@ int64_t Ogg_GetKeyframeGranule( const logical_stream_t *p_stream, int64_t i_gran static int64_t Ogg_GranuleToSampleDelta( const logical_stream_t *p_stream, int64_t i_granule ) { - if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC ) + if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC && !p_stream->special.dirac.b_old ) return (i_granule >> 9) & 0x1fff; else return -1; @@ -105,7 +111,10 @@ static int64_t Ogg_GranuleToSample( const logical_stream_t *p_stream, int64_t i_ case VLC_CODEC_OGGSPOTS: return i_granule >> p_stream->i_granule_shift; case VLC_CODEC_DIRAC: - return (i_granule >> 31); + if( p_stream->special.dirac.b_old ) + return (i_granule >> 30) + (i_granule & 0x3FFFFFFF); + else + return (i_granule >> 31); case VLC_CODEC_OPUS: case VLC_CODEC_VORBIS: case VLC_CODEC_SPEEX: _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
