我正在使用Windows Media Foundation创建视频播放应用。
我使用IMFTransform
界面创建了自定义EVR混音器,以及下面链接中提到的其他一些强制接口。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms701624(v=vs.85).aspx
我创建了自定义混音器作为DLL并且还成功注册了它。
然后我使用EVR中的以下代码添加了这个自定义混音器:
// Create the video renderer.
hr = MFCreateVideoRendererActivate(hVideoWindow, &pActivate);
// Add custom mixer
hr = pActivate->SetGUID(MF_ACTIVATE_CUSTOM_VIDEO_MIXER_CLSID, CLSID_CMyCustomMixerMFT);
EVR在我的自定义调音台中调用所需的方法,但最后我收到错误MF_E_CANNOT_CREATE_SINK
。
对于自定义调音台,我指的是我的调音台的MFT实现,我指的是来自Windows媒体基础样本的mft_grayscale
示例应用程序。从该样本中复制了大部分IMFTransform实现
https://msdn.microsoft.com/en-us/library/windows/desktop/bb970487%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
我长期坚持这个错误,并且无法找到解决这个问题的方法。
根据方法STDMETHODIMP GetDeviceID(IID *pDeviceID)
If a mixer or presenter uses Direct3D 9, it must return the value IID_IDirect3DDevice9 in pDeviceID.
The EVR's default mixer and presenter both return this value.
If you write a custom mixer or presenter, it can return some other value.
However, the mixer and presenter must use matching device identifiers.
自定义调音台应返回与演示者匹配的此值。当我在我的代码中实现自定义混音器时,我将deviceID作为IID_IDirect3DDevice9
返回。
我只有一个带有音频和视频的视频流。
GetStreamLimits
- 输入和输出流限制设置为1
GetStreamIDs
- 输入ID 0和输出ID 0
AddInputStreams
- 在我的调音台中,我无法调用此方法
As Suggested我将使用MFTrace进行调试。
答案 0 :(得分:1)
这是一种实现可在Windows 7和Microsoft MediaSession / Evr上运行的自定义视频混合器的可能方法。
我发现dxva2可以使用两种NV12流格式。当然,我们不能将流与alpha混合,但它有效。我的图形驱动程序告诉我,dxva2子流只能处理AYUV / AI44,但NV12也能正常工作(奇怪)。 NV12没有alpha,但如果我们不叠加它们,我们可以显示两个视频(也许更多)。我还发现CLSID_CColorConvertDMO无法为AYUV提供MediaSession / Evr和自定义视频混合器。可以在自定义视频混合器中完成颜色转换。
我会多次发布代码,所以请耐心等待。这里很难格式化代码。对于代码的某些部分,您需要MFNode
中的常用文件有些界面只返回E_NOTIMPL,他们只是来检查Evr需要什么。所以我省略了使用E_NOTIMPL的代码。
自定义视频混音器类:
//----------------------------------------------------------------------------------------------
// CustomVideoMixer.h
//----------------------------------------------------------------------------------------------
#ifndef MFTCUSTOMVIDEOMIXER_H
#define MFTCUSTOMVIDEOMIXER_H
class CCustomVideoMixer :
BaseObject,
public IMFVideoDeviceID,
public IMFGetService,
public IMFTopologyServiceLookupClient,
public IMFTransform,
public IMFVideoMixerControl,
public IMFVideoProcessor,
public IMFAttributes,
public IMFVideoMixerBitmap,
public IMFVideoPositionMapper
{
public:
// CustomVideoMixer.cpp
static HRESULT CreateInstance(IUnknown*, REFIID, void**);
// IUnknown - CustomVideoMixer.cpp
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IMFVideoDeviceID - CustomVideoMixer.cpp
STDMETHODIMP GetDeviceID(IID*);
// IMFGetService - CustomVideoMixer.cpp
STDMETHODIMP GetService(REFGUID, REFIID, LPVOID*);
// IMFTopologyServiceLookupClient - CustomVideoMixer.cpp
STDMETHODIMP InitServicePointers(IMFTopologyServiceLookup*);
STDMETHODIMP ReleaseServicePointers();
// IMFTransform - CustomVideoMixer_Transform.cpp
STDMETHODIMP GetStreamLimits(DWORD*, DWORD*, DWORD*, DWORD*);
STDMETHODIMP GetStreamCount(DWORD*, DWORD*);
STDMETHODIMP GetStreamIDs(DWORD, DWORD*, DWORD, DWORD*);
STDMETHODIMP GetInputStreamInfo(DWORD, MFT_INPUT_STREAM_INFO*);
STDMETHODIMP GetOutputStreamInfo(DWORD, MFT_OUTPUT_STREAM_INFO*);
STDMETHODIMP GetAttributes(IMFAttributes**);
STDMETHODIMP GetInputStreamAttributes(DWORD, IMFAttributes**);
STDMETHODIMP GetOutputStreamAttributes(DWORD, IMFAttributes**);
STDMETHODIMP DeleteInputStream(DWORD);
STDMETHODIMP AddInputStreams(DWORD, DWORD*);
STDMETHODIMP GetInputAvailableType(DWORD, DWORD, IMFMediaType**);
STDMETHODIMP GetOutputAvailableType(DWORD, DWORD, IMFMediaType**);
STDMETHODIMP SetInputType(DWORD, IMFMediaType*, DWORD);
STDMETHODIMP SetOutputType(DWORD, IMFMediaType*, DWORD);
STDMETHODIMP GetInputCurrentType(DWORD, IMFMediaType**);
STDMETHODIMP GetOutputCurrentType(DWORD, IMFMediaType**);
STDMETHODIMP GetInputStatus(DWORD, DWORD*);
STDMETHODIMP GetOutputStatus(DWORD*);
STDMETHODIMP SetOutputBounds(LONGLONG, LONGLONG);
STDMETHODIMP ProcessEvent(DWORD, IMFMediaEvent*);
STDMETHODIMP ProcessMessage(MFT_MESSAGE_TYPE, ULONG_PTR);
STDMETHODIMP ProcessInput(DWORD, IMFSample*, DWORD);
STDMETHODIMP ProcessOutput(DWORD, DWORD, MFT_OUTPUT_DATA_BUFFER*, DWORD*);
// IMFVideoMixerControl - CustomVideoMixer_Mixer.cpp
STDMETHODIMP GetStreamOutputRect(DWORD, MFVideoNormalizedRect*);
STDMETHODIMP GetStreamZOrder(DWORD, DWORD*);
STDMETHODIMP SetStreamOutputRect(DWORD, const MFVideoNormalizedRect*);
STDMETHODIMP SetStreamZOrder(DWORD, DWORD);
// IMFVideoProcessor - CustomVideoMixer_Mixer.cpp
STDMETHODIMP GetAvailableVideoProcessorModes(UINT*, GUID**);
STDMETHODIMP GetBackgroundColor(COLORREF*);
STDMETHODIMP GetFilteringRange(DWORD, DXVA2_ValueRange*);
STDMETHODIMP GetFilteringValue(DWORD, DXVA2_Fixed32*);
STDMETHODIMP GetProcAmpRange(DWORD, DXVA2_ValueRange*);
STDMETHODIMP GetProcAmpValues(DWORD, DXVA2_ProcAmpValues*);
STDMETHODIMP GetVideoProcessorCaps(LPGUID, DXVA2_VideoProcessorCaps*);
STDMETHODIMP GetVideoProcessorMode(LPGUID);
STDMETHODIMP SetBackgroundColor(COLORREF);
STDMETHODIMP SetFilteringValue(DWORD, DXVA2_Fixed32*);
STDMETHODIMP SetProcAmpValues(DWORD, DXVA2_ProcAmpValues*);
STDMETHODIMP SetVideoProcessorMode(LPGUID);
// IMFAttributes - CustomVideoMixer_Attributes.cpp
STDMETHODIMP Compare(IMFAttributes*, MF_ATTRIBUTES_MATCH_TYPE, BOOL*);
STDMETHODIMP CompareItem(REFGUID, REFPROPVARIANT, BOOL*);
STDMETHODIMP CopyAllItems(IMFAttributes*);
STDMETHODIMP DeleteAllItems();
STDMETHODIMP DeleteItem(REFGUID);
STDMETHODIMP GetAllocatedBlob(REFGUID, UINT8**, UINT32*);
STDMETHODIMP GetAllocatedString(REFGUID, LPWSTR*, UINT32*);
STDMETHODIMP GetBlob(REFGUID, UINT8*, UINT32, UINT32*);
STDMETHODIMP GetBlobSize(REFGUID, UINT32*);
STDMETHODIMP GetCount(UINT32*);
STDMETHODIMP GetDouble(REFGUID, double*);
STDMETHODIMP GetGUID(REFGUID, GUID*);
STDMETHODIMP GetItem(REFGUID, PROPVARIANT*);
STDMETHODIMP GetItemByIndex(UINT32, GUID*, PROPVARIANT*);
STDMETHODIMP GetItemType(REFGUID, MF_ATTRIBUTE_TYPE*);
STDMETHODIMP GetString(REFGUID, LPWSTR, UINT32, UINT32*);
STDMETHODIMP GetStringLength(REFGUID, UINT32*);
STDMETHODIMP GetUINT32(REFGUID, UINT32*);
STDMETHODIMP GetUINT64(REFGUID, UINT64*);
STDMETHODIMP GetUnknown(REFGUID, REFIID, LPVOID*);
STDMETHODIMP LockStore();
STDMETHODIMP SetBlob(REFGUID, const UINT8*, UINT32);
STDMETHODIMP SetDouble(REFGUID, double);
STDMETHODIMP SetGUID(REFGUID, REFGUID);
STDMETHODIMP SetItem(REFGUID, REFPROPVARIANT);
STDMETHODIMP SetString(REFGUID, LPCWSTR);
STDMETHODIMP SetUINT32(REFGUID, UINT32);
STDMETHODIMP SetUINT64(REFGUID, UINT64);
STDMETHODIMP SetUnknown(REFGUID, IUnknown*);
STDMETHODIMP UnlockStore();
// IMFVideoMixerBitmap - CustomVideoMixer_Bitmap.cpp
STDMETHODIMP ClearAlphaBitmap();
STDMETHODIMP GetAlphaBitmapParameters(MFVideoAlphaBitmapParams*);
STDMETHODIMP SetAlphaBitmap(const MFVideoAlphaBitmap*);
STDMETHODIMP UpdateAlphaBitmapParameters(const MFVideoAlphaBitmapParams*);
// IMFVideoPositionMapper - CustomVideoMixer_Bitmap.cpp
STDMETHODIMP MapOutputCoordinateToInputStream(float, float, DWORD, DWORD, float*, float*);
private:
// CustomVideoMixer.cpp
CCustomVideoMixer();
virtual ~CCustomVideoMixer();
CriticSection m_CriticSection;
volatile long m_nRefCount;
CDxva2Manager m_cDxva2Manager;
IMediaEventSink* m_pMediaEventSink;
IMFMediaType* m_pRefInputType;
IMFMediaType* m_pSubInputType;
IMFMediaType* m_pOutputType;
BOOL m_bDraining;
DWORD m_dwInputStreamCount;
BOOL m_bHaveRefOuput;
BOOL m_bHaveSubOuput;
// CustomVideoMixer.cpp
HRESULT SetD3DManager(IDirect3DDeviceManager9*);
HRESULT BeginStreaming(ULONG_PTR);
HRESULT Flush();
// CustomVideoMixer_Type.cpp
HRESULT GetOutputType(IMFMediaType**);
};
#endif
CustomVideoMixer.cpp:
//----------------------------------------------------------------------------------------------
// CustomVideoMixer.cpp
//----------------------------------------------------------------------------------------------
#include "StdAfx.h"
CCustomVideoMixer::CCustomVideoMixer()
: m_nRefCount(1),
m_pMediaEventSink(NULL),
m_pRefInputType(NULL),
m_pSubInputType(NULL),
m_pOutputType(NULL),
m_bDraining(FALSE),
m_dwInputStreamCount(1),
m_bHaveRefOuput(FALSE),
m_bHaveSubOuput(FALSE)
{
TRACE_TRANSFORM((L"CustomVideoMixer::CTOR"));
}
CCustomVideoMixer::~CCustomVideoMixer() {
TRACE_TRANSFORM((L"CustomVideoMixer::DTOR"));
AutoLock lock(m_CriticSection);
Flush();
m_cDxva2Manager.ReleaseDxva2();
SAFE_RELEASE(m_pMediaEventSink);
SAFE_RELEASE(m_pRefInputType);
SAFE_RELEASE(m_pSubInputType);
SAFE_RELEASE(m_pOutputType);
}
HRESULT CCustomVideoMixer::CreateInstance(IUnknown* pUnkOuter, REFIID iid, void** ppv) {
TRACE_TRANSFORM((L"CustomVideoMixer::CreateInstance"));
HRESULT hr;
IF_FAILED_RETURN(hr = (ppv == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (pUnkOuter != NULL ? CLASS_E_NOAGGREGATION : S_OK));
CCustomVideoMixer* pMFT = new (std::nothrow)CCustomVideoMixer;
IF_FAILED_RETURN(pMFT == NULL ? E_OUTOFMEMORY : S_OK);
LOG_HRESULT(hr = pMFT->QueryInterface(iid, ppv));
SAFE_RELEASE(pMFT);
return hr;
}
ULONG CCustomVideoMixer::AddRef() {
LONG lRef = InterlockedIncrement(&m_nRefCount);
TRACE_REFCOUNT((L"CustomVideoMixer::AddRef m_nRefCount = %d", lRef));
return lRef;
}
ULONG CCustomVideoMixer::Release() {
ULONG uCount = InterlockedDecrement(&m_nRefCount);
TRACE_REFCOUNT((L"CustomVideoMixer::Release m_nRefCount = %d", uCount));
if (uCount == 0) {
delete this;
}
return uCount;
}
HRESULT CCustomVideoMixer::QueryInterface(REFIID riid, void** ppv) {
TRACE_TRANSFORM((L"CustomVideoMixer::QI : riid = %s", GetIIDString(riid)));
// IMFQualityAdvise
// IEVRTrustedVideoPlugin
static const QITAB qit[] = {
QITABENT(CCustomVideoMixer, IMFVideoDeviceID),
QITABENT(CCustomVideoMixer, IMFGetService),
QITABENT(CCustomVideoMixer, IMFTopologyServiceLookupClient),
QITABENT(CCustomVideoMixer, IMFTransform),
QITABENT(CCustomVideoMixer, IMFVideoMixerControl),
QITABENT(CCustomVideoMixer, IMFVideoProcessor),
QITABENT(CCustomVideoMixer, IMFAttributes),
QITABENT(CCustomVideoMixer, IMFVideoMixerBitmap),
QITABENT(CCustomVideoMixer, IMFVideoPositionMapper),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
HRESULT CCustomVideoMixer::GetDeviceID(IID* pDeviceID) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetDeviceID"));
HRESULT hr;
IF_FAILED_RETURN(hr = (pDeviceID == NULL ? E_POINTER : S_OK));
*pDeviceID = IID_IDirect3DDevice9;
return hr;
}
HRESULT CCustomVideoMixer::GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetService : guidService = %s - riid = %s", MFServiceString(guidService), GetIIDString(riid)));
HRESULT hr;
IF_FAILED_RETURN(hr = (ppvObject == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (guidService != MR_VIDEO_MIXER_SERVICE ? MF_E_UNSUPPORTED_SERVICE : S_OK));
if (riid == IID_IMFVideoMixerControl || riid == IID_IMFVideoProcessor || riid == IID_IMFTransform) {
hr = QueryInterface(riid, ppvObject);
}
else {
LOG_HRESULT(hr = MF_E_UNSUPPORTED_SERVICE);
}
return hr;
}
HRESULT CCustomVideoMixer::InitServicePointers(IMFTopologyServiceLookup* pLookup) {
TRACE_TRANSFORM((L"CustomVideoMixer::InitServicePointers"));
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd319606(v=vs.85).aspx
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd406901(v=vs.85).aspx
HRESULT hr;
IF_FAILED_RETURN(hr = (pLookup == NULL ? E_POINTER : S_OK));
AutoLock lock(m_CriticSection);
//IF_FAILED_RETURN(hr = (IsActive() ? MF_E_INVALIDREQUEST : S_OK));
SAFE_RELEASE(m_pMediaEventSink);
DWORD dwObjectCount = 1;
(void)pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_pMediaEventSink), &dwObjectCount);
IF_FAILED_RETURN(hr = (m_pMediaEventSink == NULL ? E_POINTER : S_OK));
// IMFClock* pInterface = NULL;
// (void)pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pInterface), &dwObjectCount);
// SAFE_RELEASE(pInterface);
// IMFVideoPresenter* pInterface = NULL;
// (void)pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pInterface), &dwObjectCount);
// IF_FAILED_RETURN(hr = (pInterface == NULL ? E_POINTER : S_OK));
// SAFE_RELEASE(pInterface);
// IMFVideoRenderer* pInterface2 = NULL;
// (void)pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pInterface2), &dwObjectCount);
// IF_FAILED_RETURN(hr = (pInterface2 == NULL ? E_POINTER : S_OK));
// SAFE_RELEASE(pInterface2);
return hr;
}
HRESULT CCustomVideoMixer::ReleaseServicePointers() {
TRACE_TRANSFORM((L"CustomVideoMixer::ReleaseServicePointers"));
AutoLock lock(m_CriticSection);
SAFE_RELEASE(m_pMediaEventSink);
return S_OK;
}
HRESULT CCustomVideoMixer::SetD3DManager(IDirect3DDeviceManager9* pDeviceManager) {
TRACE_TRANSFORM((L"CustomVideoMixer::SetD3DManager"));
HRESULT hr = S_OK;
m_cDxva2Manager.ReleaseDxva2();
if (pDeviceManager != NULL) {
if (m_pRefInputType != NULL && m_pOutputType != NULL)
IF_FAILED_RETURN(hr = m_cDxva2Manager.InitDxva2(pDeviceManager, m_pOutputType, m_pRefInputType, m_pSubInputType));
}
return hr;
}
HRESULT CCustomVideoMixer::BeginStreaming(ULONG_PTR ulParam) {
TRACE_TRANSFORM((L"CustomVideoMixer::BeginStreaming"));
HRESULT hr;
IF_FAILED_RETURN(hr = (m_pMediaEventSink == NULL ? E_POINTER : S_OK));
//IF_FAILED_RETURN(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, ulParam, 0));
IF_FAILED_RETURN(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, 0, 0));
IF_FAILED_RETURN(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, 1, 0));
// MF_E_INVALIDSTREAMNUMBER
// MF_E_TRANSFORM_TYPE_NOT_SET
return hr;
}
HRESULT CCustomVideoMixer::Flush() {
TRACE_TRANSFORM((L"CustomVideoMixer::Flush"));
m_bDraining = FALSE;
m_bHaveRefOuput = FALSE;
m_bHaveSubOuput = FALSE;
return S_OK;
}
CustomVideoMixer_Transform.cpp:
//----------------------------------------------------------------------------------------------
// CustomVideoMixer_Transform.cpp
//----------------------------------------------------------------------------------------------
#include "StdAfx.h"
HRESULT CCustomVideoMixer::GetStreamLimits(DWORD* pdwInputMinimum, DWORD* pdwInputMaximum, DWORD* pdwOutputMinimum, DWORD* pdwOutputMaximum) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetStreamLimits"));
HRESULT hr;
IF_FAILED_RETURN(hr = ((pdwInputMinimum == NULL || pdwInputMaximum == NULL || pdwOutputMinimum == NULL || pdwOutputMaximum == NULL) ? E_POINTER : S_OK));
*pdwInputMinimum = 1;
*pdwInputMaximum = 16;
*pdwOutputMinimum = 1;
*pdwOutputMaximum = 1;
return hr;
}
HRESULT CCustomVideoMixer::GetStreamCount(DWORD* pcInputStreams, DWORD* pcOutputStreams) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetStreamCount"));
HRESULT hr;
IF_FAILED_RETURN(hr = ((pcInputStreams == NULL || pcOutputStreams == NULL) ? E_POINTER : S_OK));
*pcInputStreams = m_dwInputStreamCount;
*pcOutputStreams = 1;
return hr;
}
HRESULT CCustomVideoMixer::GetStreamIDs(DWORD dwInputIDArraySize, DWORD* pdwInputIDs, DWORD dwOutputIDArraySize, DWORD* pdwOutputIDs) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetStreamIDs"));
HRESULT hr;
IF_FAILED_RETURN(hr = (dwInputIDArraySize == 0 || dwOutputIDArraySize == 0 ? MF_E_BUFFERTOOSMALL : S_OK));
IF_FAILED_RETURN(hr = (pdwInputIDs == NULL || pdwOutputIDs == NULL ? E_POINTER : S_OK));
*pdwOutputIDs = 0;
if (m_dwInputStreamCount == 1)
*pdwInputIDs = 0;
else
IF_FAILED_RETURN(hr = E_FAIL);
return hr;
}
HRESULT CCustomVideoMixer::GetInputStreamInfo(DWORD dwInputStreamID, MFT_INPUT_STREAM_INFO* pStreamInfo) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetInputStreamInfo"));
TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (pStreamInfo == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
pStreamInfo->dwFlags =
MFT_INPUT_STREAM_WHOLE_SAMPLES |
MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE |
MFT_INPUT_STREAM_DOES_NOT_ADDREF;
pStreamInfo->hnsMaxLatency = 0;
pStreamInfo->cbSize = 0;
pStreamInfo->cbMaxLookahead = 0;
pStreamInfo->cbAlignment = 0;
return hr;
}
HRESULT CCustomVideoMixer::GetOutputStreamInfo(DWORD dwOutputStreamID, MFT_OUTPUT_STREAM_INFO* pStreamInfo) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputStreamInfo"));
TRACE_TRANSFORM((L"dwOutputStreamID = %d", dwOutputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (pStreamInfo == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
AutoLock lock(m_CriticSection);
pStreamInfo->dwFlags =
MFT_OUTPUT_STREAM_WHOLE_SAMPLES |
MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE |
MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
pStreamInfo->cbAlignment = 0;
pStreamInfo->cbSize = 0;
return hr;
}
HRESULT CCustomVideoMixer::GetAttributes(IMFAttributes** ppAttributes) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetAttributes"));
HRESULT hr;
IF_FAILED_RETURN(hr = (ppAttributes == NULL ? E_POINTER : S_OK));
*ppAttributes = this;
(*ppAttributes)->AddRef();
return hr;
}
HRESULT CCustomVideoMixer::GetInputStreamAttributes(DWORD dwInputStreamID, IMFAttributes** ppAttributes) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetInputStreamAttributes"));
TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
IF_FAILED_RETURN(hr = (ppAttributes == NULL ? E_POINTER : S_OK));
*ppAttributes = this;
(*ppAttributes)->AddRef();
return hr;
}
HRESULT CCustomVideoMixer::GetOutputStreamAttributes(DWORD dwOutputStreamID, IMFAttributes** ppAttributes) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputStreamAttributes"));
TRACE_TRANSFORM((L"dwOutputStreamID = %d", dwOutputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
IF_FAILED_RETURN(hr = (ppAttributes == NULL ? E_POINTER : S_OK));
*ppAttributes = this;
(*ppAttributes)->AddRef();
return hr;
}
HRESULT CCustomVideoMixer::DeleteInputStream(DWORD dwStreamID) {
TRACE_TRANSFORM((L"CustomVideoMixer::DeleteInputStream"));
TRACE_TRANSFORM((L"dwStreamID = %d", dwStreamID));
if (dwStreamID == 0)
return MF_E_INVALIDREQUEST;
else if (dwStreamID != 1)
return MF_E_INVALIDSTREAMNUMBER;
else if(m_dwInputStreamCount != 2)
return MF_E_INVALIDREQUEST;
//MF_E_TRANSFORM_INPUT_REMAINING
m_dwInputStreamCount--;
return S_OK;
}
HRESULT CCustomVideoMixer::AddInputStreams(DWORD cStreams, DWORD* adwStreamIDs) {
TRACE_TRANSFORM((L"CustomVideoMixer::AddInputStreams"));
HRESULT hr;
IF_FAILED_RETURN(hr = (cStreams != 1 ? E_INVALIDARG : S_OK));
IF_FAILED_RETURN(hr = (adwStreamIDs == NULL ? E_INVALIDARG : S_OK));
IF_FAILED_RETURN(hr = (*adwStreamIDs != 1 ? E_INVALIDARG : S_OK));
if (m_dwInputStreamCount == 1)
m_dwInputStreamCount++;
else
IF_FAILED_RETURN(hr = E_INVALIDARG);
return S_OK;
}
HRESULT CCustomVideoMixer::GetInputAvailableType(DWORD dwInputStreamID, DWORD dwTypeIndex, IMFMediaType** ppType) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetInputAvailableType"));
TRACE_TRANSFORM((L"dwInputStreamID = %d - dwTypeIndex = %d", dwInputStreamID, dwTypeIndex));
return MF_E_NO_MORE_TYPES;
}
HRESULT CCustomVideoMixer::GetOutputAvailableType(DWORD dwOutputStreamID, DWORD dwTypeIndex, IMFMediaType** ppType) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputAvailableType"));
TRACE_TRANSFORM((L"dwOutputStreamID = %d - dwTypeIndex = %d", dwOutputStreamID, dwTypeIndex));
HRESULT hr;
IF_FAILED_RETURN(hr = (ppType == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
IF_FAILED_RETURN(hr = (dwTypeIndex != 0 ? MF_E_NO_MORE_TYPES : S_OK));
AutoLock lock(m_CriticSection);
if (m_pRefInputType == NULL) {
hr = MF_E_TRANSFORM_TYPE_NOT_SET;
}
else {
hr = GetOutputType(ppType);
}
return hr;
}
HRESULT CCustomVideoMixer::SetInputType(DWORD dwInputStreamID, IMFMediaType* pType, DWORD dwFlags) {
TRACE_TRANSFORM((L"CustomVideoMixer::SetInputType"));
TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
IF_FAILED_RETURN(hr = (dwFlags & ~MFT_SET_TYPE_TEST_ONLY ? E_INVALIDARG : S_OK));
BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
TRACE_TRANSFORM((L"bReallySet = %s", bReallySet ? L"TRUE" : L"FALSE"));
AutoLock lock(m_CriticSection);
if (pType) {
LogMediaType(pType);
}
else {
if (dwInputStreamID == 0)
SAFE_RELEASE(m_pRefInputType);
else
SAFE_RELEASE(m_pSubInputType);
return hr;
}
if (bReallySet) {
if (dwInputStreamID == 0) {
SAFE_RELEASE(m_pRefInputType);
m_pRefInputType = pType;
m_pRefInputType->AddRef();
}
else {
SAFE_RELEASE(m_pSubInputType);
m_pSubInputType = pType;
m_pSubInputType->AddRef();
}
}
return hr;
}
HRESULT CCustomVideoMixer::SetOutputType(DWORD dwOutputStreamID, IMFMediaType* pType, DWORD dwFlags) {
TRACE_TRANSFORM((L"CustomVideoMixer::SetOutputType"));
TRACE_TRANSFORM((L"dwOutputStreamID = %d", dwOutputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
IF_FAILED_RETURN(hr = (dwFlags & ~MFT_SET_TYPE_TEST_ONLY ? E_INVALIDARG : S_OK));
BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
TRACE_TRANSFORM((L"bReallySet = %s", bReallySet ? L"TRUE" : L"FALSE"));
AutoLock lock(m_CriticSection);
if (pType) {
LogMediaType(pType);
}
else {
SAFE_RELEASE(m_pOutputType);
return hr;
}
if (bReallySet) {
SAFE_RELEASE(m_pOutputType);
m_pOutputType = pType;
m_pOutputType->AddRef();
}
return hr;
}
HRESULT CCustomVideoMixer::GetInputCurrentType(DWORD dwInputStreamID, IMFMediaType** ppType) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetInputCurrentType"));
TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (ppType == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
AutoLock lock(m_CriticSection);
IMFMediaType* m_pInputType = dwInputStreamID == 0 ? m_pRefInputType : m_pSubInputType;
if (!m_pInputType) {
hr = MF_E_TRANSFORM_TYPE_NOT_SET;
}
else {
// Todo : clone MediaType
*ppType = m_pInputType;
(*ppType)->AddRef();
}
return hr;
}
HRESULT CCustomVideoMixer::GetOutputCurrentType(DWORD dwOutputStreamID, IMFMediaType** ppType) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputCurrentType"));
TRACE_TRANSFORM((L"dwOutputStreamID = %d", dwOutputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (ppType == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (dwOutputStreamID != 0 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
AutoLock lock(m_CriticSection);
if (!m_pOutputType) {
hr = MF_E_TRANSFORM_TYPE_NOT_SET;
}
else {
// Todo : clone MediaType
*ppType = m_pOutputType;
(*ppType)->AddRef();
}
return hr;
}
HRESULT CCustomVideoMixer::GetInputStatus(DWORD dwInputStreamID, DWORD* pdwFlags) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetInputStatus"));
TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (pdwFlags == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
AutoLock lock(m_CriticSection);
// I think we can always process
*pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;
return hr;
}
HRESULT CCustomVideoMixer::GetOutputStatus(DWORD* pdwFlags) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputStatus"));
HRESULT hr;
IF_FAILED_RETURN(hr = (pdwFlags == NULL ? E_POINTER : S_OK));
AutoLock lock(m_CriticSection);
/*if (m_bHaveOuput) {
*pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY;
}
else {
*pdwFlags = 0;
}*/
return hr;
}
HRESULT CCustomVideoMixer::SetOutputBounds(LONGLONG /*hnsLowerBound*/, LONGLONG /*hnsUpperBound*/) {
TRACE_TRANSFORM((L"CustomVideoMixer::SetOutputBounds"));
return E_NOTIMPL;
}
HRESULT CCustomVideoMixer::ProcessEvent(DWORD /*dwInputStreamID*/, IMFMediaEvent* /*pEvent */) {
TRACE_TRANSFORM((L"CustomVideoMixer::ProcessEvent"));
return E_NOTIMPL;
}
HRESULT CCustomVideoMixer::ProcessMessage(MFT_MESSAGE_TYPE eMessage, ULONG_PTR ulParam) {
TRACE_TRANSFORM((L"CustomVideoMixer::ProcessMessage : %s (Param = %d)", MFTMessageString(eMessage), ulParam));
HRESULT hr = S_OK;
AutoLock lock(m_CriticSection);
switch (eMessage) {
case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
//case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
hr = BeginStreaming(ulParam);
break;
case MFT_MESSAGE_COMMAND_FLUSH:
case MFT_MESSAGE_NOTIFY_END_STREAMING:
case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
hr = Flush();
break;
case MFT_MESSAGE_COMMAND_DRAIN:
m_bDraining = TRUE;
break;
case MFT_MESSAGE_SET_D3D_MANAGER:
hr = SetD3DManager(reinterpret_cast<IDirect3DDeviceManager9*>(ulParam));
// hr = MF_E_UNSUPPORTED_D3D_TYPE...
break;
}
return hr;
}
HRESULT CCustomVideoMixer::ProcessInput(DWORD dwInputStreamID, IMFSample* pSample, DWORD dwFlags) {
TRACE_TRANSFORM((L"CustomVideoMixer::ProcessInput"));
TRACE_TRANSFORM((L"dwInputStreamID = %d", dwInputStreamID));
HRESULT hr;
IF_FAILED_RETURN(hr = (pSample == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (dwInputStreamID > 1 ? MF_E_INVALIDSTREAMNUMBER : S_OK));
IF_FAILED_RETURN(hr = (dwFlags != 0 ? E_INVALIDARG : S_OK));
AutoLock lock(m_CriticSection);
if (m_bHaveRefOuput || m_bHaveSubOuput) {
return MF_E_NOTACCEPTING;
}
if (SUCCEEDED(hr = m_cDxva2Manager.ProcessInput(pSample, dwInputStreamID))) {
if (dwInputStreamID == 0) {
m_bHaveRefOuput = TRUE;
LOG_HRESULT(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, 0, 0));
}
else {
m_bHaveSubOuput = TRUE;
LOG_HRESULT(hr = m_pMediaEventSink->Notify(EC_SAMPLE_NEEDED, 1, 0));
}
}
return hr;
}
HRESULT CCustomVideoMixer::ProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount, MFT_OUTPUT_DATA_BUFFER* pOutputSamples, DWORD* pdwStatus) {
TRACE_TRANSFORM((L"CustomVideoMixer::ProcessOutput"));
HRESULT hr;
IF_FAILED_RETURN(hr = (dwFlags != 0 ? E_INVALIDARG : S_OK));
IF_FAILED_RETURN(hr = (cOutputBufferCount != 1 ? E_INVALIDARG : S_OK));
IF_FAILED_RETURN(hr = ((pOutputSamples == NULL || pdwStatus == NULL) ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (pOutputSamples[0].dwStreamID != 0 ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (pOutputSamples[0].pSample == NULL ? E_INVALIDARG : S_OK));
AutoLock lock(m_CriticSection);
if (m_bHaveRefOuput || m_bHaveSubOuput) {
IF_FAILED_RETURN(hr = m_cDxva2Manager.ProcessOutput(pOutputSamples[0].pSample));
if(m_bHaveRefOuput)
m_bHaveRefOuput = FALSE;
if (m_bHaveSubOuput)
m_bHaveSubOuput = FALSE;
}
else {
return MF_E_TRANSFORM_NEED_MORE_INPUT;
}
return hr;
}
答案 1 :(得分:0)
您尝试将Mixer
形式的自定义代码注入到具有IMFMediaSink
接口的对象中,该接口由Microsoft编写,并且您有MF_E_CANNOT_CREATE_SINK
- 错误消息,将任何错误推广到MediaSink 。此错误可能有数百个原因。对于这种情况,Microsoft开发了一个特殊工具 - MFTrace
。它记录了由Microsoft开发的代码内部。此外,无法识别错误的原因,因为您没有提供代码。例如 - 您在方法GetStreamLimits
中设置的流限制数,或者您在方法GetStreamIDs
中设置的ID,或代码处理调用方法AddInputStreams
的方式。只有IMFTransform
有23种方法。
你的问题有如此小的信息,以至于无法推荐有用的东西。
问候。
答案 2 :(得分:0)
代码的其余部分。
CustomVideoMixer_Attributes.cpp:
//----------------------------------------------------------------------------------------------
// CustomVideoMixer_Attributes.cpp
//----------------------------------------------------------------------------------------------
#include "StdAfx.h"
HRESULT CCustomVideoMixer::GetUINT32(REFGUID guidKey, UINT32* punValue) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetUINT32"));
if (punValue == NULL)
return E_POINTER;
if (guidKey == MF_SA_D3D_AWARE) {
TRACE_TRANSFORM((L"MF_SA_D3D_AWARE"));
*punValue = TRUE;
return S_OK;
}
else if(guidKey == MF_SA_REQUIRED_SAMPLE_COUNT) {
TRACE_TRANSFORM((L"MF_SA_REQUIRED_SAMPLE_COUNT"));
*punValue = 1;
return S_OK;
}
else {
TRACE_TRANSFORM((L"ERROR : MF_E_ATTRIBUTENOTFOUND"));
}
return MF_E_ATTRIBUTENOTFOUND;
}
HRESULT CCustomVideoMixer::SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize) {
TRACE_TRANSFORM((L"CustomVideoMixer::SetBlob"));
if (guidKey == VIDEO_ZOOM_RECT) {
TRACE_TRANSFORM((L"VIDEO_ZOOM_RECT"));
return S_OK;
}
else {
TRACE_TRANSFORM((L"ERROR : MF_E_ATTRIBUTENOTFOUND"));
}
return MF_E_ATTRIBUTENOTFOUND;
}
CustomVideoMixer_Type.cpp:
//----------------------------------------------------------------------------------------------
// CustomVideoMixer_Type.cpp
//----------------------------------------------------------------------------------------------
#include "StdAfx.h"
HRESULT CCustomVideoMixer::GetOutputType(IMFMediaType** ppType) {
TRACE_TRANSFORM((L"CustomVideoMixer::GetOutputType"));
HRESULT hr = S_OK;
IMFMediaType* pOutputType = NULL;
try {
IF_FAILED_THROW(hr = MFCreateMediaType(&pOutputType));
IF_FAILED_THROW(hr = pOutputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video));
// MFVideoFormat_ARGB32 MFVideoFormat_RGB32
IF_FAILED_THROW(hr = pOutputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32));
IF_FAILED_THROW(hr = pOutputType->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, TRUE));
IF_FAILED_THROW(hr = pOutputType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE));
IF_FAILED_THROW(hr = pOutputType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive));
IF_FAILED_THROW(hr = MFSetAttributeRatio(pOutputType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1));
*ppType = pOutputType;
(*ppType)->AddRef();
}
catch (HRESULT) {}
SAFE_RELEASE(pOutputType);
return hr;
}
Dxva2部分:
//----------------------------------------------------------------------------------------------
// Dxva2Manager.h
//----------------------------------------------------------------------------------------------
#ifndef DXVA2MANAGER_H
#define DXVA2MANAGER_H
class CDxva2Manager {
public:
CDxva2Manager();
~CDxva2Manager() { ReleaseDxva2(); }
HRESULT InitDxva2(IDirect3DDeviceManager9*, IMFMediaType*, IMFMediaType*, IMFMediaType*);
void ReleaseDxva2();
HRESULT ProcessInput(IMFSample*, const DWORD);
HRESULT ProcessOutput(IMFSample*);
private:
IDirectXVideoProcessor* m_pVideoProcessor;
IDirect3DSurface9* m_pRefSurface9;
IDirect3DSurface9* m_pSubSurface9;
LONGLONG m_llDuration;
LONGLONG m_llTime;
UINT32 m_uiRefWidth;
UINT32 m_uiRefHeight;
UINT32 m_uiRefLine;
UINT32 m_uiSubWidth;
UINT32 m_uiSubHeight;
UINT32 m_uiSubLine;
HRESULT GetDxva2VideoDesc(DXVA2_VideoDesc*, IMFMediaType*);
};
#endif
Dxva2Manager.cpp:
//----------------------------------------------------------------------------------------------
// Dxva2Manager.cpp
//----------------------------------------------------------------------------------------------
#include "StdAfx.h"
CDxva2Manager::CDxva2Manager() :
m_pVideoProcessor(NULL),
m_pRefSurface9(NULL),
m_pSubSurface9(NULL),
m_llDuration(0LL),
m_llTime(0LL),
m_uiRefWidth(0),
m_uiRefHeight(0),
m_uiRefLine(0),
m_uiSubWidth(0),
m_uiSubHeight(0),
m_uiSubLine(0)
{
}
HRESULT CDxva2Manager::InitDxva2(IDirect3DDeviceManager9* pDeviceManager, IMFMediaType* pOutputType, IMFMediaType* pRefInputType, IMFMediaType* pSubInputType) {
assert(m_pVideoProcessor == NULL);
assert(m_pRefSurface9 == NULL);
assert(m_pSubSurface9 == NULL);
HRESULT hr;
IF_FAILED_RETURN(hr = (pDeviceManager == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (pOutputType == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (pRefInputType == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (pSubInputType == NULL ? E_POINTER : S_OK));
IDirectXVideoProcessorService* pVideoProcessorService = NULL;
HANDLE hD3d9Device = INVALID_HANDLE_VALUE;
GUID subtype = GUID_NULL;
UINT32 uiWidth = 0;
UINT32 uiHeight = 0;
D3DFORMAT D3DFormat = D3DFMT_UNKNOWN;
DXVA2_VideoDesc dxva2VideoDesc = { 0 };
UINT uiCount = 0;
UINT uiStreamCount = 1;
GUID* guids = NULL;
try {
IF_FAILED_THROW(hr = pDeviceManager->OpenDeviceHandle(&hD3d9Device));
IF_FAILED_THROW(hr = pDeviceManager->GetVideoService(hD3d9Device, IID_PPV_ARGS(&pVideoProcessorService)));
IF_FAILED_THROW(hr = GetDxva2VideoDesc(&dxva2VideoDesc, pRefInputType));
IF_FAILED_THROW(hr = pVideoProcessorService->GetVideoProcessorDeviceGuids(&dxva2VideoDesc, &uiCount, &guids));
IF_FAILED_THROW(hr = pVideoProcessorService->CreateVideoProcessor(guids[0], &dxva2VideoDesc, D3DFMT_X8R8G8B8, uiStreamCount, &m_pVideoProcessor));
IF_FAILED_THROW(hr = pRefInputType->GetGUID(MF_MT_SUBTYPE, &subtype));
IF_FAILED_THROW(hr = MFGetAttributeSize(pRefInputType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight));
if (subtype == MFVideoFormat_NV12)
D3DFormat = (D3DFORMAT)D3DFMT_NV12;
else
IF_FAILED_THROW(hr = E_FAIL);
IF_FAILED_THROW(hr = pVideoProcessorService->CreateSurface(uiWidth, uiHeight, 0, D3DFormat, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &m_pRefSurface9, NULL));
m_uiRefWidth = uiWidth;
m_uiRefHeight = uiHeight;
m_uiRefLine = m_uiRefHeight + (m_uiRefHeight / 2);
IF_FAILED_THROW(hr = pSubInputType->GetGUID(MF_MT_SUBTYPE, &subtype));
IF_FAILED_THROW(hr = MFGetAttributeSize(pSubInputType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight));
/*if (subtype == MFVideoFormat_AYUV)
D3DFormat = (D3DFORMAT)D3DFMT_AYUV;
else
IF_FAILED_THROW(hr = E_FAIL);*/
m_uiSubWidth = uiWidth;
m_uiSubHeight = uiHeight;
m_uiSubLine = m_uiSubHeight + (m_uiSubHeight / 2);
IF_FAILED_THROW(hr = pVideoProcessorService->CreateSurface(uiWidth, uiHeight, 0, D3DFormat, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &m_pSubSurface9, NULL));
}
catch (HRESULT) {}
CoTaskMemFree(guids);
if (hD3d9Device != INVALID_HANDLE_VALUE) {
LOG_HRESULT(pDeviceManager->CloseDeviceHandle(hD3d9Device));
}
SAFE_RELEASE(pVideoProcessorService);
return hr;
}
void CDxva2Manager::ReleaseDxva2() {
SAFE_RELEASE(m_pVideoProcessor);
SAFE_RELEASE(m_pRefSurface9);
SAFE_RELEASE(m_pSubSurface9);
m_llDuration = 0LL;
m_llTime = 0LL;
m_uiRefWidth = 0;
m_uiRefHeight = 0;
m_uiRefLine = 0;
m_uiSubWidth = 0;
m_uiSubHeight = 0;
m_uiSubLine = 0;
}
HRESULT CDxva2Manager::ProcessInput(IMFSample* pSample, const DWORD dwStreamId) {
HRESULT hr = S_OK;
IMFMediaBuffer* pBuffer = NULL;
BYTE* pData = NULL;
DWORD dwLength = 0;
IDirect3DSurface9* pSurface9 = NULL;
D3DLOCKED_RECT d3dRect;
LONG lStride = 0;
UINT32 uiWidth;
UINT32 uiLine;
IMF2DBuffer* p2DBuffer = NULL;
try {
if (dwStreamId == 0) {
IF_FAILED_THROW(hr = pSample->GetSampleTime(&m_llTime));
IF_FAILED_THROW(hr = pSample->GetSampleDuration(&m_llDuration));
}
IF_FAILED_THROW(hr = pSample->GetBufferByIndex(0, &pBuffer));
IF_FAILED_THROW(hr = pBuffer->QueryInterface(IID_PPV_ARGS(&p2DBuffer)));
IF_FAILED_THROW(hr = p2DBuffer->Lock2D(&pData, &lStride));
if (dwStreamId == 0) {
pSurface9 = m_pRefSurface9;
uiWidth = m_uiRefWidth;
uiLine = m_uiRefLine;
}
else if (dwStreamId == 1) {
pSurface9 = m_pSubSurface9;
//uiWidth = m_uiSubWidth * 4;
//uiLine = m_uiSubHeight;
uiWidth = m_uiSubWidth;
uiLine = m_uiSubLine;
}
IF_FAILED_THROW(hr = pSurface9->LockRect(&d3dRect, NULL, 0));
IF_FAILED_THROW(hr = MFCopyImage((BYTE*)d3dRect.pBits, d3dRect.Pitch, pData, lStride, uiWidth, uiLine));
IF_FAILED_THROW(hr = pSurface9->UnlockRect());
}
catch (HRESULT) {}
if (pBuffer && pData) {
LOG_HRESULT(p2DBuffer->Unlock2D());
}
SAFE_RELEASE(p2DBuffer);
SAFE_RELEASE(pBuffer);
return hr;
}
HRESULT CDxva2Manager::ProcessOutput(IMFSample* pSample) {
HRESULT hr = S_OK;
IMFMediaBuffer* pBuffer = NULL;
IDirect3DSurface9* pSurface = NULL;
DXVA2_VideoProcessBltParams blt = { 0 };
RECT rc = { 0, 0, m_uiRefWidth, m_uiRefHeight };
DXVA2_AYUVSample16 color;
color.Cr = 0x0000;
color.Cb = 0xFFFF;
color.Y = 0x0000;
color.Alpha = 0xFFFF;
const UINT EX_COLOR_INFO[][2] =
{
// SDTV ITU-R BT.601 YCbCr to driver's optimal RGB range
{ DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_Unknown },
// SDTV ITU-R BT.601 YCbCr to studio RGB [16...235]
{ DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_16_235 },
// SDTV ITU-R BT.601 YCbCr to computer RGB [0...255]
{ DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_0_255 },
// HDTV ITU-R BT.709 YCbCr to driver's optimal RGB range
{ DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_Unknown },
// HDTV ITU-R BT.709 YCbCr to studio RGB [16...235]
{ DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_16_235 },
// HDTV ITU-R BT.709 YCbCr to computer RGB [0...255]
{ DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_0_255 }
};
DXVA2_Fixed32 ProcAmpValues[4] = { 0 };
DXVA2_Fixed32 NFilterValues[6] = { 0 };
DXVA2_Fixed32 DFilterValues[6] = { 0 };
DXVA2_VideoSample samples[2] = { 0 };
UINT uiStreamCount = 2;
blt.TargetFrame = m_llTime;
blt.TargetRect = rc;
blt.ConstrictionSize.cx = rc.right;
blt.ConstrictionSize.cy = rc.bottom;
blt.BackgroundColor = color;
blt.DestFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_Unknown;
blt.DestFormat.NominalRange = EX_COLOR_INFO[0][1];
blt.DestFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_Unknown;
blt.DestFormat.VideoLighting = DXVA2_VideoLighting_dim;
blt.DestFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;
blt.DestFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;
blt.DestFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
blt.ProcAmpValues.Brightness = ProcAmpValues[0];
blt.ProcAmpValues.Contrast.Value = 1;
blt.ProcAmpValues.Hue = ProcAmpValues[2];
blt.ProcAmpValues.Saturation.Value = 1;
blt.Alpha = DXVA2_Fixed32OpaqueAlpha();
blt.NoiseFilterLuma.Level = NFilterValues[0];
blt.NoiseFilterLuma.Threshold = NFilterValues[1];
blt.NoiseFilterLuma.Radius = NFilterValues[2];
blt.NoiseFilterChroma.Level = NFilterValues[3];
blt.NoiseFilterChroma.Threshold = NFilterValues[4];
blt.NoiseFilterChroma.Radius = NFilterValues[5];
blt.DetailFilterLuma.Level = DFilterValues[0];
blt.DetailFilterLuma.Threshold = DFilterValues[1];
blt.DetailFilterLuma.Radius = DFilterValues[2];
blt.DetailFilterChroma.Level = DFilterValues[3];
blt.DetailFilterChroma.Threshold = DFilterValues[4];
blt.DetailFilterChroma.Radius = DFilterValues[5];
samples[0].Start = m_llTime;
samples[0].End = m_llTime + m_llDuration;
samples[0].SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_MPEG2;
samples[0].SampleFormat.NominalRange = DXVA2_NominalRange_16_235;
samples[0].SampleFormat.VideoTransferMatrix = EX_COLOR_INFO[0][0];
samples[0].SampleFormat.VideoLighting = DXVA2_VideoLighting_dim;
samples[0].SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;
samples[0].SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;
samples[0].SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
samples[0].SrcSurface = m_pRefSurface9;
samples[0].SrcRect = rc;
rc.bottom = m_uiRefHeight / 2;
samples[0].DstRect = rc;
samples[0].PlanarAlpha = DXVA2FloatToFixed(float(0xFF) / 0xFF);
rc.right = m_uiSubWidth;
rc.bottom = m_uiSubHeight;
samples[1] = samples[0];
samples[1].SampleFormat = samples[0].SampleFormat;
samples[1].SampleFormat.SampleFormat = DXVA2_SampleSubStream;
samples[1].SrcSurface = m_pSubSurface9;
samples[1].SrcRect = rc;
rc.top = m_uiSubHeight / 2;
samples[1].DstRect = rc;
try {
IF_FAILED_THROW(hr = pSample->ConvertToContiguousBuffer(&pBuffer));
IF_FAILED_THROW(hr = MFGetService(pBuffer, MR_BUFFER_SERVICE, __uuidof(IDirect3DSurface9), (void**)&pSurface));
IF_FAILED_THROW(hr = m_pVideoProcessor->VideoProcessBlt(pSurface, &blt, samples, uiStreamCount, NULL));
}
catch (HRESULT) {}
SAFE_RELEASE(pBuffer);
SAFE_RELEASE(pSurface);
return hr;
}
HRESULT CDxva2Manager::GetDxva2VideoDesc(DXVA2_VideoDesc* dxva2VideoDesc, IMFMediaType* pRefInputType) {
HRESULT hr;
IF_FAILED_RETURN(hr = (dxva2VideoDesc == NULL ? E_POINTER : S_OK));
IF_FAILED_RETURN(hr = (pRefInputType == NULL ? E_POINTER : S_OK));
D3DFORMAT D3DFormat = D3DFMT_UNKNOWN;
GUID subtype = { 0 };
UINT32 uiWidth = 0;
UINT32 uiHeight = 0;
UINT32 uiNumerator = 0;
UINT32 uiDenominator = 0;
const UINT EX_COLOR_INFO[][2] =
{
// SDTV ITU-R BT.601 YCbCr to driver's optimal RGB range
{ DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_Unknown },
// SDTV ITU-R BT.601 YCbCr to studio RGB [16...235]
{ DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_16_235 },
// SDTV ITU-R BT.601 YCbCr to computer RGB [0...255]
{ DXVA2_VideoTransferMatrix_BT601, DXVA2_NominalRange_0_255 },
// HDTV ITU-R BT.709 YCbCr to driver's optimal RGB range
{ DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_Unknown },
// HDTV ITU-R BT.709 YCbCr to studio RGB [16...235]
{ DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_16_235 },
// HDTV ITU-R BT.709 YCbCr to computer RGB [0...255]
{ DXVA2_VideoTransferMatrix_BT709, DXVA2_NominalRange_0_255 }
};
IF_FAILED_RETURN(hr = pRefInputType->GetGUID(MF_MT_SUBTYPE, &subtype));
IF_FAILED_RETURN(hr = MFGetAttributeSize(pRefInputType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight));
IF_FAILED_RETURN(hr = MFGetAttributeRatio(pRefInputType, MF_MT_FRAME_RATE, &uiNumerator, &uiDenominator));
if (subtype == MFVideoFormat_NV12)
D3DFormat = (D3DFORMAT)D3DFMT_NV12;
else
IF_FAILED_RETURN(hr = E_FAIL);
dxva2VideoDesc->SampleWidth = uiWidth;
dxva2VideoDesc->SampleHeight = uiHeight;
dxva2VideoDesc->SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_MPEG2;
dxva2VideoDesc->SampleFormat.NominalRange = DXVA2_NominalRange_16_235;
dxva2VideoDesc->SampleFormat.VideoTransferMatrix = EX_COLOR_INFO[0][0];
dxva2VideoDesc->SampleFormat.VideoLighting = DXVA2_VideoLighting_dim;
dxva2VideoDesc->SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;
dxva2VideoDesc->SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;
dxva2VideoDesc->SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
dxva2VideoDesc->Format = D3DFormat;
dxva2VideoDesc->InputSampleFreq.Numerator = uiNumerator;
dxva2VideoDesc->InputSampleFreq.Denominator = uiDenominator;
dxva2VideoDesc->OutputFrameFreq.Numerator = uiNumerator;
dxva2VideoDesc->OutputFrameFreq.Denominator = uiDenominator;
return hr;
}
答案 3 :(得分:0)
最后,EvrMediaSession代码:
//----------------------------------------------------------------------------------------------
// Main.cpp
//----------------------------------------------------------------------------------------------
#pragma once
#define WIN32_LEAN_AND_MEAN
#define STRICT
#include <WinSDKVer.h>
#include <new>
#include <windows.h>
//----------------------------------------------------------------------------------------------
// Common MFNode Files
#ifdef _DEBUG
#define MF_USE_LOGGING 1
#else
#define MF_USE_LOGGING 0
#endif
#include "C:\Project\MFNode\Common\MFInclude.h"
// {B2F74C92-79DF-45DE-9C55-A99DE8276679}
DEFINE_GUID(CLSID_CustomVideoMixer, 0xb2f74c92, 0x79df, 0x45de, 0x9c, 0x55, 0xa9, 0x9d, 0xe8, 0x27, 0x66, 0x79);
#define WINDOWAPPLICATION_CLASS L"WindowApplication"
// Hardcoded : change if needed
#define VIDEO_WIDTH_1 320
#define VIDEO_HEIGHT_1 240
#define VIDEO_FILE_1 L"C:\\Project\\h264\\big_buck_bunny_240p_5mb.mp4"
#define VIDEO_FILE_2 L"C:\\Project\\h264\\big_buck_bunny_240p_5mb - Copie.mp4"
HWND g_hWnd = NULL;
HANDLE g_hSessionEvent = NULL;
IMFMediaSession* g_pSession = NULL;
IMFMediaSource* g_pVideoSource1 = NULL;
IMFMediaSource* g_pVideoSource2 = NULL;
IMFMediaSource* g_pAggregatedSource = NULL;
class CCustomAsyncCallback : public IMFAsyncCallback {
public:
CCustomAsyncCallback() : m_nRefCount(1) {}
virtual ~CCustomAsyncCallback() {}
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) {
static const QITAB qit[] = {
QITABENT(CCustomAsyncCallback, IMFAsyncCallback),
{ 0 }
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) AddRef() {
LONG lRef = InterlockedIncrement(&m_nRefCount);
return lRef;
}
STDMETHODIMP_(ULONG) Release() {
ULONG uCount = InterlockedDecrement(&m_nRefCount);
if (uCount == 0) {
delete this;
}
return uCount;
}
// IMFAsyncCallback
STDMETHODIMP GetParameters(DWORD*, DWORD*) { return E_NOTIMPL; }
STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult) {
IMFMediaEvent* pEvent = NULL;
HRESULT hr = S_OK;
HRESULT hrStatus;
MediaEventType EventType;
AutoLock lock(m_CriticSection);
try {
IF_FAILED_THROW(hr = g_pSession->EndGetEvent(pAsyncResult, &pEvent));
IF_FAILED_THROW(hr = pEvent->GetType(&EventType));
TRACE((L"Invoke %s", MFEventString(EventType)));
IF_FAILED_THROW(hr = pEvent->GetStatus(&hrStatus));
if (FAILED(hrStatus)) {
LOG_HRESULT(hr = hrStatus);
LOG_HRESULT(hr = g_pSession->BeginGetEvent(this, NULL));
SAFE_RELEASE(pEvent);
//SetEvent(g_hSessionEvent);
return S_OK;
}
if (EventType == MESessionTopologyStatus) {
MF_TOPOSTATUS TopoStatus = MF_TOPOSTATUS_INVALID;
LOG_HRESULT(hr = pEvent->GetUINT32(MF_EVENT_TOPOLOGY_STATUS, (UINT32*)&TopoStatus));
TRACE((L"TopoStatus %s", MFTopologyStatusString(TopoStatus)));
if(TopoStatus == MF_TOPOSTATUS_READY)
SetEvent(g_hSessionEvent);
}
if (EventType != MESessionClosed) {
LOG_HRESULT(hr = g_pSession->BeginGetEvent(this, NULL));
}
else {
SetEvent(g_hSessionEvent);
}
}
catch (HRESULT) {}
SAFE_RELEASE(pEvent);
return S_OK;
}
private:
CriticSection m_CriticSection;
volatile long m_nRefCount;
};
CCustomAsyncCallback* g_pCustomAsyncCallback = NULL;
void FreeMediaObject();
HRESULT ProcessVideo();
HRESULT CreateMediaSource(IMFMediaSource**, LPCWSTR);
HRESULT CreateAggregatedSource(IMFMediaSource*, IMFMediaSource*, IMFMediaSource**);
HRESULT CreateTopologyAggregated(IMFTopology**, IMFMediaSource*);
HRESULT BuildTopology(IMFTopology*, IMFPresentationDescriptor*, IMFMediaSource*, IMFStreamSink*, IMFStreamSink*);
HRESULT CreateSourceStreamNode(IMFMediaSource*, IMFPresentationDescriptor*, IMFStreamDescriptor*, IMFTopologyNode**);
HRESULT CreateOutputNode(IMFStreamDescriptor*, IMFTopologyNode**, IMFStreamSink*);
HRESULT InitWindow(const UINT, const UINT);
LRESULT CALLBACK WindowApplicationMsgProc(HWND, UINT, WPARAM, LPARAM);
void main() {
HRESULT hr;
LOG_HRESULT(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
if (SUCCEEDED(hr)) {
LOG_HRESULT(hr = MFStartup(MF_VERSION, MFSTARTUP_LITE));
if (SUCCEEDED(hr)) {
LOG_HRESULT(hr = ProcessVideo());
if (SUCCEEDED(hr)) {
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
FreeMediaObject();
LOG_HRESULT(hr = MFShutdown());
}
CoUninitialize();
}
}
void FreeMediaObject() {
HRESULT hr = S_OK;
if (g_pSession != NULL) {
LOG_HRESULT(hr = g_pSession->Close());
DWORD dwWaitResult = WaitForSingleObject(g_hSessionEvent, 10000);
if (dwWaitResult == WAIT_TIMEOUT)
{
assert(FALSE);
}
}
if (g_pAggregatedSource) {
g_pAggregatedSource->Shutdown();
SAFE_RELEASE(g_pAggregatedSource);
}
SAFE_RELEASE(g_pVideoSource1);
SAFE_RELEASE(g_pVideoSource2);
SAFE_RELEASE(g_pCustomAsyncCallback);
if (g_pSession) {
LOG_HRESULT(hr = g_pSession->Shutdown());
ULONG ulTest = g_pSession->Release();
g_pSession = NULL;
assert(ulTest == 0);
}
if (g_hSessionEvent)
{
CloseHandle(g_hSessionEvent);
g_hSessionEvent = NULL;
}
if (IsWindow(g_hWnd)) {
DestroyWindow(g_hWnd);
UnregisterClass(WINDOWAPPLICATION_CLASS, GetModuleHandle(NULL));
g_hWnd = NULL;
}
}
HRESULT ProcessVideo() {
HRESULT hr = S_OK;
IMFTopology* pTopology = NULL;
PROPVARIANT varStart;
PropVariantInit(&varStart);
varStart.vt = VT_EMPTY;
try {
g_pCustomAsyncCallback = new (std::nothrow)CCustomAsyncCallback();
IF_FAILED_THROW(hr = (g_pCustomAsyncCallback == NULL ? E_OUTOFMEMORY : S_OK));
g_hSessionEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
IF_FAILED_THROW(hr = (g_hSessionEvent == NULL ? E_OUTOFMEMORY : S_OK));
IF_FAILED_THROW(hr = CreateMediaSource(&g_pVideoSource1, VIDEO_FILE_1));
IF_FAILED_THROW(hr = CreateMediaSource(&g_pVideoSource2, VIDEO_FILE_2));
IF_FAILED_THROW(hr = CreateAggregatedSource(g_pVideoSource1, g_pVideoSource2, &g_pAggregatedSource));
IF_FAILED_THROW(hr = CreateTopologyAggregated(&pTopology, g_pAggregatedSource));
IF_FAILED_THROW(hr = MFCreateMediaSession(NULL, &g_pSession));
IF_FAILED_THROW(hr = g_pSession->BeginGetEvent((IMFAsyncCallback*)g_pCustomAsyncCallback, NULL));
IF_FAILED_THROW(hr = g_pSession->SetTopology(0, pTopology));
DWORD dwWaitResult = WaitForSingleObject(g_hSessionEvent, 10000);
if (dwWaitResult == WAIT_TIMEOUT)
{
IF_FAILED_THROW(hr = E_FAIL);
}
LOG_HRESULT(hr = g_pSession->Start(&GUID_NULL, &varStart));
}
catch (HRESULT) {}
SAFE_RELEASE(pTopology);
PropVariantClear(&varStart);
return hr;
}
HRESULT CreateMediaSource(IMFMediaSource** ppSource, LPCWSTR szURL) {
HRESULT hr = S_OK;
MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
IMFSourceResolver* pSourceResolver = NULL;
IUnknown* pSource = NULL;
try {
IF_FAILED_THROW(hr = MFCreateSourceResolver(&pSourceResolver));
IF_FAILED_THROW(hr = pSourceResolver->CreateObjectFromURL(szURL, MF_RESOLUTION_MEDIASOURCE, NULL, &ObjectType, &pSource));
IF_FAILED_THROW(hr = pSource->QueryInterface(IID_PPV_ARGS(ppSource)));
}
catch (HRESULT) {}
SAFE_RELEASE(pSource);
SAFE_RELEASE(pSourceResolver);
return hr;
}
HRESULT CreateAggregatedSource(IMFMediaSource* pSource1, IMFMediaSource* pSource2, IMFMediaSource** ppAggregatedSource) {
IMFCollection* pCollection = NULL;
HRESULT hr = MFCreateCollection(&pCollection);
if (SUCCEEDED(hr)) {
hr = pCollection->AddElement(pSource1);
}
if (SUCCEEDED(hr)) {
hr = pCollection->AddElement(pSource2);
}
if (SUCCEEDED(hr)) {
hr = MFCreateAggregateSource(pCollection, ppAggregatedSource);
}
SAFE_RELEASE(pCollection);
return hr;
}
HRESULT CreateTopologyAggregated(IMFTopology** ppTopology, IMFMediaSource* pSource) {
assert(ppTopology != NULL);
assert(pSource != NULL);
HRESULT hr = S_OK;
IMFTopology* pTopology = NULL;
IMFPresentationDescriptor* pSourcePD = NULL;
IMFActivate* pEvrActivate = NULL;
//IMFVideoRenderer* pVideoRenderer = NULL;
IMFMediaSink* pEvrSink = NULL;
IMFStreamSink* pStreamSink1 = NULL;
IMFStreamSink* pStreamSink2 = NULL;
try {
IF_FAILED_THROW(hr = MFCreateTopology(&pTopology));
IF_FAILED_THROW(hr = pSource->CreatePresentationDescriptor(&pSourcePD));
IF_FAILED_THROW(hr = InitWindow(VIDEO_WIDTH_1, VIDEO_HEIGHT_1));
IF_FAILED_THROW(hr = MFCreateVideoRendererActivate(g_hWnd, &pEvrActivate));
IF_FAILED_THROW(hr = pEvrActivate->SetGUID(MF_ACTIVATE_CUSTOM_VIDEO_MIXER_CLSID, CLSID_CustomVideoMixer));
//IF_FAILED_THROW(hr = pEvrActivate->ActivateObject(__uuidof(IMFVideoRenderer), reinterpret_cast<void**>(&pVideoRenderer)));
//IF_FAILED_THROW(hr = pVideoRenderer->InitializeRenderer(NULL, NULL));
IF_FAILED_THROW(hr = pEvrActivate->ActivateObject(__uuidof(IMFMediaSink), reinterpret_cast<void**>(&pEvrSink)));
IF_FAILED_THROW(hr = pEvrSink->GetStreamSinkByIndex(0, &pStreamSink1));
IF_FAILED_THROW(hr = pEvrSink->AddStreamSink(1, NULL, &pStreamSink2));
IF_FAILED_THROW(hr = BuildTopology(pTopology, pSourcePD, pSource, pStreamSink1, pStreamSink2));
*ppTopology = pTopology;
(*ppTopology)->AddRef();
}
catch (HRESULT) {}
SAFE_RELEASE(pStreamSink2);
SAFE_RELEASE(pStreamSink1);
SAFE_RELEASE(pEvrSink);
//SAFE_RELEASE(pVideoRenderer);
SAFE_RELEASE(pEvrActivate);
SAFE_RELEASE(pTopology);
SAFE_RELEASE(pSourcePD);
return hr;
}
HRESULT BuildTopology(IMFTopology* pTopology, IMFPresentationDescriptor* pSourcePD, IMFMediaSource* pSource, IMFStreamSink* pStreamSink1, IMFStreamSink* pStreamSink2) {
assert(pTopology != NULL);
HRESULT hr = S_OK;
IMFStreamDescriptor* pSourceSD = NULL;
IMFTopologyNode* pSourceNode = NULL;
IMFTopologyNode* pOutputNode = NULL;
IMFMediaTypeHandler* pHandler = NULL;
BOOL bSelected = FALSE;
DWORD dwStreamCount;
GUID guidMajorType = GUID_NULL;
BOOL bRef = TRUE;
try {
IF_FAILED_THROW(hr = pSourcePD->GetStreamDescriptorCount(&dwStreamCount));
for (DWORD i = 0; i < dwStreamCount; i++) {
IF_FAILED_THROW(hr = pSourcePD->GetStreamDescriptorByIndex(i, &bSelected, &pSourceSD));
if (bSelected) {
IF_FAILED_THROW(hr = pSourceSD->GetMediaTypeHandler(&pHandler));
IF_FAILED_THROW(hr = pHandler->GetMajorType(&guidMajorType));
if (guidMajorType == MFMediaType_Video) {
IF_FAILED_THROW(hr = CreateSourceStreamNode(pSource, pSourcePD, pSourceSD, &pSourceNode));
if (bRef) {
bRef = FALSE;
IF_FAILED_THROW(hr = CreateOutputNode(pSourceSD, &pOutputNode, pStreamSink1));
IF_FAILED_THROW(hr = pTopology->AddNode(pSourceNode));
IF_FAILED_THROW(hr = pTopology->AddNode(pOutputNode));
IF_FAILED_THROW(hr = pSourceNode->ConnectOutput(0, pOutputNode, 0));
}
else {
IF_FAILED_THROW(hr = CreateOutputNode(pSourceSD, &pOutputNode, pStreamSink2));
IF_FAILED_THROW(hr = pTopology->AddNode(pSourceNode));
IF_FAILED_THROW(hr = pTopology->AddNode(pOutputNode));
IF_FAILED_THROW(hr = pSourceNode->ConnectOutput(0, pOutputNode, 0));
}
}
/*else if (guidMajorType == MFMediaType_Audio) {
IF_FAILED_THROW(hr = CreateSourceStreamNode(pSource, pSourcePD, pSourceSD, &pSourceNode));
IF_FAILED_THROW(hr = CreateOutputNode(pSourceSD, &pOutputNode, NULL));
IF_FAILED_THROW(hr = pTopology->AddNode(pSourceNode));
IF_FAILED_THROW(hr = pTopology->AddNode(pOutputNode));
IF_FAILED_THROW(hr = pSourceNode->ConnectOutput(0, pOutputNode, 0));
}*/
else {
IF_FAILED_THROW(hr = pSourcePD->DeselectStream(i));
}
SAFE_RELEASE(pHandler);
SAFE_RELEASE(pOutputNode);
SAFE_RELEASE(pSourceNode);
}
SAFE_RELEASE(pSourceSD);
}
}
catch (HRESULT) {}
SAFE_RELEASE(pHandler);
SAFE_RELEASE(pOutputNode);
SAFE_RELEASE(pSourceNode);
SAFE_RELEASE(pSourceSD);
return hr;
}
HRESULT CreateSourceStreamNode(IMFMediaSource* pSource, IMFPresentationDescriptor* pSourcePD, IMFStreamDescriptor* pSourceSD, IMFTopologyNode** ppNode) {
if (!pSource || !pSourcePD || !pSourceSD || !ppNode) {
return E_POINTER;
}
IMFTopologyNode* pNode = NULL;
HRESULT hr = S_OK;
try {
IF_FAILED_THROW(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode));
IF_FAILED_THROW(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource));
IF_FAILED_THROW(hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pSourcePD));
IF_FAILED_THROW(hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSourceSD));
*ppNode = pNode;
(*ppNode)->AddRef();
}
catch (HRESULT) {}
SAFE_RELEASE(pNode);
return hr;
}
HRESULT CreateOutputNode(IMFStreamDescriptor* pSourceSD, IMFTopologyNode** ppNode, IMFStreamSink* pStreamSink) {
IMFTopologyNode* pNode = NULL;
IMFMediaTypeHandler* pHandler = NULL;
IMFMediaType* pMediaType = NULL;
IMFActivate* pActivate = NULL;
GUID guidMajorType = GUID_NULL;
HRESULT hr = S_OK;
try {
IF_FAILED_THROW(hr = pSourceSD->GetMediaTypeHandler(&pHandler));
IF_FAILED_THROW(hr = pHandler->GetMajorType(&guidMajorType));
IF_FAILED_THROW(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode));
if (MFMediaType_Video == guidMajorType) {
IF_FAILED_THROW(hr = pHandler->GetCurrentMediaType(&pMediaType));
IF_FAILED_THROW(hr = pMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive));
IF_FAILED_THROW(hr = pHandler->SetCurrentMediaType(pMediaType));
IF_FAILED_THROW(hr = pNode->SetObject(pStreamSink));
}
else if (MFMediaType_Audio == guidMajorType) {
IF_FAILED_THROW(hr = MFCreateAudioRendererActivate(&pActivate));
IF_FAILED_THROW(hr = pNode->SetObject(pActivate));
}
else {
IF_FAILED_THROW(hr = E_FAIL);
}
*ppNode = pNode;
(*ppNode)->AddRef();
}
catch (HRESULT) {}
SAFE_RELEASE(pNode);
SAFE_RELEASE(pHandler);
SAFE_RELEASE(pMediaType);
SAFE_RELEASE(pActivate);
return hr;
}
HRESULT InitWindow(const UINT uiWidth, const UINT uiHeight) {
WNDCLASSEX WndClassEx;
WndClassEx.cbSize = sizeof(WNDCLASSEX);
WndClassEx.style = CS_HREDRAW | CS_VREDRAW;
WndClassEx.lpfnWndProc = WindowApplicationMsgProc;
WndClassEx.cbClsExtra = 0L;
WndClassEx.cbWndExtra = 0L;
WndClassEx.hInstance = GetModuleHandle(NULL);
WndClassEx.hIcon = NULL;
WndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClassEx.hbrBackground = NULL;
WndClassEx.lpszMenuName = NULL;
WndClassEx.lpszClassName = WINDOWAPPLICATION_CLASS;
WndClassEx.hIconSm = NULL;
if (!RegisterClassEx(&WndClassEx)) {
return E_FAIL;
}
int iWndL = uiWidth + 8 + GetSystemMetrics(SM_CXSIZEFRAME) * 2;
int iWndH = uiHeight + 8 + GetSystemMetrics(SM_CYSIZEFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);
int iXWnd = (GetSystemMetrics(SM_CXSCREEN) - iWndL) / 2;
int iYWnd = (GetSystemMetrics(SM_CYSCREEN) - iWndH) / 2;
if ((g_hWnd = CreateWindowEx(WS_EX_ACCEPTFILES, WINDOWAPPLICATION_CLASS, WINDOWAPPLICATION_CLASS, WS_OVERLAPPEDWINDOW, iXWnd, iYWnd,
iWndL, iWndH, GetDesktopWindow(), NULL, GetModuleHandle(NULL), NULL)) == NULL) {
return E_FAIL;
}
RECT rc;
GetClientRect(g_hWnd, &rc);
// If failed change iWndL or/and iWndH to be TRUE
assert(rc.right == VIDEO_WIDTH_1 && rc.bottom == VIDEO_HEIGHT_1);
ShowWindow(g_hWnd, SW_SHOW);
return S_OK;
}
LRESULT CALLBACK WindowApplicationMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (msg == WM_PAINT) {
ValidateRect(hWnd, NULL);
return 0L;
}
else if (msg == WM_ERASEBKGND) {
return 1L;
}
else if (msg == WM_CLOSE) {
PostQuitMessage(0);
return 0L;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}