STDMETHODIMP CDecDXVA2::InitDecoder(AVCodecID codec, const CMediaType *pmt) { HRESULT hr = S_OK; DbgLog((LOG_TRACE, 10, L"CDecDXVA2::InitDecoder(): Initializing DXVA2 decoder")); DestroyDecoder(false); m_DisplayDelay = DXVA2_QUEUE_SURFACES; // Reduce display delay for DVD decoding for lower decode latency if (m_pCallback->GetDecodeFlags() & LAV_VIDEO_DEC_FLAG_DVD) m_DisplayDelay /= 2; // If we have a DXVA Decoder, check if its capable // If we don't have one yet, it may be handed to us later, and compat is checked at that point GUID input = GUID_NULL; if (m_pDXVADecoderService) { D3DFORMAT output; hr = FindVideoServiceConversion(codec, &input, &output); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> No decoder device available that can decode codec '%S' to NV12", avcodec_get_name(codec))); return E_FAIL; } } m_bFailHWDecode = FALSE; DbgLog((LOG_TRACE, 10, L"-> Creation of DXVA2 decoder successfull, initializing ffmpeg")); hr = CDecAvcodec::InitDecoder(codec, pmt); if (FAILED(hr)) { return hr; } if (((codec == AV_CODEC_ID_H264 || codec == AV_CODEC_ID_MPEG2VIDEO) && m_pAVCtx->pix_fmt != AV_PIX_FMT_YUV420P && m_pAVCtx->pix_fmt != AV_PIX_FMT_YUVJ420P && m_pAVCtx->pix_fmt != AV_PIX_FMT_DXVA2_VLD && m_pAVCtx->pix_fmt != AV_PIX_FMT_NONE) || (codec == AV_CODEC_ID_H264 && m_pAVCtx->profile != FF_PROFILE_UNKNOWN && !H264_CHECK_PROFILE(m_pAVCtx->profile))) { DbgLog((LOG_TRACE, 10, L"-> Incompatible profile detected, falling back to software decoding")); return E_FAIL; } m_dwSurfaceWidth = FFALIGN(m_pAVCtx->coded_width, 16); m_dwSurfaceHeight = FFALIGN(m_pAVCtx->coded_height, 16); if (FAILED(CheckHWCompatConditions(input))) { return E_FAIL; } return S_OK; }
/** * Called from both native and non-native mode * Initialize all the common DXVA2 interfaces and device handles */ HRESULT CDecDXVA2::SetD3DDeviceManager(IDirect3DDeviceManager9 *pDevManager) { HRESULT hr = S_OK; ASSERT(pDevManager); m_pD3DDevMngr = pDevManager; RetrieveVendorId(pDevManager); // This should really be null here, but since we're overwriting it, make sure its actually released SafeRelease(&m_pDXVADecoderService); hr = CreateDXVAVideoService(m_pD3DDevMngr, &m_pDXVADecoderService); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> Creation of DXVA2 Decoder Service failed with hr: %X", hr)); goto done; } // If the decoder was initialized already, check if we can use this device if (m_pAVCtx) { DbgLog((LOG_TRACE, 10, L"-> Checking hardware for format support...")); GUID input = GUID_NULL; D3DFORMAT output; hr = FindVideoServiceConversion(m_pAVCtx->codec_id, &input, &output); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> No decoder device available that can decode codec '%S' to NV12", avcodec_get_name(m_pAVCtx->codec_id))); goto done; } if (FAILED(CheckHWCompatConditions(input))) { hr = E_FAIL; goto done; } DXVA2_VideoDesc desc; ZeroMemory(&desc, sizeof(desc)); desc.SampleWidth = m_pAVCtx->coded_width; desc.SampleHeight = m_pAVCtx->coded_height; desc.Format = output; DXVA2_ConfigPictureDecode config; hr = FindDecoderConfiguration(input, &desc, &config); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> No decoder configuration available for codec '%S'", avcodec_get_name(m_pAVCtx->codec_id))); goto done; } LPDIRECT3DSURFACE9 pSurfaces[DXVA2_MAX_SURFACES] = {0}; UINT numSurfaces = max(config.ConfigMinRenderTargetBuffCount, 1); hr = m_pDXVADecoderService->CreateSurface(m_dwSurfaceWidth, m_dwSurfaceHeight, numSurfaces, output, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, pSurfaces, NULL); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> Creation of surfaces failed with hr: %X", hr)); goto done; } IDirectXVideoDecoder *decoder = NULL; hr = m_pDXVADecoderService->CreateVideoDecoder(input, &desc, &config, pSurfaces, numSurfaces, &decoder); // Release resources, decoder and surfaces SafeRelease(&decoder); int i = DXVA2_MAX_SURFACES; while (i > 0) { SafeRelease(&pSurfaces[--i]); } if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> Creation of decoder failed with hr: %X", hr)); goto done; } } done: return hr; }
STDMETHODIMP CDecDXVA2::InitDecoder(AVCodecID codec, const CMediaType *pmt) { HRESULT hr = S_OK; DbgLog((LOG_TRACE, 10, L"CDecDXVA2::InitDecoder(): Initializing DXVA2 decoder")); // Hack-ish check to avoid re-creating the full decoder when only the aspect ratio changes. // Re-creating the DXVA2 decoder can lead to issues like missing frames or a several second delay if (m_pDecoder) { CMediaType mediaTypeCheck = m_MediaType; if (mediaTypeCheck.formattype == FORMAT_VideoInfo2 && pmt->formattype == FORMAT_VideoInfo2) { VIDEOINFOHEADER2 *vih2Old = (VIDEOINFOHEADER2 *)mediaTypeCheck.Format(); VIDEOINFOHEADER2 *vih2New = (VIDEOINFOHEADER2 *)pmt->Format(); vih2Old->dwPictAspectRatioX = vih2New->dwPictAspectRatioX; vih2Old->dwPictAspectRatioY = vih2New->dwPictAspectRatioY; if (mediaTypeCheck == *pmt) { DbgLog((LOG_TRACE, 10, L"-> Skipping re-init because media type is unchanged.")); m_MediaType = *pmt; return S_OK; } } } DestroyDecoder(false); m_DisplayDelay = DXVA2_QUEUE_SURFACES; // Intel GPUs don't like the display and performance goes way down, so disable it. if (m_dwVendorId == VEND_ID_INTEL) m_DisplayDelay = 0; // Reduce display delay for DVD decoding for lower decode latency if (m_pCallback->GetDecodeFlags() & LAV_VIDEO_DEC_FLAG_DVD) m_DisplayDelay /= 2; // If we have a DXVA Decoder, check if its capable // If we don't have one yet, it may be handed to us later, and compat is checked at that point GUID input = GUID_NULL; if (m_pDXVADecoderService) { D3DFORMAT output; hr = FindVideoServiceConversion(codec, &input, &output); if (FAILED(hr)) { DbgLog((LOG_TRACE, 10, L"-> No decoder device available that can decode codec '%S' to NV12", avcodec_get_name(codec))); return E_FAIL; } } m_bFailHWDecode = FALSE; DbgLog((LOG_TRACE, 10, L"-> Creation of DXVA2 decoder successfull, initializing ffmpeg")); hr = CDecAvcodec::InitDecoder(codec, pmt); if (FAILED(hr)) { return hr; } if (((codec == AV_CODEC_ID_H264 || codec == AV_CODEC_ID_MPEG2VIDEO || codec == AV_CODEC_ID_HEVC) && m_pAVCtx->pix_fmt != AV_PIX_FMT_YUV420P && m_pAVCtx->pix_fmt != AV_PIX_FMT_YUVJ420P && m_pAVCtx->pix_fmt != AV_PIX_FMT_DXVA2_VLD && m_pAVCtx->pix_fmt != AV_PIX_FMT_NONE) || (codec == AV_CODEC_ID_H264 && m_pAVCtx->profile != FF_PROFILE_UNKNOWN && !H264_CHECK_PROFILE(m_pAVCtx->profile)) || ((codec == AV_CODEC_ID_WMV3 || codec == AV_CODEC_ID_VC1) && m_pAVCtx->profile == FF_PROFILE_VC1_COMPLEX) || (codec == AV_CODEC_ID_HEVC && !HEVC_CHECK_PROFILE(m_pAVCtx->profile))) { DbgLog((LOG_TRACE, 10, L"-> Incompatible profile detected, falling back to software decoding")); return E_FAIL; } m_dwSurfaceWidth = GetAlignedDimension(m_pAVCtx->coded_width); m_dwSurfaceHeight = GetAlignedDimension(m_pAVCtx->coded_height); if (FAILED(CheckHWCompatConditions(input))) { return E_FAIL; } m_MediaType = *pmt; return S_OK; }