基於FFmpeg的Dxva2硬解碼及Direct3D顯示(五)


解碼及顯示

解碼

  1. 循環讀取視頻幀

    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);
    
  2. 解碼

    兩個重要的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);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM