The following code utilizes ltmmSampleSource and ltmmConvert to generate an AVI file from generated 24-bit device independent bitmaps.
#define MAKE_MEDIA_PATH(pFileName) (TEXT("C:\\LEADTOOLS 17.5\\Media\\")TEXT(pFileName)) // define helper macros for using interfaces under C #ifndef COBJMACROS #define COBJMACROS #endif // 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 <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 CreateCountingAviExample (LPCWSTR 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 = 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 format to FORMAT_VideoInfo bstr = SysAllocString(L"{05589f80-c356-11ce-bf01-00aa0055595a}"); hr = IltmmMediaTypeDisp_put_FormatType (pMediaType, 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 = IltmmMediaTypeDisp_SetFormatData (pMediaType, sizeof(vih), var); if(FAILED(hr)) goto error; // fixed image size samples hr = IltmmMediaTypeDisp_put_FixedSizeSamples(pMediaType, VARIANT_TRUE); if(FAILED(hr)) goto error; hr = IltmmMediaTypeDisp_put_SampleSize (pMediaType, vih.bmiHeader.biSizeImage); if(FAILED(hr)) goto error; // set the source media type hr = IltmmSampleSource_SetMediaType (pSampleSource, pMediaType); if(FAILED(hr)) goto error; // set the convert object source hr = IltmmConvert_put_SourceObject (pConvert, (IUnknown*) pSampleSource); if(FAILED(hr)) goto error; #ifdef _DEBUG { IUnknown* punk; IltmmConvert_get_SourceObject(pConvert, &punk); assert(punk != NULL); if(punk) IUnknown_Release(punk); } #endif // set the convert output file name bstr = SysAllocString(pszAviFile); hr = IltmmConvert_put_TargetFile (pConvert, 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 = IltmmConvert_StartConvert(pConvert); 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 = IltmmSampleSource_GetSampleBuffer (pSampleSource, 1000, &pMediaSample); if(FAILED(hr)) goto converterror; // set the time in 100 nanoseconds (based on frame rate) stoptime.QuadPart = starttime.QuadPart + vih.AvgTimePerFrame; hr = IltmmMediaSampleDisp_SetTime (pMediaSample, starttime.HighPart, starttime.LowPart, stoptime.HighPart, stoptime.LowPart); if(FAILED(hr)) { IUnknown_Release(pMediaSample); goto converterror; } // media time is equal to the frame number mstoptime.QuadPart = mstarttime.QuadPart + 1; hr = IltmmMediaSampleDisp_SetMediaTime (pMediaSample, mstarttime.HighPart, mstarttime.LowPart, mstoptime.HighPart, mstoptime.LowPart); if(FAILED(hr)) { IUnknown_Release(pMediaSample); goto converterror; } // this is a sync point hr = IltmmMediaSampleDisp_put_SyncPoint (pMediaSample, VARIANT_TRUE); if(FAILED(hr)) { IUnknown_Release(pMediaSample); goto converterror; } // set the sample data hr = IltmmMediaSampleDisp_SetData (pMediaSample, vih.bmiHeader.biSizeImage, var); if(FAILED(hr)) { IUnknown_Release(pMediaSample); goto converterror; } // send the sample downstream hr = IltmmSampleSource_DeliverSample (pSampleSource, 1000, pMediaSample); if(FAILED(hr)) { IUnknown_Release(pMediaSample); goto converterror; } // adjust the next time values starttime = stoptime; mstarttime = mstoptime; // release the sample buffer IUnknown_Release(pMediaSample); } // all done, inform the downstream filters hr = IltmmSampleSource_DeliverEndOfStream (pSampleSource, 1000); if(FAILED(hr)) goto converterror; // stop hr = IltmmConvert_StopConvert(pConvert); 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) IUnknown_Release(pConvert); if(pSampleSource) IUnknown_Release(pSampleSource); if(pMediaType) IUnknown_Release(pMediaType); CoUninitialize(); return hr; } int main() { CreateCountingAviExample(MAKE_MEDIA_PATH("count.avi"), 10); return 0; }