winapi - MFTransform 编码器->ProcessInput 返回 E_FAIL

标签 winapi visual-c++ ms-media-foundation

当我运行encoder->ProcessInput(stream_id,sample.Get(),0)时,我收到一个E_FAIL(“未指定错误”)错误,这不是很有帮助。

我要么尝试(1)找出真正的错误是什么和/或(2)克服这个未指定的错误。

最终,我的目标是实现这一目标:http://alax.info/blog/1716

这是我正在做的事情的要点:

(此 block 发生错误)

void encode_frame(ComPtr<ID3D11Texture2D> texture) {
    _com_error error = NULL;
    IMFTransform *encoder = nullptr;
    encoder = get_encoder();

    if (!encoder) {
        cout << "Did not get a valid encoder to utilize\n";
        return;
    }

    cout << "Making it Direct3D aware...\n";
    setup_D3_aware_mft(encoder);

    cout << "Setting up input/output media types...\n";
    setup_media_types(encoder);

    error = encoder->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, NULL); // flush all stored data
    error = encoder->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
    error = encoder->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL); // first sample is about to be processed, req for async
    cout << "Encoding image...\n";

    IMFMediaEventGenerator *event_generator = nullptr;
    error = encoder->QueryInterface(&event_generator);

    while (true) {

        IMFMediaEvent *event = nullptr;
        MediaEventType type;

        error = event_generator->GetEvent(0, &event);
        error = event->GetType(&type);

        uint32_t stream_id = get_stream_id(encoder); // Likely just going to be 0
        uint32_t frame = 1;

        uint64_t sample_duration = 0;
        ComPtr<IMFSample> sample = nullptr;
        IMFMediaBuffer *mbuffer = nullptr;
        DWORD length = 0;
        uint32_t img_size = 0;

        MFCalculateImageSize(desktop_info.input_sub_type, desktop_info.width, desktop_info.height, &img_size);

        switch (type) {
        case METransformNeedInput:
            ThrowIfFailed(MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), texture.Get(), 0, false, &mbuffer),
                mbuffer, "Failed to generate a media buffer");

            ThrowIfFailed(MFCreateSample(&sample), sample.Get(), "Couldn't create sample buffer");
            ThrowIfFailed(sample->AddBuffer(mbuffer), sample.Get(), "Couldn't add buffer");

            // Test (delete this) - fake buffer
            /*byte *buffer_data;
            MFCreateMemoryBuffer(img_size, &mbuffer);
            mbuffer->Lock(&buffer_data, NULL, NULL);
            mbuffer->GetCurrentLength(&length);
            memset(buffer_data, 0, img_size);
            mbuffer->Unlock();
            mbuffer->SetCurrentLength(img_size);
            sample->AddBuffer(mbuffer);*/

            MFFrameRateToAverageTimePerFrame(desktop_info.fps, 1, &sample_duration);
            sample->SetSampleDuration(sample_duration);

            // ERROR
            ThrowIfFailed(encoder->ProcessInput(stream_id, sample.Get(), 0), sample.Get(), "ProcessInput failed.");

我像这样设置媒体类型:

void setup_media_types(IMFTransform *encoder) {
    IMFMediaType *output_type = nullptr;
    IMFMediaType *input_type = nullptr;

    ThrowIfFailed(MFCreateMediaType(&output_type), output_type, "Failed to create output type");
    ThrowIfFailed(MFCreateMediaType(&input_type), input_type, "Failed to create input type");

    /*
        List of all MF types: 
        https://learn.microsoft.com/en-us/windows/desktop/medfound/alphabetical-list-of-media-foundation-attributes
    */

    _com_error error = NULL;
    int stream_id = get_stream_id(encoder);

    error = output_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
    error = output_type->SetGUID(MF_MT_SUBTYPE, desktop_info.output_sub_type);
    error = output_type->SetUINT32(MF_MT_AVG_BITRATE, desktop_info.bitrate); 
    error = MFSetAttributeSize(output_type, MF_MT_FRAME_SIZE, desktop_info.width, desktop_info.height);
    error = MFSetAttributeRatio(output_type, MF_MT_FRAME_RATE, desktop_info.fps, 1);
    error = output_type->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive); // motion will be smoother, fewer artifacts
    error = output_type->SetUINT32(MF_MT_MPEG2_PROFILE, eAVEncH264VProfile_High);
    error = output_type->SetUINT32(MF_MT_MPEG2_LEVEL, eAVEncH264VLevel3_1);
    error = output_type->SetUINT32(CODECAPI_AVEncCommonRateControlMode, eAVEncCommonRateControlMode_CBR); // probably will change this

    ThrowIfFailed(encoder->SetOutputType(stream_id, output_type, 0), output_type, "Couldn't set output type");

    error = input_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
    error = input_type->SetGUID(MF_MT_SUBTYPE, desktop_info.input_sub_type);
    error = input_type->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
    error = MFSetAttributeSize(input_type, MF_MT_FRAME_SIZE, desktop_info.width, desktop_info.height);
    error = MFSetAttributeRatio(input_type, MF_MT_FRAME_RATE, desktop_info.fps, 1);
    error = MFSetAttributeRatio(input_type, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);

    ThrowIfFailed(encoder->SetInputType(stream_id, input_type, 0), input_type, "Couldn't set input type");
}

我的desktop_info结构是:

struct desktop_info {
    int fps = 30;
    int width = 2560;
    int height = 1440;
    uint32_t bitrate = 10 * 1000000; // 10Mb
    GUID input_sub_type = MFVideoFormat_ARGB32;
    GUID output_sub_type = MFVideoFormat_H264;
} desktop_info;

我的程序在到达 ProcessInput 之前的输出:

Hello World!
Number of devices: 3
Device #0
Adapter: Intel(R) HD Graphics 630
Got some information about the device:
        \\.\DISPLAY2
        Attached to desktop : 1
Got some information about the device:
        \\.\DISPLAY1
        Attached to desktop : 1
Did not find another adapter. Index higher than the # of outputs.
Successfully duplicated output from IDXGIOutput1
Accumulated frames: 0
Created a 2D texture...
Number of encoders/processors available: 1
Encoder name: Intel« Quick Sync Video H.264 Encoder MFT
Making it Direct3D aware...
Setting up input/output media types...

如果您好奇在 ProcessInput 之前我的 Locals 是什么:http://prntscr.com/mx1i9t

最佳答案

这可能是一个“不受欢迎”的答案,因为它没有专门为 MFT 提供解决方案,但经过 8 个月的努力研究这个东西,我强烈建议不要使用 MFT 并直接实现编码器。

我的解决方案是实现像 NVENC/QSV 这样的硬件编码器,如果客户端没有可用的硬件加速,您可以依靠像 x264 这样的软件编码器。

原因是 MFT 更加不透明,并且 Microsoft 没有提供良好的文档/支持。我想您会发现您还需要对编码器的设置和参数调整进行更多控制,其中每个编码器实现都略有不同。

关于winapi - MFTransform 编码器->ProcessInput 返回 E_FAIL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55131516/

相关文章:

c++ - C++ 程序中的 TCHAR 和未解析的外部符号 (LNK2019) 错误?

c++ - 通过c++ WinAPI计算MD5哈希值

c++ - 是否可以直接识别覆盖整个堆栈的错误代码?

c - 有没有一种方法可以根据 printf/更简单的函数(轻松地)定义 fprintf?

windows - 使用 Media Foundation 进行硬件 H264 编码 ID3D11Texture2D

c++ - Media Foundation 中的属性窗口

video - 媒体基金会。使用自定义 IMFMediaSource 从位图编码视频

C++ 编译错误 : "cast from ' WCHAR *' to ' WORD' loses precision"

c - 如何访问 UNICODE_STRING 命令行变量?

c++ - 如何获取MFC运行时创建的Treeview(CTreeCtrl)的Click事件?