imx VPU解码分析4-抽丝剥茧wrap与hantro的关系

        前面已经分析了wrap和hantro,但是二者是如何结合的,wrap是如何封装hantro的,提供了哪些接口,封装了哪些细节还不太清楚,此文来探究下。这里还是只关注解码。

imx VPU解码分析1-wrap-CSDN博客

imx VPU解码分析2-hantro_huntenganw的博客-CSDN博客

imx VPU解码分析3-wrap的示例-CSDN博客

        上述文章已经分析了vpu_wrapper.h文件,这是wrap库对外的接口。vpu_wrapper_hantro.c这个文件就是封装的hantro接口,包含了hantro解码需要用到的api。

        这里分析下vpu_wrapper_hantro.c,看看具体如何操作的。

        首先看看头文件的包含:

#include "codec.h"

#include "codec_h264.h"

#include "codec_jpeg.h"

#include "codec_mpeg4.h"

#include "codec_vc1.h"

#include "codec_rv.h"

#include "codec_mpeg2.h"

#include "codec_vp6.h"

#include "codec_avs.h"

#include "codec_vp8.h"

#include "codec_webp.h"

#include "codec_hevc.h"

#include "codec_vp9.h"

        这些头文件在hantro/openmax_il/source/decoder下,即包含了这些相应的解码方式。

        然后是定义了几个内部结构体:

typedef enum

{

  VPU_DEC_STATE_OPEN=0,

  VPU_DEC_STATE_INITOK,

  VPU_DEC_STATE_REGFRMOK,

  VPU_DEC_STATE_DEC,

  VPU_DEC_STATE_STARTFRAMEOK,

  VPU_DEC_STATE_OUTOK,

  VPU_DEC_STATE_EOS,

  VPU_DEC_STATE_CORRUPT

}VpuDecState;

        这个结构体是具体的解码状态。可以对比VpuDecBufRetCode看看。

typedef struct

{

  /* open parameters */

  VpuCodStd CodecFormat;

  const void *pdwl;

  /* hantro decoder */

  CODEC_PROTOTYPE *codec;

  OMX_VIDEO_PARAM_CONFIGTYPE config;

  /* decode parameters */

  int iframeSearchEnable;

  int skipFrameMode;

  int skipFrameNum;

  int inputType; /*normal, kick, drain(EOS)*/

  int streamBufDelaySize; /*unit: bytes. used in stream mode:  valid data size should reach the threshold before decoding*/

  int initDataCountThd;

  VpuDecErrInfo nLastErrorInfo;  /*it record the last error info*/

  /*resolution for some special formats, such as package VC1 header,...*/

  int picWidth;

  int picHeight;

  /* init info */

  VpuDecInitInfo initInfo;

  /* out frame info */

  VpuDecOutFrameInfo frameInfo;

  /*used to store extended frame info*/

  VpuFrameExtInfo frmExtInfo;

  /* frame buffer management */

  int frameNum;

  VpuFrameBuffer frameBuf[VPU_MAX_FRAME_INDEX];  /*buffer node*/

  int frameBufState[VPU_MAX_FRAME_INDEX];  /*record frame state for clearing display frame(if user forgot to clear them)*/

  /* bitstream buffer pointer info */

  unsigned char* pBsBufVirtStart;

  unsigned char* pBsBufPhyStart;

  unsigned char* pBsBufPhyEnd;

  int nBsBufLen;

  int nBsBufOffset;

  /* state */

  VpuDecState state;

  /*management of consumed bytes: used to sync with frame boundary*/

  int nDecFrameRptEnabled; /*1:support frame reported; 0: not support*/

  int nAccumulatedConsumedStufferBytes;/*stuffer size between frames: if it <0, indicate that some frames are contained in config data*/

  int nAccumulatedConsumedFrmBytes; /*frame size: >=0*/

  int nAccumulatedConsumedBytes; /*it should match with the input data size == nAccumulatedConsumedStufferBytes+nAccumulatedConsumedFrmBytes*/

  VpuFrameBuffer* pLastDecodedFrm; /*the nearest decoded frame*/

  int nAdditionalSeqBytes; /*seq header inserted by wrapper itself , or config data */

  int nAdditionalFrmHeaderBytes; /*frame header inserted by wrapper itself */

  unsigned int nLastFrameEndPosPhy; /*point to the previous frame tail: used to compute the stuff data length between frames*/

  int nDecResolutionChangeEnabled; /*1: support resolution change notification; 0: not support*/

  int nPrivateSeqHeaderInserted;

  int nIsAvcc; /*for H.264/HEVC format*/

  int nNalSizeLen;

  int nNalNum; /*added for nal_size_length = 1 or 2*/

  bool eosing;

  bool ringbuffer;

  bool config_tile;

  int nFrameSize;

  int nOutFrameCount;

  int total_frames;

  long long total_time;

  int slice_info_num;

  RvDecSliceInfo slice_info[128];

  int frame_size;

  bool bSecureMode;

  bool bConsumeInputLater;

  int nSecureBufferAllocSize;

}VpuDecObj;

        这个结构体就是此文件中最重要的了,基本汇聚了所有信息,统统打包。

typedef struct

{

  VpuDecObj obj;

}VpuDecHandleInternal;

        这个结构体就把VpuDecObj再次包装下,在下面的函数中,既用了VpuDecObj,又用了VpuDecHandleInternal,暂时不明白为啥这么做。

下面看看有哪些关键函数。

先看看static修饰的函数:

//将数据复制到解码器

static void VpuPutInBuf(VpuDecObj* pObj, unsigned char *pIn, unsigned int len, bool useRingBuffer);

//解码器对不同格式进行解析,通过pInData->pVirAddr == (unsigned char *)0x01 && pInData->nSize //== 0来判断数据读完,这里读完解码器中还有几帧数据待解

static VpuDecRetCode VPU_DecProcessInBuf(VpuDecObj* pObj, VpuBufferNode* pInData);

//查找解码帧

static int VpuSearchFrameIndex(VpuDecObj* pObj, unsigned char *pInPhysY);

//获取解码帧

static VpuDecRetCode VPU_DecGetFrame(VpuDecObj* pObj, int* pOutBufRetCode);

//解码指针的处理,结构返回值

static VpuDecRetCode VPU_DecDecode(VpuDecObj* pObj, int* pOutBufRetCode);

下面是对外的函数,所有函数的返回值都是VpuDecRetCode :

//加载解码器

VpuDecRetCode VPU_DecLoad()

//申请内存

VpuDecRetCode VPU_DecQueryMem(VpuMemInfo* pOutMemInfo)

//打开解码器,进行各种内存、指针、DWL的初始化,创建相应格式的解码器

VpuDecRetCode VPU_DecOpen(VpuDecHandle *pOutHandle, VpuDecOpenParam * pInParam,VpuMemInfo* pInMemInfo)

//查看支持的解码VpuDecCapability值

VpuDecRetCode VPU_DecGetCapability(VpuDecHandle InHandle,VpuDecCapability eInCapability, int* pOutCapbility)

//关闭解码支持

VpuDecRetCode VPU_DecDisCapability(VpuDecHandle InHandle,VpuDecCapability eInCapability)

//解码模式设置,参看VpuDecConfig结构体

VpuDecRetCode VPU_DecConfig(VpuDecHandle InHandle, VpuDecConfig InDecConf, void* pInParam)

//主解码函数

VpuDecRetCode VPU_DecDecodeBuf(VpuDecHandle InHandle, VpuBufferNode* pInData,

    int* pOutBufRetCode)

//获取初始化参数

VpuDecRetCode VPU_DecGetInitialInfo(VpuDecHandle InHandle, VpuDecInitInfo * pOutInitInfo)

//更新注册帧信息

VpuDecRetCode VPU_DecRegisterFrameBuffer(VpuDecHandle InHandle,VpuFrameBuffer *pInFrameBufArray, int nNum)

//获取解码帧

VpuDecRetCode VPU_DecGetOutputFrame(VpuDecHandle InHandle, VpuDecOutFrameInfo * pOutFrameInfo)

//获取解码帧信息

VpuDecRetCode VPU_DecGetConsumedFrameInfo(VpuDecHandle InHandle,VpuDecFrameLengthInfo* pOutFrameLengthInfo)

//释放帧缓冲区

VpuDecRetCode VPU_DecOutFrameDisplayed(VpuDecHandle InHandle, VpuFrameBuffer* pInFrameBuf)

//释放解码器

VpuDecRetCode VPU_DecFlushAll(VpuDecHandle InHandle)

//关闭解码器

VpuDecRetCode VPU_DecClose(VpuDecHandle InHandle)

//卸载解码器

VpuDecRetCode VPU_DecUnLoad()

//reset解码器

VpuDecRetCode VPU_DecReset(VpuDecHandle InHandle)

//获取内存

VpuDecRetCode VPU_DecGetMem(VpuMemDesc* pInOutMem)

//释放内存

VpuDecRetCode VPU_DecFreeMem(VpuMemDesc* pInMem)

        具体的解码过程在前文已经介绍,这里挑几个重点的函数探究下内部过程。

        VPU_DecOpen函数打开对应的编译器,对应前文讲的codec几个头文件,支持下面的解码器:

HantroHwDecOmx_decoder_create_h264

HantroHwDecOmx_decoder_create_mpeg2

HantroHwDecOmx_decoder_create_mpeg4

HantroHwDecOmx_decoder_create_vc1

HantroHwDecOmx_decoder_create_jpeg

HantroHwDecOmx_decoder_create_webp

HantroHwDecOmx_decoder_create_avs,

HantroHwDecOmx_decoder_create_vp6

HantroHwDecOmx_decoder_create_vp8

HantroHwDecOmx_decoder_create_hevc

HantroHwDecOmx_decoder_create_vp9

        VPU_DecDecodeBuf函数核心解码函数,如下示意图显示了其内部调用关系:

imx VPU解码分析4-抽丝剥茧wrap与hantro的关系_第1张图片

        这样基本就清晰了,可以看到最终调用了内层的decode函数来执行具体的解码过程,这个函数在codec.h中定义如下。

// Decode n bytes of data given in the stream buffer object.

// On return consumed should indicate how many bytes were consumed from the buffer.

//

// The function should return one of following:

//

//    CODEC_NEED_MORE  - nothing happened, codec needs more data.

//    CODEC_HAS_INFO   - headers were parsed and information about stream is ready.

//    CODEC_HAS_FRAME  - codec has one or more headers ready

//    less than zero   - one of the enumerated error values

//

// Parameters:

//

//    CODEC_PROTOTYPE  - this codec instance

//    STREAM_BUFFER    - data to be decoded

//    OMX_U32          - pointer to an integer that should on return indicate how many bytes were used from the input buffer

//    FRAME            - where to store any frames that are ready immediately

CODEC_STATE(*decode)(CODEC_PROTOTYPE *, STREAM_BUFFER *, OMX_U32 *, FRAME *);

        DecGetOutputFrame函数就是获取解码帧数据了。VPU_DEC_OUTPUT_DIS这个信号就可以取数据了。取完数据,使用DecOutFrameDisplayed函数释放掉。

        这样分析一遍wrap和hantro的联系就基本清晰了。

你可能感兴趣的:(嵌入式,Linux,音视频,视频编解码)