//
// CAnalogInputFilters.cpp
//
/*-----------------------------------------------------*\
HQ Tech, Make Technology Easy!
More information, please go to http://hqtech.nease.net.
/*-----------------------------------------------------*/
#include "stdafx.h"
#include <streams.h>
#include "CAnalogInputFilters.h"
#include "crossbar.h"
#include "CVideoCaptureFilter.h"
#include "CAudioCaptureFilter.h"
#include "COverlayMixerFilter.h"
#include "CSmartTeeFilter.h"
#include "CLiveCapture.h"
#include "UDsUtils.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define _Trying_VMR
////////////////////////////////////////////////////////////////////////
CAnalogInputFilters::CAnalogInputFilters(CDXGraph * inGraph) :
CLiveInputFilters(inGraph),
cNTSCMaskBits(0x0000000f),
cPALMaskBits(0x00100ff0),
cSECAMMaskBits(0x000ff000)
{
mVideoCapture = NULL;
mAudioCapture = NULL;
mOverlayMixer = NULL;
mCrossbar = NULL;
mGraphBuilder = NULL;
mHasPreviewPin = TRUE;
}
CAnalogInputFilters::~CAnalogInputFilters()
{
Release();
if (mLiveCapture)
{
mLiveCapture->SetVMRPreferred(FALSE);
mLiveCapture->SetImageGrab(TRUE);
}
}
BOOL CAnalogInputFilters::Create(void)
{
ASSERT(mGraph);
ASSERT(mLiveCapture);
HRESULT hr = S_OK;
mVideoCapture = new CVideoCaptureFilter(mGraph->GetGraph(),
mLiveCapture->GetVideoDevice());
mAudioCapture = new CAudioCaptureFilter(mGraph->GetGraph(),
mLiveCapture->GetAudioDevice());
mSmartTee = new CSmartTeeFilter(mGraph->GetGraph());
mOverlayMixer = new COverlayMixerFilter(mGraph->GetGraph());
BOOL pass = CLiveInputFilters::Create();
if (pass)
{
pass = mVideoCapture->CreateFilter();
}
if (pass)
{
hr = CoCreateInstance((REFCLSID)CLSID_CaptureGraphBuilder2, 0,
CLSCTX_INPROC, (REFIID)IID_ICaptureGraphBuilder2, (void **)&mGraphBuilder);
pass = (mGraphBuilder != NULL);
}
if (pass)
{
mGraphBuilder->SetFiltergraph(mGraph->GetGraph());
// Build preview filter chain and filters before the capture filter
hr = mGraphBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
mVideoCapture->GetFilter(), 0, 0);
if (hr == VFW_S_NOPREVIEWPIN)
{
// Faked preview pin (using smart tee)
mHasPreviewPin = FALSE;
}
else if (hr != S_OK)
{
pass = FALSE;
}
}
if (pass)
{
CreateCrossBar(mVideoCapture->GetFilter());
// Remove all filters following the capture filter
UDsUtils::NukeDownstream(mGraph->GetGraph(), mVideoCapture->GetFilter());
SetVideoConnector(mLiveCapture->GetVideoConnector());
SetVideoResolution(mLiveCapture->GetVideoResolution());
#ifdef _Trying_VMR
if (!IsAGPCard() && mLiveCapture->GetWorkMode() == MD_Preview)
{
mLiveCapture->SetVMRPreferred(TRUE);
mLiveCapture->SetImageGrab(FALSE);
}
else
{
// AGP card doesn't use VMR
mLiveCapture->SetVMRPreferred(FALSE);
mLiveCapture->SetImageGrab(TRUE);
}
#endif // _Trying_VMR
AdjustOutput();
CheckSmartTee();
}
// Audio part
if (pass)
{
mAudioCapture->CreateFilter();
if (mLiveCapture->IsAudioConnectorValid())
{
mAudioCapture->SetConnector(mLiveCapture->GetAudioConnector());
}
else
{
mLiveCapture->SetNotifying(FALSE);
mLiveCapture->SetAudioConnector(mAudioCapture->GetConnector());
mLiveCapture->SetNotifying(TRUE);
}
}
return pass;
}
BOOL CAnalogInputFilters::IsAGPCard(void)
{
if (FindVideoPin(&PIN_CATEGORY_VIDEOPORT))
{
return TRUE;
}
return FALSE;
}
IPin * CAnalogInputFilters::GetVideoOutPin(void)
{
// Check smart tee first
if (mSmartTee && mSmartTee->GetFilter())
{
return mSmartTee->GetCapturePin();
}
return FindVideoPin(&PIN_CATEGORY_CAPTURE);
}
IPin * CAnalogInputFilters::GetPreviewPin(void)
{
// If AGP card, provide VP pin
if (IsAGPCard())
{
BOOL pass = TRUE;
if (!mOverlayMixer->GetFilter())
{
mOverlayMixer->CreateFilter();
IPin * pOut = FindVideoPin(&PIN_CATEGORY_VIDEOPORT);
IPin * pIn = mOverlayMixer->GetPin(TRUE);
pass = mGraph->ConnectFilters(pOut, pIn);
}
if (pass)
{
return mOverlayMixer->GetPin(FALSE);
}
}
// Check smart tee first
if (mSmartTee && mSmartTee->GetFilter())
{
return mSmartTee->GetPreviewPin();
}
IPin * pin = NULL;
if (mHasPreviewPin)
{
pin = FindVideoPin(&PIN_CATEGORY_PREVIEW);
}
else
{
// If the capture filter has no preview at all
pin = FindVideoPin(&PIN_CATEGORY_CAPTURE);
}
return pin;
}
IPin * CAnalogInputFilters::GetAudioOutPin(void)
{
if (mAudioCapture->GetFilter())
{
return mAudioCapture->GetPin(FALSE);
}
return NULL;
}
void CAnalogInputFilters::Release(void)
{
SAFE_DELETE(mCrossbar);
SAFE_DELETE(mSmartTee);
SAFE_DELETE(mOverlayMixer);
SAFE_DELETE(mVideoCapture);
SAFE_DELETE(mAudioCapture);
SAFE_RELEASE(mGraphBuilder);
}
IPin * CAnalogInputFilters::FindVideoPin(const GUID * inCategory)
{
if (mVideoCapture && mGraphBuilder)
{
IPin * pPin = NULL;
HRESULT hr = mGraphBuilder->FindPin(
mVideoCapture->GetFilter(), // Pointer to the capture filter.
PINDIR_OUTPUT, // Look for an output pin.
inCategory,
NULL, // Any media type.
FALSE, // Pin can be connected.
0, // Retrieve the first matching pin.
&pPin // Receives a pointer to the pin.
);
if (SUCCEEDED(hr))
{
pPin->Release();
return pPin;
}
}
return NULL;
}
BOOL CAnalogInputFilters::CreateCrossBar(IBaseFilter * inFilter)
{
IEnumPins * pins = NULL;
HRESULT hr = inFilter->EnumPins(&pins);
if (FAILED(hr))
{
return FALSE;
}
IPin * pPin= NULL;
IKsPropertySet * pKs = NULL;
ULONG count = 0;
BOOL found = FALSE;
PIN_INFO pinInfo;
while (!found && SUCCEEDED(pins->Next(1, &pPin, &count)) && count)
{
if (S_OK == pPin->QueryPinInfo(&pinInfo))
{
if (pinInfo.dir == PINDIR_INPUT)
{
// Is this pin an ANALOGVIDEOIN input pin?
if (pPin->QueryInterface(IID_IKsPropertySet, (void **)&pKs) == S_OK)
{
GUID guid;
DWORD dw = 0;
if (pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, 0, 0,
&guid, sizeof(GUID), &dw) == S_OK)
{
if (guid == PIN_CATEGORY_ANALOGVIDEOIN)
{
found = TRUE;
}
}
pKs->Release();
}
if (found)
{
SAFE_DELETE(mCrossbar);
HRESULT hr = S_OK;
mCrossbar = new CCrossbar(pPin, &hr);
}
}
pinInfo.pFilter->Release();
}
pPin->Release();
}
pins->Release();
return found;
}
AM_MEDIA_TYPE * CAnalogInputFilters::SelectMediaType(void)
{
// RGB media type is preferred.
// Preferred sequence: RGB32, RGB24, RGB565, RGB555, YUY2, UYVY
VIDEO_STREAM_CONFIG_CAPS pSCC;
AM_MEDIA_TYPE * pmt = NULL;
HRESULT hr = S_OK;
int nCounts, nSize;
int preferredIndex = -1;
enum {
RGB32 = 0, RGB24, RGB565, RGB555, YUY2, UYVY, Unknown
} currentPreferred, temp;
currentPreferred = Unknown;
IAMStreamConfig * pCfg = GetStreamConfig(&PIN_CATEGORY_CAPTURE);
pCfg->GetNumberOfCapabilities(&nCounts, &nSize);
for (int i = 0; i < nCounts; i++)
{
if (pCfg->GetStreamCaps(i, &pmt, (BYTE *)&pSCC) == S_OK)
{
if (pmt->subtype == MEDIASUBTYPE_RGB32)
{
temp = RGB32;
}
else if (pmt->subtype == MEDIASUBTYPE_RGB24)
{
temp = RGB24;
}
else if (pmt->subtype == MEDIASUBTYPE_RGB565)
{
temp = RGB565;
}
else if (pmt->subtype == MEDIASUBTYPE_RGB555)
{
temp = RGB555;
}
else if (pmt->subtype == MEDIASUBTYPE_YUY2)
{
temp = YUY2;
}
else if (pmt->subtype == MEDIASUBTYPE_UYVY)
{
temp = UYVY;
}
else
{
temp = Unknown;
}
if (temp < currentPreferred)
{
current