[FFmpeg-cvslog] Fix Theora-in-ogg keyframe handling.

Reimar Döffinger git at videolan.org
Sun Feb 12 18:57:06 CET 2012


ffmpeg | branch: master | Reimar Döffinger <Reimar.Doeffinger at gmx.de> | Sun Feb 12 10:52:42 2012 +0100| [ff925491955036647c6de26c07070cc2afafda51] | committer: Reimar Döffinger

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 at gmx.de>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=ff925491955036647c6de26c07070cc2afafda51
---

 libavformat/oggenc.c |   15 +++++++++++++--
 1 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index ac6eb87..315b8da 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<<oggstream->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;



More information about the ffmpeg-cvslog mailing list