跳到主要内容

摄像头实验-编码视频流

硬件要求:

  • 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.视频编码架构

image-20241106175525675

典型的编码流程包括了输入图像的接收、图像内容的遮挡和覆盖、图像的编码、以及码流的输出等过程。

编码模块由VENC接收通道、编码通道、2D接收通道、2D运算模块组成。编码能力和2D运算能力见下表。

编码数据流程图中的绿色箭头所示路径,为单独做2D运算的流程。蓝色箭头所示路径为单独做编码运算的流程。紫色箭头所示路径为先做2D运算再进行编码的流程。

表 1-1 编码能力

H264HEVCJPEG
输入格式YUV420 NV12 8bit, ARGB8888, BGRA8888YUV420 NV12 8bit, ARGB8888, BGRA8888YUV420 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 ProfileYUV420 and YUV422 JPEG baseline sequential
最大分辨率3840x21603840x21608192x8192
码率控制模式CBR/VBR/FIXQPCBR/VBR/FIXQPFIXQP
GOPI/P帧I/P帧-
编码通道4路4路4路

注意:H264/HEVC/JPEG共用4路。

表1-2 2D运算能力

video输入格式video输出格式叠加数据格式最大分辨率
I420/NV12/ARGB8888/BGRA8888同输入格式ARGB8888/ARGB4444/ARGB15553840x2160

1.1 编码通道

编码通道作为基本容器,保存编码通道的多种用户设置和管理编码通道的多种内部资源。编码通道完成图像叠加和编码的功能。2D模块实现图像叠加运算,编码器模块实现图像编码,两者既可以单独使用,也可以协同使用。

encode channel

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

image-20241018211707565

@cd sample_venc_100ask; make clean

image-20241018211812935

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

执行完成后效果如下所示:

image-20241021102839994

3.输入q并按下回车即可退出程序。

2.4 程序解析

代码流程图如下所示:

image-20241024154711051

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);