2019-04-04

2019-04-27  本文已影响0人  镜中月_7921

## 解码及显示

[TOC]

### 解码

1. 循环读取视频帧

  ```c++

  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显示的大概步骤是解码数据放在缓冲区,也就是这里离屏的概念,然后将离屏数据拷贝到后台缓冲表面,后台表面和前台表面不停的交替实现显示。

```C++

// 离屏

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

```

上一篇 下一篇

猜你喜欢

热点阅读