--- a/hedgewars/uVideoRec.pas Mon Jul 09 16:42:13 2012 +0400
+++ b/hedgewars/uVideoRec.pas Mon Jul 09 17:03:57 2012 +0400
@@ -62,21 +62,22 @@
{$IFDEF WIN32}
procedure AVWrapper_Init(
AddLog: TAddFileLogRaw;
- filename, desc, soundFile, format, vcodec, acodec, preset: PChar;
- width, height, framerateNum, framerateDen, vquality, aquality: LongInt); cdecl; external AVWrapperLibName;
+ filename, desc, soundFile, format, vcodec, acodec: PChar;
+ width, height, framerateNum, framerateDen, vquality: LongInt); cdecl; external AVWrapperLibName;
procedure AVWrapper_Close; cdecl; external AVWrapperLibName;
procedure AVWrapper_WriteFrame( pY, pCb, pCr: PByte ); cdecl; external AVWrapperLibName;
{$ELSE}
procedure AVWrapper_Init(
AddLog: TAddFileLogRaw;
- filename, desc, soundFile, format, vcodec, acodec, preset: PChar;
- width, height, framerateNum, framerateDen, vquality, aquality: LongInt); cdecl; external;
+ filename, desc, soundFile, format, vcodec, acodec: PChar;
+ width, height, framerateNum, framerateDen, vquality: LongInt); cdecl; external;
procedure AVWrapper_Close; cdecl; external;
procedure AVWrapper_WriteFrame( pY, pCb, pCr: PByte ); cdecl; external;
{$ENDIF}
type TFrame = record
- ticks: LongWord;
+ realTicks: LongWord;
+ gameTicks: LongWord;
CamX, CamY: LongInt;
zoom: single;
end;
@@ -86,7 +87,7 @@
cameraFile: File of TFrame;
audioFile: File;
numPixels: LongWord;
- startTime, numFrames: LongWord;
+ startTime, numFrames, curTime, progress, maxProgress: LongWord;
cameraFilePath, soundFilePath: shortstring;
thumbnailSaved : Boolean;
@@ -95,13 +96,12 @@
begin
AddFileLog('BeginVideoRecording');
- numPixels:= cScreenWidth*cScreenHeight;
-
{$IOCHECKS OFF}
// open file with prerecorded camera positions
cameraFilePath:= UserPathPrefix + '/VideoTemp/' + RecPrefix + '.txtin';
Assign(cameraFile, cameraFilePath);
Reset(cameraFile);
+ maxProgress:= FileSize(cameraFile);
if IOResult <> 0 then
begin
AddFileLog('Error: Could not read from ' + cameraFilePath);
@@ -109,6 +109,7 @@
end;
{$IOCHECKS ON}
+ // store some description in output file
desc:= '';
if UserNick <> '' then
desc+= 'Player: ' + UserNick + #10;
@@ -126,10 +127,10 @@
cAVFormat+= #0;
cAudioCodec+= #0;
cVideoCodec+= #0;
- cVideoPreset+= #0;
- AVWrapper_Init(@AddFileLogRaw, @filename[1], @desc[1], @soundFilePath[1], @cAVFormat[1], @cVideoCodec[1], @cAudioCodec[1], @cVideoPreset[1],
- cScreenWidth, cScreenHeight, cVideoFramerateNum, cVideoFramerateDen, cAudioQuality, cVideoQuality);
+ AVWrapper_Init(@AddFileLogRaw, @filename[1], @desc[1], @soundFilePath[1], @cAVFormat[1], @cVideoCodec[1], @cAudioCodec[1],
+ cScreenWidth, cScreenHeight, cVideoFramerateNum, cVideoFramerateDen, cVideoQuality);
+ numPixels:= cScreenWidth*cScreenHeight;
YCbCr_Planes[0]:= GetMem(numPixels);
YCbCr_Planes[1]:= GetMem(numPixels div 4);
YCbCr_Planes[2]:= GetMem(numPixels div 4);
@@ -147,6 +148,9 @@
exit(false);
end;
+ curTime:= 0;
+ numFrames:= 0;
+ progress:= 0;
BeginVideoRecording:= true;
end;
@@ -161,7 +165,7 @@
AVWrapper_Close();
DeleteFile(cameraFilePath);
DeleteFile(soundFilePath);
- SendIPC(_S'v');
+ SendIPC(_S'v'); // inform frontend that we finished
end;
function pixel(x, y, color: LongInt): LongInt;
@@ -171,6 +175,7 @@
procedure EncodeFrame;
var x, y, r, g, b: LongInt;
+ s: shortstring;
begin
// read pixels from OpenGL
glReadPixels(0, 0, cScreenWidth, cScreenHeight, GL_RGBA, GL_UNSIGNED_BYTE, RGB_Buffer);
@@ -194,24 +199,35 @@
AVWrapper_WriteFrame(YCbCr_Planes[0], YCbCr_Planes[1], YCbCr_Planes[2]);
- // inform frontend that we have encoded new frame (p for progress)
- SendIPC(_S'p');
+ // inform frontend that we have encoded new frame
+ s[0]:= #3;
+ s[1]:= 'p'; // p for progress
+ SDLNet_Write16(progress*10000 div maxProgress, @s[2]);
+ SendIPC(s);
+ inc(numFrames);
end;
// returns new game ticks
function LoadNextCameraPosition: LongInt;
var frame: TFrame;
begin
-{$IOCHECKS OFF}
- if eof(cameraFile) then
- exit(-1);
- BlockRead(cameraFile, frame, 1);
-{$IOCHECKS ON}
- WorldDx:= frame.CamX;
- WorldDy:= frame.CamY + cScreenHeight div 2;
- zoom:= frame.zoom*cScreenWidth;
- ZoomValue:= zoom;
- LoadNextCameraPosition:= frame.ticks;
+ LoadNextCameraPosition:= GameTicks;
+ // we need to skip or duplicate frames to match target framerate
+ while Int64(curTime)*cVideoFramerateNum < Int64(numFrames)*cVideoFramerateDen*1000 do
+ begin
+ {$IOCHECKS OFF}
+ if eof(cameraFile) then
+ exit(-1);
+ BlockRead(cameraFile, frame, 1);
+ {$IOCHECKS ON}
+ curTime:= frame.realTicks;
+ WorldDx:= frame.CamX;
+ WorldDy:= frame.CamY + cScreenHeight div 2;
+ zoom:= frame.zoom*cScreenWidth;
+ ZoomValue:= zoom;
+ inc(progress);
+ LoadNextCameraPosition:= frame.gameTicks;
+ end;
end;
// Callback which records sound.
@@ -247,9 +263,8 @@
begin
AddFileLog('BeginPreRecording');
- numFrames:= 0;
thumbnailSaved:= false;
- RecPrefix:= FormatDateTime('YYYY-MM-DD_HH-mm-ss', Now());
+ RecPrefix:= FormatDateTime('YYYY-MM-DD_HH-mm-ss', Now()) + inttostr(GameTicks);
Mix_QuerySpec(@frequency, @format, @channels);
AddFileLog('sound: frequency = ' + IntToStr(frequency) + ', format = ' + IntToStr(format) + ', channels = ' + IntToStr(channels));
@@ -310,22 +325,17 @@
end;
procedure SaveCameraPosition;
-var curTime: LongInt;
- frame: TFrame;
+var frame: TFrame;
begin
if (not thumbnailSaved) and (ScreenFade = sfNone) then
SaveThumbnail();
- curTime:= SDL_GetTicks();
- while Int64(curTime - startTime)*cVideoFramerateNum > Int64(numFrames)*cVideoFramerateDen*1000 do
- begin
- frame.ticks:= GameTicks;
- frame.CamX:= WorldDx;
- frame.CamY:= WorldDy - cScreenHeight div 2;
- frame.zoom:= zoom/cScreenWidth;
- BlockWrite(cameraFile, frame, 1);
- inc(numFrames);
- end;
+ frame.realTicks:= SDL_GetTicks() - startTime;
+ frame.gameTicks:= GameTicks;
+ frame.CamX:= WorldDx;
+ frame.CamY:= WorldDy - cScreenHeight div 2;
+ frame.zoom:= zoom/cScreenWidth;
+ BlockWrite(cameraFile, frame, 1);
end;
procedure freeModule;