HRESULT CDecDXVA2::AdditionaDecoderInit() { /* Create ffmpeg dxva_context, but only fill it if we have a decoder already. */ dxva_context *ctx = (dxva_context *)av_mallocz(sizeof(dxva_context)); if (m_pDecoder) { FillHWContext(ctx); } m_pAVCtx->thread_count = 1; m_pAVCtx->strict_std_compliance = FF_COMPLIANCE_STRICT; m_pAVCtx->hwaccel_context = ctx; m_pAVCtx->get_format = get_dxva2_format; m_pAVCtx->get_buffer2 = get_dxva2_buffer; m_pAVCtx->opaque = this; m_pAVCtx->slice_flags |= SLICE_FLAG_ALLOW_FIELD; return S_OK; }
HRESULT CDecD3D11::AdditionaDecoderInit() { AVD3D11VAContext *ctx = av_d3d11va_alloc_context(); if (m_pDecoder) { FillHWContext(ctx); } m_pAVCtx->thread_count = 1; m_pAVCtx->hwaccel_context = ctx; m_pAVCtx->get_format = get_d3d11_format; m_pAVCtx->get_buffer2 = get_d3d11_buffer; m_pAVCtx->opaque = this; m_pAVCtx->slice_flags |= SLICE_FLAG_ALLOW_FIELD; // disable error concealment in hwaccel mode, it doesn't work either way m_pAVCtx->error_concealment = 0; av_opt_set_int(m_pAVCtx, "enable_er", 0, AV_OPT_SEARCH_CHILDREN); return S_OK; }
HRESULT CDecDXVA2::CreateDXVA2Decoder(int nSurfaces, IDirect3DSurface9 **ppSurfaces) { DbgLog((LOG_TRACE, 10, L"-> CDecDXVA2::CreateDXVA2Decoder")); HRESULT hr = S_OK; LPDIRECT3DSURFACE9 pSurfaces[DXVA2_MAX_SURFACES]; if (!m_pDXVADecoderService) return E_FAIL; DestroyDecoder(false, true); GUID input = GUID_NULL; D3DFORMAT output; FindVideoServiceConversion(m_pAVCtx->codec_id, &input, &output); if (!nSurfaces) { m_dwSurfaceWidth = GetAlignedDimension(m_pAVCtx->coded_width); m_dwSurfaceHeight = GetAlignedDimension(m_pAVCtx->coded_height); m_NumSurfaces = GetBufferCount(); hr = m_pDXVADecoderService->CreateSurface(m_dwSurfaceWidth, m_dwSurfaceHeight, m_NumSurfaces - 1, output, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, pSurfaces, nullptr); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> Creation of surfaces failed with hr: %X", hr)); m_NumSurfaces = 0; return E_FAIL; } ppSurfaces = pSurfaces; } else { m_NumSurfaces = nSurfaces; for (int i = 0; i < m_NumSurfaces; i++) { ppSurfaces[i]->AddRef(); } } if (m_NumSurfaces <= 0) { DbgLog((LOG_TRACE, 10, L"-> No surfaces? No good!")); return E_FAIL; } // get the device, for ColorFill() to init the surfaces in black IDirect3DDevice9 *pDev = nullptr; ppSurfaces[0]->GetDevice(&pDev); for (int i = 0; i < m_NumSurfaces; i++) { m_pSurfaces[i].index = i; m_pSurfaces[i].d3d = ppSurfaces[i]; m_pSurfaces[i].age = 0; m_pSurfaces[i].used = false; // fill the surface in black, to avoid the "green screen" in case the first frame fails to decode. if (pDev) pDev->ColorFill(ppSurfaces[i], NULL, D3DCOLOR_XYUV(0, 128, 128)); } // and done with the device SafeRelease(&pDev); DbgLog((LOG_TRACE, 10, L"-> Successfully created %d surfaces (%dx%d)", m_NumSurfaces, m_dwSurfaceWidth, m_dwSurfaceHeight)); DXVA2_VideoDesc desc; ZeroMemory(&desc, sizeof(desc)); desc.SampleWidth = m_pAVCtx->coded_width; desc.SampleHeight = m_pAVCtx->coded_height; desc.Format = output; hr = FindDecoderConfiguration(input, &desc, &m_DXVAVideoDecoderConfig); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> FindDecoderConfiguration failed with hr: %X", hr)); return hr; } IDirectXVideoDecoder *decoder = nullptr; hr = m_pDXVADecoderService->CreateVideoDecoder(input, &desc, &m_DXVAVideoDecoderConfig, ppSurfaces, m_NumSurfaces, &decoder); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> CreateVideoDecoder failed with hr: %X", hr)); return E_FAIL; } m_pDecoder = decoder; m_guidDecoderDevice = input; /* fill hwaccel_context */ FillHWContext((dxva_context *)m_pAVCtx->hwaccel_context); memset(m_pRawSurface, 0, sizeof(m_pRawSurface)); for (int i = 0; i < m_NumSurfaces; i++) { m_pRawSurface[i] = m_pSurfaces[i].d3d; } return S_OK; }
STDMETHODIMP CDecD3D11::CreateD3D11Decoder() { HRESULT hr = S_OK; AVD3D11VADeviceContext *pDeviceContext = (AVD3D11VADeviceContext *)((AVHWDeviceContext *)m_pDevCtx->data)->hwctx; // release the old decoder, it needs to be re-created SafeRelease(&m_pDecoder); // find a decoder configuration GUID profileGUID = GUID_NULL; DXGI_FORMAT surface_format = d3d11va_map_sw_to_hw_format(m_pAVCtx->sw_pix_fmt); hr = FindVideoServiceConversion(m_pAVCtx->codec_id, m_pAVCtx->profile, surface_format, &profileGUID); if (FAILED(hr)) { DbgLog((LOG_ERROR, 10, L"-> No video service profile found")); return hr; } // get decoder configuration D3D11_VIDEO_DECODER_DESC desc = { 0 }; desc.Guid = profileGUID; desc.OutputFormat = surface_format; desc.SampleWidth = m_pAVCtx->coded_width; desc.SampleHeight = m_pAVCtx->coded_height; D3D11_VIDEO_DECODER_CONFIG decoder_config = { 0 }; hr = FindDecoderConfiguration(&desc, &decoder_config); if (FAILED(hr)) { DbgLog((LOG_ERROR, 10, L"-> No valid video decoder configuration found")); return hr; } m_DecoderConfig = decoder_config; // update surface properties m_dwSurfaceWidth = dxva_align_dimensions(m_pAVCtx->codec_id, m_pAVCtx->coded_width); m_dwSurfaceHeight = dxva_align_dimensions(m_pAVCtx->codec_id, m_pAVCtx->coded_height); m_DecodePixelFormat = m_pAVCtx->sw_pix_fmt; m_SurfaceFormat = surface_format; if (m_bReadBackFallback == false && m_pAllocator) { ALLOCATOR_PROPERTIES properties; hr = m_pAllocator->GetProperties(&properties); if (FAILED(hr)) return hr; m_dwSurfaceCount = properties.cBuffers; } else { m_dwSurfaceCount = GetBufferCount(); } // allocate a new frames context for the dimensions and format hr = AllocateFramesContext(m_dwSurfaceWidth, m_dwSurfaceHeight, m_DecodePixelFormat, m_dwSurfaceCount, &m_pFramesCtx); if (FAILED(hr)) { DbgLog((LOG_ERROR, 10, L"-> Error allocating frames context")); return hr; } // release any old output views and allocate memory for the new ones if (m_pOutputViews) { for (int i = 0; i < m_nOutputViews; i++) { SafeRelease(&m_pOutputViews[i]); } av_freep(&m_pOutputViews); } m_pOutputViews = (ID3D11VideoDecoderOutputView **)av_mallocz_array(m_dwSurfaceCount, sizeof(*m_pOutputViews)); m_nOutputViews = m_dwSurfaceCount; // allocate output views for the frames AVD3D11VAFramesContext *pFramesContext = (AVD3D11VAFramesContext *)((AVHWFramesContext *)m_pFramesCtx->data)->hwctx; for (int i = 0; i < m_nOutputViews; i++) { D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc = { 0 }; viewDesc.DecodeProfile = profileGUID; viewDesc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D; viewDesc.Texture2D.ArraySlice = i; hr = pDeviceContext->video_device->CreateVideoDecoderOutputView(pFramesContext->texture, &viewDesc, &m_pOutputViews[i]); if (FAILED(hr)) { DbgLog((LOG_ERROR, 10, L"-> Failed to create video decoder output views")); return E_FAIL; } } // create the decoder hr = pDeviceContext->video_device->CreateVideoDecoder(&desc, &decoder_config, &m_pDecoder); if (FAILED(hr)) { DbgLog((LOG_ERROR, 10, L"-> Failed to create video decoder object")); return E_FAIL; } FillHWContext((AVD3D11VAContext *)m_pAVCtx->hwaccel_context); return S_OK; }