diff options
author | Benoit Bolsee <benoit.bolsee@online.be> | 2010-02-26 01:12:16 +0300 |
---|---|---|
committer | Benoit Bolsee <benoit.bolsee@online.be> | 2010-02-26 01:12:16 +0300 |
commit | af987c12b533266475f90ca469761a1c7dca9902 (patch) | |
tree | de1a4b085c562fe7dfb5ff7087b849da8e1279d0 /source/gameengine/VideoTexture/VideoFFmpeg.cpp | |
parent | 0bef9d9c926f682eb29a9c016346901784cb4cc5 (diff) |
VideoTexture: fix a bug with AV sync that was causing a loss of sync in case of rewind to the begining of the file.
Diffstat (limited to 'source/gameengine/VideoTexture/VideoFFmpeg.cpp')
-rw-r--r-- | source/gameengine/VideoTexture/VideoFFmpeg.cpp | 52 |
1 files changed, 34 insertions, 18 deletions
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp index c33cb9a671d..6f7e9b82911 100644 --- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp +++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp @@ -304,6 +304,10 @@ void *VideoFFmpeg::cacheThread(void *data) CachePacket *cachePacket; bool endOfFile = false; int frameFinished = 0; + double timeBase = av_q2d(video->m_formatCtx->streams[video->m_videoStream]->time_base); + int64_t startTs = video->m_formatCtx->streams[video->m_videoStream]->start_time; + if (startTs == AV_NOPTS_VALUE) + startTs = 0; while (!video->m_stopThread) { @@ -390,7 +394,8 @@ void *VideoFFmpeg::cacheThread(void *data) currentFrame->frame->data, currentFrame->frame->linesize); // move frame to queue, this frame is necessarily the next one - currentFrame->framePosition = ++video->m_curPosition; + video->m_curPosition = (long)((cachePacket->packet.dts-startTs) * (video->m_baseFrameRate*timeBase) + 0.5); + currentFrame->framePosition = video->m_curPosition; pthread_mutex_lock(&video->m_cacheMutex); BLI_addtail(&video->m_frameCacheBase, currentFrame); pthread_mutex_unlock(&video->m_cacheMutex); @@ -731,14 +736,15 @@ void VideoFFmpeg::calcImage (unsigned int texId, double ts) // get actual time double startTime = PIL_check_seconds_timer(); double actTime; - if (m_isFile && ts >= 0.0) + // timestamp passed from audio actuators can sometimes be slightly negative + if (m_isFile && ts >= -0.5) { // allow setting timestamp only when not streaming actTime = ts; - if (m_eof && actTime * actFrameRate() < m_lastFrame) + if (actTime * actFrameRate() < m_lastFrame) { - // user is asking to rewind while the playback is already finished in the cache. - // we must clean the cache otherwise the eof condition will prevent any further reading. + // user is asking to rewind, force a cache clear to make sure we will do a seek + // note that this does not decrement m_repeat if ts didn't reach m_range[1] stopCache(); } } @@ -840,8 +846,9 @@ AVFrame *VideoFFmpeg::grabFrame(long position) int frameFinished; int posFound = 1; bool frameLoaded = false; - long long targetTs = 0; + int64_t targetTs = 0; CacheFrame *frame; + int64_t dts = 0; if (m_cacheStarted) { @@ -875,6 +882,10 @@ AVFrame *VideoFFmpeg::grabFrame(long position) { return frame->frame; } + if (frame->framePosition > position) + // this can happen after rewind if the seek didn't find the first frame + // the frame in the buffer is ahead of time, just leave it there + return NULL; // this frame is not useful, release it pthread_mutex_lock(&m_cacheMutex); BLI_remlink(&m_frameCacheBase, frame); @@ -882,6 +893,11 @@ AVFrame *VideoFFmpeg::grabFrame(long position) pthread_mutex_unlock(&m_cacheMutex); } while (true); } + double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base); + int64_t startTs = m_formatCtx->streams[m_videoStream]->start_time; + if (startTs == AV_NOPTS_VALUE) + startTs = 0; + // come here when there is no cache or cache has been stopped // locate the frame, by seeking if necessary (seeking is only possible for files) if (m_isFile) @@ -901,7 +917,9 @@ AVFrame *VideoFFmpeg::grabFrame(long position) m_frame, &frameFinished, packet.data, packet.size); if (frameFinished) - m_curPosition++; + { + m_curPosition = (long)((packet.dts-startTs) * (m_baseFrameRate*timeBase) + 0.5); + } } av_free_packet(&packet); if (position == m_curPosition+1) @@ -911,16 +929,13 @@ AVFrame *VideoFFmpeg::grabFrame(long position) // if the position is not in preseek, do a direct jump if (position != m_curPosition + 1) { - double timeBase = av_q2d(m_formatCtx->streams[m_videoStream]->time_base); int64_t pos = (int64_t)((position - m_preseek) / (m_baseFrameRate*timeBase)); - int64_t startTs = m_formatCtx->streams[m_videoStream]->start_time; int seekres; if (pos < 0) pos = 0; - if (startTs != AV_NOPTS_VALUE) - pos += startTs; + pos += startTs; if (position <= m_curPosition || !m_eof) { @@ -952,9 +967,7 @@ AVFrame *VideoFFmpeg::grabFrame(long position) } } // this is the timestamp of the frame we're looking for - targetTs = (int64_t)(position / (m_baseFrameRate * timeBase)); - if (startTs != AV_NOPTS_VALUE) - targetTs += startTs; + targetTs = (int64_t)(position / (m_baseFrameRate * timeBase)) + startTs; posFound = 0; avcodec_flush_buffers(m_codecCtx); @@ -978,14 +991,17 @@ AVFrame *VideoFFmpeg::grabFrame(long position) avcodec_decode_video(m_codecCtx, m_frame, &frameFinished, packet.data, packet.size); - + // remember dts to compute exact frame number + dts = packet.dts; if (frameFinished && !posFound) { - if (packet.dts >= targetTs) + if (dts >= targetTs) + { posFound = 1; + } } - if(frameFinished && posFound == 1) + if (frameFinished && posFound == 1) { AVFrame * input = m_frame; @@ -1028,7 +1044,7 @@ AVFrame *VideoFFmpeg::grabFrame(long position) m_eof = m_isFile && !frameLoaded; if (frameLoaded) { - m_curPosition = position; + m_curPosition = (long)((dts-startTs) * (m_baseFrameRate*timeBase) + 0.5); if (m_isThreaded) { // normal case for file: first locate, then start cache |