我正在尝试使用视频处理器 MFT 进行一些基本的色彩空间转换。我的相机本身支持 NV12,我需要 RGB24,来编写一些着色器,以提供类似卡通的效果。
下面是用于执行 MF 的 Media 类的定义。
class Media : public IMFSourceReaderCallback //this class inhertis from IMFSourceReaderCallback
{
CRITICAL_SECTION criticalSection;
long referenceCount;
WCHAR *wSymbolicLink;
UINT32 cchSymbolicLink;
IMFSourceReader* sourceReader;
MFT_REGISTER_TYPE_INFO *inputVideoTypes;
MFT_REGISTER_TYPE_INFO *outputVideoTypes;
IMFMediaType* mediaType = NULL;
IMFMediaType* streamType = NULL;
IMFMediaType* streamType2 = NULL;
IMFMediaType* streamType3 = NULL;
IMFTransform **VP;
public:
LONG stride;
float bytesPerPixel;
GUID videoFormat;
UINT height;
UINT width;
WCHAR deviceNameString[2048];
BYTE* rawData;
UINT32 count;
DWORD devices_found = 0;
HRESULT CreateCaptureDevice();
HRESULT SetSourceReader(IMFActivate *device);
HRESULT IsMediaTypeSupported(IMFMediaType* type);
HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride);
HRESULT Close();
Media();
~Media();
// the class must implement the methods from IUnknown
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// the class must implement the methods from IMFSourceReaderCallback
STDMETHODIMP OnReadSample(HRESULT status, DWORD streamIndex, DWORD streamFlags, LONGLONG timeStamp, IMFSample *sample);
STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *);
STDMETHODIMP OnFlush(DWORD);
};
我正在按以下方式设置 IMFTransform:
inputVideoTypes = new MFT_REGISTER_TYPE_INFO;
inputVideoTypes->guidMajorType = MFMediaType_Video;
inputVideoTypes->guidSubtype = MFVideoFormat_NV12;
outputVideoTypes = new MFT_REGISTER_TYPE_INFO;
outputVideoTypes->guidMajorType = MFMediaType_Video;
outputVideoTypes->guidSubtype = MFVideoFormat_RGB24;
hr = sourceReader->GetNativeMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, i, &streamType2);
IMFActivate **transformActivateArray = NULL;
UINT32 MFTcount;
hr = MFTEnumEx(MFT_CATEGORY_VIDEO_PROCESSOR, MFT_ENUM_FLAG_ALL, inputVideoTypes, outputVideoTypes, &transformActivateArray, &MFTcount);
if (FAILED(hr))
{
exit(3);
}
if (MFTcount == 0)
exit(7);
VP = new IMFTransform*[MFTcount];
for (DWORD i = 0; i < MFTcount; i++)
{
hr = transformActivateArray[i]->ActivateObject(__uuidof(IMFTransform), (void**)&VP[i]);
}
DWORD* inputCount = new DWORD[MFTcount];
DWORD* outputCount = new DWORD[MFTcount];
for (DWORD i = 0; i < MFTcount; i++)
{
hr = VP[i]->GetStreamCount(&inputCount[i], &outputCount[i]);
}
DWORD **inputids = new DWORD*[MFTcount];
DWORD **outputids = new DWORD*[MFTcount];
for (DWORD i = 0; i < MFTcount; i++)
{
inputids[i] = new DWORD[inputCount[i]];
outputids[i] = new DWORD[outputCount[i]];
}
for (DWORD i = 0; i < MFTcount; i++)
{
VP[i]->GetStreamIDs(inputCount[i], inputids[i], outputCount[i], outputids[i]);
if (FAILED(hr))
exit(5);
}
DWORD flag1 = -1;
DWORD flag2 = -1;
for (DWORD i = 0; i < MFTcount; i++)
{
for (DWORD j = 0; j < inputCount[i]; j++)
{
hr = VP[i]->GetInputAvailableType(0, 0, &streamType);
if (SUCCEEDED(hr))
{
flag1 = i;
flag2 = j;
break;
}
}
}
if (flag1 == -1 && flag2 == -1)
exit(2);
hr = VP[0]->SetInputType(0, streamType2, 0);
hr = VP[0]->GetOutputAvailableType(0, 0, &streamType3);
hr = VP[0]->SetOutputType(0, streamType3, 0);
问题是 SetOutput 方法返回:找不到所需的属性,而且我真的不明白,出了什么问题。
谁能指出我做事不好的地方吗?
谢谢
编辑:LogMedia输入类型:
MF_MT_FRAME_SIZE 1280 x 720
MF_MT_YUV_MATRIX 2
MF_MT_MAJOR_TYPE MFMediaType_Video
MF_MT_VIDEO_LIGHTING 3
MF_MT_VIDEO_CHROMA_SITING 1
MF_MT_AM_FORMAT_TYPE {F72A76A0-EB0A-11D0-ACE4-0000C0CC16BA}
MF_MT_FIXED_SIZE_SAMPLES 1
MF_MT_VIDEO_NOMINAL_RANGE 1
MF_MT_FRAME_RATE 30 x 1
MF_MT_PIXEL_ASPECT_RATIO 1 x 1
MF_MT_ALL_SAMPLES_INDEPENDENT 1
MF_MT_FRAME_RATE_RANGE_MIN 128849018881
MF_MT_VIDEO_PRIMARIES 2
MF_MT_INTERLACE_MODE 2
MF_MT_FRAME_RATE_RANGE_MAX 128849018881
{EA031A62-8BBB-43C5-B5C4-572D2D231C18} 1
MF_MT_SUBTYPE MFVideoFormat_NV12
输出日志不起作用
Exception thrown: read access violation.
**pType** was nullptr.
EDIT2
我只有一个通过 EnumEx 方法枚举的 VP,并且它具有固定数量的输入 (1) 和输出 (1) 流,因此前一个日志是唯一的输入日志
Edit 3
hr = VP->SetInputType(0, streamType2, 0);
//MediaFoundationSamples::LogMediaType(streamType2);
DWORD dwIndex = 4;
hr = VP->GetOutputAvailableType(0, dwIndex, &streamType3);
hr = MFSetAttributeSize(streamType3, MF_MT_FRAME_SIZE, 1280, 720);
hr = streamType3->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, 1);
hr = MFSetAttributeRatio(streamType3, MF_MT_FRAME_RATE, 30, 1);
hr = MFSetAttributeRatio(streamType3, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
streamType3->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1);
streamType3->SetUINT32(MF_MT_INTERLACE_MODE, 2);
MediaFoundationSamples::LogMediaType(streamType3);
hr = VP->SetOutputType(0, streamType3, 0);
hr = VP->GetInputStreamInfo(0, &InputInfo);
hr = VP->GetOutputStreamInfo(0, &OutputInfo);
onReadSample 方法中的处理如下所示:
hr = VP->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
hr = VP->ProcessInput(0, sample, 0);
DWORD statusFlags;
hr = VP->GetOutputStatus(&statusFlags);
while (statusFlags == 0)
{
hr = VP->ProcessInput(0, sample, 0);
hr = VP->GetOutputStatus(&statusFlags);
}
DWORD outputStatus = 0;
IMFSample* outputSample;
MFCreateSample(&outputSample);
MFT_OUTPUT_DATA_BUFFER outputBuffer = {};
outputBuffer.pSample = outputSample;
hr = VP->ProcessOutput(0, OutputInfo.cbSize, &outputBuffer, &outputStatus);