Fix Theora-in-ogg keyframe handling.

To make seeking work correctly, we must write a new granule for
each keyframe.
Unfortunately we currently have no regression tests due to no
included Theora encoder.
A test based on -vcodec copy from a Theora FATE sample should
probably be added.

Signed-off-by: Reimar Döffinger <Reimar.Doeffinger@gmx.de>
This commit is contained in:
Reimar Döffinger 2012-02-12 10:52:42 +01:00
parent b223035511
commit ff92549195

View File

@ -131,6 +131,11 @@ static int ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags)
return 0; return 0;
} }
static int ogg_key_granule(OGGStreamContext *oggstream, int64_t granule)
{
return oggstream->kfgshift && !(granule & ((1<<oggstream->kfgshift)-1));
}
static int64_t ogg_granule_to_timestamp(OGGStreamContext *oggstream, int64_t granule) static int64_t ogg_granule_to_timestamp(OGGStreamContext *oggstream, int64_t granule)
{ {
if (oggstream->kfgshift) if (oggstream->kfgshift)
@ -199,9 +204,15 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
int i, segments, len, flush = 0; int i, segments, len, flush = 0;
// Handles VFR by flushing page because this frame needs to have a timestamp // Handles VFR by flushing page because this frame needs to have a timestamp
// For theora, keyframes also need to have a timestamp to correctly mark
// them as such, otherwise seeking will not work correctly at the very
// least with old libogg versions.
// Do not try to flush empty packets though, that will create broken files.
if (st->codec->codec_id == CODEC_ID_THEORA && if (st->codec->codec_id == CODEC_ID_THEORA &&
ogg_granule_to_timestamp(oggstream, granule) > oggstream->page.size &&
ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1) { (ogg_granule_to_timestamp(oggstream, granule) >
ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1 ||
ogg_key_granule(oggstream, granule))) {
if (oggstream->page.granule != -1) if (oggstream->page.granule != -1)
ogg_buffer_page(s, oggstream); ogg_buffer_page(s, oggstream);
flush = 1; flush = 1;