问题
I am trying to do some basic color space conversion using Video Processor MFT. My camera natively supports NV12 and I need RGB24, to code some shader which will provide cartoon-like effect.
Here is definition of class Media which is used to perform MF.
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);
};
I am doing setup of IMFTransform in the following way:
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);
The problem is that SetOutput method returns: cannot find a demanded attribute, and I dont really get, what is wrong. Can anyone point where I am doing things bad way? Thank you
EDIT: LogMediaType of input:
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
Logs of Output dosen't work
Exception thrown: read access violation.
**pType** was nullptr.
EDIT2
I have only one VP enumerated by EnumEx method, and it has fixed number of input (1) and output (1) streams, so previous log is the only one log for input
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);
and processing in onReadSample method looks like:
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);
回答1:
From Mediafoundation samples, you have LogMediaType function LogMediaType
Can you show log for streamType2/streamType3.
Also check existing video media type from here video-format-attributes
It could help you to find the missing attribute.
EDIT1
Beacause i use Windows Seven, i don't have the Video Processor MFT. I use Color Converter DSP, who can also do the color space conversion Color Converter DSP
IMFTransform* pVideoColorConverter = NULL;
IMFMediaType* pVideoOutputType = NULL;
// RGB24 media type at index 10, but can be different on your system
DWORD dwRGB24Index = 10;
hr = CoCreateInstance(CLSID_CColorConvertDMO, NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, reinterpret_cast<void**>(&pVideoColorConverter);
hr = pVideoColorConverter->SetInputType(0, pVideoInputType, 0);
hr = pVideoColorConverter->GetOutputAvailableType(0, dwRGB24Index, &pVideoOutputType);
hr = pVideoColorConverter->SetOutputType(0, pVideoOutputType, 0);
LogMediaType(pVideoInputType);
LogMediaType(pVideoOutputType);
Here is the log :
pVideoInputType (my camera provide YUY2 not NV12) :
MF_MT_MAJOR_TYPE MFMediaType_Video
MF_MT_SUBTYPE MFVideoFormat_YUY2
MF_MT_FRAME_SIZE 640 x 480
MF_MT_DEFAULT_STRIDE 1280
MF_MT_ALL_SAMPLES_INDEPENDENT 1
MF_MT_FIXED_SIZE_SAMPLES 1
MF_MT_SAMPLE_SIZE 614400
MF_MT_AVG_BITRATE 147456000
MF_MT_FRAME_RATE 30 x 1
MF_MT_PIXEL_ASPECT_RATIO 1 x 1
MF_MT_INTERLACE_MODE 2
MF_MT_AM_FORMAT_TYPE {05589F80-C356-11CE-BF01-00AA0055595A}
MF_MT_FRAME_RATE_RANGE_MAX 128849018881
MF_MT_FRAME_RATE_RANGE_MIN 42949672961333333
pVideoOutputType :
MF_MT_MAJOR_TYPE MFMediaType_Video
MF_MT_SUBTYPE MFVideoFormat_RGB24
MF_MT_FRAME_SIZE 640 x 480
MF_MT_FRAME_RATE 10000000 x 333333
MF_MT_GEOMETRIC_APERTURE <<byte array>>
MF_MT_PIXEL_ASPECT_RATIO 1 x 1
MF_MT_INTERLACE_MODE 2
MF_MT_DEFAULT_STRIDE 1920
MF_MT_ALL_SAMPLES_INDEPENDENT 1
MF_MT_FIXED_SIZE_SAMPLES 1
MF_MT_SAMPLE_SIZE 921600
EDIT2
Ok, your video input type seems to be correct.
Can you now log all input type (streamType) from all VP :
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]);
if(FAILED(hr)){
exit(3);
}
}
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++){
hr = VP[i]->GetStreamIDs(inputCount[i], inputids[i], outputCount[i], outputids[i]);
// By convention, if an MFT has exactly one fixed input stream and one fixed output stream, it should assign the identifier 0 to both streams
if(hr == E_NOTIMPL && inputCount[i] == 1 && outputCount[i] == 1){
inputids[i][0] = 0;
outputids[i][0] = 0;
}
else if(FAILED(hr)){
exit(4);
}
}
for(DWORD i = 0; i < MFTcount; i++){
// todo : log VP = i
for(DWORD j = 0; j < inputCount[i]; j++){
// todo : log stream id = inputids[i][j]
DWORD dwTypeIndex = 0;
hr = S_OK;
while(hr == S_OK){
// todo :log dwTypeIndex
hr = VP[i]->GetInputAvailableType(inputids[i][j], dwTypeIndex, &streamType);
if(SUCCEEDED(hr)){
LogMediaType(streamType);
SAFE_RELEASE(streamType);
dwTypeIndex++;
}
else{
// todo : check hr, should be MF_E_NO_MORE_TYPES
// if hr == E_NOTIMPL/MF_E_INVALIDSTREAMNUMBER... should be error
}
}
}
}
EDIT3
Here is a use of the Video Processor MFT : VideoProcessor MTF sample
It seems that you need to provide a D3DManager before using it (HRESULT DX11VideoRenderer::CPresenter::CreateXVP(void) -> line 1118)
I'm not sure for the D3DManager because i can't test it on my system.
hr = CoCreateInstance(CLSID_VideoProcessorMFT, nullptr, CLSCTX_INPROC_SERVER, IID_IMFTransform, (void**)&m_pXVP);
if (FAILED(hr))
{
break;
}
hr = m_pXVP->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, ULONG_PTR(m_pDXGIManager));
if (FAILED(hr))
{
break;
}
// Tell the XVP that we are the swapchain allocator
hr = m_pXVP->GetAttributes(&pAttributes);
if (FAILED(hr))
{
break;
}
hr = pAttributes->SetUINT32(MF_XVP_PLAYBACK_MODE, TRUE);
if (FAILED(hr))
{
break;
}
Check all m_pXVP and m_pXVPControl from the code.
EDIT4
According to your inputType, try to manually create the outputType, adding this attributes :
MF_MT_MAJOR_TYPE MFMediaType_Video
MF_MT_SUBTYPE MFVideoFormat_RGB24
MF_MT_FRAME_SIZE 1280 x 720
MF_MT_FIXED_SIZE_SAMPLES 1
MF_MT_FRAME_RATE 30 x 1
MF_MT_PIXEL_ASPECT_RATIO 1 x 1
MF_MT_ALL_SAMPLES_INDEPENDENT 1
MF_MT_INTERLACE_MODE 2
So just after SetInputType, create the video media output type, and then call SetOutputType with this new mediaType.
You can first try only with MF_MT_MAJOR_TYPE/MF_MT_SUBTYPE/MF_MT_FRAME_SIZE, and then add others, one by one.
来源:https://stackoverflow.com/questions/51368961/setup-of-imtransform-video-processor-for-color-space-conversion