当前位置:网站首页 > 技术经理的晋升之路 > 正文

读取pcap文件中的csi(pcapng文件怎么解析读取)



本文档适用于本店所有海思、国科开发板,包括GK7205Hi3516Hi3518Hi3519Hi3520Hi3521Hi3531等

从“SampleSourceCode”目录将mpp_xxx.tgz拷贝至虚拟机ubuntu的nfs服务器目录/home/swann/nfs或/root/hisi,中的任意目录,并在虚拟机中解压、编译

零基础玩转IPC之——海思VENC例程源码详解(sample_venc)_文件描述符

生成sample_venc可执行程序

零基础玩转IPC之——海思VENC例程源码详解(sample_venc)_SYS_02

零基础玩转IPC之——海思VENC例程源码详解(sample_venc)_SYS_03

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

零基础玩转IPC之——海思VENC例程源码详解(sample_venc)_文件描述符_04

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

零基础玩转IPC之——海思VENC例程源码详解(sample_venc)_文件描述符_05

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

零基础玩转IPC之——海思VENC例程源码详解(sample_venc)_SYS_06

零基础玩转IPC之——海思VENC例程源码详解(sample_venc)_文件描述符_07

零基础玩转IPC之——海思VENC例程源码详解(sample_venc)_文件描述符_08

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;

到此这篇读取pcap文件中的csi(pcapng文件怎么解析读取)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • 华为ensp模拟器的路由器实验(华为模拟器ensp路由器配置)2026-01-28 14:00:05
  • 华为ensp模拟器的路由器实验(华为模拟器ensp路由器启动不了)2026-01-28 14:00:05
  • 华为模拟器路由器接口配置ip地址是什么(华为模拟器路由器配置命令)2026-01-28 14:00:05
  • 电路工作原理说明(电路工作原理说明书)2026-01-28 14:00:05
  • g电路中代表什么意思(g电路中代表什么意思的符号)2026-01-28 14:00:05
  • 批量删除文件夹名称中的同一个字(怎样批量删除文件名中的指定字符)2026-01-28 14:00:05
  • 华为模拟器路由器网关怎么配(华为模拟器如何连接多个路由器)2026-01-28 14:00:05
  • 双管反激电路图(双管反激电路工作原理)2026-01-28 14:00:05
  • vue路由守卫导航栏权限配置(vue中的路由导航守卫)2026-01-28 14:00:05
  • 双管反激电路优缺点(双管反激式开关电源)2026-01-28 14:00:05
  • 全屏图片