@@ -66,7 +66,7 @@ cvar_t scr_screenshot_timestamp = {CF_CLIENT | CF_ARCHIVE, "scr_screenshot_times
66
66
#ifdef CONFIG_VIDEO_CAPTURE
67
67
cvar_t cl_capturevideo = {CF_CLIENT , "cl_capturevideo" , "0" , "enables saving of video to a .avi file using uncompressed I420 colorspace and PCM audio, note that scr_screenshot_gammaboost affects the brightness of the output)" };
68
68
cvar_t cl_capturevideo_demo_stop = {CF_CLIENT | CF_ARCHIVE , "cl_capturevideo_demo_stop" , "1" , "automatically stops video recording when demo ends" };
69
- cvar_t cl_capturevideo_printfps = {CF_CLIENT | CF_ARCHIVE , "cl_capturevideo_printfps" , "1" , "prints the frames per second captured in capturevideo (is only written to the log file, not to the console, as that would be visible on the video)" };
69
+ cvar_t cl_capturevideo_printfps = {CF_CLIENT | CF_ARCHIVE , "cl_capturevideo_printfps" , "1" , "prints the frames per second captured in capturevideo (is only written to stdout and any log file, not to the console as that would be visible on the video), value is seconds of wall time between prints " };
70
70
cvar_t cl_capturevideo_width = {CF_CLIENT | CF_ARCHIVE , "cl_capturevideo_width" , "0" , "scales all frames to this resolution before saving the video" };
71
71
cvar_t cl_capturevideo_height = {CF_CLIENT | CF_ARCHIVE , "cl_capturevideo_height" , "0" , "scales all frames to this resolution before saving the video" };
72
72
cvar_t cl_capturevideo_realtime = {CF_CLIENT , "cl_capturevideo_realtime" , "0" , "causes video saving to operate in realtime (mostly useful while playing, not while capturing demos), this can produce a much lower quality video due to poor sound/video sync and will abort saving if your machine stalls for over a minute" };
@@ -1077,8 +1077,7 @@ static void SCR_CaptureVideo_BeginVideo(void)
1077
1077
cls .capturevideo .starttime = cls .capturevideo .lastfpstime = host .realtime ;
1078
1078
cls .capturevideo .soundsampleframe = 0 ;
1079
1079
cls .capturevideo .realtime = cl_capturevideo_realtime .integer != 0 ;
1080
- cls .capturevideo .screenbuffer = (unsigned char * )Mem_Alloc (tempmempool , vid .mode .width * vid .mode .height * 4 );
1081
- cls .capturevideo .outbuffer = (unsigned char * )Mem_Alloc (tempmempool , width * height * (4 + 4 ) + 18 );
1080
+ cls .capturevideo .outbuffer = (unsigned char * )Mem_Alloc (tempmempool , width * height * 4 + 18 ); // +18 ?
1082
1081
Sys_TimeString (timestring , sizeof (timestring ), cl_capturevideo_nameformat .string );
1083
1082
dpsnprintf (cls .capturevideo .basename , sizeof (cls .capturevideo .basename ), "video/%s%03i" , timestring , cl_capturevideo_number .integer );
1084
1083
Cvar_SetValueQuick (& cl_capturevideo_number , cl_capturevideo_number .integer + 1 );
@@ -1139,6 +1138,8 @@ Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
1139
1138
cls .capturevideo .yuvnormalizetable [2 ][i ] = 16 + i * (240 - 16 ) / 256 ;
1140
1139
}
1141
1140
1141
+ GL_CaptureVideo_BeginVideo ();
1142
+
1142
1143
if (cl_capturevideo_ogg .integer )
1143
1144
{
1144
1145
if (SCR_CaptureVideo_Ogg_Available ())
@@ -1162,16 +1163,10 @@ void SCR_CaptureVideo_EndVideo(void)
1162
1163
1163
1164
Con_Printf ("Finishing capture of %s.%s (%d frames, %d audio frames)\n" , cls .capturevideo .basename , cls .capturevideo .formatextension , cls .capturevideo .frame , cls .capturevideo .soundsampleframe );
1164
1165
1165
- if (cls .capturevideo .videofile )
1166
- {
1167
- cls .capturevideo .endvideo ();
1168
- }
1166
+ GL_CaptureVideo_EndVideo (); // must be called before writeEndVideo !
1169
1167
1170
- if (cls .capturevideo .screenbuffer )
1171
- {
1172
- Mem_Free (cls .capturevideo .screenbuffer );
1173
- cls .capturevideo .screenbuffer = NULL ;
1174
- }
1168
+ if (cls .capturevideo .videofile )
1169
+ cls .capturevideo .writeEndVideo ();
1175
1170
1176
1171
if (cls .capturevideo .outbuffer )
1177
1172
{
@@ -1182,98 +1177,24 @@ void SCR_CaptureVideo_EndVideo(void)
1182
1177
memset (& cls .capturevideo , 0 , sizeof (cls .capturevideo ));
1183
1178
}
1184
1179
1185
- static void SCR_ScaleDownBGRA (unsigned char * in , int inw , int inh , unsigned char * out , int outw , int outh )
1186
- {
1187
- // TODO optimize this function
1188
-
1189
- int x , y ;
1190
- float area ;
1191
-
1192
- // memcpy is faster than me
1193
- if (inw == outw && inh == outh )
1194
- {
1195
- memcpy (out , in , 4 * inw * inh );
1196
- return ;
1197
- }
1198
-
1199
- // otherwise: a box filter
1200
- area = (float )outw * (float )outh / (float )inw / (float )inh ;
1201
- for (y = 0 ; y < outh ; ++ y )
1202
- {
1203
- float iny0 = y / (float )outh * inh ; int iny0_i = (int ) floor (iny0 );
1204
- float iny1 = (y + 1 ) / (float )outh * inh ; int iny1_i = (int ) ceil (iny1 );
1205
- for (x = 0 ; x < outw ; ++ x )
1206
- {
1207
- float inx0 = x / (float )outw * inw ; int inx0_i = (int ) floor (inx0 );
1208
- float inx1 = (x + 1 ) / (float )outw * inw ; int inx1_i = (int ) ceil (inx1 );
1209
- float r = 0 , g = 0 , b = 0 , alpha = 0 ;
1210
- int xx , yy ;
1211
-
1212
- for (yy = iny0_i ; yy < iny1_i ; ++ yy )
1213
- {
1214
- float ya = min (yy + 1 , iny1 ) - max (iny0 , yy );
1215
- for (xx = inx0_i ; xx < inx1_i ; ++ xx )
1216
- {
1217
- float a = ya * (min (xx + 1 , inx1 ) - max (inx0 , xx ));
1218
- r += a * in [4 * (xx + inw * yy )+ 0 ];
1219
- g += a * in [4 * (xx + inw * yy )+ 1 ];
1220
- b += a * in [4 * (xx + inw * yy )+ 2 ];
1221
- alpha += a * in [4 * (xx + inw * yy )+ 3 ];
1222
- }
1223
- }
1224
-
1225
- out [4 * (x + outw * y )+ 0 ] = (unsigned char ) (r * area );
1226
- out [4 * (x + outw * y )+ 1 ] = (unsigned char ) (g * area );
1227
- out [4 * (x + outw * y )+ 2 ] = (unsigned char ) (b * area );
1228
- out [4 * (x + outw * y )+ 3 ] = (unsigned char ) (alpha * area );
1229
- }
1230
- }
1231
- }
1232
-
1233
- static void SCR_CaptureVideo_VideoFrame (int newframestepframenum )
1234
- {
1235
- int x = 0 , y = 0 ;
1236
- int width = cls .capturevideo .width , height = cls .capturevideo .height ;
1237
-
1238
- if (newframestepframenum == cls .capturevideo .framestepframe )
1239
- return ;
1240
-
1241
- CHECKGLERROR
1242
- // speed is critical here, so do saving as directly as possible
1243
-
1244
- GL_ReadPixelsBGRA (x , y , vid .mode .width , vid .mode .height , cls .capturevideo .screenbuffer );
1245
-
1246
- SCR_ScaleDownBGRA (cls .capturevideo .screenbuffer , vid .mode .width , vid .mode .height , cls .capturevideo .outbuffer , width , height );
1247
-
1248
- cls .capturevideo .videoframes (newframestepframenum - cls .capturevideo .framestepframe );
1249
- cls .capturevideo .framestepframe = newframestepframenum ;
1250
-
1251
- if (cl_capturevideo_printfps .integer && host .realtime > cls .capturevideo .lastfpstime + 1 )
1252
- {
1253
- double fps1 = (cls .capturevideo .frame - cls .capturevideo .lastfpsframe ) / (host .realtime - cls .capturevideo .lastfpstime + 0.0000001 );
1254
- double fps = (cls .capturevideo .frame ) / (host .realtime - cls .capturevideo .starttime + 0.0000001 );
1255
- Sys_Printf ("capturevideo: (%.1fs) last second %.3ffps, total %.3ffps\n" , cls .capturevideo .frame / cls .capturevideo .framerate , fps1 , fps );
1256
- cls .capturevideo .lastfpstime = host .realtime ;
1257
- cls .capturevideo .lastfpsframe = cls .capturevideo .frame ;
1258
- }
1259
- }
1260
-
1261
1180
void SCR_CaptureVideo_SoundFrame (const portable_sampleframe_t * paintbuffer , size_t length )
1262
1181
{
1263
1182
cls .capturevideo .soundsampleframe += (int )length ;
1264
- cls .capturevideo .soundframe (paintbuffer , length );
1183
+ cls .capturevideo .writeSoundFrame (paintbuffer , length );
1265
1184
}
1266
1185
1267
1186
static void SCR_CaptureVideo (void )
1268
1187
{
1269
1188
int newframenum ;
1189
+ int newframestepframenum ;
1190
+
1270
1191
if (cl_capturevideo .integer )
1271
1192
{
1272
1193
if (!cls .capturevideo .active )
1273
1194
SCR_CaptureVideo_BeginVideo ();
1274
1195
if (cls .capturevideo .framerate != cl_capturevideo_fps .value * cl_capturevideo_framestep .integer )
1275
1196
{
1276
- Con_Printf ("You can not change the video framerate while recording a video.\n" );
1197
+ Con_Printf (CON_WARN "You can not change the video framerate while recording a video.\n" );
1277
1198
Cvar_SetValueQuick (& cl_capturevideo_fps , cls .capturevideo .framerate / (double ) cl_capturevideo_framestep .integer );
1278
1199
}
1279
1200
// for AVI saving we have to make sure that sound is saved before video
@@ -1290,17 +1211,32 @@ static void SCR_CaptureVideo(void)
1290
1211
if (newframenum - cls .capturevideo .frame > 60 * (int )ceil (cls .capturevideo .framerate ))
1291
1212
{
1292
1213
Cvar_SetValueQuick (& cl_capturevideo , 0 );
1293
- Con_Printf ("video saving failed on frame %i, your machine is too slow for this capture speed.\n" , cls .capturevideo .frame );
1214
+ Con_Printf (CON_ERROR "video saving failed on frame %i, your machine is too slow for this capture speed.\n" , cls .capturevideo .frame );
1294
1215
SCR_CaptureVideo_EndVideo ();
1295
1216
return ;
1296
1217
}
1297
1218
// write frames
1298
- SCR_CaptureVideo_VideoFrame (newframenum / cls .capturevideo .framestep );
1219
+ newframestepframenum = newframenum / cls .capturevideo .framestep ;
1220
+ if (newframestepframenum != cls .capturevideo .framestepframe )
1221
+ GL_CaptureVideo_VideoFrame (newframestepframenum );
1222
+ cls .capturevideo .framestepframe = newframestepframenum ;
1223
+ // report progress
1224
+ if (cl_capturevideo_printfps .value && host .realtime > cls .capturevideo .lastfpstime + cl_capturevideo_printfps .value )
1225
+ {
1226
+ double fps1 = (cls .capturevideo .frame - cls .capturevideo .lastfpsframe ) / (host .realtime - cls .capturevideo .lastfpstime + 0.0000001 );
1227
+ double fps = (cls .capturevideo .frame ) / (host .realtime - cls .capturevideo .starttime + 0.0000001 );
1228
+ Sys_Printf ("captured %.1fs of video, last second %.3ffps (%.1fx), total %.3ffps (%.1fx)\n" ,
1229
+ cls .capturevideo .frame / cls .capturevideo .framerate ,
1230
+ fps1 , fps1 / cls .capturevideo .framerate ,
1231
+ fps , fps / cls .capturevideo .framerate );
1232
+ cls .capturevideo .lastfpstime = host .realtime ;
1233
+ cls .capturevideo .lastfpsframe = cls .capturevideo .frame ;
1234
+ }
1299
1235
cls .capturevideo .frame = newframenum ;
1300
1236
if (cls .capturevideo .error )
1301
1237
{
1302
1238
Cvar_SetValueQuick (& cl_capturevideo , 0 );
1303
- Con_Printf ("video saving failed on frame %i, out of disk space? stopping video capture.\n" , cls .capturevideo .frame );
1239
+ Con_Printf (CON_ERROR "video saving failed on frame %i, out of disk space? stopping video capture.\n" , cls .capturevideo .frame );
1304
1240
SCR_CaptureVideo_EndVideo ();
1305
1241
}
1306
1242
}
0 commit comments