@(HI3518EV200学习)
主要分析的三个文件:
- mpp下的makefile.param
- mpp/sample下的makefile.param
- mpp/sample/venc下的makefile
mpp/sample/venc下的makefile
# Hisilicon Hi3516 sample Makefile
include ../Makefile.param # 包含mpp/sample下的makefile.param
#ifeq ($(SAMPLE_PARAM_FILE), )
# SAMPLE_PARAM_FILE:=../Makefile.param
# include $(SAMPLE_PARAM_FILE)
#endif
# target source
SRC := $(wildcard *.c) #通配 展开
OBJ := $(SRC:%.c=%.o) #所有的.c替换.o
TARGET := $(OBJ:%.o=%) #所有X.o变为X
.PHONY : clean all #.PHONY是一个伪目标
all: $(TARGET) 所有的目标
# SENSOR_LIBS MPI_LIBS 在mpp/sample下的makefile.param 中指定
# AUDIO_LIBA CC CFLAGS 在mpp下的makefile.param
$(TARGET):%:%.o $(COMM_OBJ)
$(CC) $(CFLAGS) -lpthread -lm -o $@ $^ $(MPI_LIBS) $(AUDIO_LIBA) $(SENSOR_LIBS)
clean: #清除编译生成文件
@rm -f $(TARGET)
@rm -f $(OBJ)
@rm -f $(COMM_OBJ)
cleanstream: #清理指定格式流文件
@rm -f *.h264
@rm -f *.jpg
@rm -f *.mjp
@rm -f *.mp4
**mpp/sample下的makefile.param **
# Hisilicon Hi3518e sample Makefile.param
ifeq ($(PARAM_FILE), )
PARAM_FILE:=../../../mpp/Makefile.param #PARAM_FILE为空,包含mpp下的makefile.param
include $(PARAM_FILE)
endif
ifeq ($(WDR),) #判断WDR是否定义
WDR :=n
endif
#以下CHIP_ID如果未定义,则定义
#CHIP_ID ?= CHIP_HI3516C_V200
CHIP_ID ?= CHIP_HI3518E_V200
#CHIP_ID ?= CHIP_HI3518E_V201
################# select sensor type for your sample ####################
#SENSOR_TYPE ?= APTINA_9M034_DC_720P_30FPS
#SENSOR_TYPE ?= SONY_IMX222_DC_1080P_30FPS
#SENSOR_TYPE ?= SONY_IMX222_DC_720P_30FPS
#SENSOR_TYPE ?= APTINA_AR0130_DC_720P_30FPS
#SENSOR_TYPE ?= PANASONIC_MN34222_MIPI_1080P_30FPS
#SENSOR_TYPE ?= APTINA_AR0230_HISPI_1080P_30FPS
SENSOR_TYPE ?= OMNIVISION_OV9712_DC_720P_30FPS
#SENSOR_TYPE ?= OMNIVISION_OV9732_DC_720P_30FPS
#SENSOR_TYPE ?= OMNIVISION_OV9750_MIPI_720P_30FPS
#SENSOR_TYPE ?= OMNIVISION_OV9752_MIPI_720P_30FPS
#SENSOR_TYPE ?= OMNIVISION_OV2718_MIPI_1080P_25FPS
##########################################################################
SENSOR_LIBS := $(REL_LIB)/libisp.a #REL_LIB在mpp下的makefile.param有定义
#以下根据不同的sensor,选择不同的sensor.a
ifeq ($(SENSOR_TYPE), APTINA_AR0130_DC_720P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_ar0130.a
endif
ifeq ($(SENSOR_TYPE), APTINA_AR0130_DC_960P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_ar0130.a
endif
ifeq ($(SENSOR_TYPE), APTINA_9M034_DC_720P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_9m034.a
endif
ifeq ($(SENSOR_TYPE), APTINA_9M034_DC_960P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_9m034.a
endif
ifeq ($(SENSOR_TYPE), SONY_IMX222_DC_1080P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_imx222.a
endif
ifeq ($(SENSOR_TYPE), SONY_IMX222_DC_720P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_imx222.a
endif
ifeq ($(SENSOR_TYPE), APTINA_AR0230_HISPI_1080P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_ar0230.a
endif
ifeq ($(SENSOR_TYPE), PANASONIC_MN34222_MIPI_1080P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_mn34222.a
endif
ifeq ($(SENSOR_TYPE), OMNIVISION_OV9712_DC_720P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_ov9712.a
endif
ifeq ($(SENSOR_TYPE), OMNIVISION_OV9732_DC_720P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_ov9732.a
endif
ifeq ($(SENSOR_TYPE), OMNIVISION_OV9750_MIPI_720P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_ov9750.a
endif
ifeq ($(SENSOR_TYPE), OMNIVISION_OV9752_MIPI_720P_30FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_ov9752.a
endif
ifeq ($(SENSOR_TYPE), OMNIVISION_OV2718_MIPI_1080P_25FPS)
SENSOR_LIBS += $(REL_LIB)/libsns_ov2718.a
endif
#iniparser
SENSOR_LIBS += $(REL_LIB)/lib_cmoscfg.a
SENSOR_LIBS += $(REL_LIB)/lib_iniparser.a
#########################################################################
# 指定包含文件的路径
COMMON_DIR:=$(PWD)/../common
INC_FLAGS := -I$(COMMON_DIR)
INC_FLAGS += -I$(REL_INC)
INC_FLAGS += -I$(SDK_PATH)/mpp/component/acodec
ifeq ($(MPP_BUILD), y)
INC_FLAGS += -I$(SDK_PATH)/mpp/$(EXTDRV)/tw2865
INC_FLAGS += -I$(SDK_PATH)/mpp/$(EXTDRV)/tlv320aic31
else
INC_FLAGS += -I$(SDK_PATH)/mpp/extdrv/tw2865
INC_FLAGS += -I$(SDK_PATH)/mpp/$(EXTDRV)/tlv320aic31
endif
ISP_VERSION := ISP_V2
SENSOR_LIBS += $(REL_LIB)/lib_hiae.a
SENSOR_LIBS += $(REL_LIB)/lib_hiawb.a
SENSOR_LIBS += $(REL_LIB)/lib_hiaf.a
SENSOR_LIBS += $(REL_LIB)/lib_hidefog.a
MPI_LIBS := $(REL_LIB)/libmpi.a
MPI_LIBS += $(REL_LIB)/libive.a
MPI_LIBS += $(REL_LIB)/libmd.a
CFLAGS := -Wall -g $(INC_FLAGS) -D$(HIARCH) -DHICHIP=$(HICHIP) -DSENSOR_TYPE=$(SENSOR_TYPE) -D$(HIDBG) -D$(HI_FPGA) -DCHIP_ID=$(CHIP_ID) -lpthread -lm -ldl -D$(ISP_VERSION)
ifeq ($(CHIP_ID), CHIP_HI3516C_V200)
CFLAGS += -Dhi3516cv200
endif
ifeq ($(CHIP_ID), CHIP_HI3518E_V200)
CFLAGS += -Dhi3518ev200
endif
ifeq ($(CHIP_ID), CHIP_HI3518E_V201)
CFLAGS += -Dhi3518ev201
endif
ifeq ($(SENSOR_TYPE), APTINA_AR0230_HISPI_1080P_30FPS)
CFLAGS += -DHI_MIPI_ENABLE
endif
ifeq ($(SENSOR_TYPE), OMNIVISION_OV4682_MIPI_1080P_30FPS)
CFLAGS += -DHI_MIPI_ENABLE
endif
ifeq ($(SENSOR_TYPE), OMNIVISION_OV4682_MIPI_720P_30FPS)
CFLAGS += -DHI_MIPI_ENABLE
endif
ifeq ($(SENSOR_TYPE), PANASONIC_MN34222_MIPI_1080P_30FPS)
CFLAGS += -DHI_MIPI_ENABLE
endif
ifeq ($(SENSOR_TYPE), OMNIVISION_OV9750_MIPI_720P_30FPS)
CFLAGS += -DHI_MIPI_ENABLE
endif
ifeq ($(SENSOR_TYPE), OMNIVISION_OV9752_MIPI_720P_30FPS)
CFLAGS += -DHI_MIPI_ENABLE
endif
################ select audio codec type for your sample ################
ACODEC_TYPE ?= ACODEC_TYPE_INNER
#external acodec
#ACODEC_TYPE ?= ACODEC_TYPE_AK7756
#ACODEC_TYPE ?= ACODEC_TYPE_TLV320AIC31
ifeq ($(ACODEC_TYPE), ACODEC_TYPE_INNER)
CFLAGS += -DHI_ACODEC_TYPE_INNER
endif
ifeq ($(ACODEC_TYPE), ACODEC_TYPE_AK7756)
CFLAGS += -DHI_ACODEC_TYPE_AK7756
endif
ifeq ($(ACODEC_TYPE), ACODEC_TYPE_TLV320AIC31)
CFLAGS += -DHI_ACODEC_TYPE_TLV320AIC31
endif
#########################################################################
CFLAGS += $(LIBS_CFLAGS)
CFLAGS += -DLCD_ILI9342
COMM_SRC := $(wildcard $(COMMON_DIR)/*.c)
#DEL_SRC := $(COMMON_DIR)/sample_comm_audio.c
#COMM_SRC := $(filter-out $(DEL_SRC), $(COMM_SRC))
COMM_OBJ := $(COMM_SRC:%.c=%.o)
**mpp下的makefile.param **太多了,就不列出来了
sample_venc.c中的main如下
int main(int argc, char *argv[])
{
HI_S32 s32Ret;
if ( (argc < 2) || (1 != strlen(argv[1])))
{
SAMPLE_VENC_Usage(argv[0]); //打印帮助 使用
return HI_FAILURE;
}
signal(SIGINT, SAMPLE_VENC_HandleSig); //异常处理
signal(SIGTERM, SAMPLE_VENC_HandleSig);
switch (*argv[1])
{
//根据不同的参数,视频编码输出不同的组合
case '0':/* H.264@1080p@30fps+H.265@1080p@30fps+H.264@D1@30fps */
s32Ret = SAMPLE_VENC_1080P_CLASSIC();
break;
case '1':/* 1*1080p mjpeg encode + 1*1080p jpeg */
s32Ret = SAMPLE_VENC_1080P_MJPEG_JPEG();
break;
case '2':/* low delay */
s32Ret = SAMPLE_VENC_LOW_DELAY();
break;
case '3':/* roibg framerate */
s32Ret = SAMPLE_VENC_ROIBG_CLASSIC();
break;
case '4':/* Thumbnail of 1*1080p jpeg */
s32Ret = SAMPLE_VENC_1080P_JPEG_Thumb();
break;
#ifndef hi3518ev201
case '5':/* H.264 Svc-t */
s32Ret = SAMPLE_VENC_SVC_H264();
break;
#endif
default:
printf("the index is invaild!\n");
SAMPLE_VENC_Usage(argv[0]);
return HI_FAILURE;
}
if (HI_SUCCESS == s32Ret)
printf("program exit normally!\n");
else
printf("program exit abnormally!\n");
exit(s32Ret);
}
之前使用的参数为0,就先以参数为0进行分析 SAMPLE_VENC_1080P_CLASSIC
抽重点语句解析
step 1: init sys variable //系统各个值的初始化
①、根据sensor类型获取sensor的size
②、根据size决定encode流有几路及大小
③、配置每一路编码流程的video buffer (pixformat支持420和422、宽度16、32、64对齐)
SAMPLE_COMM_VI_GetSizeBySensor() //获取sensor的类型来更新检查当前视频的size
//我们用OV9712,走这个分支,所以会有三个视频
else if (PIC_HD720 == enSize[0])
{
enSize[1] = PIC_VGA;
enSize[2] = PIC_QVGA;
s32ChnNum = 3;
}
//三个流 ,走这个分支
if(s32ChnNum >= 3)
{
u32BlkSize = SAMPLE_COMM_SYS_CalcPicVbBlkSize(gs_enNorm,\
enSize[2], SAMPLE_PIXEL_FORMAT, SAMPLE_SYS_ALIGN_WIDTH); //根据视频参数,计算VB块大小
stVbConf.astCommPool[2].u32BlkSize = u32BlkSize;
stVbConf.astCommPool[2].u32BlkCnt = g_u32BlkCnt; //这个值为4
}
step 2: mpp system init.
系统去初始化 HI_MPI_SYS_Exit()
视频缓存区去初始化 HI_MPI_SYS_Exit()
设置视频缓存区属性 HI_MPI_VB_SetConf()
初始化MPP视频缓存池 HI_MPI_VB_Init()
配置系统控制参数 HI_MPI_SYS_SetConf()
初始化MPP系统 HI_MPI_SYS_Init()
SAMPLE_COMM_SYS_Init() //先去初始化,后初始化
step 3: start vi dev & chn to capture 视频输入部分配置 开启VI,并捕获
①、VI配置
1、视频输入接口、视频输入制式、旋转属性、WDR工作模式、mirror,、flip属性
2、视频采集接口开启,根据sensor类型来决定注册sensor,ISP初始化(3A注册)、运行ISP HI_MPI_ISP_Run()
3、设置VI设备属性HI_MPI_VI_SetDevAttr()、启动VI设备 HI_MPI_VI_EnableDev()
4、设置通道属性 HI_MPI_VI_SetChnAttr()、 启动VI通道 HI_MPI_VI_EnableChn
step 4: start vpss and vi bind vpss 开启视频处理并绑定
①、创建一个 VPSS GROUP HI_MPI_VPSS_CreateGrp()
②、设置3DNR HI_MPI_VPSS_SetNRParam()
③、启用HI_MPI_VPSS_StartGrp()
④、绑定VI和VPSS HI_MPI_SYS_Bind()
step5:start stream venc(开启venc流视频编码)
①、Create Venc Channel HI_MPI_VENC_CreateChn()
②、Start Recv Venc Pictures HI_MPI_VENC_StartRecvPic()
③、VENC绑定VPSS通道 SAMPLE_COMM_VENC_BindVpss()
step 6: stream venc process – get stream, then save it to file. 开启venc处理,获取流,并保存到文件
①、check & prepare save-file & venc-fd
②、Start to get streams of each channel.
③、 close save-file
码率控制器实现对编码码率进行控制
从信息学的角度分析,图像的压缩比越低,压缩图像的质量越高;图像压缩比例越高,压缩图像的质量越低。对于场景变化的真实场景,图像质量稳定,编码码率会波动;编码码率稳定,图像质量会波动。以 H.264 编码为例,通常图像 Qp 越低,图像的质量越好,码率越高;图像 Qp 越高,图像质量越差,码率越低。
码率模式:H.264\H.265 协议编码通道 CBR、VBR、AVBR、FIXQP
MJPEG 协议编码通道 CBR、VBR、FIXQP 三种码率控制模式
CBR
CBR(Constant Bit Rate)固定比特率。即在码率统计时间内保证编码码率平稳。码率稳定主要由两个量来评估,这两个量都可以由用户在创建编码通道时指定。
码率统计时间 u32StatTime
行级码率控制调节幅度 u32RowQpDelta
VBR
VBR(Variable Bit Rate)可变比特率,即允许在码率统计时间内编码码率波动,从而保证编码图像质量平稳。以 H.264 编码为例,VENC 模块提供用户可设置 MaxQp,MinQp,MaxBitrate 和 ChangePos。MaxQp,MinQp 用于控制图像的质量范围,MaxBitrate 用于钳位码率统计时间内的最大编码码率,ChangePos 用于控制开始调整Qp 的码率基准线。当编码码率大于 MaxBitrateChangePos 时,图像 qp 会逐步向MaxQp 调整,如果图像 QP 达到 MaxQp,QP 会被钳位到最大值,MaxBitrate 的钳位效果失效,编码码率有可能会超出 MaxBitrate。当编码码率小于 MaxBitrateChangePos时,图像 QP 会逐步向 MinQp 调整,如果图像 QP 达到 MinQp,此时编码的码率已经达到最大值,而且图像质量最好。
AVBR
AVBR(Adaptive Variable Bit Rate)可变比特率,即允许在码率统计时间内编码码率波动,从而保证编码图像质量平稳。码率控制内部会检测当前场景的运动静止状态,在运动时用较高码率编码,在静止时主动降低目标码率。以 H.264 编码为例,VENC 模块提供用户可设置 MaxBitrate,ChangePos 和 MinStillPercent。MaxBitrate 表示运动场景下的最大码率,MaxBitrateChangePosMinStillPercent 表示静止情况下的最小码率。根据运动程度的不同目标码率会在最大码率和最小码率间调整。MaxQp,MinQp 用于控制图像的质量范围,码率控制以 QP 钳位为最高优先级,超出 MinQp,MaxQp 范围内码率控制将失效。
FIXQP
Fix Qp 固定 Qp 值。在码率统计时间内,编码图像所有宏块 Qp 值相同,采用用户设定的图像 Qp 值,I 帧和 P 帧的 QP 值可以分别设置。