Как использовать аппаратное ускоренное видео/декодирование H.264 с помощью DirectX 11 и Windows 7?

Я весь день разбираюсь и не очень далеко. Я нахожусь в окнах 7, используя directx 11. (Мой конечный вывод должен быть кадром видео на текстуре DX11) Я хочу декодировать некоторые очень большие видеофайлы H.264, а CPU (с помощью libav) не сокращает его.

Я просмотрел возможности libav с использованием DXVA2, но попал в дорожный блок, когда мне нужно создать IDirectXVideoDecoder, который может быть создан только с помощью интерфейса D3D9. (который у меня нет с DX11)

Всякий раз, когда я просматривал документацию DXVA, он не ссылается на DX11, было ли это удалено в DX10 или 11? (Не можете найти подтверждения об этом, ни где-нибудь, что говорит о том, что DXVA2 избыточен, возможно, что он превосходил DXVA-HD?)

Затем я просмотрел SDK для медиафайлов, поскольку это похоже на то, что я должен использовать для DX11... Но ни один из типов не существует в моих заголовках (Документы говорят просто включить, но это ничего не дает). Они также указывают минимум Windows 8, чтобы использовать его.

Я считаю, что для использования MF мне нужен SDK Windows 8, который теперь включает в себя все directx libs/headers.

Итак, это оставляет пробел с окнами 7... Возможно ли получить аппаратное ускоренное декодирование видео? и если да, какой API я должен использовать?

Ответ 1

D3D11 имеет видео api, которое в основном DXVA2 со слегка измененным интерфейсом выше. Вам нужно хорошо понимать потоки бит h.264, чтобы продолжить (действительно!). т.е. убедитесь, что у вас есть парсер h.264 под рукой, чтобы извлекать поля структур SPS и PPS и все фрагменты закодированного фрейма.

1) Получите экземпляр ID3D11VideoDevice из вашего ID3D11Device и ID3D11VideoContext из вашего непосредственного контекста устройства D3D11 ПРИМЕЧАНИЕ. В Win7 вам необходимо создать свое устройство с уровнем 9_3 для получения поддержки видео! (В Win8 он просто работает)

2) Создайте экземпляр ID3D11VideoDecoder для h.264 Используйте ID3D11VideoDevice:: GetVideoDecoderProfileCount, GetVideoDecoderProfile, CheckVideoDecodeRFormat... для итерации всех поддерживаемых профилей и поиска одного с GUID D3D11_DECODER_PROFILE_H264_VLD_NOFGT для h264 без filmgrain. В качестве OutputFormat ваш лучший выбор - DXGI_FORMAT_NV12.

3) Декодирование отдельных кадров см. Поддержка Direct3D 11 Декодирование видео в Media Foundation:

  • ID3D11VideoContext:: DecoderBeginFrame (декодер, outputView → декодированная структура кадра)
  • Буферы заполнения:
    • D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS
    • D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX
    • D3D11_VIDEO_DECODER_BUFFER_BITSTREAM
    • D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL

Буферы заполняются соответствующими структурами DXVA2 (см. dxva2.h) Полная спецификация DXVA2 находится здесь, вам нужно будет отобразить соответствующие поля h.264 sps/pps.

Смотрите:

Тогда:

  • ID3D11VideoContext:: SubmitBuffers для фиксации всех заполненных буферов
  • ID3D11VideoContext:: DecoderEndFrame для завершения текущего кадра

3) Буфер D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS также содержит информацию обо всех ссылках на фреймы/поверхность - вам нужно управлять ими самостоятельно, то есть убедиться, что поверхности/текстуры доступны для GPU!

Это довольно сложно, проверьте ffmpeg и Media Player Classic, они имеют поддержку DXVA2 (хотя и не через DX11).

4) Преобразование из NV12 в RGB (A), некоторые графические процессоры (уровни функций D3D11) позволяют использовать NV12 в качестве шейдерного ввода, а некоторые нет. В случае, если невозможно напрямую использовать NV12, посмотрите интерфейсы D3D11VideoProcessor, которые поддерживают преобразование NV12/YUV420- > RGB для всех графических процессоров с поддержкой D3D11.

Преобразование может быть выполнено в коде следующим образом:

// Setup ID3D11Video*
ID3D11VideoProcessor * d3dVideoProc = ...;
ID3D11VideoDevice    * d3dVideoDevice = ...;
ID3D11VideoProcessorEnumerator * d3dVideoProcEnum = ...;


ID3D11Texture2D * srcTextureNV12Fmt = ...;
ID3D11Texture2D * dstTextureRGBFmt = ...;

// Use Video Processor

// Create views for VideoProc In/Output
ID3D11VideoProcessorInputView * videoProcInputView;
ID3D11VideoProcessorOutputView * videoProcOutputView;

{

    D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inputViewDesc = { 0 };
    inputViewDesc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
    inputViewDesc.Texture2D.ArraySlice = arraySliceIdx;
    inputViewDesc.Texture2D.MipSlice = 0;
    hr = d3dVideoDevice->CreateVideoProcessorInputView(srcTextureNV12Fmt, d3dVideoProcEnum, &inputViewDesc, &videoProcInputView);
}


{
    D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputViewDesc = { D3D11_VPOV_DIMENSION_TEXTURE2D };
    outputViewDesc.Texture2D.MipSlice = 0;
    hr = d3dVideoDevice->CreateVideoProcessorOutputView(dstTextureRGBFmt, d3dVideoProcEnum, &outputViewDesc, &videoProcOutputView);
}


// Setup streams
D3D11_VIDEO_PROCESSOR_STREAM streams = { 0 };
streams.Enable = TRUE;
streams.pInputSurface = videoProcInputView.get();

RECT srcRect = { /* source rectangle in pixels*/ };
RECT dstRect = { /* destination rectangle in pixels*/ };

// Perform VideoProc Blit Operation (with color conversion)
hr = videoCtx_->VideoProcessorBlt(d3dVideoProc, videoProcOutputView.get(), 0, 1, &streams);

Ответ 2

В качестве продолжения я в настоящее время использую MediaFoundation с окнами 7,8 и 10, с DirectX (или просто Windows SDK в случае 8 +)

Он поддерживает гораздо меньше форматов (или, точнее, уровней разрешений/профилей), и в настоящее время я не совсем уверен, использует ли он аппаратное ускорение или нет...

Но этот API совместим, что было исходным запросом