基於FFmpeg的Dxva2硬解碼及Direct3D顯示(五)
阿新 • • 發佈:2019-01-28
模板 顏色 etc ddl oid library device col 讀取
目錄
- 解碼及顯示
- 解碼
- 顯示
- 資源清理
解碼及顯示
解碼
循環讀取視頻幀
AVPacket packet = { 0 }; while (av_read_frame(m_pFmtCtx, &packet) >= 0) { if (m_videoIndex == packet.stream_index) { Decode(m_pDecoderCtx, &packet); av_packet_unref(&packet); } } // 緩沖中的可能還有數據,所以需要將剩下的數據一並解碼 packet.data = NULL; packet.size = 0; Decode(m_pDecoderCtx, &packet); av_packet_unref(&packet);
解碼
兩個重要的FFmpeg接口:
avcodec_send_packet,發送一個包給解碼器;
avcodec_receive_frame,從解碼器取回解碼後的數據。
void Decode(AVCodecContext * pDecodeCtx, AVPacket * pPacket) { if (avcodec_send_packet(pDecodeCtx, pPacket) < 0) { return; } while (TRUE) { if (avcodec_receive_frame(pDecodeCtx, m_pFrame) != 0) { break; } DisplayVideo(m_pFrame); } }
顯示
關於D3D顯示的大概步驟是解碼數據放在緩沖區,也就是這裏離屏的概念,然後將離屏數據拷貝到後臺緩沖表面,後臺表面和前臺表面不停的交替實現顯示。
// 離屏 LPDIRECT3DSURFACE9 surface = (LPDIRECT3DSURFACE9)pFrame->data[3]; // D3DCLEAR_TARGET 清除要渲染目標(幀緩存)的顏色為D3DCOLOR_XRGB(0, 0, 0)的值 // D3DCLEAR_ZBUFFER 清除深度緩沖(確定像素遮擋關系)的值為1.0f // D3DCLEAR_STENCIL 清除模板緩沖區(用於特效)為0 // 此時1.0f和0均會被忽略 m_pD3d9Dev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); m_pD3d9Dev->BeginScene(); IDirect3DSurface9 * pBackBuffer = nullptr; if (pBackBuffer) { pBackBuffer->Release(); pBackBuffer = NULL; } // 獲取第1個交換鏈上的第一個後臺緩沖區的地址 m_pD3d9Dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); GetClientRect(m_hWnd, &m_renderRect); // 將待顯示的數據拷貝到後臺緩沖區,通過線性插值的方式顯示到指定窗口區域 m_pD3d9Dev->StretchRect(surface, NULL, pBackBuffer, &m_renderRect, D3DTEXF_LINEAR); m_pD3d9Dev->EndScene(); m_pD3d9Dev->Present(NULL, NULL, NULL, NULL); #if !CAMERA Sleep(1000 / m_frameRate); #endif
資源清理
if (m_hD3dDll)
{
FreeLibrary(m_hD3dDll);
m_hD3dDll = nullptr;
}
if (m_hDxva2Dll)
{
FreeLibrary(m_hDxva2Dll);
m_hDxva2Dll = nullptr;
}
if (m_pD3d9Dev)
{
m_pD3d9Dev->Release();
}
if (m_pD3d9DevMgr && m_hDev != INVALID_HANDLE_VALUE)
{
m_pD3d9DevMgr->CloseDeviceHandle(m_hDev);
}
if (m_pDecoderService)
{
m_pDecoderService->Release();
}
if (m_pD3d9DevMgr)
{
m_pD3d9DevMgr->Release();
}
// 釋放緩沖區
if (m_pSurface)
{
for (uint32_t i = 0; i < m_surfaceNums; i++)
{
if (m_pSurface[i])
m_pSurface[i]->Release();
}
}
// 釋放DirectX解碼器
if (m_pDecoder)
{
m_pDecoder->Release();
m_pDecoder = nullptr;
}
av_freep(&pCodecCtx->hwaccel_context);
基於FFmpeg的Dxva2硬解碼及Direct3D顯示(五)