Creating an AVI File from Bitmaps Using ltmmSampleSource for C++

The following code utilizes ltmmSampleSource and ltmmConvert to generate an AVI file from generated 24-bit device independent bitmaps.

// include the LEAD Multimedia TOOLKIT header 
#include "ltmm.h" 
 
// include amvideo.h for VIDEOINFOHEADER, available in Visual Studio or DirectX SDK 
#include <amvideo.h> 
 
// includes for string handling 
#include <tchar.h> 
#include <string.h> 
#include <stdio.h> 
#include <assert.h> 
 
///////////////////////////////////////////////////////////////// 
// CreateCountingAvi 
// create an AVI file composed of frames of counting numbers 
// pszAviFile - output file name 
// nFrames - number of frames to generate 
// 
HRESULT CreateCountingAvi(LPWSTR pszAviFile, int nFrames) 
{ 
   HRESULT hr; 
   IltmmConvert* pConvert = NULL; 
   IltmmSampleSource* pSampleSource = NULL; 
   IltmmMediaTypeDisp* pMediaType = NULL; 
   IltmmMediaSampleDisp* pMediaSample; 
   BSTR bstr; 
   VIDEOINFOHEADER vih; 
   SAFEARRAY sa; 
   VARIANT var; 
   int n; 
   HBITMAP hbmFrame; 
   HBITMAP hbmSave; 
   HDC hDC; 
   RECT rc; 
   TCHAR sz[16]; 
   LARGE_INTEGER starttime; 
   LARGE_INTEGER stoptime; 
   LARGE_INTEGER mstarttime; 
   LARGE_INTEGER mstoptime; 
   LOGFONT logfont; 
   HFONT hfntSave; 
   HFONT hfntFrame; 
   int len; 
   SIZE size; 
 
   // 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 source object 
   hr = CoCreateInstance(CLSID_ltmmSampleSource, NULL, CLSCTX_INPROC_SERVER, IID_IltmmSampleSource, (void**) &pSampleSource); 
   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 = pMediaType->put_Type(bstr); 
   SysFreeString(bstr); 
   if(FAILED(hr)) 
      goto error; 
 
   // set subtype to MEDIASUBTYPE_RGB24 
   bstr = SysAllocString(L"{e436eb7d-524f-11ce-9f53-0020af0ba770}"); 
   hr = pMediaType->put_Subtype(bstr); 
   SysFreeString(bstr); 
   if(FAILED(hr)) 
      goto error; 
 
   // set format to FORMAT_VideoInfo 
   bstr = SysAllocString(L"{05589f80-c356-11ce-bf01-00aa0055595a}"); 
   hr = pMediaType->put_FormatType(bstr); 
   SysFreeString(bstr); 
   if(FAILED(hr)) 
      goto error; 
 
   // set VIDEOINFOHEADER to 320x240 24-bit RGB image at 15 frames per second 
   memset(&vih, 0, sizeof(vih)); 
   vih.bmiHeader.biCompression = BI_RGB; 
   vih.bmiHeader.biBitCount = 24; 
   vih.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
   vih.bmiHeader.biWidth = 320; 
   vih.bmiHeader.biHeight = 240; 
   vih.bmiHeader.biPlanes = 1; 
   vih.bmiHeader.biSizeImage = (((vih.bmiHeader.biWidth * 3) + 3) & ~3) * vih.bmiHeader.biHeight; 
   vih.bmiHeader.biClrImportant = 0; 
   vih.AvgTimePerFrame = ((__int64) 10000000 / 15); 
   vih.dwBitRate = vih.bmiHeader.biSizeImage * 8 * 15; 
 
   // pass VIDEOINFOHEADER to ltmmMediaType via SAFEARRAY 
   memset(&sa, 0, sizeof(sa)); 
   sa.cbElements = sizeof(unsigned char); 
   sa.cDims = 1; 
   sa.fFeatures = (FADF_AUTO | FADF_FIXEDSIZE); 
   sa.pvData = &vih; 
   sa.rgsabound[0].cElements = sizeof(vih); 
   VariantInit(&var); 
   V_VT(&var) = (VT_ARRAY | VT_UI1); 
   V_ARRAY(&var) = &sa; 
 
   hr = pMediaType->SetFormatData(sizeof(vih), var); 
   if(FAILED(hr)) 
      goto error; 
 
   // fixed image size samples 
   hr = pMediaType->put_FixedSizeSamples(VARIANT_TRUE); 
   if(FAILED(hr)) 
      goto error; 
 
   hr = pMediaType->put_SampleSize(vih.bmiHeader.biSizeImage); 
   if(FAILED(hr)) 
      goto error; 
 
   //   set the source media type 
   hr = pSampleSource->SetMediaType(pMediaType); 
   if(FAILED(hr)) 
      goto error; 
 
   //   set the convert object source 
   hr = pConvert->put_SourceObject(pSampleSource); 
   if(FAILED(hr)) 
      goto error; 
#ifdef _DEBUG 
   { 
      IUnknown* punk; 
      pConvert->get_SourceObject(&punk); 
      assert(punk != NULL); 
      if(punk) 
         punk->Release(); 
   } 
#endif 
   // set the convert output file name 
   bstr = ::SysAllocString(pszAviFile); 
   hr = pConvert->put_TargetFile(bstr); 
   SysFreeString(bstr); 
   if(FAILED(hr)) 
      goto error; 
 
   //   need a dc to draw to    
   hDC = CreateCompatibleDC(NULL); 
   if(!hDC) 
   { 
      hr = E_OUTOFMEMORY; 
      goto error; 
   } 
 
   //   create a SAFEARRAY that points to a DIB sections bits 
   memset(&sa, 0, sizeof(sa)); 
   sa.cbElements = sizeof(unsigned char); 
   sa.cDims = 1; 
   sa.fFeatures = (FADF_AUTO | FADF_FIXEDSIZE); 
   sa.pvData = &vih; 
   sa.rgsabound[0].cElements = vih.bmiHeader.biSizeImage; 
   V_VT(&var) = (VT_ARRAY | VT_UI1); 
   V_ARRAY(&var) = &sa; 
 
   hbmFrame = CreateDIBSection(NULL, (BITMAPINFO*) &vih.bmiHeader, DIB_RGB_COLORS, &sa.pvData, NULL, 0); 
   if(!hbmFrame) 
   { 
      DeleteDC(hDC); 
      hr = E_OUTOFMEMORY; 
      goto error; 
   } 
 
   //   create a font big enough to fit the height of each frame 
   memset(&logfont, 0, sizeof(logfont)); 
   _tcscpy(logfont.lfFaceName, _T("Arial")); 
   logfont.lfHeight = vih.bmiHeader.biHeight; 
   hfntFrame = CreateFontIndirect(&logfont); 
   if(!hfntFrame) 
   { 
      DeleteDC(hDC); 
      DeleteObject(hbmFrame); 
      hr = E_OUTOFMEMORY; 
      goto error; 
   } 
 
   //   select the font and the bitmap into the device context 
   hbmSave = (HBITMAP) SelectObject(hDC, hbmFrame); 
   hfntSave = (HFONT) SelectObject(hDC, hfntFrame); 
 
   // need a rect for the ExtTextOut 
   SetRect(&rc, 0, 0, vih.bmiHeader.biWidth, vih.bmiHeader.biHeight); 
 
   // start the conversion 
   hr = pConvert->StartConvert(); 
   if(FAILED(hr)) 
      goto converterror; 
 
   starttime.QuadPart = 0; 
   mstarttime.QuadPart = 0; 
   for(n = 0; n < nFrames; n++) 
   { 
      // convert the frame number to text and draw it to the bitmap 
      len = _stprintf(sz, _T("%u"), n + 1); 
      GetTextExtentPoint32(hDC, sz, len, &size); 
      ExtTextOut(hDC, (rc.right - rc.left - size.cx) / 2, (rc.bottom - rc.top - size.cy) / 2, ETO_CLIPPED | ETO_OPAQUE, &rc, sz, len, NULL); 
      GdiFlush(); 
 
      // get a free sample buffer 
      hr = pSampleSource->GetSampleBuffer(1000, &pMediaSample); 
      if(FAILED(hr)) 
         goto converterror; 
 
      // set the time in 100 nanoseconds (based on frame rate) 
      stoptime.QuadPart = starttime.QuadPart + vih.AvgTimePerFrame; 
      hr = pMediaSample->SetTime(starttime.HighPart, starttime.LowPart, stoptime.HighPart, stoptime.LowPart); 
      if(FAILED(hr)) 
      { 
         pMediaSample->Release(); 
         goto converterror; 
      } 
 
      // media time is equal to the frame number 
      mstoptime.QuadPart = mstarttime.QuadPart + 1; 
      hr = pMediaSample->SetMediaTime(mstarttime.HighPart, mstarttime.LowPart, mstoptime.HighPart, mstoptime.LowPart); 
      if(FAILED(hr)) 
      { 
         pMediaSample->Release(); 
         goto converterror; 
      } 
 
      // this is a sync point 
      hr = pMediaSample->put_SyncPoint(VARIANT_TRUE); 
      if(FAILED(hr)) 
      { 
         pMediaSample->Release(); 
         goto converterror; 
      } 
 
      // set the sample data 
      hr = pMediaSample->SetData(vih.bmiHeader.biSizeImage, var); 
      if(FAILED(hr)) 
      { 
         pMediaSample->Release(); 
         goto converterror; 
      } 
 
      // send the sample downstream 
      hr = pSampleSource->DeliverSample(1000, pMediaSample); 
      if(FAILED(hr)) 
      { 
         pMediaSample->Release(); 
         goto converterror; 
      } 
      // adjust the next time values 
      starttime = stoptime; 
      mstarttime = mstoptime; 
 
      // release the sample buffer 
      pMediaSample->Release(); 
   } 
 
   // all done, inform the downstream filters 
   hr = pSampleSource->DeliverEndOfStream(1000); 
   if(FAILED(hr)) 
      goto converterror; 
 
   // stop 
   hr = pConvert->StopConvert(); 
   if(FAILED(hr)) 
      goto converterror; 
 
   // cleanup and exit 
   hr = S_OK; 
converterror: 
   SelectObject(hDC, hfntSave); 
   DeleteObject(hfntFrame); 
   SelectObject(hDC, hbmSave); 
   DeleteObject(hbmFrame); 
   DeleteDC(hDC); 
 
error: 
   if(pConvert) 
      pConvert->Release(); 
 
   if(pSampleSource) 
      pSampleSource->Release(); 
 
   if(pMediaType) 
      pMediaType->Release(); 
 
   CoUninitialize(); 
   return hr; 
} 
 
int main(int argc, char* argv[]) 
{ 
   CreateCountingAvi(MAKE_MEDIA_PATH("count.avi"), 10); 
   return 0; 
} 

Help Version 20.0.2020.4.2
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2020 LEAD Technologies, Inc. All Rights Reserved.

LEADTOOLS Multimedia C API Help