[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [27146] trunk/blender/source/gameengine/ VideoTexture/VideoFFmpeg.cpp: VideoTexture: fix a bug with AV sync that was causing a loss of sync in case of rewind to the begining of the file .

Benoit Bolsee benoit.bolsee at online.be
Thu Feb 25 23:12:16 CET 2010


Revision: 27146
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=27146
Author:   ben2610
Date:     2010-02-25 23:12:16 +0100 (Thu, 25 Feb 2010)

Log Message:
-----------
VideoTexture: fix a bug with AV sync that was causing a loss of sync in case of rewind to the begining of the file.

Modified Paths:
--------------
    trunk/blender/source/gameengine/VideoTexture/VideoFFmpeg.cpp

Modified: trunk/blender/source/gameengine/VideoTexture/VideoFFmpeg.cpp
===================================================================
--- trunk/blender/source/gameengine/VideoTexture/VideoFFmpeg.cpp	2010-02-25 21:20:00 UTC (rev 27145)
+++ trunk/blender/source/gameengine/VideoTexture/VideoFFmpeg.cpp	2010-02-25 22:12:16 UTC (rev 27146)
@@ -304,6 +304,10 @@
 	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 @@
 							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 @@
 		// 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 @@
 	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 @@
 			{
 				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 @@
 			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 @@
 						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 @@
 		// 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 @@
 				}
 			}
 			// 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 @@
 			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 @@
 	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





More information about the Bf-blender-cvs mailing list