This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| DirectDraw AVI Writer Submitted by

This is some pretty nice code to save AVI files from DirectDraw surfaces (whatever now that useful for). I haven't tested it in all bitdepth's, but it should work on everything over 8.
An error is that the combo box in the AVIOptions dialog doesn't fold out (??), you have to use up-down arrows to choose the compressor. I suppose you can't blame me for that though.
Greets
Tobias Johansson

Currently browsing [dxavi.zip] (2,923 bytes) - [DirectXAVI.h] - (1,446 bytes)

    //DirectXAVI.h : AVI code by Tobias Johansson

    #if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000

    #ifndef _DIRECTXAVI_
    #define _DIRECTXAVI_

    #include "Core.h"
    #include <vfw.h> //The VideoForWindows header file, Vfw32.lib must also be linked

    ////////////////////////////////////////////////
    //
    // WriteAVIFile - Open AVI streams
    //
    // Parameters:
    //   char *fname: name of avi file
    //   lpSurf: DirectDraw surface to capture video from
    //   int FramesPerSecond: The frame frequency of the video (25-30 is normal)
    //
    // Return 1 is succesful
    // Other value are error values
    //////////////////////////////////////////////////
    #define AVI_ERROR_WRONGSURFACE           55
    #define AVI_ERROR_UNSUPPORTEDPIXELFORMAT 66
    #define AVI_ERROR_OTHERERROR             77

    int WriteAVIFile( char *fname, LPDIRECTDRAWSURFACE7 lpSurf, int FramesPerSecond );

    /////////////////////////////////////////////////
    //
    // CloseAVI - End video capture and closes avi streams
    //
    /////////////////////////////////////////////////

    void CloseAVIFile();

    //////////////////////////////////////////////////
    //
    // WriteFrame - Write a frame to the avi file
    //
    // Parameters:
    //  lpSurf: ddraw surface for read from, preferably same surf as in WriteAVIFile
    //
    // Return 1 if succesful
    // Other values are error values
    /////////////////////////////////////////

    int WriteFrame( LPDIRECTDRAWSURFACE7 lpSurf );

    #endif

Currently browsing [dxavi.zip] (2,923 bytes) - [DirectXAVI.cpp] - (7,505 bytes)

    //DirectXAVI.cpp : AVI code by Tobias Johansson

    #include "DirectXAVI.h"

    AVISTREAMINFO aviStreamInfo;
    PAVIFILE      pAviFile = NULL;
    PAVISTREAM    psStream = NULL;
    PAVISTREAM    psCompressed = NULL;

    AVICOMPRESSOPTIONS FAR * lpOptions;

    //Width of video
    int gAVIWidth  = 0;
    //Height of video
    int gAVIHeight = 0;
    //Fps of the video
    int gAVIfps    = 0;
    //pixel depth of the video
    int gAVIBpp    = 0;
    //current video frame
    long gVideoFrame = 0;

    BOOL bAVIFileOpened = FALSE;

    #define ERROR_LOG(x) LogFile->Print(x)
    //#define ERROR_LOG(x) MessageBox(NULL, x,"Fatal Error",MB_OK)

    int WriteAVIFile( char *fname, LPDIRECTDRAWSURFACE7 lpSurf, int FramesPerSecond )
    {
      HRESULT        hr;
      DDSURFACEDESC2 ddsd;

      //See if the vfw is new enough
       WORD wVer = HIWORD( VideoForWindowsVersion() );
       if (wVer < 0x010a)
       {
         ERROR_LOG("VideoForWindows too old.\n");
         return AVI_ERROR_OTHERERROR;
       }

       _DDInit( ddsd );
       lpSurf->GetSurfaceDesc( &ddsd );

       gAVIWidth  = ddsd.dwWidth;
       gAVIHeight = ddsd.dwHeight;
       gAVIBpp    = ddsd.ddpfPixelFormat.dwRGBBitCount;
       gAVIfps    = MAX( FramesPerSecond, 0 ); //If some wiseguy tries a negative fps :)

       if( gAVIBpp <= 8 )
       {
    	   ERROR_LOG("Unsupported Pixel Format.\n");
    	   return AVI_ERROR_UNSUPPORTEDPIXELFORMAT;
       }

       AVIFileInit();

       hr = AVIFileOpen( &pAviFile, fname, OF_WRITE | OF_CREATE, NULL );
       if( hr != AVIERR_OK )
       {
    	   ERROR_LOG("AVIFileOpen failed.\n");
    	   return AVI_ERROR_OTHERERROR;
       }

       BITMAPINFO bmpVideoFormat =
       {
    	  {
    		sizeof( BITMAPINFO ),
    		gAVIWidth,
    		gAVIHeight,
    		1,
    		24,
    		BI_RGB,
    		gAVIWidth * gAVIHeight * 3,
    		0,
    		0,
    		0,
    		0
    	  }
       };

        memset(&aviStreamInfo, 0, sizeof( aviStreamInfo ));

    	aviStreamInfo.fccType                = streamtypeVIDEO;
    	aviStreamInfo.fccHandler             = 0;
    	aviStreamInfo.dwScale                = 1;
    	aviStreamInfo.dwRate                 = gAVIfps;
    	aviStreamInfo.dwSuggestedBufferSize  = 0;
    	aviStreamInfo.dwQuality              = -1;
    	SetRect(&aviStreamInfo.rcFrame, 0, 0, (int) bmpVideoFormat.bmiHeader.biWidth, (int) bmpVideoFormat.bmiHeader.biHeight);

        hr = AVIFileCreateStream( pAviFile, &psStream, &aviStreamInfo );
        if( hr != AVIERR_OK )
        {
          ERROR_LOG("Couldn't create AVI stream.\n");
    	  CloseAVIFile();
          return AVI_ERROR_OTHERERROR;
        }

        lpOptions = new AVICOMPRESSOPTIONS;
    	memset( lpOptions, 0, sizeof( AVICOMPRESSOPTIONS ));

    	if( !AVISaveOptions( gMainWnd , ICMF_CHOOSE_KEYFRAME|ICMF_CHOOSE_DATARATE , 1, &psStream, &lpOptions))
    	{
          ERROR_LOG("AVISaveOptions failed.\n");
    	  CloseAVIFile();
          return AVI_ERROR_OTHERERROR;
        }

        hr = AVIMakeCompressedStream( &psCompressed, psStream, lpOptions, NULL);
        if( hr != AVIERR_OK )
        {
          ERROR_LOG("Couldn't create compressed stream.\n");
    	  CloseAVIFile();
          return AVI_ERROR_OTHERERROR;
        }

        hr = AVIStreamSetFormat( psCompressed, 0, &bmpVideoFormat, sizeof( bmpVideoFormat ));
        if( hr != AVIERR_OK )
        {
          ERROR_LOG("AVIStreamSetFormat returned an ERROR_LOG.\n");
    	  CloseAVIFile();
          return AVI_ERROR_OTHERERROR;
        }

       gVideoFrame = 0;
       bAVIFileOpened = TRUE;

       delete lpOptions;
       return 1;
    }

    void CloseAVIFile()
    {
    	if ( psStream )
    		AVIStreamClose( psStream );

    	if ( psCompressed )
    		AVIStreamClose( psCompressed );

    	if ( pAviFile )
    		AVIFileClose( pAviFile );

    	psStream = psCompressed = NULL;
    	pAviFile = NULL;
    	AVIFileExit();
    	bAVIFileOpened = FALSE;
    }

    int WriteFrame( LPDIRECTDRAWSURFACE7 lpSurf )
    {
       DDSURFACEDESC2  ddsd;
       BYTE           *bSurface;
       BYTE           *bAVIData;
       WORD            wPitch, wPixel;
       HRESULT         hr;
       DWORD           dwIndex, dwPixel;
       int             iX, iY, iByte;

       if( !bAVIFileOpened )
    	   return AVI_ERROR_OTHERERROR;

       _DDInit( ddsd );
       lpSurf->GetSurfaceDesc( &ddsd );

       if( (gAVIWidth != (int)ddsd.dwWidth) || (gAVIHeight != (int)ddsd.dwHeight) || (gAVIBpp != (int)ddsd.ddpfPixelFormat.dwRGBBitCount ))
       {
    	   ERROR_LOG("Wrong Surface.\n");
    	   return AVI_ERROR_WRONGSURFACE;
       }

       _DDInit( ddsd );
       hr = lpSurf->Lock( NULL , &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT , NULL );
       if( FAILED( hr ))
       {
    	   ERROR_LOG("Couldn't lock surface.\n");
    	   return AVI_ERROR_OTHERERROR;
       }
       bSurface = (BYTE *)ddsd.lpSurface;
       wPitch   = (WORD)ddsd.lPitch;

       if( gAVIBpp == 16 ) wPitch /= 2;

       dwIndex  = 0;
       bAVIData = new BYTE[ gAVIWidth * gAVIHeight * 3 ];

       switch( gAVIBpp )
       {
          case 32:

              for( iY = gAVIHeight - 1; iY >= 0; iY -- )
    		  {
    	         for( iX = 0; iX < gAVIWidth; iX ++ )
    			 {

    		        dwPixel = *((DWORD *)( bSurface + iX * 4 + iY * wPitch ));

      		        iByte                  = ( dwPixel       ) & 0x000000ff; //Blue
    		        bAVIData[ dwIndex ++ ] = iByte;
    		        iByte                  = ( dwPixel >> 8  ) & 0x000000ff; //Green
    		        bAVIData[ dwIndex ++ ] = iByte;
    		        iByte                  = ( dwPixel >> 16 ) & 0x000000ff; //Red
     		        bAVIData[ dwIndex ++ ] = iByte;

    			 }
    		  }

    	  break;

    	  case 24:

              for( iY = gAVIHeight - 1; iY >= 0; iY -- )
    		  {
    	         for( iX = 0; iX < gAVIWidth; iX ++ )
    			 {
    		        bAVIData[ dwIndex ++ ] = *( bSurface + iX * 3 + iY * wPitch + 2 );
    		        bAVIData[ dwIndex ++ ] = *( bSurface + iX * 3 + iY * wPitch + 1 );
     		        bAVIData[ dwIndex ++ ] = *( bSurface + iX * 3 + iY * wPitch + 0 );
    			 }
    		  }

    	  break;

    	  case 16:

     	      if( ddsd.ddpfPixelFormat.dwGBitMask == 0x07E0 ) // 565 mode
    		  {
                for( iY = gAVIHeight - 1; iY >= 0; iY -- )
    			{
    	           for( iX = 0; iX < gAVIWidth; iX ++ )
    			   {
                       wPixel = *((WORD *)( bSurface + iX * 2 + iY * wPitch * 2));

                       iByte                  = ( 8 * (( wPixel ) & 0x001f ));
    		           bAVIData[ dwIndex ++ ] = iByte;

                       iByte                  = ( 4 * (( wPixel >> 5 ) & 0x003f ));
    		           bAVIData[ dwIndex ++ ] = iByte;

                       iByte                  = ( 8 * (( wPixel >> 11 ) & 0x001f ));
    		           bAVIData[ dwIndex ++ ] = iByte;
    			   }
    			}
    		  }
              else // 5550 (1) mode
    		  {
                for( iY = gAVIHeight - 1; iY >= 0; iY -- )
    			{
    	           for( iX = 0; iX < gAVIWidth; iX ++ )
    			   {
                       wPixel = *((WORD *)( bSurface + iX * 2 + iY * wPitch * 2));

                       iByte                  = ( 8 * (( wPixel ) & 0x001f ));
    		           bAVIData[ dwIndex ++ ] = iByte;

                       iByte                  = ( 8 * (( wPixel >> 5 ) & 0x001f ));
    		           bAVIData[ dwIndex ++ ] = iByte;

                       iByte                  = ( 8 * (( wPixel >> 10 ) & 0x001f ));
     	               bAVIData[ dwIndex ++ ] = iByte;
    			   }
    			}
    		  }

           break;

       } //switch

       hr = AVIStreamWrite( psCompressed, gVideoFrame, 1, bAVIData, gAVIWidth * gAVIHeight * 3, 0, NULL, NULL );
       if (hr != AVIERR_OK)
       {
          ERROR_LOG("Couldn't write video data.\n");
     	  CloseAVIFile();
          return AVI_ERROR_OTHERERROR;
       }

       gVideoFrame ++;
       delete bAVIData;
       lpSurf->Unlock( NULL );

       return 1;
    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.