Кодировщик MFTransform-> ProcessInput возвращает E_FAIL - PullRequest
0 голосов
/ 13 марта 2019

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

Я либо пытаюсь (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

1 Ответ

0 голосов
/ 13 марта 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.

...