mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-10 06:31:48 +00:00
fixed a bunch of /video and /stopvideo issues
chg: /video can only be used during demo playback fix: broken audio in the output files due to writing the wrong buffer fix: files sequences have a "_%3d" name suffix of adding an underscore to the extension fix: using a better supported video codec (FourCC 0x00000000) for raw BGR output fix: broken raw video output when r_width wasn't a multiple of 4 fix: /stopvideo no longer leaves sound output broken for a while after stopping
This commit is contained in:
parent
a9e7bc7226
commit
5972f247b1
5 changed files with 71 additions and 47 deletions
|
@ -10,6 +10,14 @@ add: /toggle can now accept a value sequence (2 or more entries) to loop through
|
|||
if the cvar's current value is in the sequence and not in the last spot, the next one is used
|
||||
otherwise, the first value in the sequence is used
|
||||
|
||||
fix: /video and /stopvideo fixes
|
||||
chg: /video can only be used during demo playback
|
||||
fix: broken audio in the output files
|
||||
fix: properly named file sequences
|
||||
fix: using a better supported video codec (FourCC 0x00000000) for raw BGR output
|
||||
fix: broken raw video output when r_width wasn't a multiple of 4
|
||||
fix: /stopvideo no longer leaves sound output broken for a while after stopping
|
||||
|
||||
fix: /cv and /callvote auto-completion were disabled after cgame was shut down at least once
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ typedef struct audioFormat_s
|
|||
|
||||
typedef struct aviFileData_s
|
||||
{
|
||||
qbool fileOpen;
|
||||
qbool fileOpen;
|
||||
fileHandle_t f;
|
||||
char fileName[ MAX_QPATH ];
|
||||
int fileSize;
|
||||
|
@ -55,16 +55,16 @@ typedef struct aviFileData_s
|
|||
int width, height;
|
||||
int numVideoFrames;
|
||||
int maxRecordSize;
|
||||
qbool motionJpeg;
|
||||
qbool motionJpeg;
|
||||
|
||||
qbool audio;
|
||||
qbool audio;
|
||||
audioFormat_t a;
|
||||
int numAudioFrames;
|
||||
|
||||
int chunkStack[ MAX_RIFF_CHUNKS ];
|
||||
int chunkStackTop;
|
||||
|
||||
byte *cBuffer, *eBuffer;
|
||||
byte *cBuffer, *eBuffer; // capture and encoding buffers
|
||||
} aviFileData_t;
|
||||
|
||||
static aviFileData_t afd;
|
||||
|
@ -218,12 +218,12 @@ void CL_WriteAVIHeader( void )
|
|||
WRITE_STRING( "strl" );
|
||||
WRITE_STRING( "strh" );
|
||||
WRITE_4BYTES( 56 ); //"strh" "chunk" size
|
||||
WRITE_STRING( "vids" );
|
||||
WRITE_STRING( "vids" ); //fccType
|
||||
|
||||
if( afd.motionJpeg )
|
||||
if( afd.motionJpeg ) //fccHandler
|
||||
WRITE_STRING( "MJPG" );
|
||||
else
|
||||
WRITE_STRING( " BGR" );
|
||||
WRITE_4BYTES( 0 ); //raw BGR
|
||||
|
||||
WRITE_4BYTES( 0 ); //dwFlags
|
||||
WRITE_4BYTES( 0 ); //dwPriority
|
||||
|
@ -250,13 +250,20 @@ void CL_WriteAVIHeader( void )
|
|||
WRITE_2BYTES( 1 ); //biPlanes
|
||||
WRITE_2BYTES( 24 ); //biBitCount
|
||||
|
||||
if( afd.motionJpeg ) //biCompression
|
||||
if( afd.motionJpeg ) //biCompression and biSizeImage
|
||||
{
|
||||
// we specify the pixel count
|
||||
WRITE_STRING( "MJPG" );
|
||||
WRITE_4BYTES( afd.width * afd.height );
|
||||
}
|
||||
else
|
||||
WRITE_STRING( " BGR" );
|
||||
{
|
||||
// must either specify 0 or the total byte count per image
|
||||
// but there is no reason to trust most software...
|
||||
WRITE_4BYTES( 0 ); // raw BGR
|
||||
WRITE_4BYTES( afd.width * afd.height * 3 );
|
||||
}
|
||||
|
||||
WRITE_4BYTES( afd.width *
|
||||
afd.height ); //biSizeImage
|
||||
WRITE_4BYTES( 0 ); //biXPelsPetMeter
|
||||
WRITE_4BYTES( 0 ); //biYPelsPetMeter
|
||||
WRITE_4BYTES( 0 ); //biClrUsed
|
||||
|
@ -321,8 +328,14 @@ void CL_WriteAVIHeader( void )
|
|||
|
||||
// creates an AVI file and gets it into a state where writing the actual data can begin
|
||||
|
||||
qbool CL_OpenAVIForWriting( const char* fileName )
|
||||
qbool CL_OpenAVIForWriting( const char* fileNameNoExt, qbool reOpen )
|
||||
{
|
||||
static char avi_fileNameNoExt[MAX_QPATH];
|
||||
static int avi_fileNameIndex;
|
||||
|
||||
if ( reOpen )
|
||||
CL_CloseAVI();
|
||||
|
||||
if ( afd.fileOpen )
|
||||
return qfalse;
|
||||
|
||||
|
@ -334,16 +347,22 @@ qbool CL_OpenAVIForWriting( const char* fileName )
|
|||
return qfalse;
|
||||
}
|
||||
|
||||
if ( ( afd.f = FS_FOpenFileWrite( fileName ) ) <= 0 )
|
||||
if ( reOpen ) {
|
||||
avi_fileNameIndex++;
|
||||
} else {
|
||||
Q_strncpyz( avi_fileNameNoExt, fileNameNoExt, sizeof( avi_fileNameNoExt ) );
|
||||
avi_fileNameIndex = 0;
|
||||
}
|
||||
Com_sprintf( afd.fileName, sizeof( afd.fileName ), "%s_%03d.avi", avi_fileNameNoExt, avi_fileNameIndex );
|
||||
|
||||
if ( ( afd.f = FS_FOpenFileWrite( afd.fileName ) ) <= 0 )
|
||||
return qfalse;
|
||||
|
||||
if ( ( afd.idxF = FS_FOpenFileWrite( va( "%s" INDEX_FILE_EXTENSION, fileName ) ) ) <= 0 ) {
|
||||
if ( ( afd.idxF = FS_FOpenFileWrite( va( "%s" INDEX_FILE_EXTENSION, afd.fileName ) ) ) <= 0 ) {
|
||||
FS_FCloseFile( afd.f );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
Q_strncpyz( afd.fileName, fileName, MAX_QPATH );
|
||||
|
||||
afd.frameRate = cl_aviFrameRate->integer;
|
||||
afd.framePeriod = (int)( 1000000.0f / afd.frameRate );
|
||||
afd.width = cls.glconfig.vidWidth;
|
||||
|
@ -351,8 +370,9 @@ qbool CL_OpenAVIForWriting( const char* fileName )
|
|||
|
||||
afd.motionJpeg = (cl_aviMotionJpeg->integer != 0);
|
||||
|
||||
afd.cBuffer = (byte*)Z_Malloc( afd.width * afd.height * 4 );
|
||||
afd.eBuffer = (byte*)Z_Malloc( afd.width * afd.height * 4 );
|
||||
const int maxByteCount = PAD( afd.width, 4 ) * afd.height * 4;
|
||||
afd.cBuffer = (byte*)Z_Malloc( maxByteCount );
|
||||
afd.eBuffer = (byte*)Z_Malloc( maxByteCount );
|
||||
|
||||
afd.a.rate = dma.speed;
|
||||
afd.a.format = WAV_FORMAT_PCM;
|
||||
|
@ -391,6 +411,8 @@ qbool CL_OpenAVIForWriting( const char* fileName )
|
|||
afd.moviSize = 4; // for the "movi" header signature
|
||||
afd.fileOpen = qtrue;
|
||||
|
||||
Com_Printf( "Recording to %s\n", afd.fileName );
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
@ -414,12 +436,7 @@ static qbool CL_CheckFileSize( int bytesToAdd )
|
|||
// we target can handle a 2Gb file
|
||||
if( newFileSize > INT_MAX )
|
||||
{
|
||||
// Close the current file...
|
||||
CL_CloseAVI( );
|
||||
|
||||
// ...And open a new one
|
||||
CL_OpenAVIForWriting( va( "%s_", afd.fileName ) );
|
||||
|
||||
CL_OpenAVIForWriting( NULL, qtrue );
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
@ -517,7 +534,7 @@ void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size )
|
|||
WRITE_4BYTES( bytesInBuffer );
|
||||
|
||||
SafeFS_Write( buffer, 8, afd.f );
|
||||
SafeFS_Write( pcmBuffer, bytesInBuffer, afd.f );
|
||||
SafeFS_Write( pcmCaptureBuffer, bytesInBuffer, afd.f );
|
||||
SafeFS_Write( padding, paddingSize, afd.f );
|
||||
afd.fileSize += ( chunkSize + paddingSize );
|
||||
|
||||
|
@ -625,6 +642,8 @@ qbool CL_CloseAVI( void )
|
|||
|
||||
Com_Printf( "Wrote %d:%d frames to %s\n", afd.numVideoFrames, afd.numAudioFrames, afd.fileName );
|
||||
|
||||
S_StopAllSounds();
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1815,20 +1815,25 @@ static void CL_Video_f()
|
|||
{
|
||||
char s[ MAX_OSPATH ];
|
||||
|
||||
if( !clc.demoplaying )
|
||||
{
|
||||
Com_Printf( "ERROR: ^7/video is only enabled during demo playback\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( Cmd_Argc( ) == 2 )
|
||||
{
|
||||
Com_sprintf( s, MAX_OSPATH, "videos/%s.avi", Cmd_Argv( 1 ) );
|
||||
Com_sprintf( s, MAX_OSPATH, "videos/%s", Cmd_Argv( 1 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
qtime_t t;
|
||||
Com_RealTime( &t );
|
||||
Com_sprintf( s, sizeof(s), "videos/%d_%02d_%02d-%02d_%02d_%02d.avi",
|
||||
Com_sprintf( s, sizeof(s), "videos/%d_%02d_%02d-%02d_%02d_%02d",
|
||||
1900+t.tm_year, 1+t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec );
|
||||
}
|
||||
|
||||
Com_Printf( "recording to %s\n", s );
|
||||
CL_OpenAVIForWriting( s );
|
||||
CL_OpenAVIForWriting( s, qfalse );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1999,7 +2004,7 @@ static const cvarTableItem_t cl_cvars[] =
|
|||
{ &cl_showTimeDelta, "cl_showTimeDelta", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "prints delta adjustment values and events" },
|
||||
{ &rconPassword, "rconPassword", "", CVAR_TEMP, CVART_STRING, NULL, NULL, help_rconPassword },
|
||||
{ &cl_timedemo, "timedemo", "0", 0, CVART_BOOL, NULL, NULL, "demo benchmarking mode" },
|
||||
{ &cl_aviFrameRate, "cl_aviFrameRate", "25", CVAR_ARCHIVE, CVART_INTEGER, "1", "250", help_cl_aviFrameRate },
|
||||
{ &cl_aviFrameRate, "cl_aviFrameRate", "50", CVAR_ARCHIVE, CVART_INTEGER, "24", "250", help_cl_aviFrameRate },
|
||||
{ &cl_aviMotionJpeg, "cl_aviMotionJpeg", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_cl_aviMotionJpeg },
|
||||
{ &rconAddress, "rconAddress", "", 0, CVART_STRING, NULL, NULL, help_rconAddress },
|
||||
{ &cl_maxpackets, "cl_maxpackets", "125", CVAR_ARCHIVE, CVART_INTEGER, "15", "125", "max. packet upload rate" },
|
||||
|
|
|
@ -507,7 +507,7 @@ qbool CL_Netchan_Process( netchan_t *chan, msg_t *msg );
|
|||
//
|
||||
// cl_avi.c
|
||||
//
|
||||
qbool CL_OpenAVIForWriting( const char *filename );
|
||||
qbool CL_OpenAVIForWriting( const char *fileNameNoExt, qbool reOpen );
|
||||
void CL_TakeVideoFrame( void );
|
||||
void CL_WriteAVIVideoFrame( const byte *imageBuffer, int size );
|
||||
void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size );
|
||||
|
|
|
@ -460,29 +460,21 @@ const void *RB_TakeVideoFrameCmd( const void *data )
|
|||
int frameSize;
|
||||
const videoFrameCommand_t* cmd = (const videoFrameCommand_t*)data;
|
||||
|
||||
qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, cmd->captureBuffer );
|
||||
|
||||
if( cmd->motionJpeg )
|
||||
{
|
||||
frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 95,
|
||||
cmd->width, cmd->height, cmd->captureBuffer );
|
||||
qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA, GL_UNSIGNED_BYTE, cmd->captureBuffer );
|
||||
frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 95, cmd->width, cmd->height, cmd->captureBuffer );
|
||||
ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
frameSize = cmd->width * cmd->height * 4;
|
||||
|
||||
// Vertically flip the image
|
||||
for(int i = 0; i < cmd->height; i++ )
|
||||
{
|
||||
Com_Memcpy( &cmd->encodeBuffer[ i * ( cmd->width * 4 ) ],
|
||||
&cmd->captureBuffer[ ( cmd->height - i - 1 ) * ( cmd->width * 4 ) ],
|
||||
cmd->width * 4 );
|
||||
}
|
||||
qglPixelStorei( GL_PACK_ALIGNMENT, 4 );
|
||||
qglReadPixels( 0, 0, cmd->width, cmd->height, GL_BGR, GL_UNSIGNED_BYTE, cmd->captureBuffer );
|
||||
qglPixelStorei( GL_PACK_ALIGNMENT, 1 );
|
||||
frameSize = PAD( cmd->width, 4 ) * cmd->height * 3;
|
||||
ri.CL_WriteAVIVideoFrame( cmd->captureBuffer, frameSize );
|
||||
}
|
||||
|
||||
ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize );
|
||||
|
||||
return (const void *)(cmd + 1);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue