Browse Source

fix sound glitch for lengthy AVIs

Wei Mingzhi 7 years ago
parent
commit
c45f6da617
1 changed files with 29 additions and 20 deletions
  1. 29 20
      aviplay.c

+ 29 - 20
aviplay.c

@@ -92,7 +92,7 @@ typedef struct AVIPlayState
     SDL_Surface   *surface;            // video buffer
 
     long           lVideoEndPos;
-	uint32_t       dwMillisPerFrame;       // milliseconds per frame
+	uint32_t       dwMicroSecPerFrame;       // microseconds per frame
 	uint32_t       dwBufferSize;
     SDL_AudioCVT   cvt;
 
@@ -262,7 +262,7 @@ PAL_ReadAVIInfo(
 			//
 			fseek(fp, pos - sizeof(RIFFChunkHeader), SEEK_SET);
 			avi->lVideoEndPos = next_pos[current_level - 1];
-			avi->dwMillisPerFrame = aviHeader.dwMicroSecPerFrame / 1000;
+			avi->dwMicroSecPerFrame = aviHeader.dwMicroSecPerFrame;
 			//
 			// Create surface
 			//
@@ -488,7 +488,6 @@ PAL_AVIFeedAudio(
 		buffer += feed_size;
         size -= feed_size;
     }
-
     SDL_mutexV(avi->selfMutex);
 }
 
@@ -662,12 +661,17 @@ PAL_PlayAVI(
 	BOOL       fEndPlay = FALSE;
 	RIFFChunk *buf = (RIFFChunk *)avi->pChunkBuffer;
 	uint32_t   len = avi->dwBufferSize;
+	uint32_t   dwMicroSecChange = 0;
 
     while (!fEndPlay)
     {
 		RIFFChunk *chunk = PAL_ReadDataChunk(fp, avi->lVideoEndPos, buf, len, avi->cvt.len_mult);
 		uint32_t   dwCurrentTime = SDL_GetTicks();
-		uint32_t   dwNextFrameTime = dwCurrentTime + avi->dwMillisPerFrame;
+		uint32_t   dwNextFrameTime = dwCurrentTime + (avi->dwMicroSecPerFrame / 1000);
+
+		dwMicroSecChange += avi->dwMicroSecPerFrame % 1000;
+		dwNextFrameTime += dwMicroSecChange / 1000;
+		dwMicroSecChange %= 1000;
 
 		if (chunk == NULL) break;
 
@@ -678,12 +682,13 @@ PAL_PlayAVI(
             //
             // Video frame
             //
-			PAL_RenderAVIFrameToSurface(avi->surface, chunk);
+            PAL_RenderAVIFrameToSurface(avi->surface, chunk);
             VIDEO_DrawSurfaceToScreen(avi->surface);
 
             dwCurrentTime = SDL_GetTicks();
-			// Check input states here
-			UTIL_Delay(dwCurrentTime >= dwNextFrameTime ? 1 : dwNextFrameTime - dwCurrentTime);
+
+            // Check input states here
+            UTIL_Delay(dwCurrentTime >= dwNextFrameTime ? 1 : dwNextFrameTime - dwCurrentTime);
 
             if (g_InputState.dwKeyPress & (kKeyMenu | kKeySearch))
             {
@@ -743,7 +748,7 @@ PAL_PlayAVI(
 	}
 
 	fclose(fp);
-	
+
 	return TRUE;
 }
 
@@ -754,22 +759,26 @@ AVI_FillAudioBuffer(
 	int         len
 )
 {
-	AVIPlayState *avi = (AVIPlayState *)udata;
+    AVIPlayState *avi = (AVIPlayState *)udata;
+
     SDL_mutexP(avi->selfMutex);
-	//
-	// We do not check whether Read pointer & Write pointer overlaps like DSound does
-	//
-	while (avi->fp != NULL && len > 0)
-	{
-		uint32_t fill_size = (avi->dwAudioReadPos + len > avi->dwAudBufLen) ? avi->dwAudBufLen - avi->dwAudioReadPos : len;
+    while (avi->fp != NULL && len > 0 && avi->dwAudioWritePos != avi->dwAudioReadPos)
+    {
+        uint32_t fill_size = (avi->dwAudioReadPos + len > avi->dwAudBufLen) ? avi->dwAudBufLen - avi->dwAudioReadPos : len;
 
-		memcpy(stream, avi->pbAudioBuf + avi->dwAudioReadPos, fill_size);
+        if (avi->dwAudioWritePos > avi->dwAudioReadPos &&
+            fill_size > avi->dwAudioWritePos - avi->dwAudioReadPos)
+        {
+            fill_size = avi->dwAudioWritePos - avi->dwAudioReadPos;
+        }
 
-		avi->dwAudioReadPos = (avi->dwAudioReadPos + fill_size) % avi->dwAudBufLen;
+        memcpy(stream, avi->pbAudioBuf + avi->dwAudioReadPos, fill_size);
 
-		stream += fill_size;
-		len -= fill_size;
-	}
+        avi->dwAudioReadPos = (avi->dwAudioReadPos + fill_size) % avi->dwAudBufLen;
+
+        stream += fill_size;
+        len -= fill_size;
+    }
     SDL_mutexV(avi->selfMutex);
 }