Video Path流程学习之路

2023-10-15 18:31:22 浏览数 (2)

RPC

RPC指远程过程调用(Remote Procedure Call),通俗一些理解就是两台服务器A、B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。(远程过程调用是相对于本地过程调用来说的)

RPC要解决的两个问题

1、解决分布式系统中,服务之间的调用问题。

2、远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑。

远程过程调用过程中有哪些步骤和问题:

1、要解决通讯的问题。客户端和服务端之间要建立连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。

2、要解决寻址的问题。A服务器上的应用要想办法告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称是什么,这样才能完成调用

3、序列化发送参数请求。当A服务器上的应用发起远程过程调用时,方法的参数要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,通过寻址和传输将序列化的二进制发送给B服务器。

4、对参数进行反序列化。B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。

5、返回值序列化回传。返回值还要发送会服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列号,恢复为内存中的表达方式,交给A服务器上的应用。

VDEC

VDEC是视频解码器,参考海思mpp的VDEC接口调用学习到:

一、初始化系统:

代码语言:javascript复制
HI_MPI_SYS_Exit();
HI_MPI_VB_Exit();
HI_MPI_VB_SetConfig(pstVbConfig);//整个系统中可以容纳缓存池的个数,每个缓存池缓存块的个数,缓存块的大小
HI_MPI_VB_Init();
HI_MPI_SYS_Init();

二、VDEC初始化并获取VB:

1.根据每个解码通道的需要解码的视频的宽高,像素格式,位宽 以及不同的解码方式(如:h.264 h.265等)计算每个通道需要的VB大小。 2. 模块公共视频缓存池

代码语言:javascript复制
HI_MPI_VB_ExitModCommPool(VB_UID_VDEC);
HI_MPI_VB_SetModPoolConfig(VB_UID_VDEC, &stVbConf);//设置模块公共视频缓存池属性
HI_MPI_VB_InitModCommPool(VB_UID_VDEC);

三、start VDEC:

代码语言:javascript复制
HI_MPI_VDEC_SetModParam(&stModParam);//主要是设置VB 来源选择

以下的操作,在每个解码通道都需要操作一遍。

代码语言:javascript复制
HI_MPI_VDEC_CreateChn(i, &stChnAttr[i])//创建视频解码的通道。
HI_MPI_VDEC_SetChnParam(i, &stChnParam)//设置解码通道i参数stChnParam
HI_MPI_VDEC_StartRecvStream(i)//使能解码通道i

四、start VPSS:

每个解码通道一个VPSSgroup,每个VPSSgroup中有4个phy通道

代码语言:javascript复制
HI_MPI_VPSS_SetModParam(&stModParam);//hdr支持

以下的操作,在每个解码通道都需要操作一遍。

代码语言:javascript复制
HI_MPI_VPSS_CreateGrp(VpssGrp, pstVpssGrpAttr);

for (j = 0; j < VPSS_MAX_PHY_CHN_NUM; j  )// VPSS_MAX_PHY_CHN_NUM = 4
VpssChn = j;
HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, &pastVpssChnAttr[VpssChn]);
HI_MPI_VPSS_EnableChn(VpssGrp, VpssChn);

HI_MPI_VPSS_StartGrp(VpssGrp);

五、start VO:

简称

全称

中文名

备注

DHD0

Device HD0

超高清设备 0

DHD1

Device HD1

高清设备 1

VHD0

Video layer of HD0

超高清视频层 0

隶属于 DHD0

VHD1

Video layer of HD1

高清视频层 1

隶属于 DHD1

VHD2

Video layer of HD 2

高清视频层 2

Hi3559AV100 上隶属于 DHD0

Hi3519AV100/Hi3556AV100 上可以绑定至 DHD0 或者 DHD1, 用作 PIP 层。 WD: Write Back Channel Device, 回写通道设备。 图形层 G3: Graphic layer 3, 用作鼠标层, DHD0 和 DHD1 中均有此项, 但只能绑定其中一个设备, G3 默认绑定在 DHD1 上。

代码语言:javascript复制
HI_MPI_VO_SetPubAttr(VoDev, pstPubAttr);// 配置视频输出设备VoDev(根据不同的芯片,有所不同)的公共属性(hdmi或者mipi,视频的输出格式如1080P60)。
HI_MPI_VO_Enable(VoDev);//使能视频输出设备

HI_MPI_VO_GetVideoLayerAttr(VoLayer, &stLayerAttr);// VoLayer(0.1.2即高清视频层0.1.2)获取视频层属性
HI_MPI_VO_SetChnAttr(VoLayer, i, &stChnAttr);//同一个图层VoLayer中,不同的视频输出通道i的属性
HI_MPI_VO_EnableChn(VoLayer, i);//使能同一个图层的不同的视频输出通道。

HI_MPI_VO_SetVideoLayerPartitionMode(VoLayer, enVoPartMode);// 设置当前视频层VoLayer的分割模式(VO_PART_MODE_MULTI,VO_PART_MODE_SINGLE)。
HI_MPI_VO_SetDisplayBufLen(VoLayer, pstVoConfig->u32DisBufLen);
HI_MPI_VO_SetVideoLayerAttr(VoLayer, pstLayerAttr);// 设备分辨率、显示分辨率和图像分辨率
HI_MPI_VO_EnableVideoLayer(VoLayer);

以下是视频输出的硬件接口的使能: HDMI:

代码语言:javascript复制
HI_MPI_HDMI_Init();
HI_MPI_HDMI_Open(enHdmiId);
HI_MPI_HDMI_GetAttr(enHdmiId, &stAttr);
HI_MPI_HDMI_SetAttr(enHdmiId, &stAttr) ;//属性中比较重要的一点是输出的视频的格式。

如:1080P60。

代码语言:javascript复制
HI_MPI_HDMI_Start(enHdmiId);

MIPI:

代码语言:javascript复制
fd = open("/dev/hi_mipi_tx", O_RDWR);
s32Ret = ioctl(fd, HI_MIPI_TX_SET_DEV_CFG, pstMipiTxConfig);//视频的输出格式。

如:MIPI_TX_1080X1920_60_CONFIG。

/中间部分为现实屏的初始化操作。主要区别和显示屏的分辨率有关。直接参考代码中的sample中的ioctl操作/

代码语言:javascript复制
s32Ret = ioctl(fd, HI_MIPI_TX_ENABLE);

六、VDEC bind VPSS:

代码语言:javascript复制
stSrcChn.enModId   = HI_ID_VDEC;
stSrcChn.s32DevId  = 0;
stSrcChn.s32ChnId  = VdecChn;

stDestChn.enModId  = HI_ID_VPSS;
stDestChn.s32DevId = VpssGrp;
stDestChn.s32ChnId = 0;
HI_MPI_SYS_Bind(&stSrcChn, &stDestChn)

七、VPSS bind VO:

代码语言:javascript复制
stSrcChn.enModId   = HI_ID_VPSS;
stSrcChn.s32DevId  = VpssGrp;
stSrcChn.s32ChnId  = VpssChn;//固定为0

stDestChn.enModId  = HI_ID_VO;
stDestChn.s32DevId = VoLayer;//Vodev
stDestChn.s32ChnId = VoChn;//对应于VpssGrp
HI_MPI_SYS_Bind(&stSrcChn, &stDestChn)

八、send stream to vdec

(选定需要解码的文件路径和文件名) 每个解码通道创建一个相对应的线程,当应用程序退出时,直接退出线程即可。

代码语言:javascript复制
pthread_join(pVdecThread[i], HI_NULL);

pthread_create(&pVdecThread[i], 0, SAMPLE_COMM_VDEC_SendStream, (HI_VOID *)&pstVdecSend[i]);

SAMPLE_COMM_VDEC_SendStream:
fpStrm = fopen(cStreamFile, "rb");//打开视频文件
while(1)
{
        fseek(fpStrm, s32UsedBytes, SEEK_SET);
        s32ReadLen = fread(pu8Buf, 1, pstVdecThreadParam->s32MinBufSize, fpStrm);
        有区别于vdec,按stream和frame
        HI_MPI_VDEC_SendStream(pstVdecThreadParam->s32ChnId, &stStream, pstVdecThreadParam->s32MilliSec);
}
/* send the flag of stream end */
memset(&stStream, 0, sizeof(VDEC_STREAM_S) );
stStream.bEndOfStream = HI_TRUE;
HI_MPI_VDEC_SendStream(pstVdecThreadParam->s32ChnId, &stStream, -1); //在发送完所有码流后,可以发送 bEndOfStream 为 1 的空码流包,表示当前码流文件结束,解码器会把所有码流全部解完并输出全部图像。

九、应用退出:

代码语言:javascript复制
pthread_join(pVdecThread[i], HI_NULL);
vpss vo unbind:HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
vdec vpss unbind

HI_MPI_HDMI_Stop(enHdmiId)
HI_MPI_HDMI_Close(enHdmiId)
HI_MPI_HDMI_DeInit()

HI_MPI_VO_DisableChn(VoLayer, i);
HI_MPI_VO_DisableVideoLayer(VoLayer);
HI_MPI_VO_Disable(VoDev);

HI_MPI_VPSS_StopGrp(VpssGrp);//停止每个vpssgroup
HI_MPI_VPSS_DisableChn(VpssGrp, VpssChn);//禁止vpss下的通道
HI_MPI_VPSS_DestroyGrp(VpssGrp);//销毁VpssGrp

//多个解码通道的话,每个通道都要分别执行
HI_MPI_VDEC_StopRecvStream(i)//解码通道i停止接收数据流
HI_MPI_VDEC_DestroyChn(i)//销毁解码通道i

HI_MPI_VB_ExitModCommPool(VB_UID_VDEC);//VDEC退出模块公共视频缓存池

HI_MPI_SYS_Exit();
HI_MPI_VB_Exit();

至此整个视频的解码流程就到此结束

关于面向海思芯片VDEC的学习还可以看视频编解码(二):海思VDEC模块视频解码代码解析

这个博主的也挺好的:海思多媒体(MPP)开发(3)——视频输出(VO)与视频解码(VDEC)

海思多媒体处理平台(MPP)分为:视频输入(VI),视频处理(VPSS),视频编码(VENC),视频解码(VDEC),视频输出(VO)、视频侦测分析(VDA),音频输入(AI),音频输出(AO),音频编码(AENC),音频解码(ADEC),区域管理(REGION)等模块. 这里介绍视频解码(VDEC)和视频输出模块(VO)。

其实音视频解码流程都差不多,可以参考的芯片厂家很多

VBM

暂时搞不懂

VMN

暂时搞不懂

0 人点赞