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 Collections
Raster .NET | C API | C++ Class Library | HTML5 JavaScript
Document .NET | C API | C++ Class Library | HTML5 JavaScript
Medical .NET | C API | C++ Class Library | HTML5 JavaScript
Medical Web Viewer .NET
Multimedia
Direct Show .NET | C API | Filters
Media Foundation .NET | C API | Transforms
Supported Platforms
.NET, Java, Android, and iOS/macOS Assemblies
Imaging, Medical, and Document
C API/C++ Class Libraries
Imaging, Medical, and Document
HTML5 JavaScript Libraries
Imaging, Medical, and Document
Your email has been sent to support! Someone should be in touch! If your matter is urgent please come back into chat.
Chat Hours:
Monday - Friday, 8:30am to 6pm ET
Thank you for your feedback!
Please fill out the form again to start a new chat.
All agents are currently offline.
Chat Hours:
Monday - Friday
8:30AM - 6PM EST
To contact us please fill out this form and we will contact you via email.