== FFMPEG ==
authorPeter Schlaile <peter@schlaile.de>
Mon, 1 Nov 2010 18:13:10 +0000 (18:13 +0000)
committerPeter Schlaile <peter@schlaile.de>
Mon, 1 Nov 2010 18:13:10 +0000 (18:13 +0000)
This fixes a rather subtle seeking issue with ffmpeg and Sony
XDCAM-footage.

Problem is: MPEG2 streams within an MP4 container can contain a start
time - at several places. There is a starttime within the video
and audio streams and one within the container.

FFMpeg commandline tool only uses the container starttime and we used
the stream starttime.

The world would be a better place, if those two timestamps always match
up, since in XDCAM-footage those two starttimes differ in 4
frames - and the container has the right one.

We now always use the container start time as ffmpeg commandline tool
does (in the hope, that there is a good explaination for this and this
is the right thing(tm) to do).

I tested this also with HDV footage, which seems to work with the new
code, too.

Additional fix: disabled seek_by_bytes again, since it will only work
correctly, if ffmpeg guessed the HDV bitrate right (which it doesn't).
If you have seeking issues with HDV and have an older version of ffmpeg
installed, please upgrade, newer versions have some fixes in them.

intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
source/blender/imbuf/intern/anim_movie.c

index 09fdb31e93838e7fa9f9d0d5823b4abb859370d2..5526b0dcf5a01a0814ea2ee46ea0dfb1e5d3a76d 100644 (file)
@@ -246,10 +246,8 @@ void AUD_FFMPEGReader::seek(int position)
 {
        if(position >= 0)
        {
-               uint64_t st_time = m_formatCtx->streams[m_stream]->start_time;
-               double time_base = 
-                       av_q2d(m_formatCtx->streams[m_stream]->time_base);
-               uint64_t seek_pos = position / time_base / m_specs.rate;
+               uint64_t st_time = m_formatCtx->start_time;
+               uint64_t seek_pos = position * AV_TIME_BASE / m_specs.rate;
 
                if (seek_pos < 0) {
                        seek_pos = 0;
@@ -259,9 +257,14 @@ void AUD_FFMPEGReader::seek(int position)
                        seek_pos += st_time;
                }
 
+               double pts_time_base = 
+                       av_q2d(m_formatCtx->streams[m_stream]->time_base);
+               uint64_t pts_st_time =
+                       ((st_time != AV_NOPTS_VALUE) ? st_time : 0)
+                       / pts_time_base / (uint64_t) AV_TIME_BASE;
 
                // a value < 0 tells us that seeking failed
-               if(av_seek_frame(m_formatCtx, m_stream, seek_pos,
+               if(av_seek_frame(m_formatCtx, -1, seek_pos,
                                 AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
                {
                        avcodec_flush_buffers(m_codecCtx);
@@ -284,7 +287,7 @@ void AUD_FFMPEGReader::seek(int position)
                                        {
                                                // calculate real position, and read to frame!
                                                m_position = (packet.pts - 
-                                                       ((st_time != AV_NOPTS_VALUE) ? st_time : 0)) * time_base * m_specs.rate;
+                                                       pts_st_time) * pts_time_base * m_specs.rate;
 
                                                if(m_position < position)
                                                {
@@ -307,6 +310,7 @@ void AUD_FFMPEGReader::seek(int position)
                }
                else
                {
+                       fprintf(stderr, "seeking failed!\n");
                        // Seeking failed, do nothing.
                }
        }
index 8df0d69bcfa477fcfa2bdb0c3180faa69b235232..421ef08dc25e15f55befbfaebc9868fb13b8e143 100644 (file)
@@ -839,7 +839,15 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
                }
        }
 
+/* disable seek_by_bytes for now, since bitrates are guessed wrong!
+   also: MPEG2TS-seeking was fixed in later versions of ffmpeg, so problem
+   is somewhat fixed by now (until we add correct timecode management code...)
+*/
+#if 0
        seek_by_bytes = !!(anim->pFormatCtx->iformat->flags & AVFMT_TS_DISCONT);
+#else
+       seek_by_bytes = FALSE;
+#endif
 
        if (position != anim->curposition + 1) { 
 #ifdef FFMPEG_OLD_FRAME_RATE
@@ -851,12 +859,9 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
                        av_q2d(anim->pFormatCtx->streams[anim->videoStream]
                                   ->r_frame_rate);
 #endif
-               double time_base = 
-                       av_q2d(anim->pFormatCtx->streams[anim->videoStream]
-                                  ->time_base);
+               double pts_time_base = av_q2d(anim->pFormatCtx->streams[anim->videoStream]->time_base);
                long long pos;
-               long long st_time = anim->pFormatCtx
-                       ->streams[anim->videoStream]->start_time;
+               long long st_time = anim->pFormatCtx->start_time;
                int ret;
 
                if (seek_by_bytes) {
@@ -876,7 +881,7 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
                        }
 
                        if (st_time != AV_NOPTS_VALUE) {
-                               pos += st_time * AV_TIME_BASE * time_base;
+                               pos += st_time;
                        }
                }
 
@@ -891,9 +896,9 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
                }
 
                pts_to_search = (long long) 
-                       (((double) position) / time_base / frame_rate);
+                       (((double) position) / pts_time_base / frame_rate);
                if (st_time != AV_NOPTS_VALUE) {
-                       pts_to_search += st_time;
+                       pts_to_search += st_time / pts_time_base/ AV_TIME_BASE;
                }
 
                pos_found = 0;