📄 capture.cpp
字号:
HRESULT CCaptureGraph::BuildVideoPreview()
{
HRESULT hr;
CComPtr <IPin> lpPin = NULL;
//pPreview = FindPinOnFilter(m_pVideoSmartTee, __T("Output2"))
lpPin = FindPinOnFilter(m_pVideoSmartTee, __T("Output2"));
if (lpPin == NULL)
{
AfxMessageBox("预览pin出错");
return E_FAIL;
}
hr = m_pGB->Render(lpPin);
CComPtr <IVideoWindow> lpVideoWindow;
hr = m_pGB->QueryInterface(IID_IVideoWindow, (void**)&lpVideoWindow);
if (FAILED(hr))
{
return hr;
}
hr = lpVideoWindow->put_Owner((OAHWND)m_hWndOwner);
lpVideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
CRect rc;
GetClientRect(m_hWndOwner, &rc);
lpVideoWindow->put_Top(0);
lpVideoWindow->put_Left(0);
lpVideoWindow->put_Width(rc.Width());
lpVideoWindow->put_Height(rc.Height());
lpVideoWindow->put_Visible(-1);
lpVideoWindow->put_AutoShow(-1);
return hr;
}
HRESULT CCaptureGraph::OpenCrossBar()
{
HRESULT hr;
CComPtr<IBaseFilter> pNULL;
hr = AddFilter(CLSID_NullRenderer, &pNULL);
if(FAILED(hr))
{
TRACE("cant add smarttee filter to graph");
return hr;
}
//获得lpgraphBuilder2_
CComPtr<ICaptureGraphBuilder2> lpgraphBuilder2_;
hr = lpgraphBuilder2_.CoCreateInstance(CLSID_CaptureGraphBuilder2);
if (FAILED(hr))
{
return hr;
}
hr = lpgraphBuilder2_->SetFiltergraph(m_pGB);
hr = lpgraphBuilder2_->RenderStream( &PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, m_pVideoCapture, 0, pNULL );
hr = lpgraphBuilder2_->RenderStream( &PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, m_pVideoCapture, 0, pNULL );
if (SUCCEEDED(hr))
{
IAMCrossbar *pX;
hr = lpgraphBuilder2_->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Interleaved, m_pVideoCapture,
IID_IAMCrossbar, (void **)&pX);
if(FAILED(hr))
{
hr = lpgraphBuilder2_->FindInterface(&PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, m_pVideoCapture,
IID_IAMCrossbar, (void **)&pX);
}
if (SUCCEEDED(hr))
{
ISpecifyPropertyPages *pSpec;
CAUUID cauuid;
hr = pX->QueryInterface(IID_ISpecifyPropertyPages,
(void **)&pSpec);
if(S_OK == hr)
{
hr = pSpec->GetPages(&cauuid);
hr = OleCreatePropertyFrame(m_hWndOwner, 30, 30, NULL, 1,
(IUnknown **)&pX, cauuid.cElems,
(GUID *)cauuid.pElems, 0, 0, NULL);
CoTaskMemFree(cauuid.pElems);
pSpec->Release();
}
pX->Release();
}
}
return hr;
}
//构建并预览一般的Graph的视频部分
HRESULT CCaptureGraph::BuildGeneralVideo()
{
HRESULT hr;
if (NULL == m_pVideoCapture)
{
AfxMessageBox("视频采集设备出错");
return E_FAIL;
}
hr = m_pGB->AddFilter(m_pVideoCapture, NULL);
if (FAILED(hr))
{
return hr;
}
if (TRUE == m_bISCrossBar)
{
hr = OpenCrossBar();
}
//如果有字幕的Filter
if (NULL != m_pVideoOverlay)
{
hr = AddVideoOverlayFilter();
if (FAILED(hr))
{
return hr;
}
}
else
{
if (NULL == m_pVideoEncoder)
{
AfxMessageBox("视频编码器出错");
return E_FAIL;
}
hr = m_pGB->AddFilter(m_pVideoEncoder, NULL);
if (FAILED(hr))
{
return hr;
}
//如果是DMO组件
if (IsDMOFilter())
{
hr = BuildVideoDMOEncoder();
if (FAILED(hr))
{
return hr;
}
}
else
{
hr = ConnectPins(m_pVideoCapture, NULL, m_pVideoEncoder, NULL);
if (FAILED(hr))
{
AfxMessageBox("视频编码器出错。请重新选择视频编码器");
return hr;
}
}
}
hr = AddFilter(CLSID_InfTee, &m_pVideoSmartTee);
if (FAILED(hr))
{
return hr;
}
hr = ConnectPins(m_pVideoEncoder, NULL, m_pVideoSmartTee, NULL);
if (FAILED(hr))
{
AfxMessageBox("视频编码器出错,请重新选择视频编码器");
return hr;
}
//[VideoSmartTee] -> [TVSink]
hr = ConnectPins(m_pVideoSmartTee, __T("Output1"), m_pTVStreamSink, __T("Video"));
if(FAILED(hr))
{
AfxMessageBox("不能进行播放,请重新选择音频编码器。");
return hr;
}
if (m_bIsPreview)
{
hr = BuildVideoPreview();
}
return hr;
}
HRESULT CCaptureGraph::BuildSaveGraph()
{
HRESULT hr;
//Add AVI Muxer and Filewriter
if(FAILED(AddFilter(CLSID_AviDest, &m_pAVIMuxer)))
{
TRACE("cant add Avi mux filter to graph");
return E_FAIL;
}
if(FAILED(AddFilter(CLSID_FileWriter, &m_pFileWriter)))
{
TRACE("cant add Filewriter filter to graph");
return E_FAIL;
}
IConfigAviMux* lpAviMux = NULL;
hr = m_pAVIMuxer->QueryInterface(IID_IConfigAviMux, (void**)&lpAviMux);
if (FAILED(hr))
{
AfxMessageBox("AVI 设置失败");
lpAviMux->Release();
return E_FAIL;
}
hr = lpAviMux->SetOutputCompatibilityIndex(TRUE);
if (FAILED(hr))
{
AfxMessageBox("AVI 设置失败");
lpAviMux->Release();
return E_FAIL;
}
hr = lpAviMux->SetMasterStream(0);//为音频输入PIN序号
if (FAILED(hr))
{
AfxMessageBox("AVI 设置失败");
lpAviMux->Release();
return E_FAIL;
}
lpAviMux->Release();
//[AudioSmartTee] --> [AVIMux]
if(FAILED(ConnectPins(m_pAudioSmartTee, __T("Output2"), m_pAVIMuxer, __T("Input 01"))))
{
AfxMessageBox("不能保存音频。");
return E_FAIL;
}
if (!m_bIsOnlyAudio)//如果不是只采音频的情况
{
if ( m_bIsPreview )
{
//[VideoSmartTee] --> [AVIMux]
if(FAILED(ConnectPins(m_pVideoSmartTee, __T("Output3"), m_pAVIMuxer, __T("Input 02"))))
{
AfxMessageBox("不能保存视频。");
return E_FAIL;
}
}
else
{
//[VideoSmartTee] --> [AVIMux]
if(FAILED(ConnectPins(m_pVideoSmartTee, __T("Output2"), m_pAVIMuxer, __T("Input 02"))))
{
AfxMessageBox("不能保存视频。");
return E_FAIL;
}
}
}
//Set Output FileName
IFileSinkFilter *pFileSink = NULL;
m_pFileWriter->QueryInterface(IID_IFileSinkFilter, (VOID**)(&pFileSink));
if (NULL == pFileSink)
{
return E_FAIL;
}
WCHAR wstrFilename[MAX_PATH];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
m_szAVIFile, -1,
wstrFilename, sizeof(wstrFilename) / sizeof(WCHAR));
pFileSink->SetFileName(wstrFilename, NULL);
pFileSink->Release();
hr = ConnectPins(m_pAVIMuxer, NULL, m_pFileWriter, NULL);
if(FAILED(hr))
{
AfxMessageBox("不能保存成文件。");
return E_FAIL;
}
return hr;
}
HRESULT CCaptureGraph::BuildGeneralGraph()
{
HRESULT hr;
hr = BuildGeneralAudio();
if (FAILED(hr))
{
return hr;
}
//构建视频部分
if (FALSE == m_bIsOnlyAudio)
{
hr = BuildGeneralVideo();
}
if (FAILED(hr))
{
return hr;
}
if (m_bSave)
{
hr = BuildSaveGraph();
}
return hr;
}
// audio compression format
HRESULT CCaptureGraph::EnumAudioWaveFormat(CListBox* pLB)// called by main dlg
{
IPin *pOutPin;
//ASSERT(m_pCurAudioAMT);
if(FAILED(pOutPin = FindPinOnFilter(m_pAudioEncoder, NULL)))
{
TRACE("cant get outpin of Audio encoder!");
return E_FAIL;
}
IEnumMediaTypes *pEmt;
if(FAILED(pOutPin->EnumMediaTypes(&pEmt)))
{
pOutPin->Release();
return E_FAIL;
}
for(int i = 0; i < pLB->GetCount(); i++)
HeapFree(GetProcessHeap(), 0, pLB->GetItemDataPtr(i));
pLB->ResetContent();
ULONG uFetch;
AM_MEDIA_TYPE *pamt;
CString strTemp;
CString strFormat;
int liResult = 0;//保存两个当前媒体类型和枚举媒题类型的比较结果
while(pEmt->Next(1, &pamt, &uFetch) == S_OK)
{
if(pamt->formattype == FORMAT_WaveFormatEx)
{
WAVEFORMATEX *pw = (WAVEFORMATEX *)(pamt->pbFormat);
strTemp.Format("%.3fKbits/s, %dHz", (pw->nAvgBytesPerSec*8)/1024.0, pw->nSamplesPerSec);
if(pw->nChannels == 1)
strFormat.Format("%s, mono", strTemp);
else
strFormat.Format("%s, stereo", strTemp);
AM_MEDIA_TYPE *pwfe = (AM_MEDIA_TYPE *)HeapAlloc(GetProcessHeap(),
HEAP_NO_SERIALIZE|HEAP_ZERO_MEMORY,
sizeof(AM_MEDIA_TYPE) + pamt->cbFormat);
memcpy(pwfe, pamt, sizeof(AM_MEDIA_TYPE));
pwfe->pbFormat = (LPBYTE)(pwfe+1);
memcpy(pwfe->pbFormat, pw, pamt->cbFormat);
int idx = pLB->AddString(strFormat);
pLB->SetItemDataPtr(idx, pwfe);
//Arthur:0806Add
//当前媒体类型不动,这里只是负责选择,如果当前类型在枚举的时候已经不存在,则依然不动。
//如果用户选择了新的则改变,否则继续不动。
if (!m_pCurAudioAMT)
{
continue;
}
if (m_pCurAudioAMT->cbFormat == pwfe->cbFormat)
{
liResult = memcmp(m_pCurAudioAMT, pwfe,sizeof(AM_MEDIA_TYPE) - 4);
if (!liResult)
{//如果两者一样就将这项选择
liResult = memcmp(m_pCurAudioAMT->pbFormat, pwfe->pbFormat,m_pCurAudioAMT->cbFormat);
if (!liResult)
{
pLB->SetCurSel(idx);
}
}
}
}
}
pEmt->Release();
pOutPin->Release();
return S_OK;
}
void CCaptureGraph::SetAudioWaveformat(AM_MEDIA_TYPE* pamt)// called by selector dlg
{
if(pamt)
{
//Arthur:0806Modify
WAVEFORMATEX *pwfe = (WAVEFORMATEX *)pamt;//Arthur:Bug.该指针根本就没用
//
if (!m_pCurAudioAMT)
{
m_pCurAudioAMT = (AM_MEDIA_TYPE *)HeapAlloc(GetProcessHeap(),
HEAP_NO_SERIALIZE|HEAP_ZERO_MEMORY,
sizeof(AM_MEDIA_TYPE) + pamt->cbFormat);
}
ZeroMemory(m_pCurAudioAMT, sizeof(AM_MEDIA_TYPE) + m_pCurAudioAMT->cbFormat);
int iii = sizeof(AM_MEDIA_TYPE);
memcpy(m_pCurAudioAMT, pamt, sizeof(AM_MEDIA_TYPE));
BYTE* ii = (LPBYTE)(m_pCurAudioAMT+1);
m_pCurAudioAMT->pbFormat = (LPBYTE)(m_pCurAudioAMT+1);//arthur:指针加1。则相当于空出一个AM_MEDIA_TYPE。在这
//赋给pbFormat
memcpy(m_pCurAudioAMT->pbFormat, pamt->pbFormat, pamt->cbFormat);
}
}
// used to enum fiters in specified catagory
HRESULT CCaptureGraph::EnumSpeciFilters(IID iidEnumType, CStringArray &strArrayType)
{
HRESULT hr;
IMoniker *pMoniker =NULL;
ULONG cFetched;
// Create the system device enumerator
ICreateDevEnum* pDevEnum = NULL;
hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **) &pDevEnum);
if (FAILED(hr))
{
TRACE1(TEXT("Couldn't create system enumerator! hr=0x%x"), hr);
return hr;
}
IEnumMoniker *pClassEnum = NULL;
hr = pDevEnum->CreateClassEnumerator(iidEnumType, &pClassEnum, 0);
if (FAILED(hr))
{
pDevEnum->Release();
TRACE1(TEXT("Couldn't create class enumerator! hr=0x%x"), hr);
return hr;
}
if (pClassEnum == NULL)
{
pDevEnum->Release();
return S_OK;
}
while (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))
{
IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if (SUCCEEDED(hr))
{
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
int cch = lstrlenW(varName.bstrVal) + 1;
CHAR* lpszFilterName = new char[cch * 2];
if (!lpszFilterName)
return E_OUTOFMEMORY;
WideCharToMultiByte(GetACP(), 0, varName.bstrVal, -1,
lpszFilterName, cch, NULL, NULL);
if(iidEnumType == VIDEO_CAP)
strArrayType.Add(lpszFilterName);
else if(iidEnumType == AUDIO_CAP)
strArrayType.Add(lpszFilterName);
else if(iidEnumType == VIDEO_COMPRESS)
{
if(strcmp(lpszFilterName, "Microsoft H.261 Video Codec") != 0 &&
strcmp(lpszFilterName, "Microsoft H.263 Video Codec") != 0 &&
strcmp(lpszFilterName, "Microsoft RLE") != 0 &&
strcmp(lpszFilterName, "ffdshow video encoder") != 0)
strArrayType.Add(lpszFilterName);
}
else if(iidEnumType == AUDIO_COMPRESS)
{
if(strcmp(lpszFilterName, "WM Speech Encoder DMO") != 0 &&
strcmp(lpszFilterName, "ACELP.net") != 0)
strArrayType.Add(lpszFilterName);
}
else
ASSERT(FALSE);
delete [] lpszFilterName;
}
VariantClear(&varName);
pPropBag->Release();
}
pMoniker->Release();
}
pClassEnum->Release();
pDevEnum->Release();
return S_OK;
}
// used to create filter
HRESULT CCaptureGraph::FindFilterByName(LPTSTR strName, IBaseFilter **ppFilter, IID iidEnumType)
{
if(ppFilter == NULL)
return E_INVALIDARG;
*ppFilter = NULL;
HRESULT hr;
IMoniker *pMoniker =NULL;
ULONG cFetched;
// Create the system device enumerator
ICreateDevEnum* pDevEnum = NULL;
hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **) &pDevEnum);
if (FAILED(hr))
{
TRACE1(TEXT("Couldn't create system enumerator! hr=0x%x"), hr);
return hr;
}
IEnumMoniker *pClassEnum = NULL;
hr = pDevEnum->CreateClassEnumerator(iidEnumType, &pClassEnum, 0);
if (FAILED(hr))
{
pDevEnum->Release();
TRACE1(TEXT("Couldn't create class enumerator! hr=0x%x"), hr);
return hr;
}
if (pClassEnum == NULL)
{
pDevEnum->Release();
return S_OK;
}
while (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))
{
IPropertyBag *pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if (SUCCEEDED(hr))
{
VARIANT varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -