videorecorder.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  ***************************************************************************/
00009 
00010 
00011 #include "videorecorder.h"
00012 
00013 #ifdef XVIDEXPORT
00014 
00015 #include "../libs/revel/revel.h"
00016 #include "../events.h"
00017 #include "../gameoptions.h"
00018 
00019 class VideoRecorderInternals {
00020    public:
00021      VideoRecorderInternals() : open(false), frameCounterOut(0), frameCounterIn(0), lastFrame(NULL) {};
00022      ~VideoRecorderInternals() { if ( lastFrame ) delete[] lastFrame; };
00023      int encoderHandle; 
00024      Revel_Params revParams;
00025      bool open;
00026      int framerate;
00027      int ascFramerateLimit;
00028      long lastTick;
00029      ASCString filename;
00030      int frameCounterOut; //<! counts all frames that where send to the videorecorder
00031      int frameCounterIn;  //<! counts all frames that where passed to the video encoder
00032      int* lastFrame;
00033 };
00034 
00035 
00036 void checkErrors( const Revel_Error& err )
00037 {
00038     if (err != REVEL_ERR_NONE)
00039     {
00040             printf("Revel Error : %d\n", err);
00041     }   
00042 }
00043 
00044 
00045 VideoRecorder::VideoRecorder( const ASCString& filename, const SDL_Surface* surf, int framerate, int ascFramerateLimit, int quality  )
00046 {
00047     data = new VideoRecorderInternals();
00048     data->framerate = framerate;
00049     data->lastTick = getTicker();
00050     data->filename = filename;
00051     data->ascFramerateLimit = ascFramerateLimit;
00052    
00053     Revel_Error revError = Revel_CreateEncoder(&data->encoderHandle);
00054     checkErrors( revError );
00055    
00056     Revel_InitializeParams(&data->revParams);
00057     data->revParams.width = surf->w;
00058     data->revParams.height = surf->h;
00059     data->revParams.frameRate = data->framerate;
00060     float q = quality;
00061     q /= 100.0f;
00062     data->revParams.quality = q;
00063     data->revParams.codec = REVEL_CD_XVID;
00064 
00065     data->revParams.hasAudio = 0;
00066 
00067     // Initiate encoding
00068     revError = Revel_EncodeStart(data->encoderHandle, filename.c_str(), &data->revParams);
00069     data->open = true;
00070 }
00071 
00072 void VideoRecorder::storeFrame( const SDL_Surface* surf )
00073 {
00074    if ( !surf )
00075       surf = SDL_GetVideoSurface();
00076 
00077    if ( !surf )
00078       return;
00079 
00080    Revel_VideoFrame frame;
00081    frame.width = surf->w;
00082    frame.height = surf->h;
00083    frame.bytesPerPixel = 4;
00084    
00085    bool directScreenRender = false;
00086    /*
00087    if ( surf->pitch == surf->w*4 && surf->format->BytesPerPixel == 4 ) {
00088       if ( surf->format->Rshift == 0 && surf->format->Gshift == 8 && surf->format->Bshift == 16 ) {
00089          frame.pixelFormat = REVEL_PF_RGBA;
00090          directScreenRender = true;
00091       }
00092       
00093       if ( surf->format->Rshift == 24 && surf->format->Gshift == 16 && surf->format->Bshift == 8 ) {
00094          frame.pixelFormat = REVEL_PF_ABGR;
00095          directScreenRender = true;
00096       }
00097    }
00098    */
00099    
00100    
00101    if ( directScreenRender ) {
00102       int frameSize;
00103       frame.pixels = surf->pixels;
00104       Revel_Error revError = Revel_EncodeFrame(data->encoderHandle, &frame, &frameSize);
00105       checkErrors( revError);
00106    } else {
00107       frame.pixelFormat = REVEL_PF_RGBA;
00108       int* buf;
00109       frame.pixels = buf = new int[frame.width*frame.height];   
00110       
00111       Uint32* pix = (Uint32*)frame.pixels;
00112       
00113       bool diff = false;
00114       int* lastBuf = data->lastFrame;
00115       if ( !data->lastFrame )
00116          diff = true;
00117       
00118       for ( int y = 0; y < surf->h; ++y ) {
00119          Uint32* src = ((Uint32*) surf->pixels) + (surf->pitch/4*y);
00120          for ( int x = 0 ; x < surf->w; ++x ) {
00121             Uint8 r,g,b,a;
00122             SDL_GetRGBA( *src, surf->format, &r,&g,&b,&a);
00123             *pix = r + (g<<8) + (b<<16) + (a<<24);
00124             if ( lastBuf ) {
00125                if ( *pix != *lastBuf )
00126                   diff = true;
00127                ++lastBuf;
00128             }
00129             ++pix;
00130             ++src;
00131          }
00132       }
00133       if ( diff || 1 ) {
00134          int frameSize;
00135          Revel_Error revError = Revel_EncodeFrame(data->encoderHandle, &frame, &frameSize);
00136          checkErrors( revError);
00137          ++data->frameCounterIn;
00138        }
00139       if ( data->lastFrame )
00140          delete[] data->lastFrame;
00141       data->lastFrame = buf;
00142    }
00143    
00144    ++data->frameCounterOut;
00145    
00146    // we are limiting the playback to the specified framerate
00147    while ( getTicker() < data->lastTick + 100/data->ascFramerateLimit )
00148       releasetimeslice();
00149    
00150    data->lastTick = getTicker();
00151 }
00152 
00153 void VideoRecorder::close()
00154 {
00155    if ( data->open ) {
00156       int totalSize;
00157       Revel_Error revError = Revel_EncodeEnd(data->encoderHandle, &totalSize);
00158       checkErrors( revError );
00159       Revel_DestroyEncoder(data->encoderHandle);      
00160    }
00161    printf("recorded %d / %d frames\n", data->frameCounterOut, data->frameCounterIn );
00162 }
00163 
00164 const ASCString VideoRecorder::getFilename()
00165 {
00166    return data->filename;  
00167 }
00168 
00169 
00170 VideoRecorder::~VideoRecorder()
00171 {
00172    close();
00173    delete data;
00174 }
00175 
00176 #else
00177 
00178 VideoRecorder::VideoRecorder( const ASCString& filename, const SDL_Surface* surf, int framerate, int ascFramerateLimit, int quality  ) {}
00179 const ASCString VideoRecorder::getFilename() { return ""; }
00180 void VideoRecorder::storeFrame( const SDL_Surface* surf ) {}
00181 void VideoRecorder::close() {}
00182 VideoRecorder::~VideoRecorder() {}
00183 
00184 #endif

Generated on Mon May 21 01:26:39 2012 for Advanced Strategic Command by  doxygen 1.5.1