visual-studio - 用于色彩空间转换的 IMTransform 视频处理器的设置

标签 visual-studio image-processing sdk ms-media-foundation color-space

我正在尝试使用视频处理器 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 方法返回:找不到所需的属性,而且我真的不明白,出了什么问题。 谁能指出我做事不好的地方吗? 谢谢

编辑:输入的LogMediaType:

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.

编辑2

我只有一个通过 EnumEx 方法枚举的 VP,并且它具有固定数量的输入 (1) 和输出 (1) 流,因此前一个日志是唯一的输入日志

编辑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);

最佳答案

从 Mediafoundation 示例中,您有 LogMediaType 函数 LogMediaType

您可以显示streamType2/streamType3的日志吗?

另请从此处检查现有视频媒体类型 video-format-attributes

它可以帮助您找到丢失的属性。

编辑1

因为我使用 Windows 7,所以我没有视频处理器 MFT。我使用Color Converter DSP,它也可以做颜色空间转换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);

这是日志:

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

编辑2

好的,您的视频输入类型似乎是正确的。

您现在可以记录所有 VP 的所有输入类型(streamType)吗:

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
            }
        }
    }
}

编辑3

这是视频处理器 MFT 的使用:VideoProcessor MTF sample

看来你需要在使用它之前提供一个D3DManager(HRESULT DX11VideoRenderer::CPresenter::CreateXVP(void) -> line 1118)

我不确定 D3DManager,因为我无法在我的系统上测试它。

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;
}

从代码中检查所有 m_pXVP 和 m_pXVPControl。

编辑4

根据您的inputType,尝试手动创建outputType,添加以下属性:

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

因此,在 SetInputType 之后,创建视频媒体输出类型,然后使用此新媒体类型调用 SetOutputType。

您可以先仅尝试使用 MF_MT_MAJOR_TYPE/MF_MT_SUBTYPE/MF_MT_FRAME_SIZE,然后再一一添加其他。

关于visual-studio - 用于色彩空间转换的 IMTransform 视频处理器的设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51368961/

相关文章:

visual-studio - 如何在没有 Visual Studio 的情况下对 DirectX 进行编程

c++ - unicode utf-16代理对打印问题

c# - 获取非项目文件的FileCodeModel

c++ - Visual Studio 生成的静态库最大文件大小或其他限制?

c# - 计算图像中唯一颜色数量的算法

assembly - 将代码从水平翻转“8bpp .bmp图像”更改为在x86中水平翻转“1bpp .bmp图像”

image-processing - 傅立叶域 - 我的理论/术语正确吗?

python - Pyvmomi 这是做什么的?

android - 如何只为一个模块启用proguard

android - 解析数据时出错 org.json.JSONException : Value <? java.lang.String 类型的 xml 无法转换为 JSONArray