15

I've been researching all day and not gotten very far. I'm on windows 7, using directx 11. (My final output is to be a frame of video onto a DX11 texture) I want to decode some very large H.264 video files, and the CPU (using libav) doesn't cut it.

I've looked at the hwaccel capabilities of libav using DXVA2, but hit a road block when I need to create a IDirectXVideoDecoder, which can only be created with a D3D9 interface. (which I don't have using DX11)

Whenever I've looked up DXVA documentation, it doesn't reference DX11, was this removed in DX10 or 11? (Can't find any confirmation of this, nor anywhere that says DXVA2 is redundant, possibly that it's been superceeded by DXVA-HD?)

Then I've looked into the media foundation SDK as that looks like what I'm supposed to use for DX11... But none of the types exist in my headers (The docs say to just include <d3d11.h>, but this yields nothing). They also specify a minimum of windows 8 to use it.

I believe to use MF I need the windows 8 SDK, which now includes all the directx libs/headers.

So this leaves a gap with windows 7... Is it possible to get hardware accelerated video decoding? and if so, which API am I supposed to be using?

Edit: As another follow up, my MediaFoundation (and AVF, android, magic leap, etc etc) implementation is in my open source project https://github.com/NewChromantics/PopH264 Edit2: But I don't know if it supports win7 :)

Soylent Graham
  • 847
  • 1
  • 12
  • 22

3 Answers3

24

D3D11 features a video api which is basically DXVA2 with a slightly altered interface above. You need a good understand of h.264 bitstreams to proceed (really!). i.e. make sure you have a h.264 parser at hand to extract fields of the SPS and PPS structures and all slices of an encoded frame.

1) Obtain ID3D11VideoDevice instance from your ID3D11Device, and ID3D11VideoContext from your immediate D3D11 device context NOTE: On Win7, you have to create your device with feature level 9_3 to get video support! (In Win8 it just works)

2) Create a ID3D11VideoDecoder instance for h.264 Use ID3D11VideoDevice::GetVideoDecoderProfileCount, GetVideoDecoderProfile, CheckVideoDecodeRFormat... to iterate through all supported profiles, and find one with GUID D3D11_DECODER_PROFILE_H264_VLD_NOFGT for h264 without filmgrain. As OutputFormat your best bet is DXGI_FORMAT_NV12.

3) Decoding of the individual frames see Supporting Direct3D 11 Video Decoding in Media Foundation:

  • ID3D11VideoContext::DecoderBeginFrame( decoder, outputView -> decoded frame texture )
  • 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

The buffers are filled with the corresponding DXVA2 structures (see dxva2.h) The full DXVA2 spec is here, you'll need it to map the h.264 sps/pps fields accordingly.

See:

Then:

  • ID3D11VideoContext::SubmitBuffers to commit all filled buffers
  • ID3D11VideoContext::DecoderEndFrame to finish the current frame

3) D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS buffer also contains info on all references frames/surface - you need to manage them yourself, i.e. make sure the surfaces/textures are available to the GPU!

It's quite complicated, check ffmpeg and Media Player Classic, they both have DXVA2 (though not via DX11) support.

4) Convert from NV12 to RGB(A), some GPUs (D3D11 feature levels) allow to use NV12 as shader input, some don't. In case it's not possible to use NV12 directly, have a look at the D3D11VideoProcessor interfaces which feature NV12/YUV420->RGB conversion for all GPUs with D3D11 support.

The conversion could be performed in code like this:

// 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);
Roman R.
  • 68,205
  • 6
  • 94
  • 158
youaresoomean
  • 296
  • 3
  • 9
  • Thanks, a comment on the page in 3) suggests it's win8 only (which is what I believed). Now at least I know what I should/could be using, I'll try it and see if it runs on win7. I've already written a [human readable] h264 parser for when I was trying to make an OpenCL decoder, so that's the first bit done :) As mentioned in OP ffmpeg is not an option as it has no DX11 support. – Soylent Graham Jul 09 '14 at 15:43
  • I may also give up on this and just try NVidia and AMD's video decoding options, I was just hoping for a generic (directx) solution originally. – Soylent Graham Jul 09 '14 at 15:44
  • 1
    We actively use it on Win7, the only requirement is that Windows 7 Platform Update is installed. FFMPEG was more intended as a source on how to fill the DXVA2 structs :) – youaresoomean Jul 10 '14 at 08:45
  • Hello, I would like to ask you what exactly in D3D11 converts NV12/YUV420 to RGB I was trying to find anythink about that on MSDN but no sucess. Thank you very much for your answer youaresoomean – Teamol Jul 30 '15 at 13:39
  • @Teamol I added sample code on how to do the conversion to the original answer. – youaresoomean Jul 31 '15 at 06:32
  • I first found your comment about two weeks ago. Since then I've been trying to implement what you suggest, I analyzed and compared my code with the FFmpeg Chromium, MPC-HC and Kodi. But I still get an error from SubmitBuffers (0x887601E0, which is DDERR_TOOBIGSIZE). All these open source projects I mentioned are beasts to compile, so I can't really run them under a debugger. Do you know of a simpler open source codebase I could use as a working example? – Doub Nov 08 '17 at 00:52
  • I do not understand why this is the best answer, when these are just lies. ID3D11VideoDevice is not available on Windows7, the original question. – mofo77 Jan 30 '20 at 22:18
2

As a follow up, I am currently using MediaFoundation with windows 7,8 and 10, with directx(or just Windows SDK in the case of 8+)

It supports far fewer formats (or rather, resolutions/profile levels), and currently I'm not exactly sure if it's using hardware acceleration or not...

But this API is compatible, which was the original query

Soylent Graham
  • 847
  • 1
  • 12
  • 22
1

How do I use Hardware accelerated video/H.264 decoding with directx 11 and windows 7?

You can't.

ID3D11VideoDevice is only avalaible for windows 8 ID3D11VideoDevice.

ID3D11VideoDecoder is only avalaible for windows 8 ID3D11VideoDecoder.

On windows 7, you just can use directx 9 for Hardware accelerated video/H.264. Thanks Microsoft. The good new, IDirect3D9Ex works... yeah... The other good news, GPU decoding performance is very good using DirectX9 on Windows 7.

Here is a source code for windows 7 and DirectX 9 : mofo7777, under H264Dxva2Decoder project.

mofo77
  • 1,447
  • 9
  • 17