// Mpeg2Handler.cpp: implementation of the CMPEG2Handler class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MPEG2CaptureApp.h"
#include "MPEG2CaptureAppDlg.h"
#include "MPEG2Handler.h"
#include "DirectShowGraph.h"
#include "eVideoDecoder.h"
#include "MSFTAudioDecoder.h"
extern int use_vmr9;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CLSID clsidCat;
CMPEG2Handler::CMPEG2Handler(CMPEG2CaptureAppDlg *dlg)
{
dsGraph = new CDirectShowGraph(dlg);
graph_mode = STOP_MODE;
m_dlg = dlg;
/* Here we initialize the audio and video decoder */
/* You can create your own two classes to select your favorite MPEG decoders */
dsGraph->videoDecoder = new CeVideoDecoder(dsGraph);
dsGraph->audioDecoder = new CMSFTAudioDecoder(dsGraph);
}
CMPEG2Handler::~CMPEG2Handler()
{
if (graph_mode != STOP_MODE) {
Stop();
}
//FullScreeMode(0);
BSTR strCaption;
if (dsGraph && dsGraph->m_pVW && S_OK == dsGraph->m_pVW->get_Caption(&strCaption))
{
CString str = strCaption;
::SysFreeString( strCaption );
HWND h = ::FindWindow(NULL,str);
if (h)
::SendMessage(h , WM_CLOSE , 0 , 0);
}
if (dsGraph && dsGraph->m_pME)
dsGraph->m_pME->SetNotifyWindow((OAHWND)NULL, 0, 0);
// Hide video window and remove owner. This is not necessary here,
// since we are about to destroy the filter graph, but it is included
// for demonstration purposes. Remember to hide the video window and
// clear its owner when destroying a window that plays video.
if(dsGraph && dsGraph->m_pVW) {
dsGraph->m_pVW->NotifyOwnerMessage((LONG_PTR) m_dlg->GetSafeHwnd(), WM_CLOSE, 0, 0);
dsGraph->m_pVW->put_Visible(OAFALSE);
}
if (dsGraph)
{
dsGraph->FreeAllResources();
delete dsGraph;
}
dsGraph = NULL;
}
HRESULT CMPEG2Handler::Record(char *FileName)
{
HRESULT hr ;
hr = dsGraph->MakeGraph();
if (hr != 1)
throw (0);
hr = dsGraph->AddCaptureDevice();
if (hr != S_OK)
throw (0);
hr = dsGraph->AddMpeg2Demultiplex(1); /* 1 means record on. */
if (hr != S_OK)
throw (0);
hr = dsGraph->GetVideoDecoder()->AddVideoDecoder();
if (hr != S_OK)
throw (0);
hr = dsGraph->GetAudioDecoder()->AddAudioDecoder();
if (hr != S_OK)
throw (0);
hr = dsGraph->AddDumpFilter();
if (hr != S_OK)
throw (0);
wchar_t wcstr[400];
mbstowcs(wcstr, FileName, 400);
hr = dsGraph->pFileSourceInterface->SetFileName(wcstr , NULL);
if (hr != S_OK)
throw (0);
char temp[100];
sprintf (temp , "Output%d" , 2) ;
dsGraph->pInfeeFilterOutPin[1] = dsGraph->GET_PIN(dsGraph->pInfeeFilter ,
temp ,
PINDIR_OUTPUT);
hr = dsGraph->m_pGraph->Connect(dsGraph->pInfeeFilterOutPin[1] ,
dsGraph->pDumpInPin) ;
if (hr != S_OK)
throw (0);
VInPin = dsGraph->GetVideoDecoder()->GetVideoDecoderInPin();
/* now the connection */
hr = dsGraph->m_pGraph->Connect(dsGraph->pDemuxVideoOutPin ,
VInPin) ;
if (hr != S_OK)
throw (0);
VOutPin = dsGraph->GetVideoDecoder()->GetVideoDecoderOutPin();
switch (use_vmr9) {
case 0 :
hr = dsGraph->AddVideoRendererFilter();
if (hr != S_OK)
throw (0);
hr = dsGraph->m_pGraph->Connect(VOutPin ,
dsGraph->pRendererInPin) ;
if (hr != S_OK)
throw (0);
break;
case 1:
hr = dsGraph->InitializeWindowlessVMR9(pWindow);
if (hr != S_OK)
throw (0);
hr = dsGraph->pBuilder->Render(VOutPin);
if (hr != S_OK)
throw (0);
break;
case 2:
hr = dsGraph->InitializeWindowlessVMR(pWindow);
if (hr != S_OK)
throw (0);
hr = dsGraph->pBuilder->Render(VOutPin);
if (hr != S_OK)
throw (0);
break;
default:
{
hr = dsGraph->AddVideoRendererFilter();
if (hr != S_OK)
throw (0);
}
}
AInPin = dsGraph->GetAudioDecoder()->GetAudioDecoderInPin();
if (AInPin == NULL)
throw (0);
hr = dsGraph->m_pGraph->Connect(dsGraph->pDemuxAudioOutPin ,
AInPin) ;
if (hr != S_OK)
throw (0);
AOutPin = dsGraph->GetAudioDecoder()->GetAudioDecoderOutPin();
hr = dsGraph->pBuilder->Render(AOutPin);
if (hr != S_OK)
throw (0);
hr = dsGraph->pCaptureDevice->QueryInterface(IID_IAMVideoProcAmp, (void **)&dsGraph->pVideoAmp);
if (hr != S_OK)
throw (0);
hr = GetCrossbarInterface();
if (hr != S_OK)
throw (0);
hr = GetAnalogVideoInterface();
if (hr != S_OK)
throw (0);
return hr;
}
HRESULT CMPEG2Handler::Preview()
{
HRESULT hr ;
hr = dsGraph->MakeGraph();
if (hr != 1)
throw (0);
hr = dsGraph->AddCaptureDevice();
if (hr != S_OK)
throw (0);
hr = dsGraph->AddMpeg2Demultiplex();
if (hr != S_OK)
throw (0);
switch (use_vmr9) {
case 0 :
hr = dsGraph->AddVideoRendererFilter();
if (hr != S_OK)
throw (0);
break;
case 1:
hr = dsGraph->InitializeWindowlessVMR9(pWindow);
if (hr != S_OK)
throw (0);
break;
case 2:
hr = dsGraph->InitializeWindowlessVMR(pWindow);
if (hr != S_OK)
throw (0);
break;
default:
{
hr = dsGraph->AddVideoRendererFilter();
if (hr != S_OK)
throw (0);
}
}
hr = dsGraph->GetVideoDecoder()->AddVideoDecoder();
if (hr != S_OK)
throw (0);
hr = dsGraph->GetAudioDecoder()->AddAudioDecoder();
if (hr != S_OK)
throw (0);
VInPin = dsGraph->GetVideoDecoder()->GetVideoDecoderInPin();
hr = GetCrossbarInterface();
if (hr != S_OK)
throw (0);
hr = GetAnalogVideoInterface();
if (hr != S_OK)
throw (0);
/* now the connection */
hr = dsGraph->m_pGraph->Connect(dsGraph->pDemuxVideoOutPin ,
VInPin) ;
if (hr != S_OK)
throw (0);
VOutPin = dsGraph->GetVideoDecoder()->GetVideoDecoderOutPin();
hr = dsGraph->pBuilder->Render(VOutPin);
if (hr != S_OK)
throw (0);
AInPin = dsGraph->GetAudioDecoder()->GetAudioDecoderInPin();
hr = dsGraph->m_pGraph->Connect(dsGraph->pDemuxAudioOutPin ,
AInPin) ;
if (hr != S_OK)
throw (0);
AOutPin = dsGraph->GetAudioDecoder()->GetAudioDecoderOutPin();
hr = dsGraph->pBuilder->Render(AOutPin);
if (hr != S_OK)
throw (0);
hr = dsGraph->pCaptureDevice->QueryInterface(IID_IAMVideoProcAmp, (void **)&dsGraph->pVideoAmp);
if (hr != S_OK)
throw (0);
return hr;
}
HRESULT CMPEG2Handler::Run()
{
HRESULT hr ;
dsGraph->SetupWindow(pWindow);
if (dsGraph->pCaptureDevice) {
hr = dsGraph->pCaptureDevice->QueryInterface(IID_IAMVideoControl,
(void **)&dsGraph->pVideoControl);
if (hr != S_OK)
return hr;
}
hr = dsGraph->m_pMC->Run();
graph_mode = RUNNING_MODE;
return hr;
}
HRESULT CMPEG2Handler::Stop()
{
HRESULT hr ;
if (graph_mode == STOP_MODE)
return S_OK;
hr = dsGraph->m_pMC->Stop();
hr = dsGraph->m_pVW->put_Visible(OAFALSE);
graph_mode = STOP_MODE;
return hr;
}
HRESULT CMPEG2Handler::Play()
{
HRESULT hr = dsGraph->m_pMC->Run();
graph_mode = PAUSE_MODE;
return hr;
}
HRESULT CMPEG2Handler::Pause()
{
HRESULT hr = dsGraph->m_pMC->Pause();
graph_mode = PAUSE_MODE;
return hr;
}
BOOL CMPEG2Handler::IsRunning()
{
if (graph_mode == RUNNING_MODE)
return TRUE;
return FALSE;
}
BOOL CMPEG2Handler::IsPaused()
{
if (graph_mode == PAUSE_MODE)
return TRUE;
return FALSE;
}
BOOL CMPEG2Handler::IsStopped()
{
if (graph_mode == STOP_MODE)
return TRUE;
return FALSE;
}
HRESULT CMPEG2Handler::SetBrightness(int value)
{
HRESULT hr = dsGraph->pVideoAmp->Set(VideoProcAmp_Brightness,
value,
VideoProcAmp_Flags_Manual);
return hr;
}
HRESULT CMPEG2Handler::SetHue(int value)
{
HRESULT hr = dsGraph->pVideoAmp->Set(VideoProcAmp_Hue,
value,
VideoProcAmp_Flags_Manual );
return hr;
}
HRESULT CMPEG2Handler::SetChromeSaturation(int value)
{
HRESULT hr = dsGraph->pVideoAmp->Set(VideoProcAmp_Saturation,
value,
VideoProcAmp_Flags_Manual );
return hr;
}
HRESULT CMPEG2Handler::SetContrast(int value)
{
HRESULT hr = dsGraph->pVideoAmp->Set(VideoProcAmp_Contrast,
value,
VideoProcAmp_Flags_Manual );
return hr;
}
HRESULT CMPEG2Handler::GetCrossbarInterface()
{
HRESULT hr = S_OK;
USES_CONVERSION;
IEnumMoniker *pEmCat = 0;
ICreateDevEnum *pCreateDevEnum = NULL;
int nClasses=0;
// Create an enumerator
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
// Use the meta-category that contains a list of all categories.
// This emulates the behavior of GraphEdit.
hr = pCreateDevEnum->CreateClassEnumerator(
CLSID_ActiveMovieCategories, &pEmCat, 0);
ASSERT(SUCCEEDED(hr));
if(hr == S_OK)
{
IMoniker *pMCat;
ULONG cFetched;
// Enumerate over every category
while(hr = pEmCat->Next(1, &pMCat, &cFetched),
hr == S_OK)
{
IPropertyBag *pPropBag;
// Associate moniker with a file
hr = pMCat->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
if(SUCCEEDED(hr))
{
VARIANT varCatClsid;
varCatClsid.vt = VT_BSTR;
// Read CLSID string from property bag
hr = pPropBag->Read(L"CLSID", &varCatClsid, 0);
if(SUCCEEDED(hr))
{
if(CLSIDFromString(varCatClsid.bstrVal, &clsidCat) == S_OK)
{
// Use the guid if we can't get the name
WCHAR *wszCatName;
TCHAR szCatDesc[MAX_PATH];
VARIANT varCatName;
varCatName.vt = VT_BSTR;
// Read filter name
hr = pPropBag->Read(L"FriendlyName", &varCatName, 0);
if(SUCCEEDED(hr))
wszCatName = varCatName.bstrVal;
else
wszCatName = varCatClsid.bstrVal;
#ifndef UNICODE
WideCharToMultiByte(
CP_ACP, 0, wszCatName, -1,
szCatDesc, sizeof(szCatDesc), 0, 0);
#else
lstrcpy(szCatDesc, W2T(wszCatName));
#endif
if(SUCCEEDED(hr))
SysFreeString(varCatName.bstrVal);
// Add category name and CLSID to list box
//AddFilterCategory(szCatDesc, &clsidCat);
nClasses++;
if (strcmp(szCatDesc , "WDM Streaming Crossbar Devices") == 0) {
break;
}
}
SysFreeString(varCatClsid.bstrVal);
}
pPropBag->Release();
}
else
{
break;
}
pMCat->Release();
} // for loop
pEmCat->Release();
}
pCreateDevEnum->Release();
ICreateDevEnum * m_pSysDevEnum;
// Instantiate the system device enumerator
m_pSysDevEnum = NULL;
IEnumMoniker *pEnumCat = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC, IID_ICreateDevEnum,
(void **)&m_pSysDevEnum);
// Enumerate all filters of the selected category
hr = m_pSysDevEnum->CreateClassEnumerator(clsidCat, &pEnumCat, 0);
ASSERT(SUCCEEDED(hr));
if FAILED(hr)
return hr;
// Enumerate all filters using the category enumerator
hr = EnumFilters(pEnumCat);
return hr;
}
HRESULT CMPEG2Handler::GetAnalogVideoInterface()
{
HRESULT hr = S_OK;
if (dsGraph->pAmAnalogVideo == NULL) {
hr = dsGraph->pCaptureDevice->QueryInterface(IID_IAMAnalogVideoDecoder ,
(void **)&dsGraph->pAmAnalogVideo);
if (FAILED(hr)) {
return hr;
}
}
return hr ;
}
HRESULT CMPEG2Handler::Route(int in , int out)
{
if (dsGraph->pAmCrossbar)
dsGraph->pAmCrossbar->Route (in , out);
return S_OK;
}
HRESULT CMPEG2Handler::EnumFilters(IEnumMoniker *pEnumCat)
{
HRESULT hr=S_OK;
IMoniker *pMoniker;
ULONG cFetched;
VARIANT varName={0};
int nFilters=0;
// If there are no filters of a requested type, show default string
if (!pEnumCat)
{
return S_FALSE;
}
int found = 0;
again:
// Enumerate all items associated with the moniker
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag *pPropBag;
ASSERT(pMoniker);
// Associate moniker with a file
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
ASSERT(SUCCEEDED(hr));
ASSERT(pPropBag);
if (FAILED(hr))
continue;
// Read filter name from property bag
varName.vt = VT_BSTR;
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (FAILED(hr))
continue;
// Get filter name (converting BSTR name to a CString)
CString str(varName.bstrVal);
SysFreeString(varName.bstrVal);
nFilters++;
if (str != "BeCapture Crossbar")
goto again;
found = 1;
// Read filter's CLSID from property bag. This CLSID string will be
// converted to a binary CLSID and passed to AddFilter(), which will
// add the filter's name to the listbox and its CLSID to the listbox
// item's DataPtr item. When the user clicks on a filter name in
// the listbox, we'll read the stored CLSID, convert it to a string,
// and use it to find the filter's filename in the registry.
VARIANT varFilterClsid;
varFilterClsid.vt = VT_BSTR;
// Read CLSID string from property bag
hr = pPropBag->Read(L"CLSID", &varFilterClsid, 0);
if(SUCCEEDED(hr))
{
CLSID clsidFilter;
// Add filter name and CLSID to listbox
if(CLSIDFromString(varFilterClsid.bstrVal, &clsidFilter) == S_OK)
{
// Bind Moniker to a filter object
hr = pMoniker->BindToObject(0,0,IID_IBaseFilter,
(void**)&dsGraph->pCrossbarDevice);
if (FAILED(hr))
{
return hr;
}
hr = dsGraph->pCrossbarDevice->QueryInterface(IID_IAMCrossbar, (void **)&dsGraph->pAmCrossbar);
if (FAILED(hr)) {
return hr;
}
}
SysFreeString(varFilterClsid.bstrVal);
}
// Cleanup interfaces
SAFE_RELEASE(pPropBag);
SAFE_RELEASE(pMoniker);
if (found)
break;
}
return hr;
}