From ff925491955036647c6de26c07070cc2afafda51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Sun, 12 Feb 2012 10:52:42 +0100 Subject: [PATCH] Fix Theora-in-ogg keyframe handling. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- libavformat/oggenc.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index ac6eb8737d..315b8da049 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -131,6 +131,11 @@ static int ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags) return 0; } +static int ogg_key_granule(OGGStreamContext *oggstream, int64_t granule) +{ + return oggstream->kfgshift && !(granule & ((1<kfgshift)-1)); +} + static int64_t ogg_granule_to_timestamp(OGGStreamContext *oggstream, int64_t granule) { if (oggstream->kfgshift) @@ -199,9 +204,15 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st, int i, segments, len, flush = 0; // 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 && - ogg_granule_to_timestamp(oggstream, granule) > - ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1) { + oggstream->page.size && + (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) ogg_buffer_page(s, oggstream); flush = 1;