RKMedia 是瑞芯微提供的媒体处理方案,可支持应用软件快速开发。rkmedia
为 C 接口,其实现均在easymedia
中。后者提供 C++ 接口。
rkmedia
中的行人检测示例,执行的操作为:
通过命令行传入配置文件。
load_cfg 加载 RTSP 会话配置。
if (argc != 2) {
printf("You must input the file of cfg.\n");
printf("example file: oem/usr/share/rtsp-nn.cfg.\n");
return -1;
}
load_cfg(argv[1]);
create_rtsp_demo 初始化 rtsp。
RK_MPI_SYS_Init 初始化各种类型的通道数组。
// init rtsp
printf("init rtsp\n");
g_rtsplive = create_rtsp_demo(554);
// init mpi
printf("init mpi\n");
RK_MPI_SYS_Init();
逐一创建会话,绑定输入通道。
其中第二个通道设置为VI_WORK_MODE_GOD_MODE
用于 RKNN 处理。
SAMPLE_COMMON_VI_Start 设置通道属性并启动。
SAMPLE_COMMON_VENC_Start 启动视频流编码,海思中对应函数为SAMPLE_COMM_VENC_Start
。
调用 RK_MPI_VI_StartStream 开启视频流,或者调用 RK_MPI_SYS_Bind 将数据源绑定到数据接收者。
rtsp_set_video 设置编码信息。
rtsp_get_reltime
rtsp_get_ntptime
rtsp_sync_video_ts
// create session
for (int i = 0; i < cfg.session_count; i++) {
cfg.session_cfg[i].session =
rtsp_new_session(g_rtsplive, cfg.session_cfg[i].path);
// VI create
printf("VI create\n");
cfg.session_cfg[i].stViChn.enModId = RK_ID_VI;
cfg.session_cfg[i].stViChn.s32ChnId = i;
if (i == RK_NN_INDEX)
SAMPLE_COMMON_VI_Start(&cfg.session_cfg[i], VI_WORK_MODE_GOD_MODE);
else
SAMPLE_COMMON_VI_Start(&cfg.session_cfg[i], VI_WORK_MODE_NORMAL);
// VENC create
printf("VENC create\n");
cfg.session_cfg[i].stVenChn.enModId = RK_ID_VENC;
cfg.session_cfg[i].stVenChn.s32ChnId = i;
SAMPLE_COMMON_VENC_Start(&cfg.session_cfg[i]);
if (i == DRAW_INDEX)
RK_MPI_VI_StartStream(0, cfg.session_cfg[i].stViChn.s32ChnId);
else
RK_MPI_SYS_Bind(&cfg.session_cfg[i].stViChn,
&cfg.session_cfg[i].stVenChn);
// rtsp video
printf("rtsp video\n");
switch (cfg.session_cfg[i].video_type) {
case RK_CODEC_TYPE_H264:
rtsp_set_video(cfg.session_cfg[i].session, RTSP_CODEC_ID_VIDEO_H264, NULL,
0);
break;
case RK_CODEC_TYPE_H265:
rtsp_set_video(cfg.session_cfg[i].session, RTSP_CODEC_ID_VIDEO_H265, NULL,
0);
break;
default:
printf("video codec not support.\n");
break;
}
rtsp_sync_video_ts(cfg.session_cfg[i].session, rtsp_get_reltime(),
rtsp_get_ntptime());
}
create_rknn_list 创建 rknn_list 列表。
在线程中调用 GetMediaBuffer 获取缓存并调用 rockx 进行检测跟踪。
另一线程中调用 MainStream 绘制结果。
create_rknn_list(&rknn_list_);
// Get the sub-stream buffer for humanoid recognition
pthread_t read_thread;
pthread_create(&read_thread, NULL, GetMediaBuffer, NULL);
// The mainstream draws a box asynchronously based on the recognition result
pthread_t main_stream_thread;
pthread_create(&main_stream_thread, NULL, MainStream, NULL);
设置SIGINT
信号的处理函数为 sig_proc。
调用 RK_MPI_SYS_GetMediaBuffer 获得 MEDIA_BUFFER。
rtsp_tx_video
RK_MPI_MB_ReleaseBuffer 释放缓存。
rtsp_do_event
signal(SIGINT, sig_proc);
while (g_flag_run) {
for (int i = 0; i < cfg.session_count; i++) {
MEDIA_BUFFER buffer;
// send video buffer
buffer = RK_MPI_SYS_GetMediaBuffer(
RK_ID_VENC, cfg.session_cfg[i].stVenChn.s32ChnId, 0);
if (buffer) {
rtsp_tx_video(cfg.session_cfg[i].session, RK_MPI_MB_GetPtr(buffer),
RK_MPI_MB_GetSize(buffer),
RK_MPI_MB_GetTimestamp(buffer));
RK_MPI_MB_ReleaseBuffer(buffer);
}
}
rtsp_do_event(g_rtsplive);
}
RK_MPI_SYS_UnBind 解除通道间的绑定。
RK_MPI_VI_DisableChn 关闭输入通道。
RK_MPI_VENC_DestroyChn 销毁编码通道。
rtsp_del_demo
destory_rknn_list
for (int i = 0; i < cfg.session_count; i++) {
if (i != DRAW_INDEX)
RK_MPI_SYS_UnBind(&cfg.session_cfg[i].stViChn,
&cfg.session_cfg[i].stVenChn);
RK_MPI_VI_DisableChn(0, cfg.session_cfg[i].stViChn.s32ChnId);
RK_MPI_VENC_DestroyChn(cfg.session_cfg[i].stVenChn.s32ChnId);
}
rtsp_del_demo(g_rtsplive);
destory_rknn_list(&rknn_list_);
return 0;
cfg
为全局变量,demo_cfg 类型,保存多个 Session 信息。MPP_CHN_S
// cfgline:
// path=%s video_type=%d width=%u height=%u
FILE *fp