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

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

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

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

Затем я заглянул в SDK media Foundation, так как это похоже на то, что я должен использовать для DX11 ... Но ни один из типов не существует в моих заголовках (в документах говорится, что нужно просто включить ‹d3d11.h›, но это ничего не дает). Они также указывают как минимум Windows 8 для его использования.

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

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

Изменить: В качестве еще одного продолжения моя реализация MediaFoundation (и AVF, android, magic leap и т.д.) находится в моем проекте с открытым исходным кодом https://github.com/NewChromantics/PopH264 Edit2: Но я не знаю, поддерживает ли он win7 :)


person Soylent Graham    schedule 07.11.2013    source источник


Ответы (3)


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_PROVLE_DECODER_PROVL_H264 для фильма. В качестве OutputFormat лучше всего использовать DXGI_FORMAT_NV12.

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

  • ID3D11VideoContext :: DecoderBeginFrame (декодер, outputView -> текстура декодированного кадра)
  • Fill buffers:
    • 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);
person youaresoomean    schedule 08.07.2014
comment
Спасибо, комментарий на странице в 3) предполагает, что это только win8 (я так считал). Теперь, по крайней мере, я знаю, что мне следует / можно использовать, я попробую и посмотрю, работает ли он на win7. Я уже написал [читаемый человеком] парсер h264, когда я пытался создать декодер OpenCL, так что это первый шаг, сделанный :) Как упоминалось в OP, ffmpeg не вариант, поскольку он не поддерживает DX11. - person Soylent Graham; 09.07.2014
comment
Я также могу отказаться от этого и просто попробовать варианты декодирования видео NVidia и AMD, изначально я просто надеялся на универсальное (directx) решение. - person Soylent Graham; 09.07.2014
comment
Мы активно используем его на Win7, единственное требование - установлено Windows 7 Platform Update. FFMPEG был больше задуман как источник того, как заполнить структуры DXVA2 :) - person youaresoomean; 10.07.2014
comment
Здравствуйте, я хотел бы спросить вас, что именно в D3D11 преобразует NV12 / YUV420 в RGB. Я пытался найти что-нибудь об этом на MSDN, но безуспешно. Большое спасибо за ваш ответ - person Teamol; 30.07.2015
comment
@Teamol Я добавил образец кода о том, как преобразовать исходный ответ. - person youaresoomean; 31.07.2015
comment
Я впервые нашел ваш комментарий около двух недель назад. С тех пор я пытался реализовать то, что вы предлагаете, я анализировал и сравнивал свой код с FFmpeg Chromium, MPC-HC и Kodi. Но я все еще получаю сообщение об ошибке от SubmitBuffers (0x887601E0, то есть DDERR_TOOBIGSIZE). Все эти проекты с открытым исходным кодом, о которых я упоминал, сложно компилировать, поэтому я не могу запускать их под отладчиком. Вы знаете более простую базу кода с открытым исходным кодом, которую я мог бы использовать в качестве рабочего примера? - person Doub; 08.11.2017
comment
Я не понимаю, почему это лучший ответ, когда это просто ложь. ID3D11VideoDevice недоступен в Windows7, исходный вопрос. - person mofo77; 31.01.2020

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

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

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

person Soylent Graham    schedule 06.01.2016