hedgewars/uVideoRec.pas
changeset 14914 9ab78e08a34c
parent 14893 66b510a8b81c
child 14952 8e4e508d153c
equal deleted inserted replaced
14913:68e1783762bc 14914:9ab78e08a34c
    67                   zoom: single;
    67                   zoom: single;
    68               end;
    68               end;
    69 
    69 
    70 var RGB_Buffer: PByte;
    70 var RGB_Buffer: PByte;
    71     cameraFile: File;
    71     cameraFile: File;
       
    72     cameraFileName: shortstring;
    72     audioFile: File;
    73     audioFile: File;
    73     numPixels: LongWord;
    74     numPixels: LongWord;
    74     startTime, numFrames, curTime, progress, maxProgress: LongWord;
    75     startTime, numFrames, curTime, progress, maxProgress: LongWord;
    75     soundFilePath: shortstring;
    76     soundFilePath: shortstring;
    76     thumbnailSaved: boolean;
    77     thumbnailSaved: boolean;
    77     recordAudio: boolean;
    78     recordAudio: boolean;
    78 
    79 
    79 function BeginVideoRecording: Boolean;
    80 function BeginVideoRecording: Boolean;
    80 var filename, desc: shortstring;
    81 var filename, desc: shortstring;
       
    82     filenameA, descA, soundFilePathA, cAVFormatA, cVideoCodecA, cAudioCodecA: ansistring;
    81 begin
    83 begin
    82     AddFileLog('BeginVideoRecording');
    84     AddFileLog('BeginVideoRecording');
    83 
    85 
    84 {$IOCHECKS OFF}
    86 {$IOCHECKS OFF}
    85     // open file with prerecorded camera positions
    87     // open file with prerecorded camera positions
    86     filename:= shortstring(UserPathPrefix) + '/VideoTemp/' + shortstring(RecPrefix) + '.txtin';
    88     cameraFileName:= shortstring(UserPathPrefix) + '/VideoTemp/' + shortstring(RecPrefix) + '.txtin';
    87     Assign(cameraFile, filename);
    89     Assign(cameraFile, cameraFileName);
    88     Reset(cameraFile, SizeOf(TFrame));
    90     Reset(cameraFile, SizeOf(TFrame));
    89     maxProgress:= FileSize(cameraFile);
    91     maxProgress:= FileSize(cameraFile);
    90     if IOResult <> 0 then
    92     if IOResult <> 0 then
    91     begin
    93     begin
    92         AddFileLog('Error: Could not read from ' + filename);
    94         AddFileLog('Error: Could not read from ' + cameraFileName);
    93         exit(false);
    95         exit(false);
    94     end;
    96     end;
    95 {$IOCHECKS ON}
    97 {$IOCHECKS ON}
    96 
    98 
    97     { Store some description in output file.
    99     { Store some description in output file.
   119     if recordAudio then
   121     if recordAudio then
   120         soundFilePath:= shortstring(UserPathPrefix) + '/VideoTemp/' + shortstring(RecPrefix) + '.sw'
   122         soundFilePath:= shortstring(UserPathPrefix) + '/VideoTemp/' + shortstring(RecPrefix) + '.sw'
   121     else
   123     else
   122         soundFilePath:= '';
   124         soundFilePath:= '';
   123 
   125 
       
   126     filenameA:= ansistring(filename);
       
   127     descA:= ansistring(desc);
       
   128     soundFilePathA:= ansistring(soundFilePath);
       
   129     cAVFormatA:= ansistring(cAVFormat);
       
   130     cVideoCodecA:= ansistring(cVideoCodec);
       
   131     cAudioCodecA:= ansistring(cAudioCodec);
   124     if checkFails(AVWrapper_Init(@AddFileLogRaw
   132     if checkFails(AVWrapper_Init(@AddFileLogRaw
   125         , PChar(ansistring(filename))
   133         , PChar(filenameA)
   126         , PChar(ansistring(desc))
   134         , PChar(descA)
   127         , PChar(ansistring(soundFilePath))
   135         , PChar(soundFilePathA)
   128         , PChar(ansistring(cAVFormat))
   136         , PChar(cAVFormatA)
   129         , PChar(ansistring(cVideoCodec))
   137         , PChar(cVideoCodecA)
   130         , PChar(ansistring(cAudioCodec))
   138         , PChar(cAudioCodecA)
   131         , cScreenWidth, cScreenHeight, cVideoFramerateNum, cVideoFramerateDen, cVideoQuality) >= 0,
   139         , cScreenWidth, cScreenHeight, cVideoFramerateNum, cVideoFramerateDen, cVideoQuality) >= 0,
   132         'AVWrapper_Init failed',
   140         'AVWrapper_Init failed',
   133         true) then exit(false);
   141         true) then exit(false);
   134 
   142 
   135     numPixels:= cScreenWidth*cScreenHeight;
   143     numPixels:= cScreenWidth*cScreenHeight;
   156         begin
   164         begin
   157         AddFileLog('AVWrapper_Close() has failed.');
   165         AddFileLog('AVWrapper_Close() has failed.');
   158         halt(HaltVideoRec);
   166         halt(HaltVideoRec);
   159         end;
   167         end;
   160 {$IOCHECKS OFF}
   168 {$IOCHECKS OFF}
   161     // Provoke IOResult to be set
   169     if FileExists(cameraFileName) then
   162     FileSize(cameraFile);
   170         DeleteFile(cameraFileName)
   163     if IOResult = 0 then
       
   164         Erase(cameraFile)
       
   165     else
   171     else
   166         AddFileLog('Warning: Tried to delete the cameraFile but it was already deleted');
   172         AddFileLog('Warning: Tried to delete the cameraFile but it was already deleted');
   167 {$IOCHECKS ON}
   173 {$IOCHECKS ON}
   168     if recordAudio and FileExists(soundFilePath) then
   174     if recordAudio and FileExists(soundFilePath) then
   169         DeleteFile(soundFilePath);
   175         DeleteFile(soundFilePath);
   190     inc(numFrames);
   196     inc(numFrames);
   191 end;
   197 end;
   192 
   198 
   193 function LoadNextCameraPosition(var newRealTicks, newGameTicks: LongInt): Boolean;
   199 function LoadNextCameraPosition(var newRealTicks, newGameTicks: LongInt): Boolean;
   194 var frame: TFrame = (realTicks: 0; gameTicks: 0; CamX: 0; CamY: 0; zoom: 0);
   200 var frame: TFrame = (realTicks: 0; gameTicks: 0; CamX: 0; CamY: 0; zoom: 0);
       
   201     res: LongInt;
   195 begin
   202 begin
   196     // we need to skip or duplicate frames to match target framerate
   203     // we need to skip or duplicate frames to match target framerate
   197     while Int64(curTime)*cVideoFramerateNum <= Int64(numFrames)*cVideoFramerateDen*1000 do
   204     while Int64(curTime)*cVideoFramerateNum <= Int64(numFrames)*cVideoFramerateDen*1000 do
   198     begin
   205     begin
       
   206     res:= 0;
   199     {$IOCHECKS OFF}
   207     {$IOCHECKS OFF}
   200         if eof(cameraFile) then
   208         if eof(cameraFile) then
   201             exit(false);
   209             exit(false);
   202         BlockRead(cameraFile, frame, 1);
   210         BlockRead(cameraFile, frame, 1, res);
   203     {$IOCHECKS ON}
   211     {$IOCHECKS ON}
   204         curTime:= frame.realTicks;
   212         curTime:= frame.realTicks;
   205         WorldDx:= frame.CamX;
   213         WorldDx:= frame.CamX;
   206         WorldDy:= frame.CamY + cScreenHeight div 2;
   214         WorldDy:= frame.CamY + cScreenHeight div 2;
   207         zoom:= frame.zoom*cScreenWidth;
   215         zoom:= frame.zoom*cScreenWidth;
   214 end;
   222 end;
   215 
   223 
   216 // Callback which records sound.
   224 // Callback which records sound.
   217 // This procedure may be called from different thread.
   225 // This procedure may be called from different thread.
   218 procedure RecordPostMix(udata: pointer; stream: PByte; len: LongInt); cdecl;
   226 procedure RecordPostMix(udata: pointer; stream: PByte; len: LongInt); cdecl;
   219 begin
   227 var result: LongInt;
       
   228 begin
       
   229     result:= 0; // avoid warning
   220     udata:= udata; // avoid warning
   230     udata:= udata; // avoid warning
   221 {$IOCHECKS OFF}
   231 {$IOCHECKS OFF}
   222     BlockWrite(audioFile, stream^, len);
   232     BlockWrite(audioFile, stream^, len, result);
   223 {$IOCHECKS ON}
   233 {$IOCHECKS ON}
   224 end;
   234 end;
   225 
   235 
   226 procedure SaveThumbnail;
   236 procedure SaveThumbnail;
   227 var thumbpath: shortstring;
   237 var thumbpath: shortstring;
   236 
   246 
   237 // copy file (free pascal doesn't have copy file function)
   247 // copy file (free pascal doesn't have copy file function)
   238 procedure CopyFile(src, dest: shortstring);
   248 procedure CopyFile(src, dest: shortstring);
   239 var inF, outF: file;
   249 var inF, outF: file;
   240     buffer: array[0..1023] of byte;
   250     buffer: array[0..1023] of byte;
   241     result: LongInt;
   251     result, result2: LongInt;
   242     i: integer;
   252     i: integer;
   243 begin
   253 begin
   244 {$IOCHECKS OFF}
   254 {$IOCHECKS OFF}
   245     result:= 0; // avoid compiler hint and warning
   255     result:= 0; // avoid compiler hint and warning
       
   256     result2:= 0; // avoid compiler hint and warning
   246     for i:= 0 to 1023 do
   257     for i:= 0 to 1023 do
   247         buffer[i]:= 0;
   258         buffer[i]:= 0;
   248 
   259 
   249     Assign(inF, src);
   260     Assign(inF, src);
   250     Reset(inF, 1);
   261     Reset(inF, 1);
   262         exit;
   273         exit;
   263     end;
   274     end;
   264 
   275 
   265     repeat
   276     repeat
   266         BlockRead(inF, buffer, 1024, result);
   277         BlockRead(inF, buffer, 1024, result);
   267         BlockWrite(outF, buffer, result);
   278         BlockWrite(outF, buffer, result, result2);
   268     until result < 1024;
   279     until result < 1024;
   269 {$IOCHECKS ON}
   280 {$IOCHECKS ON}
   270 end;
   281 end;
   271 
   282 
   272 procedure BeginPreRecording;
   283 procedure BeginPreRecording;
   273 var format: word;
   284 var format: word;
   274     filename: shortstring;
   285     filename: shortstring;
   275     frequency, channels: LongInt;
   286     frequency, channels: LongInt;
   276 begin
   287     result: LongInt;
       
   288 begin
       
   289     result:= 0;
   277     AddFileLog('BeginPreRecording');
   290     AddFileLog('BeginPreRecording');
   278 
   291 
   279     thumbnailSaved:= false;
   292     thumbnailSaved:= false;
   280     RecPrefix:= 'hw-' + FormatDateTime('YYYY-MM-DD_HH-mm-ss-z', Now());
   293     RecPrefix:= 'hw-' + FormatDateTime('YYYY-MM-DD_HH-mm-ss-z', TDateTime(Now()));
   281 
   294 
   282     // If this video is recorded from demo executed directly (without frontend)
   295     // If this video is recorded from demo executed directly (without frontend)
   283     // then we need to copy demo so that frontend will be able to find it later.
   296     // then we need to copy demo so that frontend will be able to find it later.
   284     if recordFileName <> '' then
   297     if recordFileName <> '' then
   285     begin
   298     begin
   322         end;
   335         end;
   323 
   336 
   324     if cIsSoundEnabled then
   337     if cIsSoundEnabled then
   325         begin
   338         begin
   326         // save audio parameters in sound file
   339         // save audio parameters in sound file
   327         BlockWrite(audioFile, frequency, 4);
   340         BlockWrite(audioFile, frequency, 4, result);
   328         BlockWrite(audioFile, channels, 4);
   341         BlockWrite(audioFile, channels, 4, result);
   329 {$IOCHECKS ON}
   342 {$IOCHECKS ON}
   330 
   343 
   331         // register callback for actual audio recording
   344         // register callback for actual audio recording
   332         Mix_SetPostMix(@RecordPostMix, nil);
   345         Mix_SetPostMix(@RecordPostMix, nil);
   333         end;
   346         end;
   358         SaveThumbnail();
   371         SaveThumbnail();
   359 end;
   372 end;
   360 
   373 
   361 procedure SaveCameraPosition;
   374 procedure SaveCameraPosition;
   362 var frame: TFrame;
   375 var frame: TFrame;
   363 begin
   376     result: LongInt;
       
   377 begin
       
   378     result:= 0;
   364     if (not thumbnailSaved) and (ScreenFade = sfNone) then
   379     if (not thumbnailSaved) and (ScreenFade = sfNone) then
   365         SaveThumbnail();
   380         SaveThumbnail();
   366 
   381 
   367     frame.realTicks:= SDL_GetTicks() - startTime;
   382     frame.realTicks:= SDL_GetTicks() - startTime;
   368     frame.gameTicks:= GameTicks;
   383     frame.gameTicks:= GameTicks;
   369     frame.CamX:= WorldDx;
   384     frame.CamX:= WorldDx;
   370     frame.CamY:= WorldDy - cScreenHeight div 2;
   385     frame.CamY:= WorldDy - cScreenHeight div 2;
   371     frame.zoom:= zoom/cScreenWidth;
   386     frame.zoom:= zoom/cScreenWidth;
   372     BlockWrite(cameraFile, frame, 1);
   387     BlockWrite(cameraFile, frame, 1, result);
   373 end;
   388 end;
   374 
   389 
   375 procedure initModule;
   390 procedure initModule;
   376 begin
   391 begin
   377     // we need to make sure these variables are initialized before the main loop
   392     // we need to make sure these variables are initialized before the main loop