LEADTOOLS Multimedia API Help > Programming with LEADTOOLS Multimedia > C++ Code > 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.
#define MAKE_MEDIA_PATH(pFileName) (TEXT("C:\\LEADTOOLS 18\\Media\\")TEXT(pFileName)) // 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; }