Кодировщик MFTransform- ›ProcessInput возвращает E_FAIL

Когда я запускаю encoder->ProcessInput(stream_id, sample.Get(), 0), я получаю ошибку E_FAIL («Неопределенная ошибка»), которая не очень помогает.

Я либо пытаюсь (1) выяснить, в чем заключается настоящая ошибка, и / или (2) преодолеть эту неопределенную ошибку.

В конечном итоге моя цель - достичь этого: http://alax.info/blog/1716

Вот суть того, что я делаю:

(Ошибка возникает в этом блоке)

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://docs.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...

Если вам интересно, какими были мои Locals перед ProcessInput: http://prntscr.com/mx1i9t


person Suhail Doshi    schedule 12.03.2019    source источник
comment
Я не думаю, что это будет работать без ISample.SetSampleTime звонка. В любом случае, даже если E_FAIL недостаточно информативен, проблема, скорее всего, будет в ваших аргументах и, в частности, в экземпляре образца мультимедиа.   -  person Roman R.    schedule 13.03.2019
comment
удалось ли решить проблему? Я также столкнулся с аналогичной проблемой в аппаратных кодировщиках Intel. Однако нет проблем с аппаратными кодировщиками Nvidia и MFT программного обеспечения MS.   -  person iamrameshkumar    schedule 09.11.2019


Ответы (2)


Это может быть «непопулярный» ответ, поскольку он не предоставляет решения специально для MFT, но после 8 месяцев интенсивной работы над этим я настоятельно рекомендую не использовать MFT и напрямую реализовывать кодировщики.

Мое решение реализовывало аппаратный кодировщик, такой как NVENC / QSV, и вы могли использовать программный кодировщик, такой как x264, если у клиента нет доступного аппаратного ускорения.

Причина этого в том, что MFT гораздо более непрозрачен и плохо документирован / не поддерживается Microsoft. Я думаю, вы обнаружите, что вам нужен больший контроль над настройками и настройкой параметров кодировщика, при этом каждая реализация кодировщика немного отличается.

person Suhail Doshi    schedule 10.11.2019
comment
На мой взгляд, Media Foundation отлично подходит для Nvidia MFT. У меня проблемы только с графикой Intel. stackoverflow.com/questions/58779958/ - person iamrameshkumar; 11.11.2019

Мы видели эту ошибку, исходящую от графического драйвера Intel. (Кодировщик H.264 MFT использует графический процессор Intel для кодирования видео в формат H.264.)

В нашем случае, я думаю, ошибка была вызвана настройкой кодировщика на очень высокую скорость передачи данных, а затем настройкой на низкую скорость передачи данных. В вашем примере кода не похоже, что вы меняете скорость передачи данных, поэтому я не уверен, что это та же ошибка.

Intel выпустила новый драйвер около двух недель назад, который должен исправить обнаруженную нами ошибку. Итак, вы можете попробовать этот новый драйвер - надеюсь, он решит вашу проблему.

Новый драйвер - версия 25.20.100.6519. Вы можете получить его на веб-сайте Intel: https://downloadcenter.intel.com/download/28566/Intel-Graphics-Driver-for-Windows-10

Если новый драйвер не решает проблему, вы можете попробовать запустить свою программу на другом ПК, который использует видеокарту NVidia или AMD, чтобы проверить, возникает ли проблема только на ПК с графикой Intel.

person Anders Klemets    schedule 13.03.2019
comment
Я нигде не меняю битрейт, а только явно устанавливаю его для типа вывода. - person Suhail Doshi; 13.03.2019
comment
Я попытался обновить драйверы, но по-прежнему получаю ту же ошибку. - person Suhail Doshi; 15.03.2019
comment
@SuhailDoshi удалось ли вам решить проблему? Я также столкнулся с аналогичной проблемой в аппаратных кодировщиках Intel. Однако нет проблем с аппаратными кодировщиками Nvidia и MFT программного обеспечения MS. - person iamrameshkumar; 09.11.2019
comment
Я настоятельно рекомендую не использовать MFT из-за его непрозрачности. Я связался с инженерами Microsoft, которые даже не могут понять этого, а это их часть кодовой базы. Лучшее решение - реализовать тот тип кодировщика, который вам нужен напрямую: будь то QSV, NVENC, x264 и т. Д. Вы будете счастливее, и это будет быстрее. - person Suhail Doshi; 10.11.2019