Splitting an AVI File into Multiple Bitmaps Using ltmmSampleTarget for C

The following code utilizes ltmmSampleTarget and ltmmConvert to generate multiple device independent bitmaps from an AVI file.

// define helper macros for using interfaces under C
#define COBJMACROS
// include the LEAD Multimedia TOOLKIT header
#include "ltmm.h" 
// include amvideo.h for VIDEOINFOHEADER, available in the Visual Studio 6.0 or the DirectX SDK
#include <amvideo.h>
// includes for string handling
#include <tchar.h>
#include <wchar.h>
#include <string.h>
#include <stdio.h>

/////////////////////////////////////////////////////////////////
// SaveBMP24
// saves a bitmap to a file (supports only 24 BPP)
// pszFile - output file name
// pHeader - BITMAPINFOHEADER
// pBits - bitmap image data
//
BOOL SaveBMP24(LPCWSTR pszFile, BITMAPINFOHEADER* pHeader, void* pBits)
{
   HANDLE hFile;
   TCHAR szFile[MAX_PATH];
   BITMAPFILEHEADER bfh;
   DWORD nWritten;

#if defined(_UNICODE)
   wcscpy(szFile, pszFile);
#else
   WideCharToMultiByte(CP_ACP, 0, pszFile, -1, szFile, MAX_PATH, NULL, NULL);
#endif

   hFile = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   if(hFile == INVALID_HANDLE_VALUE)
      return FALSE;

   bfh.bfType = 0x4D42;
   bfh.bfOffBits = sizeof(bfh) + pHeader->biSize;
   bfh.bfSize = bfh.bfOffBits + pHeader->biSizeImage;
   bfh.bfReserved1 = 0;
   bfh.bfReserved2 = 0;

   if(!WriteFile(hFile, &bfh, sizeof(bfh), &nWritten, NULL) || nWritten != sizeof(bfh))
   {
      CloseHandle(hFile);
      return FALSE;
   }

   if(!WriteFile(hFile, pHeader, pHeader->biSize, &nWritten, NULL) || nWritten != pHeader->biSize)
   {
      CloseHandle(hFile);
      return FALSE;
   }

   if(!WriteFile(hFile, pBits, pHeader->biSizeImage, &nWritten, NULL) || nWritten != pHeader->biSizeImage)
   {
      CloseHandle(hFile);
      return FALSE;
   }

   CloseHandle(hFile);
   return TRUE;
}

/////////////////////////////////////////////////////////////////
// SplitAvi
// splits an avi file into individual BMP files
// pszAviFile - source file name
// pszOutputDir - directory of output BMP files (split?.bmp)
// nMaxFrames - maximum number of BMP files (frames) to generate
//
HRESULT SplitAvi(LPCWSTR pszAviFile, LPCWSTR pszOutputDir, int nMaxFrames)
{
   HRESULT hr;
   IltmmConvert* pConvert = NULL;
   IltmmSampleTarget* pSampleTarget = NULL;
   IltmmMediaTypeDisp* pMediaType = NULL;
   IltmmMediaSampleDisp* pMediaSample;
   VARIANT varFormat;
   VARIANT varBuffer;
   VIDEOINFOHEADER* pVIH;
   void* pBuffer;
   BSTR bstr;
   int n;
   WCHAR szFile[MAX_PATH];
   
   // initialize COM library
   hr = CoInitialize(NULL);
   if(FAILED(hr))
      goto error;
   
   // create the convert object
   hr = CoCreateInstance(&CLSID_ltmmConvert, NULL, CLSCTX_INPROC_SERVER, &IID_IltmmConvert, (void**) &pConvert);
   if(FAILED(hr))
      goto error;
   
   // create the target object
   hr = CoCreateInstance(&CLSID_ltmmSampleTarget, NULL, CLSCTX_INPROC_SERVER, &IID_IltmmSampleTarget, (void**) &pSampleTarget);
   if(FAILED(hr))
      goto error;
   
   // create the media type object
   hr = CoCreateInstance(&CLSID_ltmmMediaType, NULL, CLSCTX_INPROC_SERVER, &IID_IltmmMediaTypeDisp, (void**) &pMediaType);
   if(FAILED(hr))
      goto error;
   
   // set type to MEDIATYPE_Video
   bstr = SysAllocString(L"{73646976-0000-0010-8000-00AA00389B71}");
   hr = IltmmMediaTypeDisp_put_Type (pMediaType, bstr);
   SysFreeString(bstr);
   if(FAILED(hr))
      goto error;
   
   // set subtype to MEDIASUBTYPE_RGB24
   bstr = SysAllocString(L"{e436eb7d-524f-11ce-9f53-0020af0ba770}");
   hr = IltmmMediaTypeDisp_put_Subtype (pMediaType, bstr);
   SysFreeString(bstr);
   if(FAILED(hr))
      goto error;
   
   
   //   set the accepted media type
   hr = IltmmSampleTarget_SetAcceptedMediaType (pSampleTarget, pMediaType);
   if(FAILED(hr))
      goto error;
   
   IUnknown_Release(pMediaType);
   pMediaType = NULL;

#ifdef _DEBUG
   // get it back for debugging
   hr = IltmmSampleTarget_GetAcceptedMediaType (pSampleTarget, &pMediaType);
   if(FAILED(hr))
      goto error;
   
   IUnknown_Release(pMediaType);
   pMediaType = NULL;
#endif

   //   set the convert input file name
   bstr = SysAllocString(pszAviFile);
   hr = IltmmConvert_put_SourceFile (pConvert, bstr);
   SysFreeString(bstr);
   if(FAILED(hr))
      goto error;

   //   set the convert object target
   hr = IltmmConvert_put_TargetObject (pConvert, (IUnknown*) pSampleTarget);
   if(FAILED(hr))
      goto error;
   
   // start the conversion
   hr = IltmmConvert_StartConvert(pConvert);
   if(FAILED(hr))
      goto error;

   // get the connected media type
   hr = IltmmSampleTarget_GetConnectedMediaType (pSampleTarget, &pMediaType);
   if(FAILED(hr))
      goto error;

   // get the VIDEOINFOHEADER
   hr = IltmmMediaTypeDisp_get_Format (pMediaType, &varFormat);
   if(FAILED(hr))
      goto error;

   hr = SafeArrayAccessData(V_ARRAY(&varFormat), (void**) &pVIH);
   if(FAILED(hr))
   {
      VariantClear(&varFormat);
      goto error;
   }

   for(n = 0; n < nMaxFrames; n++)
   {
      // fetch a sample
      hr = IltmmSampleTarget_GetSample (pSampleTarget, 1000, &pMediaSample);
      if(FAILED(hr) || !pMediaSample)
         break;
      // access the image bits
      hr = IltmmMediaSampleDisp_get_Buffer (pMediaSample, &varBuffer);
      if(FAILED(hr))
      {
         IUnknown_Release(pMediaSample);
         goto converterror;
      }
      hr = SafeArrayAccessData(V_ARRAY(&varBuffer), &pBuffer);
      if(FAILED(hr))
      {
         VariantClear(&varBuffer);
         IUnknown_Release(pMediaSample);
         goto converterror;
      }
      // save the image
      swprintf(szFile, L"%ssplit%u.bmp", pszOutputDir, n + 1);
      if(!SaveBMP24(szFile, &pVIH->bmiHeader, pBuffer))
      {
         SafeArrayUnaccessData(V_ARRAY(&varBuffer));
         VariantClear(&varBuffer);
         IUnknown_Release(pMediaSample);
         hr = E_FAIL;
         goto error;
      }
      SafeArrayUnaccessData(V_ARRAY(&varBuffer));
      VariantClear(&varBuffer);
      IUnknown_Release(pMediaSample);
   }

   // stop
   hr = IltmmConvert_StopConvert (pConvert);
   if(FAILED(hr))
      goto converterror;
   
   // cleanup and exit
   hr = S_OK;
converterror:
   SafeArrayUnaccessData(V_ARRAY(&varFormat));
   VariantClear(&varFormat);
error:
   
   if(pConvert)
      IUnknown_Release(pConvert);
   if(pSampleTarget)
      IUnknown_Release(pSampleTarget);
   if(pMediaType)
      IUnknown_Release(pMediaType);
   CoUninitialize();
   
   return hr;
}

int main(int argc, char* argv[])
{
   SplitAvi(L"c:\\count.avi", L"c:\\", 10);
   return 0;
}