📄 amcap.cpp
字号:
{
ErrMsg(TEXT("Cannot give graph to builder"));
goto InitCapFiltersFail;
}
// Add the video capture filter to the graph with its friendly name
hr = gcap.pFg->AddFilter(gcap.pVCap, gcap.wachFriendlyName);
if(hr != NOERROR)
{
ErrMsg(TEXT("Error %x: Cannot add vidcap to filtergraph"), hr);
goto InitCapFiltersFail;
}
// Calling FindInterface below will result in building the upstream
// section of the capture graph (any WDM TVTuners or Crossbars we might
// need).
// we use this interface to get the name of the driver
// Don't worry if it doesn't work: This interface may not be available
// until the pin is connected, or it may not be available at all.
// (eg: interface may not be available for some DV capture)
hr = gcap.pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Interleaved, gcap.pVCap,
IID_IAMVideoCompression, (void **)&gcap.pVC);
if(hr != S_OK)
{
hr = gcap.pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, gcap.pVCap,
IID_IAMVideoCompression, (void **)&gcap.pVC);
}
// !!! What if this interface isn't supported?
// we use this interface to set the frame rate and get the capture size
hr = gcap.pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Interleaved,
gcap.pVCap, IID_IAMStreamConfig, (void **)&gcap.pVSC);
if(hr != NOERROR)
{
hr = gcap.pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, gcap.pVCap,
IID_IAMStreamConfig, (void **)&gcap.pVSC);
if(hr != NOERROR)
{
// this means we can't set frame rate (non-DV only)
ErrMsg(TEXT("Error %x: Cannot find VCapture:IAMStreamConfig"), hr);
}
}
gcap.fCapAudioIsRelevant = TRUE;
AM_MEDIA_TYPE *pmt;
// default capture format
if(gcap.pVSC && gcap.pVSC->GetFormat(&pmt) == S_OK)
{
// DV capture does not use a VIDEOINFOHEADER
if(pmt->formattype == FORMAT_VideoInfo)
{
// resize our window to the default capture size
ResizeWindow(HEADER(pmt->pbFormat)->biWidth,
ABS(HEADER(pmt->pbFormat)->biHeight));
}
if(pmt->majortype != MEDIATYPE_Video)
{
// This capture filter captures something other that pure video.
// Maybe it's DV or something? Anyway, chances are we shouldn't
// allow capturing audio separately, since our video capture
// filter may have audio combined in it already!
gcap.fCapAudioIsRelevant = FALSE;
gcap.fCapAudio = FALSE;
}
DeleteMediaType(pmt);
}
// we use this interface to bring up the 3 dialogs
// NOTE: Only the VfW capture filter supports this. This app only brings
// up dialogs for legacy VfW capture drivers, since only those have dialogs
hr = gcap.pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, gcap.pVCap,
IID_IAMVfwCaptureDialogs, (void **)&gcap.pDlg);
// Use the crossbar class to help us sort out all the possible video inputs
// The class needs to be given the capture filters ANALOGVIDEO input pin
{
IPin *pP = 0;
IEnumPins *pins=0;
ULONG n;
PIN_INFO pinInfo;
BOOL Found = FALSE;
IKsPropertySet *pKs=0;
GUID guid;
DWORD dw;
BOOL fMatch = FALSE;
gcap.pCrossbar = NULL;
if(SUCCEEDED(gcap.pVCap->EnumPins(&pins)))
{
while(!Found && (S_OK == pins->Next(1, &pP, &n)))
{
if(S_OK == pP->QueryPinInfo(&pinInfo))
{
if(pinInfo.dir == PINDIR_INPUT)
{
// is this pin an ANALOGVIDEOIN input pin?
if(pP->QueryInterface(IID_IKsPropertySet,
(void **)&pKs) == S_OK)
{
if(pKs->Get(AMPROPSETID_Pin,
AMPROPERTY_PIN_CATEGORY, NULL, 0,
&guid, sizeof(GUID), &dw) == S_OK)
{
if(guid == PIN_CATEGORY_ANALOGVIDEOIN)
fMatch = TRUE;
}
pKs->Release();
}
if(fMatch)
{
HRESULT hrCreate=S_OK;
gcap.pCrossbar = new CCrossbar(pP, &hrCreate);
if (!gcap.pCrossbar || FAILED(hrCreate))
break;
hr = gcap.pCrossbar->GetInputCount(&gcap.NumberOfVideoInputs);
Found = TRUE;
}
}
pinInfo.pFilter->Release();
}
pP->Release();
}
pins->Release();
}
}
// there's no point making an audio capture filter
if(gcap.fCapAudioIsRelevant == FALSE)
goto SkipAudio;
// create the audio capture filter, even if we are not capturing audio right
// now, so we have all the filters around all the time.
//
// We want an audio capture filter and some interfaces
//
if(gcap.pmAudio == 0)
{
// there are no audio capture devices. We'll only allow video capture
gcap.fCapAudio = FALSE;
goto SkipAudio;
}
gcap.pACap = NULL;
hr = gcap.pmAudio->BindToObject(0, 0, IID_IBaseFilter, (void**)&gcap.pACap);
if(gcap.pACap == NULL)
{
// there are no audio capture devices. We'll only allow video capture
gcap.fCapAudio = FALSE;
ErrMsg(TEXT("Cannot create audio capture filter"));
goto SkipAudio;
}
//
// put the audio capture filter in the graph
//
{
WCHAR wachAudioFriendlyName[256];
IPropertyBag *pBag;
wachAudioFriendlyName[0] = 0;
// Read the friendly name of the filter to assist with remote graph
// viewing through GraphEdit
hr = gcap.pmAudio->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
if(SUCCEEDED(hr))
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read(L"FriendlyName", &var, NULL);
if(hr == NOERROR)
{
hr = StringCchCopyW(wachAudioFriendlyName, 256, var.bstrVal);
SysFreeString(var.bstrVal);
}
pBag->Release();
}
// We'll need this in the graph to get audio property pages
hr = gcap.pFg->AddFilter(gcap.pACap, wachAudioFriendlyName);
if(hr != NOERROR)
{
ErrMsg(TEXT("Error %x: Cannot add audio capture filter to filtergraph"), hr);
goto InitCapFiltersFail;
}
}
// Calling FindInterface below will result in building the upstream
// section of the capture graph (any WDM TVAudio's or Crossbars we might
// need).
// !!! What if this interface isn't supported?
// we use this interface to set the captured wave format
hr = gcap.pBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, gcap.pACap,
IID_IAMStreamConfig, (void **)&gcap.pASC);
if(hr != NOERROR)
{
ErrMsg(TEXT("Cannot find ACapture:IAMStreamConfig"));
}
SkipAudio:
// Can this filter do closed captioning?
IPin *pPin;
hr = gcap.pBuilder->FindPin(gcap.pVCap, PINDIR_OUTPUT, &PIN_CATEGORY_VBI,
NULL, FALSE, 0, &pPin);
if(hr != S_OK)
hr = gcap.pBuilder->FindPin(gcap.pVCap, PINDIR_OUTPUT, &PIN_CATEGORY_CC,
NULL, FALSE, 0, &pPin);
if(hr == S_OK)
{
pPin->Release();
gcap.fCCAvail = TRUE;
}
else
{
gcap.fCapCC = FALSE; // can't capture it, then
}
// potential debug output - what the graph looks like
// DumpGraph(gcap.pFg, 1);
return TRUE;
InitCapFiltersFail:
FreeCapFilters();
return FALSE;
}
// all done with the capture filters and the graph builder
//
void FreeCapFilters()
{
SAFE_RELEASE(gcap.pFg);
if( gcap.pBuilder )
{
delete gcap.pBuilder;
gcap.pBuilder = NULL;
}
SAFE_RELEASE(gcap.pVCap);
SAFE_RELEASE(gcap.pACap);
SAFE_RELEASE(gcap.pASC);
SAFE_RELEASE(gcap.pVSC);
SAFE_RELEASE(gcap.pVC);
SAFE_RELEASE(gcap.pDlg);
if(gcap.pCrossbar)
{
delete gcap.pCrossbar;
gcap.pCrossbar = NULL;
}
}
// build the capture graph
//
BOOL BuildCaptureGraph()
{
int cy, cyBorder;
HRESULT hr;
BOOL f;
AM_MEDIA_TYPE *pmt=0;
// we have one already
if(gcap.fCaptureGraphBuilt)
return TRUE;
// No rebuilding while we're running
if(gcap.fCapturing || gcap.fPreviewing)
return FALSE;
// We don't have the necessary capture filters
if(gcap.pVCap == NULL)
return FALSE;
if(gcap.pACap == NULL && gcap.fCapAudio)
return FALSE;
// no capture file name yet... we need one first
if(gcap.wszCaptureFile[0] == 0)
{
f = SetCaptureFile(ghwndApp);
if(!f)
return f;
}
// we already have another graph built... tear down the old one
if(gcap.fPreviewGraphBuilt)
TearDownGraph();
//
// We need a rendering section that will write the capture file out in AVI
// file format
//
GUID guid;
if( gcap.fMPEG2 )
{
guid = MEDIASUBTYPE_Mpeg2;
}
else
{
guid = MEDIASUBTYPE_Avi;
}
hr = gcap.pBuilder->SetOutputFileName(&guid, gcap.wszCaptureFile,
&gcap.pRender, &gcap.pSink);
if(hr != NOERROR)
{
ErrMsg(TEXT("Cannot set output file"));
goto SetupCaptureFail;
}
// Now tell the AVIMUX to write out AVI files that old apps can read properly.
// If we don't, most apps won't be able to tell where the keyframes are,
// slowing down editing considerably
// Doing this will cause one seek (over the area the index will go) when
// you capture past 1 Gig, but that's no big deal.
// NOTE: This is on by default, so it's not necessary to turn it on
// Also, set the proper MASTER STREAM
if( !gcap.fMPEG2 )
{
hr = gcap.pRender->QueryInterface(IID_IConfigAviMux, (void **)&gcap.pConfigAviMux);
if(hr == NOERROR && gcap.pConfigAviMux)
{
gcap.pConfigAviMux->SetOutputCompatibilityIndex(TRUE);
if(gcap.fCapAudio)
{
hr = gcap.pConfigAviMux->SetMasterStream(gcap.iMasterStream);
if(hr != NOERROR)
ErrMsg(TEXT("SetMasterStream failed!"));
}
}
}
//
// Render the video capture and preview pins - even if the capture filter only
// has a capture pin (and no preview pin) this should work... because the
// capture graph builder will use a smart tee filter to provide both capture
// and preview. We don't have to worry. It will just work.
//
// NOTE that we try to render the interleaved pin before the video pin, because
// if BOTH exist, it's a DV filter and the only way to get the audio is to use
// the interleaved pin. Using the Video pin on a DV filter is only useful if
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -