Firefly1126中RKMedia中摄像头录制程序编写
作者:互联网
Firefly1126中RKMedia中摄像头录制程序编写
1,录制视频主要流程
主要流程可分为开启录制,从摄像头获取码流,码流编码,编码保存,本录制程序中使用芯片为RV1126,摄像头为USB摄像头,分辨率为640*480,生图格式为YUYV422。
2,参考代码
主要参考代码有原厂中rkmedia_vi_venc_test.c与rkmedia_venc_local_file_test.c两个文件,新文件命名为rkmedia_vi_venc_local_file_test.c
3,添加编译信息
在同原厂SDK同一目录下sdk//external/rkmedia/examples中的CMakeList.txt中添加编译信息如下:
#--------------------------
# rkmedia_vi_venc_local_file_test
#--------------------------
add_executable(rkmedia_vi_venc_local_file_test rkmedia_vi_venc_local_file_test.c ${COMMON_SRC})
add_dependencies(rkmedia_vi_venc_local_file_test easymedia)
target_link_libraries(rkmedia_vi_venc_local_file_test easymedia)
target_include_directories(rkmedia_vi_venc_local_file_test PRIVATE ${CMAKE_SOURCE_DIR}/include)
install(TARGETS rkmedia_vi_venc_local_file_test RUNTIME DESTINATION "bin")
4,编写代码,
主要与rkmedia_vi_venc_test.c与rkmedia_venc_local_file_test.c文件中不同的地方有,
去除帧打包命令:video_packet_cb,并去除rkmedia_venc_local_file_test.c中相关读取文件相关代码,同时以开辟新线程的方式获取venc中编码码流代替vi_venc_test.c中回调函数方式,代码更清晰简洁。
相关代码如下:
// Copyright 2020 Fuzhou Rockchip Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// rkmedia_vi_venc_local_file_test.c
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include "common/sample_common.h"
#include "rkmedia_api.h"
#include "rkmedia_venc.h"
static bool quit = false;
// static FILE *g_output_file;
static RK_S32 g_s32FrameCnt = -1;
//退出信号
static void sigterm_handler(int sig) {
fprintf(stderr, "signal %d\n", sig);
quit = true;
}
//捕获视频数据保存线程
static void *GetMediaBuffer(void *arg) {
char *ot_path = (char *)arg;
printf("#Start %s thread, arg:%p, out path: %s\n", __func__, arg, ot_path);
FILE *save_file = fopen(ot_path, "w");
if (!save_file)
printf("ERROR: Open %s failed!\n", ot_path);
MEDIA_BUFFER mb = NULL;
while (!quit) {
//从VENC通道0中阻塞获取数据
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, 0, -1);
if (!mb) {
printf("RK_MPI_SYS_GetMediaBuffer get null buffer!\n");
break;
}
printf("Get packet:ptr:%p, fd:%d, size:%zu, mode:%d, channel:%d, "
"timestamp:%lld\n",
RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetFD(mb), RK_MPI_MB_GetSize(mb),
RK_MPI_MB_GetModeID(mb), RK_MPI_MB_GetChannelID(mb),
RK_MPI_MB_GetTimestamp(mb));
if (save_file)
fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), save_file);
RK_MPI_MB_ReleaseBuffer(mb);
}
if (save_file)
fclose(save_file);
return NULL;
}
static RK_CHAR optstr[] = "?::a::w:h:c:o:e:d:I:M:";
static const struct option long_options[] = {
{"aiq", optional_argument, NULL, 'a'},
{"device_name", required_argument, NULL, 'd'},
{"width", required_argument, NULL, 'w'},
{"height", required_argument, NULL, 'h'},
{"frame_cnt", required_argument, NULL, 'c'},
{"output_path", required_argument, NULL, 'o'},
{"encode", required_argument, NULL, 'e'},
{"camid", required_argument, NULL, 'I'},
{"multictx", required_argument, NULL, 'M'},
{"fps", required_argument, NULL, 'f'},
{"hdr_mode", required_argument, NULL, 'h' + 'm'},
{"vi_buf_cnt", required_argument, NULL, 'b' + 'c'},
{"help", optional_argument, NULL, '?'},
{NULL, 0, NULL, 0},
};
static void print_usage(const RK_CHAR *name) {
printf("usage example:\n");
#ifdef RKAIQ
printf("\t%s [-a [iqfiles_dir]] [-w 1920] "
"[-h 1080]"
"[-c 150] "
"[-d rkispp_scale0] "
"[-e 0] "
"[-I 0] "
"[-M 0] "
"[-o output.h264] \n",
name);
printf("\t-a | --aiq: enable aiq with dirpath provided, eg:-a "
"/oem/etc/iqfiles/, "
"set dirpath emtpty to using path by default, without this option aiq "
"should run in other application\n");
printf("\t-M | --multictx: switch of multictx in isp, set 0 to disable, set "
"1 to enable. Default: 0\n");
printf("\t--fps fps of vi.\n");
printf("\t--hdr_mode [normal hdr2 hdr3].\n");
printf("\t--vi_buf_cnt buffer count of vi.\n");
#else
printf("\t%s [-w 1920] "
"[-h 1080]"
"[-c 150] "
"[-I 0] "
"[-d rkispp_scale0] "
"[-e 0] "
"[-o output.h264] \n",
name);
#endif
printf("\t-w | --width: VI width, Default:1920\n");
printf("\t-h | --heght: VI height, Default:1080\n");
printf("\t-c | --frame_cnt: frame number of output, Default:150\n");
printf("\t-I | --camid: camera ctx id, Default 0\n");
printf("\t-d | --device_name set pcDeviceName, Default:rkispp_scale0, "
"Option:[rkispp_scale0, rkispp_scale1, rkispp_scale2]\n");
printf(
"\t-e | --encode: encode type, Default:h264, Value:h264, h265, mjpeg\n");
printf("\t-o | --output_path: output path, Default:NULL\n");
}
int main(int argc, char *argv[]) {
RK_U32 u32Width = 1920;
RK_U32 u32Height = 1080;
RK_CHAR *pDeviceName = "rkispp_scale0";
RK_CHAR *pOutPath = NULL;
RK_CHAR *pIqfilesPath = NULL;
CODEC_TYPE_E enCodecType = RK_CODEC_TYPE_H264;
RK_CHAR *pCodecName = "H264";
RK_S32 s32CamId = 0;
RK_U32 u32BufCnt = 3;
#ifdef RKAIQ
RK_BOOL bMultictx = RK_FALSE;
RK_U32 u32Fps = 30;
rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
#endif
int c;
int ret = 0;
while ((c = getopt_long(argc, argv, optstr, long_options, NULL)) != -1) {
const char *tmp_optarg = optarg;
switch (c) {
case 'a':
if (!optarg && NULL != argv[optind] && '-' != argv[optind][0]) {
tmp_optarg = argv[optind++];
}
if (tmp_optarg) {
pIqfilesPath = (char *)tmp_optarg;
} else {
pIqfilesPath = "/oem/etc/iqfiles";
}
break;
case 'w':
u32Width = atoi(optarg);
break;
case 'h':
u32Height = atoi(optarg);
break;
case 'c':
g_s32FrameCnt = atoi(optarg);
break;
case 'o':
pOutPath = optarg;
break;
case 'd':
pDeviceName = optarg;
break;
case 'e':
if (!strcmp(optarg, "h264")) {
enCodecType = RK_CODEC_TYPE_H264;
pCodecName = "H264";
} else if (!strcmp(optarg, "h265")) {
enCodecType = RK_CODEC_TYPE_H265;
pCodecName = "H265";
} else if (!strcmp(optarg, "mjpeg")) {
enCodecType = RK_CODEC_TYPE_MJPEG;
pCodecName = "MJPEG";
} else {
printf("ERROR: Invalid encoder type.\n");
return 0;
}
break;
case 'I':
s32CamId = atoi(optarg);
break;
#ifdef RKAIQ
case 'M':
if (atoi(optarg)) {
bMultictx = RK_TRUE;
}
break;
case 'f':
u32Fps = atoi(optarg);
printf("#u32Fps = %u.\n", u32Fps);
break;
case 'h' + 'm':
if (strcmp(optarg, "normal") == 0) {
hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
} else if (strcmp(optarg, "hdr2") == 0) {
hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
} else if (strcmp(optarg, "hdr3") == 0) {
hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR3;
} else {
print_usage(argv[0]);
return 0;
}
printf("#hdr_mode = %u.\n", hdr_mode);
break;
#endif
case 'b' + 'c':
u32BufCnt = atoi(optarg);
printf("#vi buffer conunt = %u.\n", u32BufCnt);
break;
case '?':
default:
print_usage(argv[0]);
return 0;
}
}
printf("#Device: %s\n", pDeviceName);
printf("#CodecName:%s\n", pCodecName);
printf("#Resolution: %dx%d\n", u32Width, u32Height);
printf("#Frame Count to save: %d\n", g_s32FrameCnt);
printf("#Output Path: %s\n", pOutPath);
printf("#CameraIdx: %d\n\n", s32CamId);
#ifdef RKAIQ
printf("#bMultictx: %d\n\n", bMultictx);
printf("#Aiq xml dirpath: %s\n\n", pIqfilesPath);
#endif
if (pIqfilesPath) {
#ifdef RKAIQ
SAMPLE_COMM_ISP_Init(s32CamId, hdr_mode, bMultictx, pIqfilesPath);
SAMPLE_COMM_ISP_Run(s32CamId);
SAMPLE_COMM_ISP_SetFrameRate(s32CamId, u32Fps);
#endif
}
// if (pOutPath) {
// g_output_file = fopen(pOutPath, "w");
// if (!g_output_file) {
// printf("ERROR: open file: %s fail, exit\n", pOutPath);
// return 0;
// }
// }
RK_MPI_SYS_Init();
VI_CHN_ATTR_S vi_chn_attr;
vi_chn_attr.pcVideoNode = pDeviceName;
vi_chn_attr.u32BufCnt = u32BufCnt;
vi_chn_attr.u32Width = u32Width;
vi_chn_attr.u32Height = u32Height;
vi_chn_attr.enPixFmt = IMAGE_TYPE_YUYV422;
vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;
vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
ret = RK_MPI_VI_SetChnAttr(s32CamId, 0, &vi_chn_attr);
ret |= RK_MPI_VI_EnableChn(s32CamId, 0);
if (ret) {
printf("ERROR: create VI[0] error! ret=%d\n", ret);
return 0;
}
VENC_CHN_ATTR_S venc_chn_attr;
memset(&venc_chn_attr, 0, sizeof(venc_chn_attr));
switch (enCodecType) {
case RK_CODEC_TYPE_H265:
venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H265;
venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H265CBR;
venc_chn_attr.stRcAttr.stH265Cbr.u32Gop = 30;
venc_chn_attr.stRcAttr.stH265Cbr.u32BitRate = u32Width * u32Height;
// frame rate: in 30/1, out 30/1.
venc_chn_attr.stRcAttr.stH265Cbr.fr32DstFrameRateDen = 1;
venc_chn_attr.stRcAttr.stH265Cbr.fr32DstFrameRateNum = 30;
venc_chn_attr.stRcAttr.stH265Cbr.u32SrcFrameRateDen = 1;
venc_chn_attr.stRcAttr.stH265Cbr.u32SrcFrameRateNum = 30;
break;
case RK_CODEC_TYPE_MJPEG:
venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_MJPEG;
venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_MJPEGCBR;
venc_chn_attr.stRcAttr.stMjpegCbr.fr32DstFrameRateDen = 1;
venc_chn_attr.stRcAttr.stMjpegCbr.fr32DstFrameRateNum = 30;
venc_chn_attr.stRcAttr.stMjpegCbr.u32SrcFrameRateDen = 1;
venc_chn_attr.stRcAttr.stMjpegCbr.u32SrcFrameRateNum = 30;
venc_chn_attr.stRcAttr.stMjpegCbr.u32BitRate = u32Width * u32Height * 8;
break;
case RK_CODEC_TYPE_H264:
default:
venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;
venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 30;
venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = u32Width * u32Height;
// frame rate: in 30/1, out 30/1.
venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 30;
venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 30;
break;
}
venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_YUYV422;
venc_chn_attr.stVencAttr.u32PicWidth = u32Width;
venc_chn_attr.stVencAttr.u32PicHeight = u32Height;
venc_chn_attr.stVencAttr.u32VirWidth = u32Width;
venc_chn_attr.stVencAttr.u32VirHeight = u32Height;
venc_chn_attr.stVencAttr.u32Profile = 77;
ret = RK_MPI_VENC_CreateChn(0, &venc_chn_attr);
if (ret) {
printf("ERROR: create VENC[0] error! ret=%d\n", ret);
return 0;
}
MPP_CHN_S stSrcChn;
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32DevId = 0;
stSrcChn.s32ChnId = 0;
MPP_CHN_S stDestChn;
stDestChn.enModId = RK_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = 0;
ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if (ret) {
printf("ERROR: Bind VI[0] and VENC[0] error! ret=%d\n", ret);
return 0;
}
printf("%s initial finish\n", __func__);
signal(SIGINT, sigterm_handler);
pthread_t read_thread;
pthread_create(&read_thread, NULL, GetMediaBuffer, pOutPath);
IMAGE_TYPE_YUYV422};
while (!quit) {
usleep(500000);
}
// if (g_output_file)
// fclose(g_output_file);
printf("%s exit!\n", __func__);
// unbind first
ret = RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
if (ret) {
printf("ERROR: UnBind VI[0] and VENC[0] error! ret=%d\n", ret);
return 0;
}
// destroy venc before vi
ret = RK_MPI_VENC_DestroyChn(0);
if (ret) {
printf("ERROR: Destroy VENC[0] error! ret=%d\n", ret);
return 0;
}
// destroy vi
ret = RK_MPI_VI_DisableChn(s32CamId, 0);
if (ret) {
printf("ERROR: Destroy VI[0] error! ret=%d\n", ret);
return 0;
}
if (pIqfilesPath) {
#ifdef RKAIQ
SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
}
return 0;
}
5,代码编译,
编写完成后,在/sdk目录下运行以下指令:
# SDK根目录,选择环境
source envsetup.sh firefly_rv1126_rv1109
# 重编rkmedia源码
make rkmedia-dirclean && make rkmedia
编译完成后,在SDK/buildroot/output/firefly_rv1126_rv1109/oem/usr/bin目录下找到rkmedia_vi_venc_local_file_test二进制可执行程序,移动到板子某一个目录下,再进行测试。
6,测试指令
在开发板存放可执行程序目标终端下输入以下指令:
./rkmedia_vi_venc_local_file_test -w 640 -h 480 -d /dev/video25 -c 30 -e h264 -o /mnt/nfs/output_test.h264
其中参数w
为摄像头输入视频宽,h
为摄像头输入视频高,d
为摄像头设备号,c
为输入视频帧率,e
为编码格式,o
为视频保存路径
标签:attr,vi,chn,Firefly1126,RKMedia,venc,printf,摄像头,RK 来源: https://www.cnblogs.com/kxqblog/p/16435824.html