00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <cmath>
00011
00012 #include "../celengine/gl.h"
00013 #include "../celengine/glext.h"
00014
00015 #include <windowsx.h>
00016 #include <celutil/debug.h>
00017 #include "avicapture.h"
00018
00019 using namespace std;
00020
00021
00022 AVICapture::AVICapture() :
00023 width(-1),
00024 height(-1),
00025 frameRate(30.0f),
00026 frameCounter(0),
00027 capturing(false),
00028 aviFile(NULL),
00029 aviStream(NULL),
00030 compAviStream(NULL),
00031 image(NULL)
00032 {
00033 AVIFileInit();
00034 }
00035
00036
00037 AVICapture::~AVICapture()
00038 {
00039 cleanup();
00040 AVIFileExit();
00041 }
00042
00043
00044 bool AVICapture::start(const string& filename,
00045 int w, int h,
00046 float fps)
00047 {
00048 if (capturing)
00049 return false;
00050
00051 width = w;
00052 height = h;
00053 frameRate = fps;
00054
00055 if (HIWORD(VideoForWindowsVersion()) < 0x010a)
00056 {
00057
00058 return false;
00059 }
00060
00061
00062
00063 int rowBytes = (width * 3 + 3) & ~0x3;
00064 image = new unsigned char[rowBytes * height];
00065
00066 HRESULT hr = AVIFileOpen(&aviFile,
00067 filename.c_str(),
00068 OF_WRITE | OF_CREATE,
00069 NULL);
00070 if (hr != AVIERR_OK)
00071 {
00072 DPRINTF(0, "Erroring creating avi file for capture.\n");
00073 return false;
00074 }
00075
00076 AVISTREAMINFO info;
00077 ZeroMemory(&info, sizeof info);
00078 info.fccType = streamtypeVIDEO;
00079 info.fccHandler = 0;
00080 info.dwScale = 1;
00081 info.dwRate = (DWORD) floor(frameRate + 0.5f);
00082 info.dwSuggestedBufferSize = rowBytes * height;
00083 SetRect(&info.rcFrame, 0, 0, width, height);
00084 hr = AVIFileCreateStream(aviFile, &aviStream, &info);
00085 if (hr != AVIERR_OK)
00086 {
00087 DPRINTF(0, "Error %08x creating AVI stream.\n", hr);
00088 cleanup();
00089 return false;
00090 }
00091
00092
00093 AVICOMPRESSOPTIONS options;
00094 AVICOMPRESSOPTIONS* arrOptions[1] = { &options };
00095 ZeroMemory(&options, sizeof options);
00096
00097 if (!AVISaveOptions(NULL, 0, 1, &aviStream,
00098 (LPAVICOMPRESSOPTIONS*) &arrOptions))
00099 {
00100
00101 cleanup();
00102 return false;
00103 }
00104
00105 hr = AVIMakeCompressedStream(&compAviStream, aviStream, &options, NULL);
00106 if (hr != AVIERR_OK)
00107 {
00108 DPRINTF(0, "Error %08x creating compressed AVI stream.\n", hr);
00109 cleanup();
00110 return false;
00111 }
00112
00113 BITMAPINFOHEADER bi;
00114 ZeroMemory(&bi, sizeof bi);
00115 bi.biSize = sizeof bi;
00116 bi.biWidth = width;
00117 bi.biHeight = height;
00118 bi.biPlanes = 1;
00119 bi.biBitCount = 24;
00120 bi.biCompression = BI_RGB;
00121 bi.biSizeImage = rowBytes * height;
00122 bi.biXPelsPerMeter = 0;
00123 bi.biYPelsPerMeter = 0;
00124 bi.biClrUsed = 0;
00125 bi.biClrImportant = 0;
00126
00127 hr = AVIStreamSetFormat(compAviStream, 0, &bi, sizeof bi);
00128 if (hr != AVIERR_OK)
00129 {
00130 DPRINTF(0, "AVIStreamSetFormat failed: %08x\n", hr);
00131 cleanup();
00132 return false;
00133 }
00134
00135 capturing = true;
00136 frameCounter = 0;
00137
00138 return true;
00139 }
00140
00141
00142 bool AVICapture::end()
00143 {
00144 capturing = false;
00145 cleanup();
00146
00147 return true;
00148 }
00149
00150
00151 bool AVICapture::captureFrame()
00152 {
00153 if (!capturing)
00154 return false;
00155
00156
00157 int viewport[4];
00158 glGetIntegerv(GL_VIEWPORT, viewport);
00159
00160 int x = viewport[0] + (viewport[2] - width) / 2;
00161 int y = viewport[1] + (viewport[3] - height) / 2;
00162 glReadPixels(x, y, width, height,
00163 GL_BGR_EXT, GL_UNSIGNED_BYTE,
00164 image);
00165
00166 int rowBytes = (width * 3 + 3) & ~0x3;
00167
00168 LONG samplesWritten = 0;
00169 LONG bytesWritten = 0;
00170 HRESULT hr = AVIStreamWrite(compAviStream,
00171 frameCounter,
00172 1,
00173 image,
00174 rowBytes * height,
00175 AVIIF_KEYFRAME,
00176 &samplesWritten,
00177 &bytesWritten);
00178 if (hr != AVIERR_OK)
00179 {
00180 DPRINTF(0, "AVIStreamWrite failed on frame %d\n", frameCounter);
00181 return false;
00182 }
00183
00184
00185
00186 frameCounter++;
00187
00188 return true;
00189 }
00190
00191
00192 void AVICapture::cleanup()
00193 {
00194 if (aviStream != NULL)
00195 {
00196 AVIStreamRelease(aviStream);
00197 aviStream = NULL;
00198 }
00199 if (compAviStream != NULL)
00200 {
00201 AVIStreamRelease(compAviStream);
00202 compAviStream = NULL;
00203 }
00204 if (aviFile != NULL)
00205 {
00206 AVIFileRelease(aviFile);
00207 aviFile = NULL;
00208 }
00209 if (image != NULL)
00210 {
00211 delete[] image;
00212 image = NULL;
00213 }
00214 }
00215
00216
00217 int AVICapture::getWidth() const
00218 {
00219 return width;
00220 }
00221
00222 int AVICapture::getHeight() const
00223 {
00224 return height;
00225 }
00226
00227 float AVICapture::getFrameRate() const
00228 {
00229 return frameRate;
00230 }
00231
00232 int AVICapture::getFrameCount() const
00233 {
00234 return frameCounter;
00235 }