aboutsummaryrefslogtreecommitdiffstats
path: root/code/renderer
diff options
context:
space:
mode:
authortma <tma@edf5b092-35ff-0310-97b2-ce42778d08ea>2006-01-04 03:12:12 +0000
committertma <tma@edf5b092-35ff-0310-97b2-ce42778d08ea>2006-01-04 03:12:12 +0000
commit98c8cf0f19d89b729825d6d37b924a84025ec07b (patch)
tree51cbf43364a63f83c5e0e2fea133038ebf8a255c /code/renderer
parent9e019da1eadfaab84999cf76ec169d6cb3bc9f25 (diff)
downloadioquake3-aero-98c8cf0f19d89b729825d6d37b924a84025ec07b.tar.gz
ioquake3-aero-98c8cf0f19d89b729825d6d37b924a84025ec07b.zip
* AVI video output
- Uses motion jpeg codec by default - Use cl_avidemo to set a framerate - \video [filename] to start capture - \stopvideo to stop capture - Audio capture is a bit ropey git-svn-id: svn://svn.icculus.org/quake3/trunk@454 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/renderer')
-rw-r--r--code/renderer/tr_backend.c3
-rw-r--r--code/renderer/tr_cmds.c27
-rw-r--r--code/renderer/tr_image.c58
-rw-r--r--code/renderer/tr_init.c47
-rw-r--r--code/renderer/tr_local.h18
-rw-r--r--code/renderer/tr_public.h3
6 files changed, 155 insertions, 1 deletions
diff --git a/code/renderer/tr_backend.c b/code/renderer/tr_backend.c
index 6c93c14..2061dd8 100644
--- a/code/renderer/tr_backend.c
+++ b/code/renderer/tr_backend.c
@@ -1081,6 +1081,9 @@ void RB_ExecuteRenderCommands( const void *data ) {
case RC_SCREENSHOT:
data = RB_TakeScreenshotCmd( data );
break;
+ case RC_VIDEOFRAME:
+ data = RB_TakeVideoFrameCmd( data );
+ break;
case RC_END_OF_LIST:
default:
diff --git a/code/renderer/tr_cmds.c b/code/renderer/tr_cmds.c
index 54f8150..3be865c 100644
--- a/code/renderer/tr_cmds.c
+++ b/code/renderer/tr_cmds.c
@@ -445,3 +445,30 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
backEnd.pc.msec = 0;
}
+/*
+=============
+RE_TakeVideoFrame
+=============
+*/
+void RE_TakeVideoFrame( int width, int height,
+ byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg )
+{
+ videoFrameCommand_t *cmd;
+
+ if( !tr.registered ) {
+ return;
+ }
+
+ cmd = R_GetCommandBuffer( sizeof( *cmd ) );
+ if( !cmd ) {
+ return;
+ }
+
+ cmd->commandId = RC_VIDEOFRAME;
+
+ cmd->width = width;
+ cmd->height = height;
+ cmd->captureBuffer = captureBuffer;
+ cmd->encodeBuffer = encodeBuffer;
+ cmd->motionJpeg = motionJpeg;
+}
diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c
index 15d6c7e..c227388 100644
--- a/code/renderer/tr_image.c
+++ b/code/renderer/tr_image.c
@@ -1852,6 +1852,64 @@ void SaveJPG(char * filename, int quality, int image_width, int image_height, un
/* And we're done! */
}
+/*
+=================
+SaveJPGToBuffer
+=================
+*/
+int SaveJPGToBuffer( byte *buffer, int quality,
+ int image_width, int image_height,
+ byte *image_buffer )
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
+ int row_stride; /* physical row width in image buffer */
+
+ /* Step 1: allocate and initialize JPEG compression object */
+ cinfo.err = jpeg_std_error(&jerr);
+ /* Now we can initialize the JPEG compression object. */
+ jpeg_create_compress(&cinfo);
+
+ /* Step 2: specify data destination (eg, a file) */
+ /* Note: steps 2 and 3 can be done in either order. */
+ jpegDest(&cinfo, buffer, image_width*image_height*4);
+
+ /* Step 3: set parameters for compression */
+ cinfo.image_width = image_width; /* image width and height, in pixels */
+ cinfo.image_height = image_height;
+ cinfo.input_components = 4; /* # of color components per pixel */
+ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+
+ /* Step 4: Start compressor */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Step 5: while (scan lines remain to be written) */
+ /* jpeg_write_scanlines(...); */
+ row_stride = image_width * 4; /* JSAMPLEs per row in image_buffer */
+
+ while (cinfo.next_scanline < cinfo.image_height) {
+ /* jpeg_write_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could pass
+ * more than one scanline at a time if that's more convenient.
+ */
+ row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
+ (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ /* Step 6: Finish compression */
+ jpeg_finish_compress(&cinfo);
+
+ /* Step 7: release JPEG compression object */
+ jpeg_destroy_compress(&cinfo);
+
+ /* And we're done! */
+ return hackSize;
+}
+
//===================================================================
/*
diff --git a/code/renderer/tr_init.c b/code/renderer/tr_init.c
index ffdd997..285ed18 100644
--- a/code/renderer/tr_init.c
+++ b/code/renderer/tr_init.c
@@ -700,6 +700,51 @@ void R_ScreenShotJPEG_f (void) {
//============================================================================
/*
+==================
+RB_TakeVideoFrameCmd
+==================
+*/
+const void *RB_TakeVideoFrameCmd( const void *data )
+{
+ const videoFrameCommand_t *cmd;
+ int frameSize;
+ int i;
+
+ cmd = (const videoFrameCommand_t *)data;
+
+ qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA,
+ GL_UNSIGNED_BYTE, cmd->captureBuffer );
+
+ // gamma correct
+ if( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma )
+ R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 );
+
+ if( cmd->motionJpeg )
+ {
+ frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 95,
+ cmd->width, cmd->height, cmd->captureBuffer );
+ }
+ else
+ {
+ frameSize = cmd->width * cmd->height * 4;
+
+ // Vertically flip the image
+ for( 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 );
+ }
+ }
+
+ ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize );
+
+ return (const void *)(cmd + 1);
+}
+
+//============================================================================
+
+/*
** GL_SetDefaultState
*/
void GL_SetDefaultState( void )
@@ -1201,5 +1246,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) {
re.GetEntityToken = R_GetEntityToken;
re.inPVS = R_inPVS;
+ re.TakeVideoFrame = RE_TakeVideoFrame;
+
return &re;
}
diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h
index 865128f..1b47f96 100644
--- a/code/renderer/tr_local.h
+++ b/code/renderer/tr_local.h
@@ -1215,6 +1215,7 @@ skin_t *R_GetSkinByHandle( qhandle_t hSkin );
int R_ComputeLOD( trRefEntity_t *ent );
+const void *RB_TakeVideoFrameCmd( const void *data );
//
// tr_shader.c
@@ -1579,6 +1580,15 @@ typedef struct {
qboolean jpeg;
} screenshotCommand_t;
+typedef struct {
+ int commandId;
+ int width;
+ int height;
+ byte *captureBuffer;
+ byte *encodeBuffer;
+ qboolean motionJpeg;
+} videoFrameCommand_t;
+
typedef enum {
RC_END_OF_LIST,
RC_SET_COLOR,
@@ -1586,7 +1596,8 @@ typedef enum {
RC_DRAW_SURFS,
RC_DRAW_BUFFER,
RC_SWAP_BUFFERS,
- RC_SCREENSHOT
+ RC_SCREENSHOT,
+ RC_VIDEOFRAME
} renderCommand_t;
@@ -1635,6 +1646,11 @@ void RE_StretchPic ( float x, float y, float w, float h,
void RE_BeginFrame( stereoFrame_t stereoFrame );
void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
void SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer);
+int SaveJPGToBuffer( byte *buffer, int quality,
+ int image_width, int image_height,
+ byte *image_buffer );
+void RE_TakeVideoFrame( int width, int height,
+ byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg );
// font stuff
void R_InitFreeType( void );
diff --git a/code/renderer/tr_public.h b/code/renderer/tr_public.h
index 9752305..6cefe16 100644
--- a/code/renderer/tr_public.h
+++ b/code/renderer/tr_public.h
@@ -97,6 +97,8 @@ typedef struct {
void (*RemapShader)(const char *oldShader, const char *newShader, const char *offsetTime);
qboolean (*GetEntityToken)( char *buffer, int size );
qboolean (*inPVS)( const vec3_t p1, const vec3_t p2 );
+
+ void (*TakeVideoFrame)( int h, int w, byte* captureBuffer, byte *encodeBuffer, qboolean motionJpeg );
} refexport_t;
//
@@ -156,6 +158,7 @@ typedef struct {
int (*CIN_PlayCinematic)( const char *arg0, int xpos, int ypos, int width, int height, int bits);
e_status (*CIN_RunCinematic) (int handle);
+ void (*CL_WriteAVIVideoFrame)( const byte *buffer, int size );
} refimport_t;