forked from bartvdbraak/blender
VideoTexture: fix a bug with AV sync that was causing a loss of sync in case of rewind to the begining of the file.
This commit is contained in:
parent
0bef9d9c92
commit
af987c12b5
@ -304,6 +304,10 @@ void *VideoFFmpeg::cacheThread(void *data)
|
|||||||
CachePacket *cachePacket;
|
CachePacket *cachePacket;
|
||||||
bool endOfFile = false;
|
bool endOfFile = false;
|
||||||
int frameFinished = 0;
|
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)
|
while (!video->m_stopThread)
|
||||||
{
|
{
|
||||||
@ -390,7 +394,8 @@ void *VideoFFmpeg::cacheThread(void *data)
|
|||||||
currentFrame->frame->data,
|
currentFrame->frame->data,
|
||||||
currentFrame->frame->linesize);
|
currentFrame->frame->linesize);
|
||||||
// move frame to queue, this frame is necessarily the next one
|
// 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);
|
pthread_mutex_lock(&video->m_cacheMutex);
|
||||||
BLI_addtail(&video->m_frameCacheBase, currentFrame);
|
BLI_addtail(&video->m_frameCacheBase, currentFrame);
|
||||||
pthread_mutex_unlock(&video->m_cacheMutex);
|
pthread_mutex_unlock(&video->m_cacheMutex);
|
||||||
@ -731,14 +736,15 @@ void VideoFFmpeg::calcImage (unsigned int texId, double ts)
|
|||||||
// get actual time
|
// get actual time
|
||||||
double startTime = PIL_check_seconds_timer();
|
double startTime = PIL_check_seconds_timer();
|
||||||
double actTime;
|
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
|
// allow setting timestamp only when not streaming
|
||||||
actTime = ts;
|
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.
|
// user is asking to rewind, force a cache clear to make sure we will do a seek
|
||||||
// we must clean the cache otherwise the eof condition will prevent any further reading.
|
// note that this does not decrement m_repeat if ts didn't reach m_range[1]
|
||||||
stopCache();
|
stopCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -840,8 +846,9 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
|
|||||||
int frameFinished;
|
int frameFinished;
|
||||||
int posFound = 1;
|
int posFound = 1;
|
||||||
bool frameLoaded = false;
|
bool frameLoaded = false;
|
||||||
long long targetTs = 0;
|
int64_t targetTs = 0;
|
||||||
CacheFrame *frame;
|
CacheFrame *frame;
|
||||||
|
int64_t dts = 0;
|
||||||
|
|
||||||
if (m_cacheStarted)
|
if (m_cacheStarted)
|
||||||
{
|
{
|
||||||
@ -875,6 +882,10 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
|
|||||||
{
|
{
|
||||||
return frame->frame;
|
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
|
// this frame is not useful, release it
|
||||||
pthread_mutex_lock(&m_cacheMutex);
|
pthread_mutex_lock(&m_cacheMutex);
|
||||||
BLI_remlink(&m_frameCacheBase, frame);
|
BLI_remlink(&m_frameCacheBase, frame);
|
||||||
@ -882,6 +893,11 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
|
|||||||
pthread_mutex_unlock(&m_cacheMutex);
|
pthread_mutex_unlock(&m_cacheMutex);
|
||||||
} while (true);
|
} 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
|
// 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)
|
// locate the frame, by seeking if necessary (seeking is only possible for files)
|
||||||
if (m_isFile)
|
if (m_isFile)
|
||||||
@ -901,7 +917,9 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
|
|||||||
m_frame, &frameFinished,
|
m_frame, &frameFinished,
|
||||||
packet.data, packet.size);
|
packet.data, packet.size);
|
||||||
if (frameFinished)
|
if (frameFinished)
|
||||||
m_curPosition++;
|
{
|
||||||
|
m_curPosition = (long)((packet.dts-startTs) * (m_baseFrameRate*timeBase) + 0.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
av_free_packet(&packet);
|
av_free_packet(&packet);
|
||||||
if (position == m_curPosition+1)
|
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 the position is not in preseek, do a direct jump
|
||||||
if (position != m_curPosition + 1)
|
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 pos = (int64_t)((position - m_preseek) / (m_baseFrameRate*timeBase));
|
||||||
int64_t startTs = m_formatCtx->streams[m_videoStream]->start_time;
|
|
||||||
int seekres;
|
int seekres;
|
||||||
|
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
pos = 0;
|
pos = 0;
|
||||||
|
|
||||||
if (startTs != AV_NOPTS_VALUE)
|
pos += startTs;
|
||||||
pos += startTs;
|
|
||||||
|
|
||||||
if (position <= m_curPosition || !m_eof)
|
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
|
// this is the timestamp of the frame we're looking for
|
||||||
targetTs = (int64_t)(position / (m_baseFrameRate * timeBase));
|
targetTs = (int64_t)(position / (m_baseFrameRate * timeBase)) + startTs;
|
||||||
if (startTs != AV_NOPTS_VALUE)
|
|
||||||
targetTs += startTs;
|
|
||||||
|
|
||||||
posFound = 0;
|
posFound = 0;
|
||||||
avcodec_flush_buffers(m_codecCtx);
|
avcodec_flush_buffers(m_codecCtx);
|
||||||
@ -978,14 +991,17 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
|
|||||||
avcodec_decode_video(m_codecCtx,
|
avcodec_decode_video(m_codecCtx,
|
||||||
m_frame, &frameFinished,
|
m_frame, &frameFinished,
|
||||||
packet.data, packet.size);
|
packet.data, packet.size);
|
||||||
|
// remember dts to compute exact frame number
|
||||||
|
dts = packet.dts;
|
||||||
if (frameFinished && !posFound)
|
if (frameFinished && !posFound)
|
||||||
{
|
{
|
||||||
if (packet.dts >= targetTs)
|
if (dts >= targetTs)
|
||||||
|
{
|
||||||
posFound = 1;
|
posFound = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(frameFinished && posFound == 1)
|
if (frameFinished && posFound == 1)
|
||||||
{
|
{
|
||||||
AVFrame * input = m_frame;
|
AVFrame * input = m_frame;
|
||||||
|
|
||||||
@ -1028,7 +1044,7 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
|
|||||||
m_eof = m_isFile && !frameLoaded;
|
m_eof = m_isFile && !frameLoaded;
|
||||||
if (frameLoaded)
|
if (frameLoaded)
|
||||||
{
|
{
|
||||||
m_curPosition = position;
|
m_curPosition = (long)((dts-startTs) * (m_baseFrameRate*timeBase) + 0.5);
|
||||||
if (m_isThreaded)
|
if (m_isThreaded)
|
||||||
{
|
{
|
||||||
// normal case for file: first locate, then start cache
|
// normal case for file: first locate, then start cache
|
||||||
|
Loading…
Reference in New Issue
Block a user