STDMETHODIMP CDecDXVA2::Flush() { CDecAvcodec::Flush(); FlushDisplayQueue(FALSE); #ifdef DEBUG int used = 0; for (int i = 0; i < m_NumSurfaces; i++) { d3d_surface_t *s = &m_pSurfaces[i]; if (s->used) { used++; } } if (used > 0) { DbgLog((LOG_TRACE, 10, L"WARNING! %d frames still in use after flush", used)); } #endif // This solves an issue with corruption after seeks on AMD systems, see JIRA LAV-5 if (m_dwVendorId == VEND_ID_ATI && m_nCodecId == AV_CODEC_ID_H264 && m_pDecoder) { if (m_bNative && m_pDXVA2Allocator) { // The allocator needs to be locked because flushes can happen async to other graph events // and in the worst case the allocator is decommited while we're using it. CAutoLock allocatorLock(m_pDXVA2Allocator); if (m_pDXVA2Allocator->IsCommited()) CreateDXVA2Decoder(m_NumSurfaces, m_pRawSurface); } else if(!m_bNative) CreateDXVA2Decoder(); } return S_OK; }
STDMETHODIMP CDecDXVA2::Flush() { CDecAvcodec::Flush(); FlushDisplayQueue(FALSE); #ifdef DEBUG int used = 0; for (int i = 0; i < m_NumSurfaces; i++) { d3d_surface_t *s = &m_pSurfaces[i]; if (s->used) { used++; } } if (used > 0) { DbgLog((LOG_TRACE, 10, L"WARNING! %d frames still in use after flush", used)); } #endif // This solves an issue with corruption after seeks on AMD systems, see JIRA LAV-5 if (m_dwVendorId == VEND_ID_ATI && m_nCodecId == AV_CODEC_ID_H264 && m_pDecoder) { if (m_bNative && m_pDXVA2Allocator && m_pDXVA2Allocator->IsCommited()) CreateDXVA2Decoder(m_NumSurfaces, m_pRawSurface); else if(!m_bNative) CreateDXVA2Decoder(); } return S_OK; }
STDMETHODIMP CDecD3D11::ReInitD3D11Decoder(AVCodecContext *c) { HRESULT hr = S_OK; // Don't allow decoder creation during first init if (m_bInInit) return S_FALSE; // sanity check that we have a device if (m_pDevCtx == nullptr) return E_FAIL; // we need an allocator at this point if (m_bReadBackFallback == false && m_pAllocator == nullptr) return E_FAIL; if (m_pDecoder == nullptr || m_dwSurfaceWidth != dxva_align_dimensions(c->codec_id, c->coded_width) || m_dwSurfaceHeight != dxva_align_dimensions(c->codec_id, c->coded_height) || m_DecodePixelFormat != c->sw_pix_fmt) { AVD3D11VADeviceContext *pDeviceContext = (AVD3D11VADeviceContext *)((AVHWDeviceContext *)m_pDevCtx->data)->hwctx; DbgLog((LOG_TRACE, 10, L"No D3D11 Decoder or image dimensions changed -> Re-Allocating resources")); // if we're not in readback mode, we need to flush all the frames if (m_bReadBackFallback == false) avcodec_flush_buffers(c); else FlushDisplayQueue(TRUE); pDeviceContext->lock(pDeviceContext->lock_ctx); hr = CreateD3D11Decoder(); pDeviceContext->unlock(pDeviceContext->lock_ctx); if (FAILED(hr)) return hr; // Update the frames context in the allocator if (m_bReadBackFallback == false) { // decommit the allocator m_pAllocator->Decommit(); // verify we were able to decommit all its resources if (m_pAllocator->DecommitInProgress()) { DbgLog((LOG_TRACE, 10, L"WARNING! D3D11 Allocator is still busy, trying to flush downstream")); m_pCallback->ReleaseAllDXVAResources(); m_pCallback->GetOutputPin()->GetConnected()->BeginFlush(); m_pCallback->GetOutputPin()->GetConnected()->EndFlush(); if (m_pAllocator->DecommitInProgress()) { DbgLog((LOG_TRACE, 10, L"WARNING! Flush had no effect, decommit of the allocator still not complete")); } else { DbgLog((LOG_TRACE, 10, L"Flush was successfull, decommit completed!")); } } // re-commit it to update its frame reference m_pAllocator->Commit(); } } return S_OK; }
HRESULT CDecD3D11::HandleDXVA2Frame(LAVFrame *pFrame) { ASSERT(pFrame->format == LAVPixFmt_D3D11); if (pFrame->flags & LAV_FRAME_FLAG_FLUSH) { if (m_bReadBackFallback) { FlushDisplayQueue(TRUE); } DeliverD3D11Frame(pFrame); return S_OK; } if (m_bReadBackFallback == false || m_DisplayDelay == 0) { DeliverD3D11Frame(pFrame); } else { LAVFrame *pQueuedFrame = m_FrameQueue[m_FrameQueuePosition]; m_FrameQueue[m_FrameQueuePosition] = pFrame; m_FrameQueuePosition = (m_FrameQueuePosition + 1) % m_DisplayDelay; if (pQueuedFrame) { DeliverD3D11Frame(pQueuedFrame); } } return S_OK; }
STDMETHODIMP CDecDXVA2::FlushFromAllocator() { if (m_pAVCtx) avcodec_flush_buffers(m_pAVCtx); FlushDisplayQueue(FALSE); return S_OK; }
STDMETHODIMP CDecDXVA2::EndOfStream() { CDecAvcodec::EndOfStream(); // Flush display queue FlushDisplayQueue(TRUE); return S_OK; }
STDMETHODIMP CDecD3D11::Flush() { CDecAvcodec::Flush(); // Flush display queue FlushDisplayQueue(FALSE); return S_OK; }
HRESULT CDecDXVA2::ReInitDXVA2Decoder(AVCodecContext *c) { HRESULT hr = S_OK; // Don't allow decoder creation during first init if (m_bInInit) return S_FALSE; if (!m_pDecoder || GetAlignedDimension(c->coded_width) != m_dwSurfaceWidth || GetAlignedDimension(c->coded_height) != m_dwSurfaceHeight) { DbgLog((LOG_TRACE, 10, L"No DXVA2 Decoder or image dimensions changed -> Re-Allocating resources")); if (!m_pDecoder && m_bNative && !m_pDXVA2Allocator) { ASSERT(0); hr = E_FAIL; } else if (m_bNative) { avcodec_flush_buffers(c); m_dwSurfaceWidth = GetAlignedDimension(c->coded_width); m_dwSurfaceHeight = GetAlignedDimension(c->coded_height); // Re-Commit the allocator (creates surfaces and new decoder) hr = m_pDXVA2Allocator->Decommit(); if (m_pDXVA2Allocator->DecommitInProgress()) { DbgLog((LOG_TRACE, 10, L"WARNING! DXVA2 Allocator is still busy, trying to flush downstream")); m_pCallback->ReleaseAllDXVAResources(); m_pCallback->GetOutputPin()->GetConnected()->BeginFlush(); m_pCallback->GetOutputPin()->GetConnected()->EndFlush(); if (m_pDXVA2Allocator->DecommitInProgress()) { DbgLog((LOG_TRACE, 10, L"WARNING! Flush had no effect, decommit of the allocator still not complete")); } else { DbgLog((LOG_TRACE, 10, L"Flush was successfull, decommit completed!")); } } hr = m_pDXVA2Allocator->Commit(); } else if (!m_bNative) { if (SyncToProcessThread() == S_FALSE) FlushDisplayQueue(TRUE); hr = CreateDXVA2Decoder(); } } return hr; }
HRESULT CDecDXVA2::HandleDXVA2Frame(LAVFrame *pFrame) { if (pFrame->flags & LAV_FRAME_FLAG_FLUSH) { if (!m_bNative) { FlushDisplayQueue(TRUE); } Deliver(pFrame); return S_OK; } if (m_bNative) { DeliverDXVA2Frame(pFrame); } else { LAVFrame *pQueuedFrame = m_FrameQueue[m_FrameQueuePosition]; m_FrameQueue[m_FrameQueuePosition] = pFrame; m_FrameQueuePosition = (m_FrameQueuePosition + 1) % m_DisplayDelay; if (pQueuedFrame) { DeliverDXVA2Frame(pQueuedFrame); } } return S_OK; }