兼容旧版本的功能
兼容性说明
为了兼容旧版本中的功能,当前版本支持以下方式实现VPC功能和VENC功能:
- 实现VPC功能:
- 在DvppCtl接口中传入入参:DVPP_CTL_VPC_PROC命令字和resize_param_in_msg结构体的参数。
- 对时延要求不高、处理的图片分辨率低、数量多的场景,可以在DvppCtl接口中传入入参:DVPP_CTL_CMDLIST_PROC和IMAGE_CONFIG结构体的参数。
这种方式是为了兼容旧版本中的功能,后续版本会删除,不推荐使用。如果使用了不推荐使用的功能,建议迁移到推荐的VPC功能,请参见VPC/JPEGE/JPEGD/PNGD功能接口。
- 实现VENC功能:调用CreateDvppApi、DvppCtl、DestroyDvppApi接口实现VENC功能,在DvppCtl接口中传入入参:DVPP_CTL_VENC_PROC命令字和venc_in_msg结构体的参数。
这种方式在为了兼容旧版本中的功能,后续版本会删除,不推荐使用。如果使用了不推荐使用的功能,建议迁移到推荐的VENC功能,请参见VENC功能接口。
VPC功能及参数说明
不推荐使用旧版本中的VPC功能,后续版本会删除。旧版本中的VPC功能和CMDLIST功能均迁移到VPC功能,请参见VPC参数说明处的参数说明进行开发。
旧版本中的VPC功能:主要用于处理媒体图像转换,包括缩放、色域转换、降bit数处理、格式转换、区块切割,叠加拼接,CMDLIST。
- VPC路数无限制,其性能指标如下表。
VPC性能由于涉及到抠图、缩放等不同的场景,当处理图片过程中的分辨率改变时,性能会对应改变。当处理过程中图像分辨率都没有比原图分辨率大时,典型场景性能指标如下:
场景
总帧率
1080p*32路
1440fps
4k*4路
360fps
当处理过程中图像分辨率大于原图分辨率时,总帧率计算公式参考如下:
总帧率=(3840*2160*360)/(W*H) fps
其中:W和H为VPC处理过程中最大的宽度和高度,例如1080p抠图到960*540,再缩放到3840*2160,此时W为3840,H为2160。
在处理过程中,缩小比例的增大会导致VPC处理性能有略微下降。
- VPC输入输出图像宽高限制:
- 输入图像宽高都需要2对齐(偶数)。
- 输出图像宽高都需要2对齐(偶数)。
此处所说的图像宽高是指图片的有效区域,实际上对于送进VPC的内存需要128*16对齐。
- VPC输入输出图像内存限制:
- VPC输入内存限制
- 输入数据地址(os虚拟地址):128字节对齐。
- 输入图像宽度内存限制:128字节对齐。
- 输入图像高度内存限制:16字节对齐。
对于yuv400sp格式图片,需要调用方申请和yuv420sp格式相同大小的空间,即:width_align_128*high_align_16*1.5。
- VPC输出内存限制
- 输出数据地址(os虚拟地址):128字节对齐。
- 输出图像宽内存限制:128字节对齐。
- 输出图像高内存限制:16字节对齐。
在使用VPC实现图像裁剪与缩放时,共需要调用两次DvppCtl,第一次调用的输入参数为resize_param_in_msg,输出参数为resize_param_out_msg,第二次调用的输入参数为vpc_in_msg,详细信息请参见入参:resize_param_in_msg~入参:vpc_in_msg。
- VPC输入内存限制
入参:resize_param_in_msg
成员变量 |
说明 |
取值范围 |
---|---|---|
int src_width |
原图的宽度(2对齐)。 须知:
原图指图片的有效区域,实际上对于送进VPC的内存需要128*16对齐。 |
最小分辨率:
最大分辨率: 4096 必填 |
int src_high |
原图的高度(2对齐)。 须知:
原图指图片的有效区域,实际上对于送进VPC的内存需要128*16对齐。 |
最小分辨率:
最大分辨率: 4096 必填 |
int hmax |
与原点在水平方向的最大偏移。 |
奇数,具体参见入参:vpc_in_msg。 |
int hmin |
与原点在水平方向的最小偏移。 |
偶数,具体参见入参:vpc_in_msg。 |
int vmax |
与原点在垂直方向的最大偏移。 |
奇数,具体参见入参:vpc_in_msg。 |
int vmin |
与原点在垂直方向的最小偏移。 |
偶数,具体参见入参:vpc_in_msg。 |
int dest_width |
输出图像宽度。 |
偶数。 |
int dest_high |
输出图像高度。 |
偶数。 |
出参:resize_param_out_msg
成员变量 |
说明 |
取值范围 |
---|---|---|
int dest_width_stride |
输出图像的宽度对齐值。 |
128 |
int dest_high_stride |
输出图像的高度对齐值。 |
16 |
int hmax |
与原点在水平方向的最大偏移。 |
奇数,具体参见入参:vpc_in_msg。 |
int hmin |
与原点在水平方向的最小偏移。 |
偶数,具体参见入参:vpc_in_msg。 |
int vmax |
与原点在垂直方向的最大偏移。 |
奇数,具体参见入参:vpc_in_msg。 |
int vmin |
与原点在垂直方向的最小偏移。 |
偶数,具体参见入参:vpc_in_msg。 |
double hinc |
水平缩放系数。 |
具体参见入参:vpc_in_msg。 |
double vinc |
垂直缩放系数。 |
具体参见入参:vpc_in_msg。 |
入参:vpc_in_msg
成员变量 |
说明 |
取值范围 |
---|---|---|
int format |
图像格式,调用方可以自行定义,只要后面的数字对应正确即可。例如:yuv420_semi_plannar对应的是0,调用方声明为yuv420sp,那么也必须对应为0。 |
yuv420_semi_plannar = 0,//0 yuv400_semi_plannar = 0,//0 yuv422_semi_plannar,//1 yuv444_semi_plannar,//2 yuv422_packed,//3 yuv444_packed,//4 rgb888_packed,//5 xrgb8888_packed,//6 必填 |
int rank |
图像排列方式,调用方可以自行定义,只要后面的数字对应正确即可。 |
具体参见表10-26 必填 |
int bitwidth |
位深,默认是8bit。10bit只有在图像格式为YUV/YVU420 Semi-Planar且为HFBC压缩场景下使用。 |
8或者10 选填 |
int cvdr_or_rdma |
输入图像走CVDR通道还是RDMA,默认走CVDR通道,RDMA通道的输入仅为VDEC输出的HFBC格式数据。 |
CVDR:1,RDMA:0。 选填 |
int width |
输入原图像宽度,2对齐(偶数)。 须知:
原图指图片的有效区域,实际上对于送进VPC的内存需要128*16对齐。 |
最小分辨率:
最大分辨率: 4096 必填 |
int high |
输入原图像高度,2对齐(偶数)。 须知:
原图指图片的有效区域,实际上对于送进VPC的内存需要128*16对齐。 |
最小分辨率:
最大分辨率: 4096 必填 |
int stride |
图像步长。 须知:
对于不同输入格式,其stride不同。 |
yuv400sp、yuv420sp、yuv422sp、yuv444sp:width对齐到128。 yuv422packed:width * 2后对齐到128 yuv444packed、rgb888:width * 3后对齐到128 xrgb8888:width * 4后对齐到128 必填 |
double hinc |
水平放大倍数,aicore输出通道配置。 |
[0.03125, 1) or (1, 4] 缩放系数配置,超出配置范围,VPC会提示出错,如果不要缩放填1。 必填 |
double vinc |
垂直放大倍数,aicore输出通道配置。 |
[0.03125, 1) or (1, 4] 缩放系数配置,超出配置范围,VPC会提示出错,如果不要缩放填1。 必填 |
double jpeg_hinc |
水平放大倍数,jpege输出通道配置。 |
[0.03125, 1) or (1, 4] 缩放系数配置,超出配置范围,VPC会提示出错。 选填(目前不适用) |
double jpeg_vinc |
垂直放大倍数,jpege输出通道配置。 |
[0.03125, 1) or (1, 4] 缩放系数配置,超出配置范围,VPC会提示出错。 选填(目前不适用) |
int hmax |
与原点在水平方向的最大偏移。 |
此值必须为奇数,如果不用裁剪,此值配置成输入宽度-1。 必填 |
int hmin |
与原点在水平方向的最小偏移。 |
此值必须为偶数。 如果不用裁剪,此值配置成0。 必填 |
int vmax |
与原点在垂直方向的最大偏移。 |
此值必须为奇数。 如果不用裁剪,此值配置成输入宽度-1。 必填 |
int vmin |
与原点在垂直方向的最小偏移。 |
此值必须为偶数。 如果不用裁剪,此值配置成0。 |
int out_width |
输出图像宽度。 |
此值必须为偶数(2对齐)。 当使用智能指针申请输出buffer时,不需要填,当使用自己申请的内存作为输出buffer时,必填。 |
int out_high |
输出图像高度。 |
此值必须为偶数(2对齐)。 当使用智能指针申请输出buffer时,不需要填,当使用自己申请的内存作为输出buffer时,必填。 |
int h_stride |
图像高度步长,同int:stride描述。此值无需配置。 |
此值默认为16,即默认输入高度为16对齐。 选填 |
char* in_buffer |
输入buffer。 |
调用方需保证输入buffer的大小与in message中配置的长度与宽度一致,即:如果输入是yuv420 semi planner nv12格式的图片,其图像大小为:宽*高*1.5,而输入的buffer大小与如上计算结果不符,则会导致VPC调用失败。 必填 |
int in_buffer_size |
输入buffer大小。 |
此值用来进行输入buffer校验。 必填 |
shared_ptr<AutoBuffer> auto_out_buffer_1 |
输出buffer1。 |
使用VPC基础功能(裁剪,缩放)需要配置此buffer,此buffer为调用方申请智能指针当做参数传入DVPP,由DVPP内部申请输出buffer。用户可读取该buffer获取输出图片。 与下一个参数out_buffer选填一个即可。 |
char* out_buffer |
输出buffer。 |
使用VPC基础功能(裁剪,缩放)需要配置此buffer,,此buffer为调用方申请的内存,需保证首地址128对齐。用户可读取该buffer获取输出图片。 与上一个参数auto_out_buffer_1选填一个即可。 |
int out_buffer_1_size |
输出buffer1大小。 |
此值用来进行输出buffer校验。 如果采用shared_ptr<AutoBuffer> auto_out_buffer_1申请输出内存则选填,如果采用 char* out_buffer申请输出内存则必填。 |
shared_ptr<AutoBuffer> auto_out_buffer_2 |
此智能指针为vpc双通道的另外一个通道输出,为预留接口 |
-- |
int out_buffer_2_size |
此buffersize为auto_out_buffer_2智能指针输出buffer2大小,为预留接口 |
-- |
int use_flag |
使用vpc功能的标志。 |
默认为0。 选填 |
VpcOverLayReverse overlay |
叠加结构体,预留。 |
预留 |
VpcCollageReverse collage |
拼接结构体,预留。 |
预留 |
RDMACHANNEL rdma |
rdma参数为HFBC数据专用配置结构体。 |
具体请参见Rdma通道结构体RDMACHANNEL。 |
VpcTurningReverse turningReverse1 |
Vpc优化预留接口。 |
|
bool isVpcUseTurning1 |
标志是否使用Vpc优化,预留接口,此标志与turningReverse1配合使用。 |
-- |
VpcTurningReverse turningReverse2 |
Vpc优化预留接口。 |
|
bool isVpcUseTurning2 |
标志是否使用Vpc优化,预留接口,此标志与turningReverse2配合使用。 |
-- |
string *yuvscaler_paraset |
yuvscaler_paraset指针接收VPC滤波参数集文件的路径和文件名数组。 说明:
|
参数集文件路径为device侧的绝对文件路径+文件名,如{"/home/HwHiAiUser/matrix/YUVScaler_pra.h"}。 |
unsigned int yuvscaler_paraset_size |
yuvscaler_paraset指针指向的string数组元素个数(默认为1)。 |
yuvscaler_paraset_size<=10 |
unsigned int index |
index变量对应yuvscaler_paraset的数组索引。 |
0<=index<10 |
输入图片格式 |
VPC的rank参数配置 |
输出图片格式 |
---|---|---|
YUV420sp NV12 |
NV12 = 0 |
YUV420sp NV21 |
YUV420sp NV21 |
NV21 = 1 |
YUV420sp NV21 |
YUV420sp NV12 |
NV12 = 1 |
YUV420sp NV12 |
YUV420sp NV21 |
NV21 = 0 |
YUV420sp NV12 |
YUV422sp NV16 |
NV16 = 1 |
YUV420sp NV12 |
YUV422sp NV61 |
NV61 = 0 |
YUV420sp NV12 |
YUV422sp NV16 |
NV16 = 0 |
YUV420sp NV21 |
YUV422sp NV61 |
NV61 = 1 |
YUV420sp NV21 |
YUV444sp 444spUV |
444spUV = 1 |
YUV420sp NV12 |
YUV444sp 444spVU |
444spVU= 0 |
YUV420sp NV12 |
YUV444sp 444spUV |
444spUV = 0 |
YUV420sp NV21 |
YUV444sp 444spVU |
444spVU= 1 |
YUV420sp NV21 |
YUV422packet YUYV |
YUYV = 2 |
YUV420sp NV12 |
YUV422packet YVYU |
YVYU = 3 |
YUV420sp NV21 |
YUV422packet UYVY |
UYVY = 4 |
YUV420sp NV12 |
YUV444packet YUV |
YUV = 5 |
YUV420sp NV12 |
RGB888 RGB |
RGB = 6 |
YUV420sp NV12 |
RGB888 BGR |
BGR = 7 |
YUV420sp NV21 |
RGB888 RGB |
BGR = 7 |
YUV420sp NV21 |
RGB888 BGR |
RGB = 6 |
YUV420sp NV12 |
XRGB8888 RGBA |
RGBA = 8 |
YUV420sp NV12 |
XRGB8888 RGBA |
BGRA = 9 |
YUV420sp NV21 |
调用示例
- VPC基础功能调用示例
gXxxxx为配置参数,参数配置与VPC调用分为两个阶段。
Step1:通过DVPP_CTL_TOOL_CASE_GET_RESIZE_PARAM命令字调用DvppCtl,获取配置参数,DvppCtl的入参为resize_paramo_in_msg,出参为resize_param_out_msg。即通过resize_param_in_msg将原始图片的宽高,裁剪区域(hmax,hmin,vamx,vmin),以及输出宽高等参数传给DVPP,DVPP通过计算将重新生成的裁剪区域(hmax,hmin,vamx,vmin)以及缩放比(hinc,vinc)返回给调用方。
Step2:调用方将第一步返回的参数通过vpc_in_msg结构体传递给DVPP,并将DvppCtl调用命令字改为DVPP_CTL_VPC_PROC,执行并获得处理结果。
dvppapi_ctl_msg dvppApiCtlMsg; vpc_in_msg vpcInMsg; resize_param_in_msg resize_in_param; resize_param_out_msg resize_out_param; resize_in_param.src_width = gWidth; resize_in_param.src_high = gHigh; resize_in_param.hmax = gHmax; resize_in_param.hmin = gHmin; resize_in_param.vmax = gVmax; resize_in_param.vmin = gVmin; resize_in_param.dest_width = floor(gHinc * (gHmax - gHmin + 1) + 0.5); resize_in_param.dest_high = floor(gVinc * (gVmax - gVmin + 1) + 0.5); printf("width =%d\n", gWidth); printf("high =%d\n", gHigh); printf("hmax =%d\n", gHmax); printf("hmin =%d\n", gHmin); printf("vmax =%d\n", gVmax); printf("vmin =%d\n", gVmin); printf("out width =%d\n", resize_in_param.dest_width); printf("out hight =%d\n", resize_in_param.dest_high ); dvppApiCtlMsg.in = (void *)(&resize_in_param); dvppApiCtlMsg.out = (void *)(&resize_out_param); IDVPPAPI *pidvppapi = NULL; CreateDvppApi(pidvppapi); if (DvppCtl(pidvppapi, DVPP_CTL_TOOL_CASE_GET_RESIZE_PARAM, &dvppApiCtlMsg) != 0) { printf("call DVPP_CTL_TOOL_CASE_GET_RESIZE_PARAM process faild!\n"); DestroyDvppApi(pidvppapi); return; } int bufferSize = 0; vpcInMsg.format = gFormat; vpcInMsg.cvdr_or_rdma = gcvdr_or_rdma; vpcInMsg.bitwidth = gBitwidth; vpcInMsg.rank = gRank; vpcInMsg.width = gWidth; vpcInMsg.high = gHigh; vpcInMsg.stride = gStride; vpcInMsg.hmax = resize_out_param.hmax; vpcInMsg.hmin = resize_out_param.hmin; vpcInMsg.vmax = resize_out_param.vmax; vpcInMsg.vmin = resize_out_param.vmin; vpcInMsg.vinc = resize_out_param.vinc; vpcInMsg.hinc = resize_out_param.hinc; printf("resize_out_param.hinc = %lf\n", resize_out_param.hinc); printf("resize_out_param.vinc = %lf\n", resize_out_param.vinc); printf("resize_out_param.hmax = %d\n", resize_out_param.hmax); printf("resize_out_param.hmin = %d\n", resize_out_param.hmin); printf("resize_out_param.vmax = %d\n", resize_out_param.vmax); printf("resize_out_param.vmin = %d\n", resize_out_param.vmin); printf("format =%d\n", vpcInMsg.format); printf("rank =%d\n", vpcInMsg.rank); printf("width =%d\n", vpcInMsg.width); printf("high =%d\n", vpcInMsg.high); printf("stride =%d\n", vpcInMsg.stride); printf("hmax =%d\n", vpcInMsg.hmax); printf("hmin =%d\n", vpcInMsg.hmin); printf("vmax =%d\n", vpcInMsg.vmax); printf("vmin =%d\n", vpcInMsg.vmin); printf("vinc =%F\n", vpcInMsg.vinc); printf("hinc =%F\n", vpcInMsg.hinc); if (vpcInMsg.cvdr_or_rdma == 0) { printf("rdma channel\n"); int buffersize ; char * payloadY ; char * payloadC ; char * headY ; char * headC ; FILE * rdmaimage = fopen(in_file_name, "rb"); if (vpcInMsg.bitwidth == 10) { buffersize = vpcInMsg.width * vpcInMsg.high * 2 + 512 * 1024; payloadY = (char*)memalign(128, buffersize); headY = payloadY + vpcInMsg.width * vpcInMsg.high * 2; headC = headY + 256 * 1024; vpcInMsg.rdma.luma_payload_addr = (long)payloadY; vpcInMsg.rdma.chroma_payload_addr = (long)payloadY + 640; } else { buffersize = vpcInMsg.width * vpcInMsg.high * 1.5 + 512 * 1024; payloadY = (char*)memalign(128, buffersize); payloadC = payloadY + vpcInMsg.width * vpcInMsg.high; headY = payloadC + vpcInMsg.width * vpcInMsg.high / 2; headC = headY + 256 * 1024; vpcInMsg.rdma.luma_payload_addr = (long)payloadY; vpcInMsg.rdma.chroma_payload_addr = (long)payloadC; } fread(payloadY, 1, buffersize, rdmaimage); vpcInMsg.rdma.luma_head_addr = (long)headY; vpcInMsg.rdma.chroma_head_addr = (long)headC; vpcInMsg.rdma.luma_head_stride = vpcInMsg.stride; vpcInMsg.rdma.chroma_head_stride = vpcInMsg.stride; vpcInMsg.rdma.luma_payload_stride = gpYStride; vpcInMsg.rdma.chroma_payload_stride = gpUVStride; fclose(rdmaimage); printf("luma payload stride= %d\n", vpcInMsg.rdma.luma_payload_stride ); printf("chroma payload stride= %d\n", vpcInMsg.rdma.chroma_payload_stride ); } else { alloc_buffer(vpcInMsg.width, vpcInMsg.high, vpcInMsg.stride, bufferSize); if (open_image(in_file_name, vpcInMsg.width, vpcInMsg.high, vpcInMsg.stride) != 0) { printf("open file failed~\n"); free(in_buffer); return; } vpcInMsg.in_buffer = in_buffer; vpcInMsg.in_buffer_size = bufferSize; } //alloc in and out buffer shared_ptr<AutoBuffer> auto_out_buffer = make_shared<AutoBuffer>(); vpcInMsg.auto_out_buffer_1 = auto_out_buffer; dvppApiCtlMsg.in = (void *)(&vpcInMsg); dvppApiCtlMsg.in_size = sizeof(vpc_in_msg); if (pidvppapi != NULL) { for (int i = 0; i < gLoop; i++) { if (DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg) != 0) { printf("call dvppctl process faild!\n"); DestroyDvppApi(pidvppapi); free(in_buffer); return; } } } else { printf("pidvppapi is null!\n"); } free(in_buffer); FILE *fp = NULL; fp = fopen(out_file_name, "wb+"); if (fp == NULL) { printf("open file %s failed~\n", out_file_name); free(in_buffer); return; } fwrite(vpcInMsg.auto_out_buffer_1->getBuffer(), 1, vpcInMsg.auto_out_buffer_1->getBufferSize(), fp); fflush(fp); fclose(fp); DestroyDvppApi(pidvppapi); return;
- RawData8k基础功能调用示例
参数配置:
dvppapi_ctl_msg dvppApiCtlMsg; vpc_in_msg vpcInMsg; vpcInMsg.width = gWidth; vpcInMsg.high = gHigh; vpcInMsg.stride = gStride; vpcInMsg.out_width = gOutWidth; vpcInMsg.out_high = gOutHigh; printf("width =%d\n", vpcInMsg.width); printf("high =%d\n", vpcInMsg.high); printf("stride =%d\n", vpcInMsg.stride); printf("out_width =%d\n", vpcInMsg.out_width); printf("out_high =%d\n", vpcInMsg.out_high); //alloc in and out buffer char *in_buffer = (char *)malloc(vpcInMsg.width * vpcInMsg.high * 1.5); if (in_buffer = NULL) { printf("malloc fail\n"); return; } shared_ptr<AutoBuffer> auto_out_buffer = make_shared<AutoBuffer>(); FILE *yuvimage = fopen(in_file_name, "rb"); if (yuvimage == NULL) { printf("no such file!,file_name=[%s]\n", in_file_name); free(in_buffer); return; } else { fread(in_buffer, 1, vpcInMsg.width * vpcInMsg.high * 3 / 2, yuvimage); } vpcInMsg.rank = gRank; vpcInMsg.in_buffer = in_buffer; vpcInMsg.in_buffer_size = vpcInMsg.width * vpcInMsg.high * 1.5; vpcInMsg.auto_out_buffer_1 = auto_out_buffer; vpcInMsg.use_flag = 1; dvppApiCtlMsg.in = (void *)(&vpcInMsg); dvppApiCtlMsg.in_size = sizeof(vpc_in_msg); IDVPPAPI *pidvppapi = NULL; CreateDvppApi(pidvppapi); if (pidvppapi != NULL) { if (DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg) != 0) { printf("call dvppctl process faild!\n"); DestroyDvppApi(pidvppapi); free(in_buffer); fclose(yuvimage); return; } } else { printf("pidvppapi is null!\n"); } DestroyDvppApi(pidvppapi); FILE *fp = NULL; fp = fopen(out_file_name, "wb+"); if (fp != NULL) { fwrite(vpcInMsg.auto_out_buffer_1->getBuffer(), 1, vpcInMsg.auto_out_buffer_1->getBufferSize(), fp); fflush(fp); fclose(fp); } else { fclose(yuvimage); return; } free(in_buffer); fclose(yuvimage); return;
- Rawdata叠加基础功能调用实例
dvppapi_ctl_msg dvppApiCtlMsg; vpc_in_msg vpcInMsg; //配置RawData叠加参数 vpcInMsg.use_flag = 2; vpcInMsg.overlay.image_type = 0; vpcInMsg.overlay.image_rank_type = 0; vpcInMsg.overlay.bit_width = 8; vpcInMsg.overlay.in_width_image = 1000; vpcInMsg.overlay.in_high_image = 1000; vpcInMsg.overlay.in_width_text = 500; vpcInMsg.overlay.in_high_text = 390; vpcInMsg.overlay.image_width_stride = 2; vpcInMsg.overlay.image_high_stride = 2; vpcInMsg.overlay.text_width_stride = 2; vpcInMsg.overlay.text_high_stride = 2; vpcInMsg.overlay.in_buffer_image = NULL; vpcInMsg.overlay.in_buffer_text = NULL; vpcInMsg.overlay.auto_overlay_out_buffer = make_shared<AutoBuffer>(); //初始化图像内存 if(NULL == (vpcInMsg.overlay.in_buffer_image = (char*)malloc(vpcInMsg.overlay.in_width_image*vpcInMsg.overlay.in_high_image*3/2))) { printf("in_buffer_image alloc failed!\n"); return ; } //打开图片至申请的内存中 char image_file[50] = "yuv_data_0"; FILE * yuvimage = fopen(image_file,"rb"); if(NULL == yuvimage) { printf("VPC_TEST: yuv image open faild!"); return ; } else { fread(vpcInMsg.overlay.in_buffer_image, 1,vpcInMsg.overlay.in_width_image*vpcInMsg.overlay.in_high_image*3/2,yuvimage); fclose(yuvimage); yuvimage = NULL; } //初始化文字内存 if(NULL == (vpcInMsg.overlay.in_buffer_text = (char*)malloc(vpcInMsg.overlay.in_width_text*vpcInMsg.overlay.in_high_text*3/2))) { printf("in_buffer_text alloc failed!"); free(vpcInMsg.overlay.in_buffer_image); return ; } //打开text图片至申请的内存中 char text_file[50] = "text_0"; FILE * yuvtext = fopen(text_file,"rb"); if(NULL == yuvtext) { printf("VPC_TEST: yuv text image open faild!"); free(vpcInMsg.overlay.in_buffer_image); return ; } else { fread(vpcInMsg.overlay.in_buffer_text, 1,vpcInMsg.overlay.in_width_text*vpcInMsg.overlay.in_high_text*3/2, yuvtext); fclose(yuvtext); yuvtext = NULL; } dvppApiCtlMsg.in = (void*)(&vpcInMsg); dvppApiCtlMsg.in_size = sizeof(vpc_in_msg); IDVPPAPI *pidvppapi = NULL; CreateDvppApi(pidvppapi); if(pidvppapi!=NULL) { if(DvppCtl(pidvppapi,DVPP_CTL_VPC_PROC,&dvppApiCtlMsg)!= 0) { printf("call dvppctl process faild!\n"); DestroyDvppApi(pidvppapi); free(vpcInMsg.overlay.in_buffer_image); free(vpcInMsg.overlay.in_buffer_text); return ; } DestroyDvppApi(pidvppapi); FILE * fp = fopen("./out_overlay_image_share","wb+"); fwrite(vpcInMsg.overlay.auto_overlay_out_buffer->getBuffer(),1,vpcInMsg.overlay.in_width_image*vpcInMsg.overlay.in_high_image*3/2,fp); fflush(fp); fclose(fp); fp=NULL; return ; } else { printf("pidvppapi is null!\n"); return ; } if(NULL != vpcInMsg.overlay.in_buffer_image) { free(vpcInMsg.overlay.in_buffer_image); vpcInMsg.overlay.in_buffer_image = NULL; } if(NULL != vpcInMsg.overlay.in_buffer_text) { free(vpcInMsg.overlay.in_buffer_text); vpcInMsg.overlay.in_buffer_text = NULL; }
- Rawdata拼接基础功能调用实例
dvppapi_ctl_msg dvppApiCtlMsg; vpc_in_msg vpcInMsg; //配置RawData拼接参数 vpcInMsg.use_flag = 3; vpcInMsg.collage.image_type = 0; vpcInMsg.collage.image_rank_type = 0; vpcInMsg.collage.bit_width = 8; vpcInMsg.collage.in_width = 1000; vpcInMsg.collage.in_high = 1000; vpcInMsg.collage.width_stride = 2; vpcInMsg.collage.high_stride = 2; vpcInMsg.collage.collage_type = 0; vpcInMsg.collage.auto_out_buffer = make_shared<AutoBuffer>(); char image_file[4][50] = {"yuv_data_0","yuv_data_1","yuv_data_2","yuv_data_3"}; //初始化图像内存without stride************begin************ for(int i=0; i<4; i++) { if(NULL == (vpcInMsg.collage.in_buffer[i] = (char*)malloc(vpcInMsg.collage.in_width* vpcInMsg.collage.in_high*3/2))) { printf("in_buffer_image alloc failed!\n"); for(int j=0; j<i; j++) { free(vpcInMsg.collage.in_buffer[j]); } return ; } //打开图片至申请的内存中 FILE * yuvimage = fopen(image_file[i],"rb"); if(NULL == yuvimage) { printf("PVC_TEST: yuv image open faild!"); return ; } else { fread(vpcInMsg.collage.in_buffer[i], 1,vpcInMsg.collage.in_width* vpcInMsg.collage.in_high*3/2,yuvimage); fclose(yuvimage); yuvimage = NULL; } } dvppApiCtlMsg.in = (void*)(&vpcInMsg); dvppApiCtlMsg.in_size = sizeof(vpc_in_msg); IDVPPAPI *pidvppapi = NULL; CreateDvppApi(pidvppapi); if(pidvppapi!=NULL) { if(DvppCtl(pidvppapi,DVPP_CTL_VPC_PROC,&dvppApiCtlMsg)!= 0) { printf("call dvppctl process faild!\n"); DestroyDvppApi(pidvppapi); for(int i=0; i<4; i++) { free(vpcInMsg.collage.in_buffer[i]); } return ; } DestroyDvppApi(pidvppapi); FILE * fp = fopen("./out_collage_image_share","wb+"); fwrite(vpcInMsg.collage.auto_out_buffer->getBuffer(),1,vpcInMsg.collage.in_width*vpcInMsg.collage.in_high*6,fp); fflush(fp); fclose(fp); fp=NULL; return ; } else { printf("pidvppapi is null!\n"); return ; } for(int i=0; i<4; i++) { if(NULL != vpcInMsg.collage.in_buffer[i]) { free(vpcInMsg.collage.in_buffer[i]); vpcInMsg.collage.in_buffer[i] = NULL; } }
- VPCAPI调用
IDVPPAPI *pidvppapi = NULL; CreateDvppApi(pidvppapi); if(pidvppapi!=NULL) { if(0 != DvppCtl(pidvppapi,DVPP_CTL_VPC_PROC,&dvppApiCtlMsg)) { printf("call dvppctl process faild!\n"); DestroyDvppApi(pidvppapi); return -1; } } else printf("pidvppapi is null!\n"); DestroyDvppApi(pidvppapi);
- VPC Resize参数配置获取功能调用示例
gXxxxx为配置参数
dvppapi_ctl_msg dvppApiCtlMsg; vpc_in_msg vpcInMsg; resize_param_in_msg resize_in_param; resize_param_out_msg resize_out_param; resize_in_param.src_width = gWidth; resize_in_param.src_high = gHigh; resize_in_param.hmax = gHmax; resize_in_param.hmin = gHmin; resize_in_param.vmax = gVmax; resize_in_param.vmin = gVmin; resize_in_param.dest_width = floor(gHinc * (gHmax - gHmin + 1) + 0.5); resize_in_param.dest_high = floor(gVinc * (gVmax - gVmin + 1) + 0.5); dvppApiCtlMsg.in = (void *)(&resize_in_param); dvppApiCtlMsg.out = (void *)(&resize_out_param); IDVPPAPI *pidvppapi = NULL; CreateDvppApi(pidvppapi); if (0 != DvppCtl(pidvppapi, DVPP_CTL_TOOL_CASE_GET_RESIZE_PARAM, &dvppApiCtlMsg)) { printf("call dvppctl process faild!\n"); DestroyDvppApi(pidvppapi); return; } int bufferSize = 0; vpcInMsg.format = gFormat; vpcInMsg.cvdr_or_rdma = gcvdr_or_rdma; vpcInMsg.bitwidth = gBitwidth; vpcInMsg.rank = gRank; vpcInMsg.width = gWidth; vpcInMsg.high = gHigh; vpcInMsg.stride = gStride; vpcInMsg.hmax = resize_out_param.hmax; vpcInMsg.hmin = resize_out_param.hmin; vpcInMsg.vmax = resize_out_param.vmax; vpcInMsg.vmin = resize_out_param.vmin; vpcInMsg.vinc = resize_out_param.vinc; vpcInMsg.hinc = resize_out_param.hinc;
CMDLIST功能及参数说明
不推荐使用CMDLIST功能,后续版本会删除。旧版本中的VPC功能和CMDLIST功能均迁移到VPC功能,请参见VPC参数说明处的参数说明进行开发。
CMDLIST是VPC的一个扩展功能,其概念为将原来需要多次启动VPC执行的功能,合并到一次的“启动”与“完成中断返回”间完成。简单来说,CMDLIST适用于对时延要求不高,处理的图片分辨率低,数量多的场景。
详细信息以及取值范围请参见表10-27。
成员变量 |
说明 |
取值范围 |
---|---|---|
unsigned int:format |
输入图像类型。 |
typedef enum { yuv420_semi_plannar =0,//0 yuv422_semi_plannar,//1 yuv444_semi_plannar,//2 yuv422_packed,//3 yuv444_packed,//4 rgb888_packed,//5 xrgb8888_packed,//6 yuv400_semi_plannar,//7 invalid_image_type,//20 }Imge_Type; |
unsigned int:rank |
输出图像格式(NV12或NV21)。 |
详见表10-26。 |
unsigned int:bitwidth |
位深,通常为8bit。10bit只有在图像格式为YUV/YVU420 Semi-Planar且为HFBC压缩场景下使用。 |
8:8bit 10:10bit |
int:is_hfbc_image |
输入图像通道,通常设置为1,走CVDR通道,仅当VDEC输出的HFBC格式数据作为输入时走RDMA通道。 |
0:RDMA 1:CVDR |
unsigned int:in_width |
输入图像宽度,必须128对齐。 |
128~4096 |
unsigned int:in_height |
输入图像高度,必须16对齐。 |
16~4096 |
unsigned int:width_step |
图像步长。 |
yuv400sp、yuv420sp、yuv422sp、yuv444sp:width对齐到128。 yuv422packed:width * 2后对齐到128。 yuv444packed、rgb888:width * 3后对齐到128。 xrgb8888:width * 4后对齐到128。 |
unsigned int:need_debug |
内部调试预留值,通常设置为0。 |
0:普通模式。 1:debug模式。 |
CMDLIST_IN_BUFFER:in_buffer |
输入图像内存地址指针,是一个联合体,普通非压缩图像选择bare_buffer,需要128对齐。HFBC压缩图像地址选择hfbc_buffer。 |
union CMDLIST_IN_BUFFER { char* bare_buffer; RDMACHANNEL* hfbc_buffer; }; 与vpc_in_msg中RDMACHANNEL相同, |
ROI_CONFIG:roi_config |
输出参数配置结构体。 |
|
IMAGE_CONFIG*:next |
下一个IMAGE_CONFIG结构体指针。多图时配置,单图时配置为NULL。 |
-- |
结构体详细定义请见DDK包下include/inc/dvpp/dvpp_config.h。
可以通过图10-6所示,直观了解输入参数信息。
此图将crop和resize操作归一化到一个图中,理解如下。
- 只做crop时,相当于resize系数为1。
- 只做resize时,相当于crop大小为原图。
- 输入图片的宽128对齐,高16对齐,且输入输出图片最大分辨率为4K。
- 内存地址对齐,需要用到如下接口。
输入输出图片内存地址128对齐,需要用HIAI_DVPP_DMalloc的申请大页内存。
申请接口:HIAI_DVPP_DMalloc(size)。
- 根据输出图片比上crop后图片计算缩放系数,需要在[0.03125,4]范围内。
- 输出内存大小需要根据输出宽128对齐,高16对齐后的分辨率计算。
- 调用一次cmdlist接口,最多支持32张图,每图最多支持256个框。
调用示例
/************************************************************************************************/ /*****用例说明:********************************************************************************** 此用例以一张1920x1088 yuv420 nv12图片作为输入 输入图片文件名: "file1_1920x1088_nv12.yuv" 对输入图片的操作:抠出5张子图,均缩放到224x224; ************************************************************************************************ ************************************************************************************************/ int main() { int ret = 0; //读取输入文件 char image_file[128] = "file1_1920x1088_nv12.yuv"; ifstream in_stream(image_file); if (!in_stream.is_open()) { printf("can not open %s.\n", image_file); return -1; } in_stream.seekg(0, ios::end); int file_len = in_stream.tellg(); char* in_buffer = (char *)HIAI_DVPP_DMalloc(file_len); in_stream.seekg(0, ios::beg); in_stream.read(in_buffer, file_len); in_stream.close(); //开始添加第一个image的配置 IMAGE_CONFIG* image_config = (IMAGE_CONFIG*)malloc(sizeof(IMAGE_CONFIG)); image_config->in_buffer.bare_buffer = in_buffer; //目前用到的都是非压缩图 image_config->format = 0; image_config->rank = 1;//输入nv12输出也为nv12,rank填1 image_config->bitwidth = 8;//目前用到的都是8bit一个单位的 image_config->in_width = 1920; image_config->in_height = 1088; image_config->width_step = 1920;//这个值同宽 //开始添加第一个抠图的配置,该例子抠图区域:(0,0),(511,511)围成的区域 ROI_CONFIG* roi_config = &image_config->roi_config; //开始配置crop参数 roi_config->crop_config.enable = 1; //注:当只要resize的时候,crop参数只要这个配置为0 roi_config->crop_config.hmin = 0; roi_config->crop_config.hmax = 511; roi_config->crop_config.vmin = 0; roi_config->crop_config.vmax = 511; //开始配置输出通道参数 roi_config->sum_out.enable = 1; //开启第一通道输出 roi_config->sum_out.out_width = 224; roi_config->sum_out.out_height = 224; int out_buffer_size = AlignUp(224,128)*AlignUp(224,16)*3/2; roi_config->sum_out.out_buffer = (char*)HIAI_DVPP_DMalloc(out_buffer_size); ROI_CONFIG* last_roi = roi_config; //开始添加第2到第5个抠图的配置 for (int i = 0 ; i < 4; i++) { ROI_CONFIG* roi_config = (ROI_CONFIG*)malloc(sizeof(ROI_CONFIG)); //开始配置crop参数 roi_config->crop_config.enable = 1; roi_config->crop_config.hmin = 100*i; roi_config->crop_config.hmax = 299 + 100*i; roi_config->crop_config.vmin = 100*i; roi_config->crop_config.vmax = 299 + 100*i; //开始配置输出通道参数 roi_config->sum_out.enable = 1; roi_config->sum_out.out_width = 224; roi_config->sum_out.out_height = 224; out_buffer_size = AlignUp(224,128)*AlignUp(224,16)*3/2; roi_config->sum_out.out_buffer = (char*)HIAI_DVPP_DMalloc(out_buffer_size); roi_config->next = nullptr; last_roi->next = roi_config; last_roi = roi_config; } //开始调用dvpp的cmdlist接口 IDVPPAPI *pidvppapi = NULL; //无论后面调用多少次,createdvppapi只要一次调用就好 ret = CreateDvppApi(pidvppapi); if (ret != 0) { printf("creat dvpp api faild!\n"); return -1; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = (void *)(image_config); dvppApiCtlMsg.in_size = sizeof(IMAGE_CONFIG); ret = DvppCtl(pidvppapi, DVPP_CTL_CMDLIST_PROC, &dvppApiCtlMsg); if (0 != ret) { printf("call cmdlist dvppctl process faild!\n"); } else { printf("cmdlist success.\n"); } ret += DestroyDvppApi(pidvppapi); roi_config = image_config->roi_config.next; while (roi_config != nullptr) { ROI_CONFIG* next_roi = roi_config->next; UNMAP(roi_config->sum_out.out_buffer, out_buffer_size); free(roi_config); roi_config = next_roi; } UNMAP(image_config->roi_config.sum_out.out_buffer, out_buffer_size); free(image_config); UNMAP(in_buffer, file_len); return ret; }
VENC功能及参数说明
不推荐使用旧版本中的VENC功能,后续版本会删除。旧版本中的VENC功能已迁移到VENC新接口,请参见VENC功能接口进行开发。
功能
实现YUV420/YVU420图片数据的编码。
- VENC支持以下格式输入:
YUV420 semi-planner NV12/NV21-8bit
- VENC输出格式为:
H264 BP/MP/HP
H265 MP
VENC性能指标
场景 |
总帧率 |
---|---|
1080p * 1路(不支持多路) |
30fps |
入参:venc_in_msg
成员变量 |
说明 |
取值范围 |
---|---|---|
Int width |
图像宽度。 |
128~1920,且为偶数。 |
Int height |
图像高度。 |
128~1920,且为偶数。 |
Int coding_type |
视频编码协议H265-main level(0)、H264-baseline level(1)、H264-main level(2)、H264-high level(3) |
0~3
|
Int YUV_store_type |
YUV图像存储格式。 |
0或者1
|
char* input_data |
输入图像数据地址。 |
不能为NULL。 |
Int input_data_size |
输入图像数据大小。 |
正数。 |
shared_ptr<AutoBuffer> output_data_queue |
输出编码码流数据地址。 |
需要配置此buffer,此buffer为调用方申请智能指针当做参数传入DVPP。用户可读取该buffer获取输出图片。 必填 |
出参
暂无。
调用示例
void TEST_3() //venc demo { int read_file_size; int unit_file_size; FILE *fp = fopen(in_file_name, "rb"); if (fp == NULL) { printf("open file: %s failed.\n", in_file_name); return; } printf("open yuv success \n"); fseek(fp, 0L, SEEK_END); int file_size = ftell(fp); fseek(fp, 0L, SEEK_SET); venc_in_msg venc_msg; venc_msg.width = gWidth; venc_msg.height = gHigh; venc_msg.coding_type = gFormat; venc_msg.YUV_store_type = gBitwidth; venc_msg.output_data_queue = make_shared<AutoBuffer>(); unit_file_size = gWidth * gHigh * 3 / 2 * MAX_FRAME_NUM_VENC; //单次文件大小为16帧 dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = (void *)(&venc_msg); dvppApiCtlMsg.in_size = sizeof(venc_in_msg); IDVPPAPI *pidvppapi = NULL; CreateDvppApi(pidvppapi); char out_filename[] = "venc.bin"; FILE *outputBufferFile; outputBufferFile = fopen (out_filename, "wb+"); do{ read_file_size = file_size>unit_file_size? unit_file_size:file_size; //每次读取文件大小不能超过16帧 venc_msg.input_data = (char *)malloc(read_file_size); int read_len = fread(venc_msg.input_data, 1, read_file_size, fp); printf("file size is %d,read len is %d.\n", read_file_size, read_len); venc_msg.input_data_size = read_len; if (pidvppapi != NULL) { if (DvppCtl(pidvppapi, DVPP_CTL_VENC_PROC, &dvppApiCtlMsg) != 0) { printf("call dvppctl process faild!\n"); DestroyDvppApi(pidvppapi); fclose(fp); fclose(outputBufferFile); return; } if (venc_msg.output_data_queue->getBufferSize() > 100) { //防止编码结果只含有头部信息 char* out_buf = venc_msg.output_data_queue->getBuffer(); int out_buf_size = venc_msg.output_data_queue->getBufferSize(); int write_size = fwrite(out_buf, 1, out_buf_size, outputBufferFile); fflush(outputBufferFile); } else { printf("venc output data is too small : %d \n", venc_msg.output_data_queue->getBufferSize()); } } else { printf("pidvppapi is null!\n"); } if (venc_msg.input_data != NULL) { free(venc_msg.input_data); venc_msg.input_data = NULL; } file_size = file_size - unit_file_size; } while (file_size > 0); DestroyDvppApi(pidvppapi); fclose(outputBufferFile); fclose(fp); return; }