Существует ли минимальный размер IMFSample при ProcessInput?

  • теперь я использую Media Foundation для обработки данных h264, и это живые данные.
  • получать данные по сокету
  • MFCreateMemoryBuffer для создания IMFMediaBuffer и копирования данных в буфер.
  • MFCreateSample
  • ProcessInput для передачи созданного образца.
  • получить выходные данные.

теперь мой вопрос: когда я впервые получаю данные и ProcessInput, все в порядке. но тогда я получу небольшие данные (может быть, всего 3 КБ?), И изображение будет неправильным и чего-то будет не хватать (только часть всего правильного изображения).

поэтому я думаю, что он не получает все данные, необходимые для IMFTransform, поэтому я буду хранить данные до тех пор, пока они не достигнут 30 КБ (или другого размера), а затем перейду к MFCreateMemoryBuffer.

да, теперь кадр изображения правильный до последнего кадра.

так что, наверное, я не получаю полные данные одного кадра, верно? как получить правильный размер одного полностью IMFSample(Frame)?

Я делаю как код @Simon Mourier, но есть изображение ошибки.

Вы настраиваете преобразование (формат, размеры и т. д.), чтобы знать размер входной выборки или, в более общем плане, то, что вы вводите в качестве входных данных. Можете ли вы уточнить свой вопрос?

Simon Mourier 19.02.2024 08:41

@SimonMourier, возможно, я неправильно спрашиваю. Я хочу спросить, какой размер (мин) данных буфера. h264, как вы знаете, сжат. и если я ничего не изменил (рабочий стол не изменился и мышь не переместилась), кадр изображения такой же, как и перед кадром. данных не будет, да? Если я наведу курсор мыши очень сильно, размер данных h264 будет очень маленьким. и я получу его, а затем передам в ProcessInput в качестве параметра, и я не смогу получить правильный выходной кадр, пока не подожду еще данных

user666 19.02.2024 08:45

Итак, если вы декодируете кадры H264, вам не нужно обрабатывать входные выборки определенного размера (это сжатые входные данные), просто подайте фрагменты имеющихся у вас данных и убедитесь, что вы обрабатываете HRESULT из ProcessInput (например, продолжайте, если MF_E_NOTACCEPTING ) и ProcessOutput (например: продолжить, если MF_E_TRANSFORM_NEED_MORE_INPUT) осторожно.

Simon Mourier 19.02.2024 09:50

спасибо @SimonMourier. как вы сказали, следует ли мне добавлять данные в буфер первого образца, когдаprocessOutputResult == MF_E_TRANSFORM_NEED_MORE_INPUT?

user666 19.02.2024 10:27

Да, для каждого фрагмента данных (то есть случайного количества байтов) создайте одну выборку с одним буфером с байтами, пока вы получаете это MF_E_TRANSFORM_NEED_MORE_INPUT.

Simon Mourier 19.02.2024 10:45

пока я получаю это MF_E_TRANSFORM_NEED_MORE_INPUT, я передаю данные в один образец и один буфер, и мне не нужно создавать больше образцов. я правильно понимаю? и MF_E_TRANSFORM_NEED_MORE_INTPUT снова не будет

user666 19.02.2024 10:58

Если хотите, могу предоставить пример кода на C++.

Simon Mourier 19.02.2024 10:59

@SimonMourier, вы сказали, создайте один образец с одним буфером. вы имеете в виду, что мне нужно создать один образец с одним буфером, когда я получаю MF_E_TRANSFORM_NEED_MORE_INPUT, а затем ProcessInput? или просто создать IMediaBuffer для AddBuffer к первому образцу?

user666 20.02.2024 01:55

@SimonMourier Я добавляю буфер (MFCreatememoryBuffer) в первый IMFSample, и там ничего не изменилось MF_E_TRANSFORM_NEED_MORE_INPUT

user666 20.02.2024 03:51
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
89
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот пример кода, который декодирует поток байтов H264 с помощью преобразования Media Foundation H.264 Video Decoder.

Он имитирует поток кусков байтов различного размера с использованием файла, но принципы те же.

Ключевые моменты:

  • Вы можете подавать фрагменты с любым количеством байтов в качестве входных данных для преобразования.
  • Для преобразования требуются выходные выборки фиксированного размера.
  • Преобразование не может выделять образцы само по себе.
  • Изначально никто не знает требуемого размера выборки, поэтому нам приходится кормить преобразование байтами, пока оно не сообщит нам, каким должен быть размер выборки.
#include <windows.h>
#include <atlbase.h>
#include <mfapi.h>
#include <mferror.h>
#include <mfidl.h>
#include <mftransform.h>
#include <cstdlib>

#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfuuid.lib")

#define HRCHECK(__expr) {auto __hr=(__expr);if (FAILED(__hr)){wprintf(L"FAILURE 0x%08X (%i)\n\tline: %u file: '%s'\n\texpr: '" _CRT_WIDE(#__expr) L"'\n",__hr,__hr,__LINE__,_CRT_WIDE(__FILE__));_CrtDbgBreak();}}
#define WIN32CHECK(__expr) {if (!(__expr)){auto __hr=HRESULT_FROM_WIN32(GetLastError());{wprintf(L"FAILURE 0x%08X (%i)\n\tline: %u file: '%s'\n\texpr: '" _CRT_WIDE(#__expr) L"'\n",__hr,__hr,__LINE__,_CRT_WIDE(__FILE__));_CrtDbgBreak();}}}

static HRESULT SetOutputType(IMFTransform* transform, GUID format)
{
    DWORD index = 0;
    do
    {
        CComPtr<IMFMediaType> outputType;
        auto hr = transform->GetOutputAvailableType(0, index++, &outputType);
        if (FAILED(hr))
            return hr;

        GUID guid;
        if (SUCCEEDED(outputType->GetGUID(MF_MT_SUBTYPE, &guid)) && guid == format)
        {
            HRCHECK(transform->SetOutputType(0, outputType, 0));
            return S_OK;
        }
    } while (true);
}

int main()
{
    HRCHECK(CoInitialize(nullptr));
    {
        HRCHECK(MFStartup(MF_VERSION));
        // open file
        auto file = CreateFile(L"h264.h264", GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
        WIN32CHECK(file != INVALID_HANDLE_VALUE);

        // create H264 transform https://learn.microsoft.com/en-us/windows/win32/medfound/h-264-video-decoder
        CComPtr<IMFTransform> decoder;
        HRCHECK(decoder.CoCreateInstance(CLSID_MSH264DecoderMFT));

        // You can check in decoder attributes that MF_MT_FIXED_SIZE_SAMPLES is set to TRUE.
        // Calling GetOutputStreamInfo this will tell you the MFT cannot provide samples
        // as MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES and MFT_OUTPUT_STREAM_PROVIDES_SAMPLES are not set

        // So we don't know enough information yet, we'll feed input samples until we get MF_E_TRANSFORM_STREAM_CHANGE and then we'll provide a sample as per doc:
        //   "If the input type contains only these two attributes, the decoder will offer a default output type, which acts as a placeholder."
        //   "When the decoder receives enough input samples to produce an output frame, it signals a format change by returning MF_E_TRANSFORM_STREAM_CHANGE"
        UINT32 sampleSize = 0;

        // input type is H264
        CComPtr<IMFMediaType> inputType;
        HRCHECK(MFCreateMediaType(&inputType));
        HRCHECK(inputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video));
        HRCHECK(inputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264));
        HRCHECK(decoder->SetInputType(0, inputType, 0)); // video is id 0

        // get (and set) NV12 output type (could be I420, IYUV, YUY2, YV12)
        HRCHECK(SetOutputType(decoder, MFVideoFormat_NV12));

        do
        {
            // get a random chunk size between 500 and 1500
            DWORD chunkSize = 500 + (1000 * (RAND_MAX - std::rand())) / RAND_MAX;

            // create an MF input buffer & read into it
            CComPtr<IMFMediaBuffer> inputBuffer;
            HRCHECK(MFCreateMemoryBuffer(chunkSize, &inputBuffer));
            BYTE* chunk;
            HRCHECK(inputBuffer->Lock(&chunk, nullptr, nullptr));
            DWORD read;
            WIN32CHECK(ReadFile(file, chunk, chunkSize, &read, nullptr));
            HRCHECK(inputBuffer->SetCurrentLength(read));
            HRCHECK(inputBuffer->Unlock());
            if (read)
            {
                CComPtr<IMFSample> inputSample;
                HRCHECK(MFCreateSample(&inputSample));
                HRCHECK(inputSample->AddBuffer(inputBuffer));

                auto hr = decoder->ProcessInput(0, inputSample, 0);
                if (hr != MF_E_NOTACCEPTING) // just go on
                {
                    HRCHECK(hr);
                }
            }
            else
            {
                // end of file, ask decoder to process all data from previous calls
                HRCHECK(decoder->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0));
            }

            CComPtr<IMFSample> outputSample;
            HRCHECK(MFCreateSample(&outputSample));
            MFT_OUTPUT_DATA_BUFFER outputBuffer{};
            outputBuffer.pSample = outputSample;

            if (sampleSize)
            {
                // now we know the size so we can (and must) allocate the MF output buffer
                CComPtr<IMFMediaBuffer> outputBuffer;
                HRCHECK(MFCreateMemoryBuffer(sampleSize, &outputBuffer));
                HRCHECK(outputSample->AddBuffer(outputBuffer));
            } // else just continue to process

            DWORD status = 0;
            auto hr = decoder->ProcessOutput(0, 1, &outputBuffer, &status);
            if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) // just go on
            {
                if (!read) // file is all read
                    break;

                continue;
            }

            // https://learn.microsoft.com/en-us/windows/win32/medfound/handling-stream-changes
            if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
            {
                // get (and set) NV12 output type (could be I420, IYUV, YUY2, YV12)
                HRCHECK(SetOutputType(decoder, MFVideoFormat_NV12));

                // now get the sample size
                CComPtr<IMFMediaType> type;
                HRCHECK(decoder->GetOutputCurrentType(0, &type));
                HRCHECK(type->GetUINT32(MF_MT_SAMPLE_SIZE, &sampleSize));
                continue;
            }
            HRCHECK(hr);

            LONGLONG time, duration;
            HRCHECK(outputSample->GetSampleTime(&time));
            HRCHECK(outputSample->GetSampleDuration(&duration));
            wprintf(L"Sample time: %I64u ms duration: %I64u ms\n", time / 10000, duration / 10000);
        } while (true);

        // close file
        CloseHandle(file);
        HRCHECK(MFShutdown());
    }
    CoUninitialize();
    return 0;
}

Полный проект доступен здесь https://github.com/smourier/MFDecodeH264

спасибо, я делаю как ваш код. но нет правильного изображения.

user666 20.02.2024 07:57

-1. Когда я впервые создаю данные IMFSample и Lock 5 МБ, все идет хорошо. -2.и жду 5(или других) секунд и отправляю еще один пакет данных. все идет не так. -3. Я использую VideoProcessor для обработки данных NV12 в RGB. это правильно? какой способ вы предлагаете мне обрабатывать данные NV12? большое спасибо !!!

user666 20.02.2024 08:02

Использование видеопроцессора для преобразования NV12 в RGB — это нормально, но в остальном я не могу сказать без какого-либо воспроизводящего кода.

Simon Mourier 20.02.2024 08:20

Спасибо . и последний вопрос: может ли DirectX напрямую отображать yuv(nv12)? или мне нужно преобразовать его в RGB?

user666 21.02.2024 01:58

Нет, вам нужно будет конвертировать, используя Learn.microsoft.com/en-us/windows/win32/medfound/colorconver‌​ter или Learn.microsoft.com/en-us/windows/win32/medfound/ … например

Simon Mourier 21.02.2024 07:53

Другие вопросы по теме