rkmedia的视频采集、编码、推流与保存以及相关API和例程解析

目录

rkmedia简介

rkmedia视频采集、编码、推流相关函数简介

RK_MPI_SYS_Init()

RK_MPI_VI_SetChnAttr()

RK_MPI_VI_EnableChn()

RK_MPI_VENC_CreateChn()

RK_MPI_SYS_RegisterOutCb()

RK_MPI_SYS_Bind()

RK_MPI_SYS_UnBind()

RK_MPI_VENC_DestroyChn()

RK_MPI_VI_DisableChn()

示例代码与流程

代码编写流程

  源码展示


rkmedia简介

        RKMedia是由瑞芯微提供的专门用于音视频处理的系统。它提供了丰富的功能,包括音视频采集、编解码、加密解密等操作。在音视频传输中,编解码是必不可少的环节,它可以减小文件大小,节省带宽。RKMedia支持多种视频编码方式,如H264,并且在H264编码中,将视频数据帧分为关键帧(I帧)、单向参考帧(P帧)和双向参考帧(B帧)进行压缩。压缩方式可以是软压缩(自己编写算法运行在CPU上)或硬压缩(使用CPU内部的专用编码器)。解压方式也可以是软解压或硬解压。RKMedia主要使用硬编码和硬解码的方式来处理音视频数据。

        RKMedia的作用包括采集音频数据(PCM格式)、对音频进行编码(AAC格式)、采集视频数据(YUV或NV12格式)、对视频进行编码(YUV转H264格式)等。此外,RKMedia还可以进行视频裁剪、检测摄像头是否有遮挡、视频合成、视频分解、视频录制等操作。在RKMedia中,还有一些专用的名词,如VI(视频采集通道)、VENC(视频编码)、VDEC(视频解码)、AI(音频采集)、AO(音频输出)、AENC(音频编码)、ADEC(音频解码)和MD(移动侦测)。通过RKMedia,开发者可以方便地进行音视频处理和应用开发。
    

rkmedia视频采集、编码、推流相关函数简介

RK_MPI_SYS_Init()

功能
	用于初始化RKMedia系统,必须在使用其他RKMedia函数之前调用
头文件
    rkmedia_api.h
库文件
    libeasymedia.so
原型
    RK_S32 RK_MPI_SYS_Init(void);
返回值
    成功 0
    失败 错误码    

RK_MPI_VI_SetChnAttr()

功能
	用于设置VI(视频采集)通道的属性,包括分辨率、帧率、像素格式等
头文件
    rkmedia_api.h
库文件
    libeasymedia.so
原型
    RK_MPI_VI_SetChnAttr(VI_PIPE ViPipe, VI_CHN ViChn, const VI_CHN_ATTR_S *pstChnAttr);
参数
    ViPipe    VI 管道号。 一般写0
    ViChn    VI 通道号。取值范围:[0, VI_MAX_CHN_NUM)]    一般写0
    pstChnAttr    VI 通道属性结构体指针    
返回值
    成功 0
    失败 错误码
typedef struct rkVI_CHN_ATTR_S 
{
    const RK_CHAR *pcVideoNode;    摄像头的节点
    RK_U32 u32Width;
    RK_U32 u32Height;    视频的高
    IMAGE_TYPE_E enPixFmt;    采集的视频的格式
    RK_U32 u32BufCnt; // VI capture video buffer cnt.缓冲帧的大小 3-5
    // VI capture video buffer type.
    VI_CHN_BUF_TYPE enBufType;    视频数据的存储方式    内存映射
    VI_CHN_WORK_MODE enWorkMode;    工作模式    常规
} VI_CHN_ATTR_S;

RK_MPI_VI_EnableChn()

功能
	用于使能VI通道,启动视频采集
头文件
    rkmedia_api.h
库文件:
    libeasymedia.so
原型
    RK_S32 RK_MPI_VI_EnableChn(VI_PIPE ViPipe, VI_CHN ViChn);
参数
    ViPipe    VI 管道号
    ViChn    VI 通道号。取值范围:[0, VI_MAX_CHN_NUM
返回值
    成功 0
    失败 错误码

RK_MPI_VENC_CreateChn()

功能
	用于创建编码通道,配置编码器的参数,如编码格式、码率、GOP大小等
头文件
    rkmedia_api.h
库文件
    libeasymedia.so
原型
    RK_S32 RK_MPI_VENC_CreateChn(VENC_CHN VeChn, VENC_CHN_ATTR_S *stVencChnAttr);
参数
    VeChn    编码通道号
    stVencChnAttr    编码通道属性指针    
返回值
    成功 0
    失败 错误码
编码属性结构体
typedef struct rkVENC_CHN_ATTR_S {
    VENC_ATTR_S stVencAttr; // 编码器的属性
    VENC_RC_ATTR_S stRcAttr; // 码率的控制属性
    VENC_GOP_ATTR_S stGopAttr; // gop属性
} VENC_CHN_ATTR_S;

编码器的属性结构体
typedef struct rkVENC_ATTR_S {
    CODEC_TYPE_E enType; // 编码的协议类型 RK_CODEC_TYPE_H264
    IMAGE_TYPE_E imageType; // 输入的图像的类型 与vi通道保持一致 IMAGE_TYPE_NV12,
    RK_U32 u32VirWidth; // 虚拟的宽
    // width, often set vir_width=(width+15)&(~15)
    RK_U32 u32VirHeight; // 虚拟的高
    // than height, often set vir_height=(height+15)&
    (~15)
    RK_U32 u32Profile; // 编码的等级 固定为77
    // H.264: 66: baseline; 77:MP; 100:HP;
    // H.265: default:Main;
    // Jpege/MJpege: default:Baseline
    RK_BOOL bByFrame; // 保留参数
    RK_U32 u32PicWidth; // 真实的宽
    RK_U32 u32PicHeight; // 真实的高
    VENC_ROTATION_E enRotation;    //旋转的角度
    union {
        VENC_ATTR_H264_S stAttrH264e; // attributes of H264e
        VENC_ATTR_H265_S stAttrH265e; // attributes of H265e
        VENC_ATTR_MJPEG_S stAttrMjpege; // attributes of Mjpeg
        VENC_ATTR_JPEG_S stAttrJpege; // attributes of jpeg
    };
} VENC_ATTR_S;

码率控制器的属性结构体
typedef struct rkVENC_RC_ATTR_S {
    /* RW; the type of rc*/
    VENC_RC_MODE_E enRcMode;//工作模式 VENC_RC_MODE_H264CBR
    union {
        VENC_H264_CBR_S stH264Cbr;
        VENC_H264_VBR_S stH264Vbr;
        VENC_H264_AVBR_S stH264Avbr;
        VENC_MJPEG_CBR_S stMjpegCbr;
        VENC_MJPEG_VBR_S stMjpegVbr;
        VENC_H265_CBR_S stH265Cbr;
        VENC_H265_VBR_S stH265Vbr;
        VENC_H265_AVBR_S stH265Avbr;
    };
} VENC_RC_ATTR_S;

typedef struct rkVENC_H264_CBR_S {
RK_U32 u32Gop;                 30
RK_U32 u32SrcFrameRateNum;     30
RK_U32 u32SrcFrameRateDen;     1
RK_FR32 fr32DstFrameRateNum;   30
RK_FR32 fr32DstFrameRateDen;    1
RK_U32 u32BitRate; // RW; Range:[2000, 98000000]; average bitrate分辨率1920*1080
} VENC_H264_CBR_S;

GOP 属性结构体。该结构体可不初始化
typedef struct rkVENC_GOP_ATTR_S {
    VENC_GOP_MODE_E enGopMode; //模式
    RK_U32 u32GopSize;    //一个gop组多少帧
    RK_S32 s32IPQpDelta;    //
    RK_U32 u32BgInterval;
    RK_S32 s32ViQpDelta;
} VENC_GOP_ATTR_S;

RK_MPI_SYS_RegisterOutCb()

功能
	用于注册VENC(视频编码)通道的回调函数,当编码完成后,会通过回调函数返回编码后的数据
头文件
    rkmedia_api.h
库文件
    libeasymedia.so
原型
    RK_S32 RK_MPI_SYS_RegisterOutCb(const MPP_CHN_S *pstChn, OutCbFunc cb);
参数
    pstChn    通道的描述结构体
    cb    回调函数
返回值
    成功 0
    失败 非零
    
通道描述结构体
typedef struct rkMPP_CHN_S {
    MOD_ID_E enModId;    模块号 RK_ID_VENC
    RK_S32 s32DevId;    设备号 0
    RK_S32 s32ChnId;    通道号 0
} MPP_CHN_S;
回调函数
	typedef void (*OutCbFunc)(MEDIA_BUFFER mb);

RK_MPI_SYS_Bind()

功能
	用于将VI通道和VENC通道进行绑定,建立数据流传输的连接
头文件
    rkmedia_api.h
库文件
    libeasymedia.so
原型
    RK_S32 RK_MPI_SYS_Bind(const MPP_CHN_S *pstSrcChn,const MPP_CHN_S *pstDestChn);
参数
    pstSrcChn     源通道指针    vi通道
    pstDestChn     目的通道指针   venc通道
返回值
    成功 0
    失败 错误码
typedef struct rkMPP_CHN_S {
    MOD_ID_E enModId;	模块号
    RK_S32 s32DevId;	设备号
    RK_S32 s32ChnId;	通道号
} MPP_CHN_S;

RK_MPI_SYS_UnBind()

功能
	用于解除VI通道和VENC通道的绑定,断开数据流传输的连接
头文件
    rkmedia_api.h
库文件
    libeasymedia.so
原型
    RK_MPI_SYS_UnBind(const MPP_CHN_S *pstSrcChn,const MPP_CHN_S *pstDestChn)
参数
    pstSrcChn    源通道指针。 
    pstDestChn    目的通道指针。
返回值
    成功 0
    失败 非零

RK_MPI_VENC_DestroyChn()

功能
	用于销毁VENC通道,释放相关资源
头文件
    rkmedia_api.h
库文件
    libeasymedia.so
原型
    RK_S32 RK_MPI_VENC_DestroyChn(VENC_CHN VeChn);
参数    
    VeChn    编码通道号。取值范围:[0, VENC_MAX_CHN_NUM)]
返回值
    成功 0
    失败 错误码

RK_MPI_VI_DisableChn()

功能
	用于失能VI通道,停止视频采集
头文件
    rkmedia_api.h
库文件
    libeasymedia.so
原型 
    RK_S32 RK_MPI_VI_DisableChn(VI_PIPE ViPipe, VI_CHN ViChn);
参数
    ViPipe    VI 管道号
    ViChn    VI 通道号。取值范围:[0, VI_MAX_CHN_NUM)]
返回值
    成功 0
    失败 错误码

示例代码与流程

代码编写流程

  1. 初始化RKMedia系统和推流服务器。
  2. 设置摄像头属性,包括分辨率、帧率等。
  3. 创建VI(视频采集)通道,并使能该通道。
  4. 创建VENC(视频编码)通道,配置编码器的参数。
  5. 注册VENC通道的回调函数,用于处理编码后的视频帧数据。
  6. 绑定VI通道和VENC通道,建立数据流传输的连接。
  7. 循环采集视频帧数据,并进行推流和保存到文件的操作。
  8. 解除VI通道和VENC通道的绑定。
  9. 销毁VENC通道。
  10. 失能VI通道。
  11. 关闭文件和释放相关资源。

  源码展示

        该代码的主要功能是通过RKMedia实现摄像头视频采集、编码、推流并将视频保存到本地文件

#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 <sys/types.h>
#include <time.h>
#include <unistd.h>

#include "common/sample_common.h"
#include "librtsp/rtsp_demo.h"
#include "rkmedia_api.h"
#include "rkmedia_venc.h"

FILE *fp = NULL;
RK_BOOL bMultictx = RK_FALSE;
RK_CHAR *pIqfilesPath = "/oem/etc/iqfiles";		//配置文件
int quit = 0;
rtsp_demo_handle g_rtsplive = NULL;
static rtsp_session_handle g_rtsp_session;


void video_packet_cb(MEDIA_BUFFER mb) {
  static RK_S32 packet_cnt = 0;
  if (quit)
    return;

  printf("#Get packet-%d, size %zu\n", packet_cnt, RK_MPI_MB_GetSize(mb));
	//推流
  if (g_rtsplive && g_rtsp_session) {
    rtsp_tx_video(g_rtsp_session, RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb),
                  RK_MPI_MB_GetTimestamp(mb));
    rtsp_do_event(g_rtsplive);
  }
  fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, fp);
  RK_MPI_MB_ReleaseBuffer(mb);	//释放帧数据
  packet_cnt++;
}


int main(int argc, char *argv[]){
	argc = argc;
	argv = argv;
	int ret = 0;
	
	RK_U32 u32Width = 1920;	//视频采集的宽度	像素点
	RK_U32 u32Height = 1080;	//视频采集的高度	像素点
	//设置摄像头属性
	RK_CHAR *pDeviceName = "rkispp_scale0";	//摄像头
	rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
    int fps = 30;	//每秒采集到视频帧的个数
    SAMPLE_COMM_ISP_Init(0, hdr_mode, bMultictx, pIqfilesPath);
    SAMPLE_COMM_ISP_Run(0);
    SAMPLE_COMM_ISP_SetFrameRate(0, fps);
	
	fp = fopen("test.h264", "w");
	if(fp == NULL){
		printf("打开录像文件失败\n");
		return -1;
	}
	//初始化推流服务器
	g_rtsplive = create_rtsp_demo(554);	//设置推流端口
	g_rtsp_session= rtsp_new_session(g_rtsplive, "/live/main_stream");//推流的路径
	rtsp_set_video(g_rtsp_session, RTSP_CODEC_ID_VIDEO_H264, NULL, 0);
	
	//同步时间
	rtsp_sync_video_ts(g_rtsp_session, rtsp_get_reltime(), rtsp_get_ntptime());
	
	RK_MPI_SYS_Init();	//初始化remedia的系统
	
	
	//设置vi通道的属性
	VI_CHN_ATTR_S pstChnAttr;
	pstChnAttr.pcVideoNode = pDeviceName;	//摄像头的节点
	pstChnAttr.u32Width = u32Width;	//视频的宽
	pstChnAttr.u32Height = u32Height;	//视频的高
	pstChnAttr.enPixFmt = IMAGE_TYPE_NV12;	//采集的视频格式
	pstChnAttr.u32BufCnt = 3;	//缓冲帧的大小
	pstChnAttr.enBufType = VI_CHN_BUF_TYPE_MMAP;	//内存映射
	pstChnAttr.enWorkMode = VI_WORK_MODE_NORMAL;	//工作模式,正常
	ret = RK_MPI_VI_SetChnAttr(0, 0, &pstChnAttr);
	if(ret != 0){
		printf("设置vi通道的属性错误\n");
		return -1;
	}
	
	
	//使能vi通道
	ret = RK_MPI_VI_EnableChn(0, 0);
	if(ret != 0){
		printf("使能vi通道失败\n");
		return -1;
	}
	
	
	//创建编码通道
	VENC_CHN_ATTR_S stVencChnAttr;
	stVencChnAttr.stVencAttr.enType = RK_CODEC_TYPE_H264;//编码协议的类型
	stVencChnAttr.stVencAttr.imageType = IMAGE_TYPE_NV12;//采集的图像的类型
	stVencChnAttr.stVencAttr.u32VirWidth = u32Width;//虚拟的宽
	stVencChnAttr.stVencAttr.u32VirHeight = u32Height;//虚拟的高
	stVencChnAttr.stVencAttr.u32Profile = 77;//编码的等级
	//stVencChnAttr.stVencAttr.bByFrame = 
	stVencChnAttr.stVencAttr.u32PicWidth = u32Width;//真实的宽
	stVencChnAttr.stVencAttr.u32PicHeight = u32Height;//真实的高
	stVencChnAttr.stVencAttr.enRotation = 0;//旋转角度
	
	stVencChnAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;//工作模式
	stVencChnAttr.stRcAttr.stH264Cbr.u32Gop = 30;//gop组帧数
	stVencChnAttr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 30;//帧率
	stVencChnAttr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
	stVencChnAttr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 30;
	stVencChnAttr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
	stVencChnAttr.stRcAttr.stH264Cbr.u32BitRate = u32Width * u32Height;//分辨率
	
	ret = RK_MPI_VENC_CreateChn(0, &stVencChnAttr);
	if(ret != 0){
		printf("创建编码通道失败\n");
		return -1;
	}
	
	//注册编码通道的回调函数
	MPP_CHN_S pstChn;
	pstChn.enModId = RK_ID_VENC;//模块号
	pstChn.s32DevId = 0;//设备号 第一个摄像头
	pstChn.s32ChnId = 0;//通道号 第一个通道
	ret = RK_MPI_SYS_RegisterOutCb(&pstChn, video_packet_cb);
	if(ret != 0){
		printf("注册编码通道的回调函数失败\n");
		return -1;
	}
	
	
	//绑定venc通道
    MPP_CHN_S pstSrcChn, pstDestChn;
	pstSrcChn.enModId = RK_ID_VI;
	pstSrcChn.s32DevId = 0;
	pstSrcChn.s32ChnId = 0;
	
	pstDestChn.enModId = RK_ID_VENC;
	pstDestChn.s32DevId = 0;
	pstDestChn.s32ChnId = 0;
	ret = RK_MPI_SYS_Bind(&pstSrcChn,&pstDestChn);
	if(ret != 0){
		printf("绑定venc通道失败\n");
		return -1;
	}
	
	
	while(1){
		usleep(60);
		break;
	}
	quit = 1;
	fclose(fp);
	
	//解除通道绑定
	ret = RK_MPI_SYS_UnBind(&pstSrcChn,&pstDestChn);
	if(ret != 0){
		printf("解除通道绑定失败\n");
		return -1;
	}
	
	
	//销毁编码通道
	ret = RK_MPI_VENC_DestroyChn(0);
	if(ret != 0){
		printf("销毁编码通道失败\n");
		return -1;
	}
	
	
	//失能vi通道
	ret = RK_MPI_VI_DisableChn(0, 0);
	if(ret != 0){
		printf("失能vi通道失败\n");
		return -1;
	}
	return 0;
}

  • 20
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值