65.9K
CodeProject 正在变化。 阅读更多。
Home

用于 Media Foundation 拓扑和 WinRT/WRL MediaCapture 的自定义媒体接收器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (3投票s)

2014年5月12日

CPOL

1分钟阅读

viewsIcon

35564

downloadIcon

443

用于 Media Foundation 拓扑和 WinRT/WRL MediaCapture 的自定义媒体接收器

引言

WinRT 和 WRL 引入了一个要求,即大多数 Media Foundation 接口不再可以直接创建。如果想要通过接收器录制音频或视频,唯一的方法就是编写数百到数千行代码来实现一个自定义接收器。这个原型将帮助大家更轻松地实现这一目标。兼容原生 C++ 和 C++/CX。它也兼容非 WinRT/非 WRL 的使用场景,因为在 Windows 8 之前也可以使用自定义接收器,但通常会使用快捷接口。

背景

建议您了解 WinRT、WRL、C++、C++/CX、MediaCapture、Media Foundation、ATL 和 COM。

Using the Code

这里的代码块适用于所有场景,包括非 WinRT/非 WRL 场景,在这种场景下,它被绑定为拓扑的输出节点。

#ifdef _WINRT_DLL
#ifdef __cplusplus_winrt
Windows::Media::MediaProperties::VideoEncodingProperties^ vidProps;
Windows::Media::MediaProperties::AudioEncodingProperties^ audProps;
Windows::Media::MediaProperties::MediaEncodingProfile^ medEncProf = 
        ref new Windows::Media::MediaProperties::MediaEncodingProfile;
medEncProf->Video = vidProps;
medEncProf->Audio = audProps;
//set any properties to pass to the Custom Sink in a PropertySet as a best practice
Windows::Foundation::Collections::IPropertySet^ pSet = 
        ref new Windows::Foundation::Collections::PropertySet();
Windows::Media::Capture::MediaCapture^ medCap;
HRESULT hr = medCap->StartPreviewToCustomSinkAsync(medEncProf, 
    ref new Platform::String(RuntimeClass_TimeStamp_WebCamSecExtensions_MediaSink), pSet);
//when finished
hr = medCap->StopPreviewAsync();
#else
ABI::Windows::Media::Capture::IMediaCapture* medCap;
ABI::Windows::Media::MediaProperties::IVideoEncodingProperties* vidProps;
ABI::Windows::Media::MediaProperties::IAudioEncodingProperties* audProps;
ABI::Windows::Foundation::IAsyncAction** pAction;
HRESULT hr;
Microsoft::WRL::ComPtr<ABI::Windows::Media::Capture::IMediaCaptureVideoPreview> imedPrevCap;
if (pAction == nullptr) return E_POINTER;
hr = medCap->QueryInterface<ABI::Windows::Media::Capture::IMediaCaptureVideoPreview>(&imedPrevCap);
if (FAILED(hr)) return hr;
Microsoft::WRL::ComPtr<IActivationFactory> objFactory;
hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference
    (RuntimeClass_Windows_Media_MediaProperties_MediaEncodingProfile).Get(), objFactory.ReleaseAndGetAddressOf());
if (FAILED(hr)) return hr;
Microsoft::WRL::ComPtr<IInspectable> medEncProf;
hr = objFactory->ActivateInstance(medEncProf.ReleaseAndGetAddressOf());
if (FAILED(hr)) return hr;
Microsoft::WRL::ComPtr<ABI::Windows::Media::MediaProperties::IMediaEncodingProfile> encProps;
hr = medEncProf.As<ABI::Windows::Media::MediaProperties::IMediaEncodingProfile>(&encProps);
if (FAILED(hr)) return hr;
hr = encProps->put_Video(vidProps);
if (FAILED(hr)) return hr;
//if audio desired must also set an audio sink stream
hr = encProps->put_Audio(audProps);
if (FAILED(hr)) return hr;
hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference
    (RuntimeClass_Windows_Foundation_Collections_PropertySet).Get(), objFactory.ReleaseAndGetAddressOf());
if (FAILED(hr)) return hr;
Microsoft::WRL::ComPtr<IInspectable> pSet;
hr = objFactory->ActivateInstance(pSet.GetAddressOf());
if (FAILED(hr)) return hr;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IPropertySet> pProps;
hr = pSet.As(&pProps);
if (FAILED(hr)) return hr;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable *>> spSetting;
hr = pSet.As(&spSetting);
if (FAILED(hr)) return hr;
hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference
    (RuntimeClass_Windows_Foundation_PropertyValue).Get(), objFactory.ReleaseAndGetAddressOf());
if (FAILED(hr)) return hr;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> spPropVal;
hr = objFactory.As(&spPropVal);
if (FAILED(hr)) return hr;
hr = imedPrevCap->StartPreviewToCustomSinkIdAsync(encProps.Get(), Microsoft::WRL::Wrappers::HStringReference
    (RuntimeClass_TimeStamp_WebCamSecExtensions_MediaSink).Get(), pProps.Get(), pAction);
//when finished
hr = imedPrevCap->StopPreviewAsync(pAction);
#endif
#else
CComPtr<IMFTopologyNode> pNode; // Create the node.
HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode);
if (SUCCEEDED(hr)) {
CComPtr<IMFMediaSink> pSink;
hr = TimeStamp::WebCamSecExtensions::MediaSink::CreateInstance<IMFMediaSink>(&pSink);
if (FAILED(hr)) return hr;
CComPtr<IMFAttributes> pAttr;
hr = pSink->QueryInterface(&pAttr);
if (FAILED(hr)) return hr;
CComPtr<IMFMediaTypeHandler> pHandler; hr = pSD->GetMediaTypeHandler(&pHandler);
if (FAILED(hr)) return hr;
CComPtr<IMFMediaType> pMediaType;
hr = pHandler->GetCurrentMediaType(&pMediaType);
if (FAILED(hr)) return hr;
hr = pAttr->SetUnknown(MF_MEDIASINK_PREFERREDTYPE, pMediaType.Detach());
if (FAILED(hr)) return hr;
hr = pNode->SetObject(pSink);
}
#endif

关注点

在 WinRT/WRL 中,参数是通过 PropertyBag 传递的,而在非 WinRT/非 WRL 代码中,则是通过 IMFAttribute 接口传递的,可以通过在自定义接收器对象上使用 IUnknown QueryInterface 来找到该接口。

必须传递一个 ICustomSinkCallback 类型的对象,并实现该接口才能利用包括初始化、清理、属性更改通知、准备样本和样本处理在内的功能。

初始化自定义接收器时,如果计划重用 MediaCapture 对象,请务必将激活名称传递给 StartPreviewToCustomSinkAsync ,而不是 CustomSink 对象的实例。MediaCapture 库中存在一个错误,如果未使用 Windows 8 和 Windows 8.1 中存在的激活 ID,会导致其进入错误状态。

该代码与 Visual Studio 2012/2013/2015 和 Windows 8/8.1/10 兼容。

历史

  • 初始版本
© . All rights reserved.