基于FFmpeg的Dxva2硬解码及Direct3D显示(五)

解码及显示

[TOC]

解码

  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);

转载于:https://www.cnblogs.com/huluwa508/p/10331525.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值