本文档适用于本店所有海思、国科开发板,包括GK7205Hi3516Hi3518Hi3519Hi3520Hi3521Hi3531等
从“SampleSourceCode”目录将mpp_xxx.tgz拷贝至虚拟机ubuntu的nfs服务器目录/home/swann/nfs或/root/hisi,中的任意目录,并在虚拟机中解压、编译
生成sample_venc可执行程序


在开发板linux系统下运行该程序

开始录制视频,等待十秒左右后按2次回车退出录制,可以看到在当前目录生成H264和H265视频裸流文件。

我们将他们拷贝到Windows下,用播放器打开查看



PS:我也想学习,如何获得开发板?逃保搜索“海思开发板总店”,仅此一家,其他都是假冒的哦
至此实验成功,接下来我们进入源代码解析
VENC流程
1.根据sensor type获得尺寸大小,缓冲池参数,将 u32BlkSize 写入 stVbConf
/
step 1: init sys variable
*/
SAMPLE_COMM_VI_GetSizeBySensor(&enSize[0]);
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,enSize[0], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH);
stVbConf.astCommPool[0].u32BlkSize = u32BlkSize;
2.调用海思SDK,将上面的参数 stVbConf 写入硬件vediobuf ,完成 VB和SYS init
/*
step 2: mpp system init.
*/
SAMPLE_COMM_SYS_Init(&stVbConf);
HI_MPI_VB_SetConf(pstVbConf)
s32Ret = HI_MPI_VB_Init();
HI_MPI_SYS_SetConf(&stSysConf);
HI_MPI_SYS_Init();
3.初始化 海思的VI模块和 sensor硬件
/*
step 3: start vi dev & chn to capture
*/
SAMPLE_COMM_VI_StartVi(&stViConfig);
SAMPLE_COMM_VI_StartIspAndVi
4.调用海思MPI,开启vpss同时绑定vi ch 和 vpss ch
/*
step 4: start vpss and vi bind vpss
*/
SAMPLE_COMM_SYS_GetPicSize(gs_enNorm, enSize[0], &stSize)//从SYS系统获取pic size参数写入 stSize
VpssGrp = 0;
SAMPLE_COMM_VPSS_StartGroup(VpssGrp, &stVpssGrpAttr)//开启vpss group 0
HI_MPI_VPSS_CreateGrp(VpssGrp, pstVpssGrpAttr);
HI_MPI_VPSS_StartGrp(VpssGrp);
SAMPLE_COMM_VI_BindVpss(stViConfig.enViMode)
SAMPLE_COMM_VI_Mode2Param(enViMode, &stViParam); //根据enViMode,填充stViParam 的s32ViDevCnt s32ViDevInterval s32ViChnCnt s32ViChnInterval参数为1
HI_MPI_SYS_Bind(&stSrcChn, &stDestChn); //调用海思MPI绑定 Videv0的Chn0 和 VpssGrp0的chn0
VpssChn = 0;
SAMPLE_COMM_VPSS_EnableChn(VpssGrp, VpssChn, &stVpssChnAttr, &stVpssChnMode, HI_NULL);
HI_MPI_VPSS_EnableChn(VpssGrp, VpssChn); //调用海思MPI使能VpssGrp0和VpssChn0
SAMPLE_COMM_SYS_GetPicSize(gs_enNorm, enSize[1], &stSize);
VpssChn = 1;
SAMPLE_COMM_VPSS_EnableChn(VpssGrp, VpssChn, &stVpssChnAttr, &stVpssChnMode, HI_NULL);
HI_MPI_VPSS_EnableChn(VpssGrp, VpssChn);
5.绑定venc和vpss对应通道,开始编码
/*
step 5: start stream venc
*/
/ enSize[0] /
VpssGrp = 0;
VpssChn = 0; //VpssGrp0-Chn0
VencChn = 0; //VencDev0-VencCh0 ,IPC has only 1 VencDev
SAMPLE_COMM_VENC_GetGopAttr(enGopMode[0],&stGopAttr,gs_enNorm); //配置venc参数
SAMPLE_COMM_VENC_Start(VencChn, enPayLoad[0], gs_enNorm, enSize[0], enRcMode,u32Profile,&stGopAttr);//开启venc模块
SAMPLE_COMM_SYS_GetPicSize(enNorm, enSize, &stPicSize); //获取尺寸,在下面写入 stVencChnAttr
HI_MPI_VENC_CreateChn(VencChn, &stVencChnAttr); //填充 stVencChnAttr,再创建 Venc Channel
HI_MPI_VENC_StartRecvPic(VencChn); //Start Recv Venc Pictures
SAMPLE_COMM_VENC_BindVpss(VencChn, VpssGrp, VpssChn); //调用海思MPI绑定 VencDev0 的Chn0 和 VpssGrp0 的chn0
/* enSize[1] /
VpssChn = 1; //VpssGrp0-Chn1
VencChn = 1; //VencDev0-VencCh1 ,IPC has only 1 VencDev
s32Ret = SAMPLE_COMM_VENC_GetGopAttr(enGopMode[1],&stGopAttr,gs_enNorm);
s32Ret = SAMPLE_COMM_VENC_Start(VencChn, enPayLoad[1],gs_enNorm, enSize[1], enRcMode,u32Profile,&stGopAttr);

s32Ret = SAMPLE_COMM_VENC_BindVpss(VencChn, VpssGrp, VpssChn);
6.调用海思MPI获取2路venc码流,并保存文件
/
step 6: stream venc process – get stream, then save it to file.
/
SAMPLE_COMM_VENC_StartGetStream(s32ChnNum);
gs_stPara.bThreadStart = HI_TRUE;
gs_stPara.s32Cnt = s32Cnt;
pthread_create(&gs_VencPid, 0, SAMPLE_COMM_VENC_GetVencStreamProc, (HI_VOID*)&gs_stPara);
/
step 1: check & prepare save-file & venc-fd
/
for (i = 0; i < s32ChnTotal; i++)
{
/* decide the stream file name, and open file to save stream /
VencChn = i;
HI_MPI_VENC_GetChnAttr(VencChn, &stVencChnAttr);
SAMPLE_COMM_VENC_GetFilePostfix(enPayLoadType[i], szFilePostfix);
pFile[i] = fopen(aszFileName[i], “wb”);
/ Set Venc Fd. */
VencFd[i] = HI_MPI_VENC_GetFd(i);
HI_MPI_VENC_GetStreamBufInfo (i, &stStreamBufInfo[i]);
}
/
step 2: Start to get streams of each channel.
/
while (HI_TRUE == pstPara->bThreadStart)
{
s32Ret = select(maxfd + 1, &read_fds, NULL, NULL, &TimeoutVal);
for (i = 0; i < s32ChnTotal; i++)
{
if (FD_ISSET(VencFd[i], &read_fds))
{
memset(&stStream, 0, sizeof(stStream));
HI_MPI_VENC_Query(i, &stStat); //step 2.1 : query how many packs in one-frame stream.
//此接口用于查询此函数调用时刻的编码器状态,stStat包含四个主要的信息,在编码通道状态结构体中,u32CurPacks 表示当前帧的码流包个数。在调用
//HI_MPI_VENC_GetStream 之前应确保 u32CurPacks 大于 0。 按帧获取时表示当前一个完整帧的包个数(如果没有一帧数据则为 0)。用户在需要按帧获取码
//流时,需要查询一个完整帧的包个数,在这种情况下,通常可以在 select 成功后执行 query 操作,此时 u32CurPacks 是当前完整帧中包的个数。
if(0 == stStat.u32CurPacks)SAMPLE_PRT(“NOTE: Current frame is NULL! “);continue; //step 2.2 : check u32CurPacks
//u32CurPacks 表示当前帧的码流包个数
stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks); //step 2.3 : malloc corresponding number of pack nodes.
//码流包信息指针 pstPack ,指向一组 VENC_PACK_S 的内存空间,该空间由调用者分配。
//如果按帧获取,则此空间不小于 N × sizeof(VENC_PACK_S)的大小,其中 N 代表当前帧之中的包的个数
stStream.u32PackCount = stStat.u32CurPacks;
HI_MPI_VENC_GetStream(i, &stStream, HI_TRUE); //step 2.4 : call mpi to get one-frame stream
//码流包个数 u32PackCount 在输入时,此值指定 stStream 中 VENC_PACK_S 的个数。按帧获取时,u32PackCount 必须不小于当前帧的包个数。
//在函数调用成功后, u32PackCount 返回实际填充 stStream 的包的个数。
SAMPLE_COMM_VENC_SaveStream(enPayLoadType[i], pFile[i], &stStream); //step 2.5 : save frame to file
SAMPLE_COMM_VENC_SaveH264(pFd, pstStream);
for (i = 0; i < pstStream->u32PackCount; i++)
{ /每个数据包的首地址 + 每个数据包的有效数据相对于首地址的偏移量/ /每个数据包的长度 - 每个数据包的有效数据相对于首地址的偏移量 = 有效数据长度/ //写入一次
fwrite(pstStream->pstPack[i].pu8Addr + pstStream->pstPack[i].u32Offset , pstStream->pstPack[i].u32Len - pstStream->pstPack[i].u32Offset, 1, fpH264File);
fflush(fpH264File); //表示立即将输出缓冲区的数据写入该文件中
}
SAMPLE_COMM_VENC_SaveMJpeg(pFd, pstStream);
SAMPLE_COMM_VENC_SaveH265(pFd, pstStream);
HI_MPI_VENC_ReleaseStream(i, &stStream); //step 2.6 : release stream
free(stStream.pstPack); //step 2.7 : free pack nodes
stStream.pstPack = NULL;
}
}
}
/*
* step 3 : close save-file
*/
for (i = 0; i < s32ChnTotal; i++)
{
fclose(pFile[i]);
}
Linux中select的用法:
在Linux中,select 函数是用于监控多个文件描述符(file descriptors)的系统调用
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数解释:
nfds:指定监控的文件描述符数量。它应该是所有监控的文件描述符集合中最大值加1,因为文件描述符是从0开始计数的。

readfds:指向一个文件描述符集合,用于监控是否有文件可读。可以使用宏函数 FD_SET() 将描述符添加到集合。
writefds:指向一个文件描述符集合,用于监控是否有文件可写。
exceptfds:指向一个文件描述符集合,用于监控异常状态。
timeout:指定 select 等待的时间,可以是:
NULL:select 将无限期等待,直到有文件描述符准备好。
0秒的时间:表示非阻塞模式,select 立即返回。
自定义时间:例如等待5秒,可以通过 struct timeval 指定。
返回值:
返回值为大于0的数值表示有多少文件描述符准备好。
返回0表示超时。
返回-1表示出错,并且设置 errno。
使用步骤:
清空文件描述符集合: 在使用 select 之前,首先需要初始化或清空文件描述符集合。
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
设置需要监控的文件描述符: 使用 FD_SET() 函数将需要监控的文件描述符加入到集合中。
FD_SET(fd, &readfds);
调用 select 函数: 通过调用 select 来监控多个文件描述符。
int ready = select(nfds, &readfds, &writefds, &exceptfds, &timeout);
检查哪些文件描述符已准备好: select 返回后,可以使用 FD_ISSET() 函数检查哪些文件描述符已经准备好。
if (FD_ISSET(fd, &readfds)) { // 该文件描述符可读 }
文件描述符集合的操作:
为了管理 select 函数的文件描述符集合,使用了以下几个宏:
FD_ZERO(fd_set *set):清空集合。
FD_SET(int fd, fd_set *set):将文件描述符 fd 添加到集合中。
FD_CLR(int fd, fd_set *set):将文件描述符 fd 从集合中移除。
FD_ISSET(int fd, fd_set *set):判断文件描述符 fd 是否在集合中,返回非0值表示在集合中。
关于VPSS的Group和Channel
GROUP
VPSS 对用户提供组( GROUP )的概念。最大可用数为 VPSS_MAX_GRP_NUM
个,各芯片的最大组数目有所不同,各 GROUP 分时复用 VPSS 硬件。每个 VPSS
GROUP 包含多个通道,通道数目视方案实现有所不同,具体描述请参见CHANNEL 。
CHANNEL
VPSS 组的通道。通道分为 2 种:物理通道和扩展通道。 VPSS 硬件提供多个物理
通道,每个通道具有缩放、裁剪等功能。扩展通道具备缩放功能,它通过绑定物
理通道,将物理通道输出作为自己的输入,把图像缩放成用户设置的目标分辨率
输出。需要特别注意的是, USER 模式主要用于对同一通道图像进行多路编码的
场景,此模式下播放控制不生效,因此预览和回放场景下不建议使用 USER 模式。
Hi3516A/Hi3518EV200/Hi3519V100/Hi3519V101/Hi3516CV300 仅支持 USER 工作模式
CHANNEL 0为原尺寸不支持裁剪缩放,CHANNEL 1可以
主要的结构体VENC_STREAM_S和VENC_PACK_S:
//帧码流结构体VENC_STREAM_S, 表示一帧图像对应的码流
typedef struct hiVENC_STREAM_S
{
VENC_PACK_S *pstPack; //指向帧码流包的指针
HI_U32 u32PackCount; //帧码流的所有包的个数
HI_U32 u32Seq; //码流序列号,按帧获取则表示帧序号,按包获取则表示包序号
union
{ //码流特征信息
VENC_STREAM_INFO_H264_S stH264Info; /the stream info of h264/
VENC_STREAM_INFO_JPEG_S stJpegInfo; /the stream info of jpeg/
VENC_STREAM_INFO_MPEG4_S stMpeg4Info; /the stream info of mpeg4/
VENC_STREAM_INFO_H265_S stH265Info; /the stream info of h265/
};
}VENC_STREAM_S;
//帧码流包结构体VENC_PACK_S, 表示一帧图像的每个包对应的码流。(一帧图像可以有多个包)
typedef struct hiVENC_PACK_S
{
HI_U32 u32PhyAddr; //每个码流包的物理地址 /the physics address of stream/
HI_U8 *pu8Addr; //每个码流包首地址 /the virtual address of stream/
HI_U32 u32Len; //每个码流包长度 /the length of stream/
HI_U64 u64PTS; //时间戳,单位us /PTS/
HI_BOOL bFrameEnd; //帧结束标识 /frame end/(1)关于帧结束标志 HI_TRUE 表示该码流包是该帧的最后一个包, HI_FALSE 表示该码流包不是该帧的最后一个包。
//码流类型,支持 H.264/JPEG/MPEG-4 协议类型的数据包。
VENC_DATA_TYPE_U DataType; /the type of stream/
HI_U32 u32Offset;//每个码流包中有效数据与码流包首地址 pu8Addr 的偏移。
HI_U32 u32DataNum;//当前码流包(类型由 DataType 指定)数据中包含其他类型码流包的个数。
VENC_PACK_INFO_S stPackInfo[8];//当前码流包数据中包含其他类型码流包数据信息
}VENC_PACK_S;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/143320.html