Using Memory Conversions for C
The following code demonstrates how to implement memory conversions:
// define helper macros for using interfaces under C
#define COBJMACROS
// include the LEAD Multimedia TOOLKIT header
#include "ltmm.h"
#include "resource.h"
#include <tchar.h>
#include <stdio.h>
#include <assert.h>
HINSTANCE g_hInstance; // application instance handle
IltmmConvert* g_pConvert; // convert object's interface pointer
// user defined message id used for conversion events
#define WM_CONVERTNOTIFY (WM_USER + 1000)
//
// ConvertDlgProc
// starts the conversion process and provides status feedback
//
// controls:
// IDC_CONVERTSTATUS - static control used for status messages
// IDC_CONVERTPROGRESS - static control used for conversion progress
// IDC_USERABORT - button control used to abort the conversion or exit the dialog
BOOL CALLBACK ConvertDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
TCHAR sz[256];
BSTR bstr1;
BSTR bstr2;
HRESULT hr;
long state;
long type;
switch (msg)
{
case WM_INITDIALOG:
// assign the notification window
IltmmConvert_SetNotifyWindow (g_pConvert, (long) hwnd, WM_CONVERTNOTIFY);
// set the abort button text
SetDlgItemText(hwnd, IDC_USERABORT, _T("Abort"));
// start the conversion
hr = IltmmConvert_StartConvert(g_pConvert);
if(FAILED(hr))
{
_stprintf(sz, _T("conversion error 0x%.8X"), lParam);
SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz);
UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS));
SetDlgItemText(hwnd, IDC_USERABORT, _T("Exit"));
MessageBeep(0);
}
return TRUE;
break;
case WM_DESTROY:
// reset the notification window
IltmmConvert_SetNotifyWindow (g_pConvert, (long) NULL, 0);
#ifdef _DEBUG
{
long state, err, pc;
TCHAR sz[1024];
// get the current state
IltmmConvert_get_State (g_pConvert, &state);
// get the current state
IltmmConvert_get_ConvertError (g_pConvert, &err);
// get the amount converted
IltmmConvert_get_PercentComplete (g_pConvert, &pc);
_stprintf(sz, _T("state = %d, error = 0x%.8X, complete = %d%%"), state, err, pc);
MessageBox(NULL, sz, _T("debug"), MB_OK);
}
#endif
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_USERABORT:
// user abort... stop conversion
IltmmConvert_get_State (g_pConvert, &state);
if(state == ltmmConvert_State_Running)
IltmmConvert_StopConvert(g_pConvert);
else
{
IltmmConvert_get_ConvertError (g_pConvert, (long*) &hr);
EndDialog(hwnd, (long) hr);
}
return TRUE;
break;
}
break;
case WM_CONVERTNOTIFY:
switch(wParam)
{
case ltmmConvert_Notify_Started:
// indicate conversion has started
IltmmConvert_get_SourceType (g_pConvert, &type);
switch(type)
{
case ltmmConvert_Source_File:
IltmmConvert_get_SourceFile (g_pConvert, &bstr1);
break;
case ltmmConvert_Source_HGlobal:
bstr1 = SysAllocString(L"[hglobal]");
break;
case ltmmConvert_Source_Array:
bstr1 = SysAllocString(L"[array]");
break;
case ltmmConvert_Source_Object:
bstr1 = SysAllocString(L"[object]");
break;
}
IltmmConvert_get_TargetType (g_pConvert, &type);
switch(type)
{
case ltmmConvert_Target_File:
IltmmConvert_get_TargetFile (g_pConvert, &bstr2);
break;
case ltmmConvert_Target_Array:
bstr2 = SysAllocString(L"[array]");
break;
case ltmmConvert_Target_Object:
bstr2 = SysAllocString(L"[object]");
break;
}
_stprintf(sz, _T("recompressing '%ls' to '%ls'..."), bstr1, bstr2);
SysFreeString(bstr1);
SysFreeString(bstr2);
SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz);
UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS));
break;
case ltmmConvert_Notify_Complete:
// indicate an conversion complete
_stprintf(sz, _T("conversion complete"));
SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz);
UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS));
SetDlgItemText(hwnd, IDC_USERABORT, _T("Exit"));
break;
case ltmmConvert_Notify_ErrorAbort:
// indicate an error
_stprintf(sz, _T("conversion error 0x%.8X"), lParam);
SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz);
UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS));
SetDlgItemText(hwnd, IDC_USERABORT, _T("Exit"));
MessageBeep(0);
break;
case ltmmConvert_Notify_UserAbort:
// indicate user abort
_stprintf(sz, _T("conversion aborted\n"));
SetDlgItemText(hwnd, IDC_CONVERTSTATUS, sz);
UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTSTATUS));
SetDlgItemText(hwnd, IDC_USERABORT, _T("Exit"));
MessageBeep(0);
break;
case ltmmConvert_Notify_Progress:
// indicate conversion progress
_stprintf(sz, _T("%3d%% complete"), lParam);
SetDlgItemText(hwnd, IDC_CONVERTPROGRESS, sz);
UpdateWindow(GetDlgItem(hwnd, IDC_CONVERTPROGRESS));
break;
}
return TRUE;
break;
}
return FALSE;
}
//
// SetAVIRecompression
// sets up LEAD video compression, MP3 audio compression, and AVI file output
//
// hwndParent = parent window for compressor property dialog boxes
//
HRESULT SetAVIRecompression(HWND hwndParent)
{
IltmmCompressors* pCompressors;
long index;
VARIANT_BOOL f;
BSTR bstr;
// select the LEAD video compressor
IltmmConvert_get_VideoCompressors (g_pConvert, &pCompressors);
bstr = SysAllocString(L"@device:sw:{33D9A760-90C8-11D0-BD43-00A0C911CE86}\LEAD
MCMP/MJPEG Codec A COmpressor combined with a DECompressor, or encoder and a decoder, which allows you to both compress and decompress that same data.COmpressor Also known as an encoder, this is a module or algorithm to compress data. Playing that data back requires a decompressor, or decoder. combined with a DECompressor, or encoder Also known as compressor, this is a module or algorithm to compress data. Playing that data back requires a decompressor, or decoder. and a decoder Also known as a decompressor, this is a module or algorithm to decompress data., which allows you to both compress and decompress that same data. (2.0)");
IltmmCompressors_Find(pCompressors, bstr, &index);
SysFreeString(bstr);
if(index < 0)
{
// compressor isn't registered
IUnknown_Release(pCompressors);
return E_FAIL;
}
IltmmCompressors_put_Selection (pCompressors, index);
IUnknown_Release(pCompressors);
// select the MP3 audio video compressor
IltmmConvert_get_AudioCompressors (g_pConvert, &pCompressors);
bstr = SysAllocString(L"@device:cm:{33D9A761-90C8-11D0-BD43-00A0C911CE86}\\85MPEG Layer-3");
IltmmCompressors_Find(pCompressors, bstr, &index);
SysFreeString(bstr);
if(index < 0)
{
// compressor isn't registered
IUnknown_Release(pCompressors);
return E_FAIL;
}
IltmmCompressors_put_Selection (pCompressors, index);
IUnknown_Release(pCompressors);
// set output format to AVI
IltmmConvert_put_TargetFormat (g_pConvert, ltmmConvert_TargetFormat_Avi);
#ifdef _DEBUG
{
long v;
IltmmConvert_get_TargetFormat(g_pConvert, &v);
assert(v == ltmmConvert_TargetFormat_Avi);
}
#endif
// set video compressor properties
IltmmConvert_HasDialog (g_pConvert, ltmmConvert_Dlg_VideoCompressor, &f);
if(f)
IltmmConvert_ShowDialog (g_pConvert, ltmmConvert_Dlg_VideoCompressor, (long) hwndParent);
// set audio compressor properties
IltmmConvert_HasDialog (g_pConvert, ltmmConvert_Dlg_AudioCompressor, &f);
if(f)
IltmmConvert_ShowDialog (g_pConvert, ltmmConvert_Dlg_AudioCompressor, (long) hwndParent);
return S_OK;
}
//
// RecompressArray
// recompresses array to array using the LEAD video and MP3 audio compressors
//
// 1. the source file is preloaded into a source array
// 2. the source array is recompressed to a target array
// 3. the target array is written to the target file
//
// pszSource = source file path
// pszTarget = target file path
//
HRESULT RecompressArray(LPCTSTR pszSource, LPCTSTR pszTarget)
{
HRESULT hr;
HANDLE hfile;
DWORD size, cb;
void* buffer;
VARIANT var;
SAFEARRAY* psaSource;
SAFEARRAY* psaTarget;
// open the source file
hfile = CreateFile(pszSource, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(hfile == INVALID_HANDLE_VALUE)
return E_FAIL;
// allocate same-sized SAFEARRAY
size = GetFileSize(hfile, NULL);
psaSource = SafeArrayCreateVector(VT_UI1, 0, size);
if(!psaSource)
{
CloseHandle(hfile);
return E_OUTOFMEMORY;
}
// read entire source into array
SafeArrayAccessData(psaSource, (void**) &buffer);
if(!ReadFile(hfile, buffer, size, &cb, NULL) || cb != size)
{
SafeArrayUnaccessData(psaSource);
CloseHandle(hfile);
SafeArrayDestroy(psaSource);
return E_FAIL;
}
SafeArrayUnaccessData(psaSource);
// close file
CloseHandle(hfile);
// assign the source array
VariantInit(&var);
V_VT(&var) = (VT_ARRAY | VT_UI1);
V_ARRAY(&var) = psaSource;
hr = IltmmConvert_put_SourceArray (g_pConvert, var);
if(FAILED(hr))
{
SafeArrayDestroy(psaSource);
return hr;
}
#ifdef _DEBUG
{
VARIANT var;
VariantInit(&var);
IltmmConvert_get_SourceArray(g_pConvert, &var);
assert(var.vt == (VT_ARRAY | VT_UI1));
}
#endif
// create the target array
psaTarget = SafeArrayCreateVector(VT_UI1, 0, 0);
if(!psaTarget)
{
IltmmConvert_ResetSource (g_pConvert);
SafeArrayDestroy(psaSource);
return E_OUTOFMEMORY;
}
// assign the target array
VariantInit(&var);
V_VT(&var) = (VT_ARRAY | VT_UI1);
V_ARRAY(&var) = psaTarget;
hr = IltmmConvert_put_TargetArray (g_pConvert, var);
if(FAILED(hr))
{
IltmmConvert_ResetSource (g_pConvert);
SafeArrayDestroy(psaSource);
SafeArrayDestroy(psaTarget);
return hr;
}
#ifdef _DEBUG
{
VARIANT var;
VariantInit(&var);
IltmmConvert_get_TargetArray(g_pConvert, &var);
assert(var.vt == (VT_ARRAY | VT_UI1));
}
#endif
// setup AVI recompression
hr = SetAVIRecompression(NULL);
if(FAILED(hr))
{
IltmmConvert_ResetTarget (g_pConvert);
IltmmConvert_ResetSource (g_pConvert);
SafeArrayDestroy(psaSource);
SafeArrayDestroy(psaTarget);
return hr;
}
// do conversion
hr = (HRESULT) DialogBox(g_hInstance, (LPCTSTR)IDD_CONVERTDLG, NULL, ConvertDlgProc);
// kill the convert objects interest in the arrays
IltmmConvert_ResetTarget (g_pConvert);
IltmmConvert_ResetSource (g_pConvert);
// don't need the source anymore
SafeArrayDestroy(psaSource);
// return if the conversion failed
if(FAILED(hr))
{
SafeArrayDestroy(psaTarget);
return hr;
}
// write the output to file
hfile = CreateFile(pszTarget, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if(hfile == INVALID_HANDLE_VALUE)
{
SafeArrayDestroy(psaTarget);
return E_FAIL;
}
SafeArrayAccessData(psaTarget, (void**) &buffer);
if(!WriteFile(hfile, buffer, psaTarget->rgsabound[0].cElements, &cb, NULL) || cb != psaTarget->rgsabound[0].cElements)
{
SafeArrayUnaccessData(psaTarget);
CloseHandle(hfile);
SafeArrayDestroy(psaTarget);
return E_FAIL;
}
SafeArrayUnaccessData(psaTarget);
CloseHandle(hfile);
SafeArrayDestroy(psaTarget);
return hr;
}
//
// RecompressHGlobal
// recompresses from global memory to a file using the LEAD video and MP3 audio compressors
//
// 1. the source file is preloaded into global memory
// 2. the source memory is recompressed to the target file
//
// pszSource = source file path
// pszTarget = target file path
//
HRESULT RecompressHGlobal(LPCTSTR pszSource, LPCTSTR pszTarget)
{
HRESULT hr;
HANDLE hfile;
BSTR bstr;
DWORD size, cb;
void* buffer;
HGLOBAL hglobal;
#ifndef _UNICODE
WCHAR wsz[MAX_PATH];
#endif
// open the source file
hfile = CreateFile(pszSource, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(hfile == INVALID_HANDLE_VALUE)
return E_FAIL;
// allocate same-sized buffer
size = GetFileSize(hfile, NULL);
hglobal = GlobalAlloc(GMEM_MOVEABLE, size);
if(!hglobal)
{
CloseHandle(hfile);
return E_OUTOFMEMORY;
}
// read entire source into buffer
buffer = GlobalLock(hglobal);
if(!ReadFile(hfile, buffer, size, &cb, NULL) || cb != size)
{
GlobalUnlock(hglobal);
CloseHandle(hfile);
GlobalFree(hglobal);
return E_FAIL;
}
GlobalUnlock(hglobal);
// close file
CloseHandle(hfile);
// assign the source buffer
hr = IltmmConvert_put_SourceHGlobal(g_pConvert, (long) hglobal);
if(FAILED(hr))
{
GlobalFree(hglobal);
return hr;
}
#ifdef _DEBUG
{
HGLOBAL hGlobal;
IltmmConvert_get_SourceHGlobal(g_pConvert, (long*) &hGlobal);
assert(hGlobal != NULL);
}
#endif
// set target file
#ifdef _UNICODE
bstr = SysAllocString(pszTarget);
#else
swprintf(wsz, L"%hs", pszTarget);
bstr = SysAllocString(wsz);
#endif
hr = IltmmConvert_put_TargetFile (g_pConvert, bstr);
SysFreeString(bstr);
if(FAILED(hr))
{
IltmmConvert_ResetSource (g_pConvert);
GlobalFree(hglobal);
return hr;
}
// setup AVI recompression
hr = SetAVIRecompression(NULL);
if(FAILED(hr))
{
IltmmConvert_ResetSource (g_pConvert);
GlobalFree(hglobal);
return hr;
}
// do conversion
hr = (HRESULT) DialogBox(g_hInstance, (LPCTSTR)IDD_CONVERTDLG, NULL, ConvertDlgProc);
IltmmConvert_ResetSource (g_pConvert);
GlobalFree(hglobal);
return hr;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HRESULT hr;
g_hInstance = hInstance;
// 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**) &g_pConvert);
if(FAILED(hr))
goto error;
hr = RecompressArray(_T("c:\\source.avi"), _T("c:\\target1.avi"));
if(FAILED(hr))
goto error;
hr = RecompressHGlobal(_T("c:\\source.avi"), _T("c:\\target2.avi"));
if(FAILED(hr))
goto error;
error:
// cleanup
if(g_pConvert)
IUnknown_Release(g_pConvert);
CoUninitialize();
return 0;
}