Advanced Strategic Command
videorecorder.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * This program is free software; you can redistribute it and/or modify *
4  * it under the terms of the GNU General Public License as published by *
5  * the Free Software Foundation; either version 2 of the License, or *
6  * (at your option) any later version. *
7  * *
8  ***************************************************************************/
9 
10 
11 #include "videorecorder.h"
12 
13 #ifdef XVIDEXPORT
14 
15 #include "../libs/revel/revel.h"
16 #include "../events.h"
17 #include "../gameoptions.h"
18 
19 class VideoRecorderInternals {
20  public:
21  VideoRecorderInternals() : open(false), frameCounterOut(0), frameCounterIn(0), lastFrame(NULL) {};
22  ~VideoRecorderInternals() { if ( lastFrame ) delete[] lastFrame; };
23  int encoderHandle;
24  Revel_Params revParams;
25  bool open;
26  int framerate;
27  int ascFramerateLimit;
28  long lastTick;
29  ASCString filename;
30  int frameCounterOut; //<! counts all frames that where send to the videorecorder
31  int frameCounterIn; //<! counts all frames that where passed to the video encoder
32  int* lastFrame;
33 };
34 
35 
36 void checkErrors( const Revel_Error& err )
37 {
38  if (err != REVEL_ERR_NONE)
39  {
40  printf("Revel Error : %d\n", err);
41  }
42 }
43 
44 
45 VideoRecorder::VideoRecorder( const ASCString& filename, const SDL_Surface* surf, int framerate, int ascFramerateLimit, int quality )
46 {
47  data = new VideoRecorderInternals();
48  data->framerate = framerate;
49  data->lastTick = getTicker();
50  data->filename = filename;
51  data->ascFramerateLimit = ascFramerateLimit;
52 
53  Revel_Error revError = Revel_CreateEncoder(&data->encoderHandle);
54  checkErrors( revError );
55 
56  Revel_InitializeParams(&data->revParams);
57  data->revParams.width = surf->w;
58  data->revParams.height = surf->h;
59  data->revParams.frameRate = data->framerate;
60  float q = quality;
61  q /= 100.0f;
62  data->revParams.quality = q;
63  data->revParams.codec = REVEL_CD_XVID;
64 
65  data->revParams.hasAudio = 0;
66 
67  // Initiate encoding
68  revError = Revel_EncodeStart(data->encoderHandle, filename.c_str(), &data->revParams);
69  data->open = true;
70 }
71 
72 void VideoRecorder::storeFrame( const SDL_Surface* surf )
73 {
74  if ( !surf )
75  surf = SDL_GetVideoSurface();
76 
77  if ( !surf )
78  return;
79 
80  Revel_VideoFrame frame;
81  frame.width = surf->w;
82  frame.height = surf->h;
83  frame.bytesPerPixel = 4;
84 
85  bool directScreenRender = false;
86  /*
87  if ( surf->pitch == surf->w*4 && surf->format->BytesPerPixel == 4 ) {
88  if ( surf->format->Rshift == 0 && surf->format->Gshift == 8 && surf->format->Bshift == 16 ) {
89  frame.pixelFormat = REVEL_PF_RGBA;
90  directScreenRender = true;
91  }
92 
93  if ( surf->format->Rshift == 24 && surf->format->Gshift == 16 && surf->format->Bshift == 8 ) {
94  frame.pixelFormat = REVEL_PF_ABGR;
95  directScreenRender = true;
96  }
97  }
98  */
99 
100 
101  if ( directScreenRender ) {
102  int frameSize;
103  frame.pixels = surf->pixels;
104  Revel_Error revError = Revel_EncodeFrame(data->encoderHandle, &frame, &frameSize);
105  checkErrors( revError);
106  } else {
107  frame.pixelFormat = REVEL_PF_RGBA;
108  int* buf;
109  frame.pixels = buf = new int[frame.width*frame.height];
110 
111  Uint32* pix = (Uint32*)frame.pixels;
112 
113  bool diff = false;
114  int* lastBuf = data->lastFrame;
115  if ( !data->lastFrame )
116  diff = true;
117 
118  for ( int y = 0; y < surf->h; ++y ) {
119  Uint32* src = ((Uint32*) surf->pixels) + (surf->pitch/4*y);
120  for ( int x = 0 ; x < surf->w; ++x ) {
121  Uint8 r,g,b,a;
122  SDL_GetRGBA( *src, surf->format, &r,&g,&b,&a);
123  *pix = r + (g<<8) + (b<<16) + (a<<24);
124  if ( lastBuf ) {
125  if ( *pix != *lastBuf )
126  diff = true;
127  ++lastBuf;
128  }
129  ++pix;
130  ++src;
131  }
132  }
133  if ( diff || 1 ) {
134  int frameSize;
135  Revel_Error revError = Revel_EncodeFrame(data->encoderHandle, &frame, &frameSize);
136  checkErrors( revError);
137  ++data->frameCounterIn;
138  }
139  if ( data->lastFrame )
140  delete[] data->lastFrame;
141  data->lastFrame = buf;
142  }
143 
144  ++data->frameCounterOut;
145 
146  // we are limiting the playback to the specified framerate
147  while ( getTicker() < data->lastTick + 100/data->ascFramerateLimit )
149 
150  data->lastTick = getTicker();
151 }
152 
154 {
155  if ( data->open ) {
156  int totalSize;
157  Revel_Error revError = Revel_EncodeEnd(data->encoderHandle, &totalSize);
158  checkErrors( revError );
159  Revel_DestroyEncoder(data->encoderHandle);
160  }
161  printf("recorded %d / %d frames\n", data->frameCounterOut, data->frameCounterIn );
162 }
163 
165 {
166  return data->filename;
167 }
168 
169 
171 {
172  close();
173  delete data;
174 }
175 
176 #else
177 
178 VideoRecorder::VideoRecorder( const ASCString& filename, const SDL_Surface* surf, int framerate, int ascFramerateLimit, int quality ) {}
179 const ASCString VideoRecorder::getFilename() { return ""; }
180 void VideoRecorder::storeFrame( const SDL_Surface* surf ) {}
183 
184 #endif
const ASCString getFilename()
void storeFrame(const SDL_Surface *surf)
int getTicker()
Definition: events.cpp:525
VideoRecorder(const ASCString &filename, const SDL_Surface *surf, int framerate=15, int ascFramerateLimit=30, int quality=100)
if(!yyg->yy_init)
Definition: scanner.cpp:695
The ASCString class provides an abstract way to manipulate strings.
Definition: ascstring.h:14
int releasetimeslice(void)
Definition: events.cpp:209