当前位置: 首页 > news >正文

rv1106抓h264流

从rkipc的rkipc_pipe_0_init我们得知,h265流的设置步骤为
设置vi通道-》使能vi通道-》创建venc通道-》设置h265通道的相关参数 -》接收帧 -》获取h265数据

根据这个步骤写rv1106抓h264流

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <sys/stat.h>
#include <stdbool.h>
#include <sys/mman.h>

#include <rk_mpi_cal.h>
#include <rk_mpi_ivs.h>
#include <rk_mpi_mb.h>
#include <rk_mpi_mmz.h>
#include <rk_mpi_rgn.h>
#include <rk_mpi_sys.h>
#include <rk_mpi_tde.h>
#include <rk_mpi_venc.h>
#include <rk_mpi_vi.h>
#include <rk_mpi_vpss.h>

#include <rk_aiq_user_api2_acgc.h>
#include <rk_aiq_user_api2_camgroup.h>
#include <rk_aiq_user_api2_imgproc.h>
#include <rk_aiq_user_api2_sysctl.h>

#define JPEG_VENC_CHN 4
#define VIDEO_PIPE_0 0
#define MAX_AIQ_CTX 8



int main(int argc, char *argv[])
{
	printf("hello world! \n");

	for (int i = 0; i < argc; i++)
	{
		printf("%d argv: ", i);
		printf("%s \n", argv[i]);
	}

	// 检查参数数量
	// if (argc != 2)
	// {
	// 	perror("Usage: ./program <filename>");
	// 	exit(1);
	// }

	int ret = -1;

	char g_iq_file_dir_[256];
	memcpy(g_iq_file_dir_, "/etc/iqfiles", strlen("/etc/iqfiles"));
	printf("g_iq_file_dir_ is %s\n", g_iq_file_dir_);

	char main_scene[32];
	char sub_scene[32];

	static int current_scenario_id = 0;
	const char *scenario = "normal";
	if (!strcmp(scenario, "normal"))
	{
		current_scenario_id = 0;
		strcpy(sub_scene, "day");
	}
	else
	{
		current_scenario_id = 1;
		strcpy(sub_scene, "night");
	}

	rk_aiq_working_mode_t g_WDRMode[MAX_AIQ_CTX];
	rk_aiq_working_mode_t WDRMode = RK_AIQ_WORKING_MODE_NORMAL;
	// must set HDR_MODE, before init
	g_WDRMode[0] = WDRMode;
	char hdr_str[16];
	snprintf(hdr_str, sizeof(hdr_str), "%d", (int)WDRMode);
	setenv("HDR_MODE", hdr_str, 1);

	rk_aiq_sys_ctx_t *aiq_ctx;
	rk_aiq_static_info_t aiq_static_info;

	//通过物理id 获取sensor_name,后面初始化要用
	rk_aiq_uapi2_sysctl_enumStaticMetasByPhyId(0, &aiq_static_info);
	if (aiq_static_info.sensor_info.phyId == -1)
	{
		printf("WARN: aiq_static_info.sensor_info.phyId is %d\n",
			   aiq_static_info.sensor_info.phyId);
	}

	printf("ID: %d, sensor_name is %s, iqfiles is %s\n", 0,
		   aiq_static_info.sensor_info.sensor_name, "/etc/iqfiles");

	
	//设置设备缓存数量,init前要完成
	rk_aiq_uapi2_sysctl_preInit_devBufCnt(aiq_static_info.sensor_info.sensor_name, "rkraw_rx", 2);

	//设置main_scene
	if (WDRMode == RK_AIQ_WORKING_MODE_NORMAL)
		strcpy(main_scene, "normal");
	else
		strcpy(main_scene, "hdr");

	printf("main_scene is %s, sub_scene is %s\n", main_scene, sub_scene);
	printf("rk_aiq_uapi2_sysctl_preInit_scene begin\n");

	//init前的系统设置
	ret = rk_aiq_uapi2_sysctl_preInit_scene(aiq_static_info.sensor_info.sensor_name, main_scene,
											sub_scene);
	if (ret < 0)
	{
		printf("%s: failed to set scene\n", aiq_static_info.sensor_info.sensor_name);
		exit(1);
	}

	//初始化
	aiq_ctx =
		rk_aiq_uapi2_sysctl_init(aiq_static_info.sensor_info.sensor_name, "/etc/iqfiles", NULL, NULL);
	printf("rk_aiq_uapi2_sysctl_init over\n");
	if (!aiq_ctx)
	{
		printf("%s: failed to rk_aiq_uapi2_sysctl_init \n", __func__);
		exit(1);
	}

	//准备好aiq环境
	if (rk_aiq_uapi2_sysctl_prepare(aiq_ctx, 0, 0, WDRMode))
	{
		printf("rk_aiq_uapi2_sysctl_prepare failed !\n");
		return -1;
	}
	printf("*************rk_aiq_uapi2_sysctl_prepare succeed\n");
	
	//启动aiq
	if (rk_aiq_uapi2_sysctl_start(aiq_ctx))
	{
		printf("rk_aiq_uapi2_sysctl_start  failed\n");
		return -1;
	}
	printf("*************rk_aiq_uapi2_sysctl_start succeed\n");

	//aiq完成

	
	//以下为rkmpi的操作
	int dev_id_ = 0;
	int pipe_id_ = 0;
	VI_CHN_BUF_WRAP_S stViWrap;

	//初始化rkmpi系统
	printf("*************RK_MPI_SYS_Init \n");
	if (RK_MPI_SYS_Init() != RK_SUCCESS)
	{
		RK_LOGE("rk mpi sys init fail!");
		return -1;
	}

	//查看vi设备的状态,没开的话打开
	VI_DEV_ATTR_S stDevAttr;
	VI_DEV_BIND_PIPE_S stBindPipe;
	memset(&stDevAttr, 0, sizeof(stDevAttr));
	memset(&stBindPipe, 0, sizeof(stBindPipe));
	// 0. get dev config status
	//vi设备是否配置,没配置的话进行配置
	printf("*************RK_MPI_VI_GetDevAttr \n");
	ret = RK_MPI_VI_GetDevAttr(dev_id_, &stDevAttr);
	if (ret == RK_ERR_VI_NOT_CONFIG)
	{
		// 0-1.config dev
		printf("RK_MPI_VI_SetDevAttr not config\n");
		ret = RK_MPI_VI_SetDevAttr(dev_id_, &stDevAttr);
		if (ret != RK_SUCCESS)
		{
			printf("RK_MPI_VI_SetDevAttr %x\n", ret);
			return -1;
		}
		else
		{
			printf("RK_MPI_VI_SetDevAttr set success\n");
		}
	}
	else
	{
		printf("RK_MPI_VI_SetDevAttr already\n");
	}

	// 1.get dev enable status
	//使能vi设备
	printf("*************RK_MPI_VI_GetDevIsEnable \n");
	ret = RK_MPI_VI_GetDevIsEnable(dev_id_);
	if (ret != RK_SUCCESS)
	{
		// 1-2.enable dev
		ret = RK_MPI_VI_EnableDev(dev_id_);
		printf("enable RK_MPI_VI\n");
		if (ret != RK_SUCCESS)
		{
			printf("RK_MPI_VI_EnableDev %x\n", ret);
			return -1;
		}
		// 1-3.bind dev/pipe
		stBindPipe.u32Num = pipe_id_;
		stBindPipe.PipeId[0] = pipe_id_;
		ret = RK_MPI_VI_SetDevBindPipe(dev_id_, &stBindPipe);
		printf("set enable RK_MPI_VI\n");
		if (ret != RK_SUCCESS)
		{
			printf("RK_MPI_VI_SetDevBindPipe %x\n", ret);
			return -1;
		}
		printf("set enable RK_MPI_VI success\n");
	}
	else
	{
		printf("RK_MPI_VI_EnableDev already\n");
	}

	//vi通道参数设置
	int max_width = 1920;
	int max_height = 1080;
	int width = 1920;
	int height = 1080;
	// 2.config channel
	VI_CHN_ATTR_S vi_chn_attr;
	memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
	vi_chn_attr.stIspOpt.u32BufCount = 2;
	vi_chn_attr.stIspOpt.enMemoryType = VI_V4L2_MEMORY_TYPE_DMABUF;
	vi_chn_attr.stIspOpt.stMaxSize.u32Width = max_width;
	vi_chn_attr.stIspOpt.stMaxSize.u32Height = max_height;
	vi_chn_attr.stSize.u32Width = width;
	vi_chn_attr.stSize.u32Height = height;
	vi_chn_attr.enPixelFormat = RK_FMT_YUV420SP;
	vi_chn_attr.u32Depth = 1;
	vi_chn_attr.enCompressMode = COMPRESS_MODE_NONE;
	printf("*************RK_MPI_VI_SetChnAttr \n");
	//设置vi通道0
	ret = RK_MPI_VI_SetChnAttr(pipe_id_, VIDEO_PIPE_0, &vi_chn_attr);
	if (ret)
	{
		printf("ERROR: create VI error! ret=%d\n", ret);
		exit(1);
	}

	// 3.enable channel
	//使能vi通道0
	printf("*************RK_MPI_VI_EnableChn \n");
	ret = RK_MPI_VI_EnableChn(pipe_id_, VIDEO_PIPE_0);
	if (ret)
	{
		printf("ERROR: create VI error! ret=%d\n", ret);
		exit(1);
	}

	//h264通道设置
	// 设置编码通道结构体的值
	VENC_CHN_ATTR_S h264_chn_attr;
	memset(&h264_chn_attr, 0, sizeof(h264_chn_attr));
	h264_chn_attr.stVencAttr.enType = RK_VIDEO_ID_AVC;
	h264_chn_attr.stVencAttr.u32Profile = 100;
	h264_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
	h264_chn_attr.stRcAttr.stH264Cbr.u32Gop = 30;
	h264_chn_attr.stRcAttr.stH264Cbr.u32BitRate = 2048;
	h264_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
	h264_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;
	h264_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
	h264_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;

	h264_chn_attr.stGopAttr.enGopMode = VENC_GOPMODE_NORMALP;

	h264_chn_attr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
	h264_chn_attr.stVencAttr.u32MaxPicWidth = width;
	h264_chn_attr.stVencAttr.u32MaxPicHeight = height;
	h264_chn_attr.stVencAttr.u32PicWidth = width;
	h264_chn_attr.stVencAttr.u32PicHeight = height;
	h264_chn_attr.stVencAttr.u32VirWidth = width;
	h264_chn_attr.stVencAttr.u32VirHeight = height;
	h264_chn_attr.stVencAttr.u32StreamBufCnt = 2;
	h264_chn_attr.stVencAttr.u32BufSize = 1036800;

	// 创建编码通道
	printf("*************RK_MPI_VENC_CreateChn \n");
	ret = RK_MPI_VENC_CreateChn(VIDEO_PIPE_0, &h264_chn_attr);
	if (ret)
	{
		printf("ERROR: create VENC error! ret=%d\n", ret);
		return -1;
	}

	//高级设置

	ret = RK_MPI_VENC_EnableMotionDeblur(VIDEO_PIPE_0, true);
	if (ret)
	{
		printf("RK_MPI_VENC_EnableMotionDeblur error! ret=%#x\n", ret);
	}

	VENC_RC_PARAM_S venc_rc_param;
	RK_MPI_VENC_GetRcParam(VIDEO_PIPE_0, &venc_rc_param);
	venc_rc_param.stParamH264.u32MinQp = 15;
	venc_rc_param.stParamH264.u32FrmMinIQp = 26;
	venc_rc_param.stParamH264.u32FrmMinQp = 28;
	venc_rc_param.stParamH264.u32FrmMaxIQp = 51;
	venc_rc_param.stParamH264.u32FrmMaxQp = 51;
	RK_MPI_VENC_SetRcParam(VIDEO_PIPE_0, &venc_rc_param);

	VENC_H264_TRANS_S pstH264Trans;
	RK_MPI_VENC_GetH264Trans(VIDEO_PIPE_0, &pstH264Trans);
	pstH264Trans.bScalingListValid = 0;
	RK_MPI_VENC_SetH264Trans(VIDEO_PIPE_0, &pstH264Trans);

	VENC_CHN_REF_BUF_SHARE_S stVencChnRefBufShare;
	memset(&stVencChnRefBufShare, 0, sizeof(VENC_CHN_REF_BUF_SHARE_S));
	stVencChnRefBufShare.bEnable = 1;
	RK_MPI_VENC_SetChnRefBufShareAttr(VIDEO_PIPE_0, &stVencChnRefBufShare);
	RK_MPI_VENC_SetChnRotation(VIDEO_PIPE_0, ROTATION_0);

	VENC_RECV_PIC_PARAM_S stRecvParam;
	memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
	stRecvParam.s32RecvPicNum = -1;
	RK_MPI_VENC_StartRecvFrame(VIDEO_PIPE_0, &stRecvParam);

	// 绑定VI到VENC

	// bind
	MPP_CHN_S vi_chn, venc_chn;
	vi_chn.enModId = RK_ID_VI;
	vi_chn.s32DevId = 0;
	vi_chn.s32ChnId = VIDEO_PIPE_0;
	venc_chn.enModId = RK_ID_VENC;
	venc_chn.s32DevId = 0;
	venc_chn.s32ChnId = VIDEO_PIPE_0;

	RK_MPI_SYS_Bind(&vi_chn, &venc_chn);

	VENC_STREAM_S stFrame;
	stFrame.pstPack = malloc(sizeof(VENC_PACK_S));
	void *h264_data;
	size_t h264_size;
	int cap_count = 0;
	char file_name[128] = {0};
	time_t t ;
	struct tm tm;

	while (1)
	{
		//获取流的数据
		if(RK_MPI_VENC_GetStream(VIDEO_PIPE_0, &stFrame, 1000) == RK_SUCCESS)
		{
			void *h264_data = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
			h264_size = stFrame.pstPack->u32Len;

			snprintf(file_name, 128, "/userdata/h264/h264%06d.h264", cap_count);

			//打开文件
			FILE *fp = fopen(file_name, "wb");
			if (fp == NULL)
			{
				printf("fp is NULL\n");
			}
			else
			{
				//写入文件
				fwrite(h264_data, 1, stFrame.pstPack->u32Len, fp);
			}
			//关闭文件
			fflush(fp);
			fclose(fp);

			// printf("h264_size: %d \n", h264_size);

			cap_count++;
			//释放frame
			ret = RK_MPI_VENC_ReleaseStream(VIDEO_PIPE_0, &stFrame);
			if (ret != RK_SUCCESS) {
				printf("RK_MPI_VENC_ReleaseStream fail %x\n", ret);
			}
		} else 
		{
			printf("RK_MPI_VENC_GetStream error \n");
		}
	}
}

测试

在rv1106上运行程序,得到每帧的文件,用ffmpeg对i帧进行转码,例如我这里h264000060.h264为i帧

$  ffmpeg -i ./h264000060.h264 -f mp4 output.mp4

用浏览器打开这个mp4

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>HTML5 Video 自动循环播放示例</title>
</head>
<body>
    <video id="myVideo" width="1920" height="1080" controls>
        <source src="output.mp4" type="video/mp4">
        Your browser does not support the video tag.
    </video>

    <script>
        const video = document.getElementById('myVideo');
        video.addEventListener('ended', function () {
            video.currentTime = 0;  
            video.play();           
        });
    </script>
</body>
</html>

发现能正常显示。

相关文章:

  • 从泛读到精读:合合信息文档解析如何让大模型更懂复杂文档
  • 【leetcode刷题记录】(java)贪心
  • Netty - 从Nginx 四层(TCP/UDP)流量中获取客户端真实/网络出口IP
  • Java实现pdf中动态插入图片
  • 如何在 Postman 中正确设置 Session 以维持用户状态?
  • 亚马逊云科技提供完全托管的DeepSeek-R1模型
  • SEO(搜索引擎优化)详解
  • 处理脚本中函数调用的异常
  • 基于深度强化学习的智能机器人路径规划技术研究
  • 第六届 蓝桥杯 嵌入式 省赛
  • Postman CORS 测试完全指南:轻松模拟跨域请求,排查 CORS 相关问题
  • 软考中级-软件设计师 23种设计模式(内含详细解析)
  • Gateway实战(二)、负载均衡
  • React 中shouldComponentUpdate生命周期方法的作用,如何利用它优化组件性能?
  • Python爬虫如何检测请求频率?
  • Docker-Volume数据卷详讲
  • 循环神经网络 - 给网络增加记忆能力
  • 优化webpack打包体积思路
  • WebSocket:实时双向通信技术详解与实战示例优化指南
  • Linux内核禁止_开启中断和处理器间中断
  • 专家:家长要以身作则,孩子是模仿者学习者有时也是评判者
  • 把中国声音带向世界,DG和Blue Note落户中国
  • 92岁上海交大退休教师捐赠百万元给学校,其父也曾设奖学金
  • 从能源装备向应急装备蓝海拓展,川润股份发布智能综合防灾应急仓
  • 4月企业新发放贷款利率处于历史低位
  • 秘鲁总理辞职