Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

avicapture.cpp

Go to the documentation of this file.
00001 // avicapture.cpp
00002 //
00003 // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
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         // We need to be running on version 1.1 or later
00058         return false;
00059     }
00060 
00061     // Compute the width of a row in bytes; pad so that rows are aligned on
00062     // 4 byte boundaries.
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     // Display a dialog to allow the user to select compression options
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         // The user either clicked on cancel or there was an error
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     // Get the dimensions of the current viewport
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     // printf("Writing frame: %d  %d => %d bytes\n",
00185     //        frameCounter, rowBytes * height, bytesWritten);
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 }

Generated on Sat Jan 14 22:30:29 2006 for Celestia by  doxygen 1.4.1