摄像头实验-编码视频流
硬件要求:
- DshanPI-CanMV开发板
- Type-C数据线 x2
- GC2093摄像头
开发环境:
- Ubuntu20.04
注意:在学习前请按照《K230 SDK环境搭建》搭建好K230的开发环境或者直接获取资料光盘中搭建好环境的Ubuntu虚拟机。
配套源码:https://pan.baidu.com/s/1VBd0n3FKO0bj8yHOWk4HEw?pwd=ov5d 提取码:ov5d
具体位置: 12_多媒体应用示例源码\06_sample_venc_100ask
1.视频编码架构
典型的编码流程包括了输入图像的接收、图像内容的遮挡和覆 盖、图像的编码、以及码流的输出等过程。
编码模块由VENC接收通道、编码通道、2D接收通道、2D运算模块组成。编码能力和2D运算能力见下表。
编码数据流程图中的绿色箭头所示路径,为单独做2D运算的流程。蓝色箭头所示路径为单独做编码运算的流程。紫色箭头所示路径为先做2D运算再进行编码的流程。
表 1-1 编码能力
H264 | HEVC | JPEG | |
---|---|---|---|
输入格式 | YUV420 NV12 8bit, ARGB8888, BGRA8888 | YUV420 NV12 8bit, ARGB8888, BGRA8888 | YUV420 NV12 8bit, YUV422 UYVY 8bit, ARGB8888, BGRA8888 |
输出格式 | YUV420 H.264 Baseline Profile(BP) ; H.264 Main Profile(MP) ; H.264 High Profile(HP); H.264 High 10 Profile(HP) | YUV420 HEVC (H.265) Main ; HEVC (H.265) Main 10 Profile | YUV420 and YUV422 JPEG baseline sequential |
最大分辨率 | 3840x2160 | 3840x2160 | 8192x8192 |
码率控制模式 | CBR/VBR/FIXQP | CBR/VBR/FIXQP | FIXQP |
GOP | I/P帧 | I/P帧 | - |
编码通道 | 4路 | 4路 | 4路 |
注意:H264/HEVC/JPEG共用4路。
表1-2 2D运算能力
video输入格式 | video输出格式 | 叠加数据格式 | 最大分辨率 |
---|---|---|---|
I420/NV12/ARGB8888/BGRA8888 | 同输入格式 | ARGB8888/ARGB4444/ARGB1555 | 3840x2160 |
1.1 编码通道
编码通道作为基本容器,保存编码通道的多种用户设置和管理编码通道的多种内部资源。编码通道完成图像叠加和编 码的功能。2D模块实现图像叠加运算,编码器模块实现图像编码,两者既可以单独使用,也可以协同使用。
2.应用层程序编译与解析
2.1 新增程序
2.1.1 新建工程文件夹
在k230_sdk/src/big/mpp/userapps/sample目录下新建工程
mkdir sample_venc_100ask
2.1.2 修改Makefile
修改k230_sdk/src/big/mpp/userapps/sample目录下的Makefile文件,新增sample_venc_100ask工程的编译规则
@cd sample_venc_100ask; make || exit 1
@cd sample_venc_100ask; make clean
2.1.3 进入工程目录
cd sample_venc_100ask/
2.1.4 新建源码文件
vi sample_venc_100ask.c
填入源码。
2.1.5 新建Makefile文件
vi Makefile
填入一下内容:
CURRECT_DIR_NAME=$(shell basename `pwd`)
LOCAL_SRC_DIR = $(shell pwd)
BIN = $(MPP_SRC_DIR)/userapps/sample/elf/$(CURRECT_DIR_NAME).elf
LIBPATH = $(MPP_LIB_PATH)
LIBS = $(MPP_LIBS)
LOCAL_CFLAGS = -I$(LOCAL_SRC_DIR)
SRCS = $(wildcard $(LOCAL_SRC_DIR)/*.c)
OBJS = $(patsubst %.c,%.o,$(SRCS))
all: $(BIN)
@-rm -f $(OBJS)
echo "${PWD}/Makefile all"
$(OBJS): %.o : %.c
@$(CC) $(CC_CFLAGS) $(LOCAL_CFLAGS) $(BSP_CFLGAS) $(RTSMART_CFLAGS) $(MPP_USER_CFLGAS) -c $< -o $@
$(BIN): $(OBJS)
$(CC) -o $(BIN) $(LINKFLAG) -Wl,--whole-archive -Wl,--no-whole-archive -n --static $(OBJS) -L$(LIBPATH) -Wl,--start-group $(LIBS) -Wl,--end-group
clean:
echo "${PWD}/Makefile clean"
-rm -rf $(BIN)
-rm -f $(OBJS)
.PHONY: all clean
2.2 程序编译
1.进入K230SDK目录
cd ~/k230_sdk
2.下载toolchain和准备源码
source tools/get_download_url.sh && make prepare_sourcecode
3.挂载工具链目录
sudo mount --bind $(pwd)/toolchain /opt/toolchain
4.配置板级型号
make CONF=k230_canmv_dongshanpi_defconfig prepare_memory
5.编译程序
make mpp-apps
等待编译完成,编译完成后,可执行程序sample_venc_100ask.elf
会生成在k230_sdk/src/big/mpp/userapps/sample/elf
目录下。
使用ADB将可执行程序传输至开发板中
adb push src/big/mpp/userapps/sample/elf/sample_venc_100ask.elf /sharefs/app
2.3 程序运行
使用串口软件访问开发板的大核串口终端。
如果没有关闭开机自启程序,可按下q+回车键可退出开机自启程序。
1.进入可执行文件目录
cd /sharefs/app
2.运行程序
./sample_venc_100ask.elf
执行完成后效果如下所示:
3.输入q
并按下回车即可退出程序。
2.4 程序解析
代码流程图如下所示:
2.4.1 初始化视频输入设备
// 初始化视频输入设备属性结构体
memset(&dev_attr, 0, sizeof(k_vicap_dev_attr));
// 初始化视频输入通道属性结构体
memset(&chn_attr, 0, sizeof(k_vicap_chn_attr));
// 初始化传感器信息结构体
memset(&sensor_info, 0, sizeof(k_vicap_sensor_info));
// 设置传感器类型
sensor_info.sensor_type = GC2093_MIPI_CSI2_1920X1080_30FPS_10BIT_LINEAR;
ret = kd_mpi_vicap_get_sensor_info(sensor_info.sensor_type, &sensor_info);
2.4.2 设置视频输入设备属性
dev_attr.acq_win.width = sensor_info.width; // 480
dev_attr.acq_win.height = sensor_info.height; // 800
dev_attr.mode = VICAP_WORK_ONLINE_MODE;
2.4.3 初始化视频输入设备
ret = kd_mpi_vicap_init(vicap_dev);
2.4.4 初始化视频缓冲区
sample_vb_init(K_FALSE);
2.4.5 设置视频输入通道属性
attr.venc_attr.pic_width = width; // 宽
attr.venc_attr.pic_height = height; // 高
attr.venc_attr.stream_buf_size = STREAM_BUF_SIZE; // 流缓冲区大小
attr.venc_attr.stream_buf_cnt = OUTPUT_BUF_CNT; // 流缓冲区数量
attr.rc_attr.rc_mode = rc_mode;
attr.rc_attr.cbr.src_frame_rate = 30;
attr.rc_attr.cbr.dst_frame_rate = 30;
attr.rc_attr.cbr.bit_rate = bitrate;
attr.venc_attr.type = type; // 编码类型
attr.venc_attr.profile = profile;
2.4.6 创建视频编码器通道
ret = kd_mpi_venc_create_chn(ch, &attr);
2.4.7 启动编码器通道
ret = kd_mpi_venc_start_chn(ch);
2.4.8 绑定视频输入和编码器
static void sample_vi_bind_venc(k_u32 chn_id)
{
k_mpp_chn venc_mpp_chn;
k_mpp_chn vi_mpp_chn;
k_s32 ret;
#ifdef ENABLE_VDSS
vi_mpp_chn.mod_id = K_ID_VICAP;
#else
vi_mpp_chn.mod_id = K_ID_VI;
#endif
venc_mpp_chn.mod_id = K_ID_VENC; // 视频编码器通道模块ID
venc_mpp_chn.dev_id = 0; // 视频编码器通道设备ID
venc_mpp_chn.chn_id = chn_id; // 视频编码器通道ID
vi_mpp_chn.dev_id = chn_id;
vi_mpp_chn.chn_id = chn_id;
ret = kd_mpi_sys_bind(&vi_mpp_chn, &venc_mpp_chn);
if (ret)
{
printf("kd_mpi_sys_bind failed:0x%x\n", ret);
}
return;
}
2.4.9 启动视频输入设备
void sample_vicap_start(k_u32 ch)
{
#ifdef ENABLE_VDSS
k_s32 ret;
ret = kd_mpi_vdss_start_pipe(0, ch);
CHECK_RET(ret, __func__, __LINE__);
#else
k_s32 ret;
ret = kd_mpi_vicap_start_stream(VICAP_DEV_ID_0);
CHECK_RET(ret, __func__, __LINE__);
#endif
}
2.4.10 创建输出线程
pthread_create(&g_venc_conf.output_tid, NULL, output_thread, &info);