Commit a0110b72 authored by Francois Cartegnie's avatar Francois Cartegnie

demux: ogg: change pts/pcr generation from packets (fix #10198, fix #9605)

Stop using headers granule and invalid granule for PCR/PTS.
Delays until first PTS/PCR is really known. Avoids 0 to PTS gap
for non zero starting streams.
parent f5d0c4b6
...@@ -173,6 +173,10 @@ static void fill_channels_info(audio_format_t *audio) ...@@ -173,6 +173,10 @@ static void fill_channels_info(audio_format_t *audio)
audio->i_original_channels = pi_channels_map[chans]; audio->i_original_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 * Open: initializes ogg demux structures
*****************************************************************************/ *****************************************************************************/
...@@ -280,11 +284,9 @@ static int Demux( demux_t * p_demux ) ...@@ -280,11 +284,9 @@ static int Demux( demux_t * p_demux )
stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek ); stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
if ( b_canseek ) if ( b_canseek )
Oggseek_ProbeEnd( p_demux ); Oggseek_ProbeEnd( p_demux );
es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 );
} }
else else
{ {
es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
p_sys->b_chained_boundary = false; p_sys->b_chained_boundary = false;
} }
} }
...@@ -372,8 +374,8 @@ static int Demux( demux_t * p_demux ) ...@@ -372,8 +374,8 @@ static int Demux( demux_t * p_demux )
ogg_stream_reset_serialno( &p_stream->os, ogg_page_serialno( &p_sys->current_page ) ); ogg_stream_reset_serialno( &p_stream->os, ogg_page_serialno( &p_sys->current_page ) );
p_stream->b_reinit = true; p_stream->b_reinit = true;
p_stream->i_pcr = VLC_TS_0; p_stream->i_pcr = VLC_TS_UNKNOWN;
p_stream->i_interpolated_pcr = VLC_TS_0; p_stream->i_interpolated_pcr = VLC_TS_UNKNOWN;
p_stream->i_previous_granulepos = -1; p_stream->i_previous_granulepos = -1;
es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0); es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0);
} }
...@@ -539,7 +541,10 @@ static int Demux( demux_t * p_demux ) ...@@ -539,7 +541,10 @@ static int Demux( demux_t * p_demux )
else else
p_sys->b_preparsing_done = true; p_sys->b_preparsing_done = true;
p_sys->i_pcr = -1; /* We will consider the lowest PCR among tracks, because the audio core badly
* handles PCR rewind (mute)
*/
mtime_t i_pcr_candidate = VLC_TS_INVALID;
for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ ) for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
{ {
logical_stream_t *p_stream = p_sys->pp_stream[i_stream]; logical_stream_t *p_stream = p_sys->pp_stream[i_stream];
...@@ -552,15 +557,24 @@ static int Demux( demux_t * p_demux ) ...@@ -552,15 +557,24 @@ static int Demux( demux_t * p_demux )
if( p_stream->fmt.i_cat == SPU_ES ) if( p_stream->fmt.i_cat == SPU_ES )
continue; continue;
if( p_stream->i_interpolated_pcr < 0 ) if( p_stream->i_interpolated_pcr < VLC_TS_0 )
continue;
if ( p_stream->b_finished || p_stream->b_initializing )
continue; continue;
if( p_sys->i_pcr < 0 || p_stream->i_interpolated_pcr < p_sys->i_pcr ) if( i_pcr_candidate < VLC_TS_0
p_sys->i_pcr = p_stream->i_interpolated_pcr; || p_stream->i_interpolated_pcr <= i_pcr_candidate )
{
i_pcr_candidate = p_stream->i_interpolated_pcr;
}
} }
if( p_sys->i_pcr >= 0 && ! b_skipping ) if ( i_pcr_candidate > VLC_TS_INVALID && p_sys->i_pcr != i_pcr_candidate )
es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr ); {
p_sys->i_pcr = i_pcr_candidate;
if( ! b_skipping )
es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr );
}
return 1; return 1;
} }
...@@ -573,8 +587,8 @@ static void Ogg_ResetStreamHelper( demux_sys_t *p_sys ) ...@@ -573,8 +587,8 @@ static void Ogg_ResetStreamHelper( demux_sys_t *p_sys )
/* we'll trash all the data until we find the next pcr */ /* we'll trash all the data until we find the next pcr */
p_stream->b_reinit = true; p_stream->b_reinit = true;
p_stream->i_pcr = -1; p_stream->i_pcr = VLC_TS_UNKNOWN;
p_stream->i_interpolated_pcr = -1; p_stream->i_interpolated_pcr = VLC_TS_UNKNOWN;
p_stream->i_previous_granulepos = -1; p_stream->i_previous_granulepos = -1;
ogg_stream_reset( &p_stream->os ); ogg_stream_reset( &p_stream->os );
} }
...@@ -843,7 +857,13 @@ static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream, ...@@ -843,7 +857,13 @@ static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream,
p_stream->i_end_trim = 0; p_stream->i_end_trim = 0;
/* Convert the granulepos into a pcr */ /* Convert the granulepos into a pcr */
if( p_oggpacket->granulepos >= 0 ) if ( p_oggpacket->granulepos == 0 )
{
/* We're in headers, and we haven't parsed 1st data packet yet */
p_stream->i_pcr = VLC_TS_UNKNOWN;
p_stream->i_interpolated_pcr = VLC_TS_UNKNOWN;
}
else if( p_oggpacket->granulepos > 0 )
{ {
if( p_stream->fmt.i_codec == VLC_CODEC_THEORA || if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
p_stream->fmt.i_codec == VLC_CODEC_KATE || p_stream->fmt.i_codec == VLC_CODEC_KATE ||
...@@ -886,7 +906,7 @@ static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream, ...@@ -886,7 +906,7 @@ static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream,
else else
{ {
int duration; int duration;
p_stream->i_pcr = -1; p_stream->i_pcr = VLC_TS_INVALID;
/* no granulepos available, try to interpolate the pcr. /* no granulepos available, try to interpolate the pcr.
* If we can't then don't touch the old value. */ * If we can't then don't touch the old value. */
...@@ -910,7 +930,7 @@ static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream, ...@@ -910,7 +930,7 @@ static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream,
VLC_TS_0 + sample * CLOCK_FREQ / p_stream->f_rate; VLC_TS_0 + sample * CLOCK_FREQ / p_stream->f_rate;
p_stream->i_interpolated_pcr += p_ogg->i_pcr_offset; p_stream->i_interpolated_pcr += p_ogg->i_pcr_offset;
} }
else if( p_stream->fmt.i_bitrate ) else if( p_stream->fmt.i_bitrate && p_stream->i_pcr > VLC_TS_UNKNOWN )
{ {
p_stream->i_interpolated_pcr += p_stream->i_interpolated_pcr +=
( p_oggpacket->bytes * CLOCK_FREQ / ( p_oggpacket->bytes * CLOCK_FREQ /
...@@ -931,7 +951,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -931,7 +951,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
block_t *p_block; block_t *p_block;
bool b_selected; bool b_selected;
int i_header_len = 0; int i_header_len = 0;
mtime_t i_pts = -1, i_interpolated_pts; mtime_t i_pts = VLC_TS_UNKNOWN, i_interpolated_pts;
demux_sys_t *p_ogg = p_demux->p_sys; demux_sys_t *p_ogg = p_demux->p_sys;
if( p_oggpacket->bytes >= 7 && if( p_oggpacket->bytes >= 7 &&
...@@ -1084,7 +1104,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -1084,7 +1104,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
p_stream->fmt.i_codec == VLC_CODEC_OPUS || p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
p_stream->fmt.i_codec == VLC_CODEC_FLAC ) p_stream->fmt.i_codec == VLC_CODEC_FLAC )
{ {
if( p_stream->i_pcr >= 0 ) if( p_stream->i_pcr > VLC_TS_INVALID )
{ {
p_stream->i_previous_pcr = p_stream->i_pcr; p_stream->i_previous_pcr = p_stream->i_pcr;
/* The granulepos is the end date of the sample */ /* The granulepos is the end date of the sample */
...@@ -1153,14 +1173,9 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -1153,14 +1173,9 @@ static void Ogg_DecodePacket( demux_t *p_demux,
else if( p_stream->fmt.i_codec == VLC_CODEC_OPUS ) else if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
p_block->i_nb_samples = Ogg_OpusPacketDuration( p_stream, p_oggpacket ); p_block->i_nb_samples = Ogg_OpusPacketDuration( p_stream, p_oggpacket );
/* Normalize PTS */ /* Normalize PTS */
if( i_pts == VLC_TS_INVALID ) i_pts = VLC_TS_0; if( i_pts == VLC_TS_UNKNOWN )
else if( i_pts == -1 && i_interpolated_pts == VLC_TS_INVALID ) i_pts = VLC_TS_INVALID;
i_pts = VLC_TS_0;
else if( i_pts == -1 && (p_stream->fmt.i_cat == VIDEO_ES || p_stream->fmt.i_codec == VLC_CODEC_OPUS) )
i_pts = i_interpolated_pts; /* FIXME : why is this incorrect for vorbis? */
else if( i_pts == -1 ) i_pts = VLC_TS_INVALID;
if( p_stream->fmt.i_cat == AUDIO_ES ) if( p_stream->fmt.i_cat == AUDIO_ES )
{ {
...@@ -1264,6 +1279,12 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -1264,6 +1279,12 @@ static void Ogg_DecodePacket( demux_t *p_demux,
memcpy( p_block->p_buffer, p_oggpacket->packet + i_header_len, memcpy( p_block->p_buffer, p_oggpacket->packet + i_header_len,
p_oggpacket->bytes - i_header_len ); p_oggpacket->bytes - i_header_len );
if ( p_ogg->i_streams == 1 && p_block->i_pts > VLC_TS_INVALID && p_ogg->i_pcr < VLC_TS_0 )
{
p_ogg->i_pcr = p_block->i_pts;
es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_ogg->i_pcr );
}
if ( p_stream->p_es ) if ( p_stream->p_es )
{ {
/* Because ES creation is delayed for preparsing */ /* Because ES creation is delayed for preparsing */
...@@ -1890,7 +1911,7 @@ static int Ogg_BeginningOfStream( demux_t *p_demux ) ...@@ -1890,7 +1911,7 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
p_ogg->i_bitrate += p_stream->fmt.i_bitrate; p_ogg->i_bitrate += p_stream->fmt.i_bitrate;
p_stream->i_pcr = p_stream->i_previous_pcr = p_stream->i_pcr = p_stream->i_previous_pcr =
p_stream->i_interpolated_pcr = -1; p_stream->i_interpolated_pcr = VLC_TS_UNKNOWN;
p_stream->b_reinit = false; p_stream->b_reinit = false;
} }
......
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