Browse Source

demux: ogg: limit discarded frames to pre-skip on bos

refs #19242
pull/162/head
Francois Cartegnie 3 years ago
parent
commit
262ab17e72
  1. 46
      modules/demux/ogg.c
  2. 7
      modules/demux/ogg.h
  3. 12
      modules/demux/oggseek.c

46
modules/demux/ogg.c

@ -530,6 +530,17 @@ static int Demux( demux_t * p_demux )
}
}
if( ogg_page_granulepos( &p_sys->current_page ) == 0 && !p_stream->b_oggds )
p_stream->page_type = OGGPAGE_HEADER;
else if( p_stream->page_type == OGGPAGE_HEADER )
p_stream->page_type = OGGPAGE_FIRST;
else
p_stream->page_type = OGGPAGE_OTHER;
if( p_stream->page_type == OGGPAGE_FIRST && p_stream->fmt.i_codec == VLC_CODEC_OPUS )
p_stream->i_skip_frames = p_stream->i_pre_skip;
/* clear the finished flag if pages after eos (ex: after a seek) */
if ( ! ogg_page_eos( &p_sys->current_page ) && p_sys->p_skelstream != p_stream )
p_stream->b_finished = false;
@ -576,15 +587,6 @@ static int Demux( demux_t * p_demux )
p_stream->i_data_start = vlc_stream_Tell( p_demux->s );
}
if( p_stream->b_reinit )
{
p_stream->b_reinit = false;
if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
{
p_stream->i_skip_frames = p_stream->i_pre_skip;
}
}
Ogg_DecodePacket( p_demux, p_stream, &oggpacket, ogg_page_eos( &p_sys->current_page ) );
}
@ -629,8 +631,18 @@ static void Ogg_ResetStream( logical_stream_t *p_stream )
p_stream->special.vorbis.i_prev_blocksize = 0;
}
#endif
if( p_stream->fmt.i_codec == VLC_CODEC_OPUS )
{
/* For Opus, trash the first 80 ms of decoded output as
well, to avoid blowing out speakers if we get unlucky.
Opus predicts content from prior frames, which can go
badly if we seek right where the stream goes from very
quiet to very loud. It will converge after a bit. */
if( p_stream->i_skip_frames < p_stream->i_pre_skip )
p_stream->i_skip_frames = __MAX( 80*48, p_stream->i_pre_skip );
}
/* we'll trash all the data until we find the next pcr */
p_stream->b_reinit = true;
p_stream->i_pcr = VLC_TICK_INVALID;
p_stream->i_next_block_flags = 0;
p_stream->b_interpolation_failed = false;
@ -1603,6 +1615,11 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
p_stream->i_serial_no = ogg_page_serialno( &p_ogg->current_page );
ogg_stream_init( &p_stream->os, p_stream->i_serial_no );
if( ogg_page_granulepos( &p_ogg->current_page ) == 0 && !p_stream->b_oggds )
p_stream->page_type = OGGPAGE_HEADER;
else
p_stream->page_type = OGGPAGE_OTHER;
TAB_APPEND( p_ogg->i_streams, p_ogg->pp_stream, p_stream );
/* Extract the initial header from the first page and verify
@ -2207,7 +2224,6 @@ static void Ogg_CreateES( demux_t *p_demux, bool stable_id )
p_stream->p_es = p_old_stream->p_es;
p_stream->b_finished = false;
p_stream->b_reinit = false;
p_stream->b_initializing = false;
p_stream->i_pre_skip = 0;
es_format_Clean( &p_stream->fmt_old );
@ -2282,7 +2298,6 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
p_ogg->i_bitrate += p_stream->fmt.i_bitrate;
p_stream->i_pcr = VLC_TICK_INVALID;
p_stream->b_reinit = false;
}
/* get total frame count for video stream; we will need this for seeking */
@ -2354,6 +2369,7 @@ static void Ogg_LogicalStreamInit( logical_stream_t *p_stream )
es_format_Init( &p_stream->fmt_old, UNKNOWN_ES, 0 );
p_stream->i_pcr = VLC_TICK_INVALID;
p_stream->i_first_frame_index = 1;
p_stream->page_type = OGGPAGE_OTHER;
date_Set( &p_stream->dts, VLC_TICK_INVALID );
p_stream->b_initializing = true;
p_stream->b_contiguous = true; /* default */
@ -2933,12 +2949,6 @@ static void Ogg_ReadOpusHeader( logical_stream_t *p_stream,
break;
}
}
/* For Opus, trash the first 80 ms of decoded output as
well, to avoid blowing out speakers if we get unlucky.
Opus predicts content from prior frames, which can go
badly if we seek right where the stream goes from very
quiet to very loud. It will converge after a bit. */
p_stream->i_pre_skip = __MAX( 80*48, p_stream->i_pre_skip );
}
static bool Ogg_ReadFlacStreamInfo( demux_t *p_demux, logical_stream_t *p_stream,

7
modules/demux/ogg.h

@ -83,13 +83,18 @@ typedef struct logical_stream_s
/* Misc */
bool b_initializing;
bool b_finished;
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;
enum
{
OGGPAGE_HEADER,
OGGPAGE_FIRST,
OGGPAGE_OTHER,
} page_type;
/* offset of first keyframe for theora; can be 0 or 1 depending on version number */
int8_t i_first_frame_index;

12
modules/demux/oggseek.c

@ -309,6 +309,15 @@ clean:
ogg_stream_clear( &os );
}
static void update_page_type( logical_stream_t *p_stream, int64_t i_granule )
{
if( i_granule == 0 )
p_stream->page_type = OGGPAGE_HEADER;
else if( p_stream->page_type == OGGPAGE_HEADER )
p_stream->page_type = OGGPAGE_FIRST;
else
p_stream->page_type = OGGPAGE_OTHER;
}
static int64_t find_first_page_granule( demux_t *p_demux,
int64_t i_pos1, int64_t i_pos2,
@ -402,6 +411,7 @@ static int64_t find_first_page_granule( demux_t *p_demux,
if ( ogg_page_granulepos( &p_sys->current_page ) <= 0 )
{
update_page_type( p_stream, ogg_page_granulepos(( &p_sys->current_page )) );
/* A negative granulepos means that the packet continues on the
* next page => read the next page */
p_sys->i_input_position += i_result;
@ -437,6 +447,8 @@ static bool OggSeekToPacket( demux_t *p_demux, logical_stream_t *p_stream,
p_sys->b_page_waiting = true;
int i=0;
update_page_type( p_stream, ogg_page_granulepos( &p_sys->current_page ) );
int64_t itarget_frame = Ogg_GetKeyframeGranule( p_stream, i_granulepos );
int64_t iframe = Ogg_GetKeyframeGranule( p_stream, ogg_page_granulepos( &p_sys->current_page ) );

Loading…
Cancel
Save