首页 > 其他分享 >rkmedia的视频采集、编码、推流与保存

rkmedia的视频采集、编码、推流与保存

时间:2023-12-12 21:00:55浏览次数:41  
标签:编码 通道 VI CHN MPI rkmedia VENC 推流 RK

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






标签:编码,通道,VI,CHN,MPI,rkmedia,VENC,推流,RK
From: https://blog.51cto.com/u_16158769/8791029

相关文章

  • Huffman 编码的估计
    \(\newcommand{\HH}{\operatorname{H}}\)我们熟知一些说法,比如一个二叉树如果第\(i\)个节点的访问次数是\(w_i\),那么最优的建树会使得总共访问节点次数是\[O\left(\sumw_i\log\frac{W}{w_i}\right)\]量级的,其中\(W=\sumw_i\).那么这个说法到底有多精确呢?......
  • ASCII编码
    一、ASCII编码简介ASCII(AmericanStandardCodeforInformationInterchange,美国标准信息交换代码)是一种基于拉丁字母的电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,涵盖了128个字符。Ascii编码解码--一个覆盖广泛主题工具的高效在线......
  • MySQL设置字符编码
    MySQL设置字符编码一、8.0设置字符集#vim/etc/mysql/my.cnf[mysqld]port=3306character-set-client-handshake=FALSEcharacter-set-server=utf8mb4collation-server=utf8mb4_unicode_ci#相对应的排序规则init_connect='SETNAMESut......
  • 深度学习面试常用代码:MHA/MQA/GQA/LN/BN/位置编码代码
    深度学习常用代码参考:https://zhuanlan.zhihu.com/p/6505754261.MHA(MultiHeadAttention)代码实现#1.MHA实现importtorchimporttorch.nnasnnimporttorch.nn.functionalasFclassScaleDotProductAttention(nn.Module):def__init__(self,):......
  • 字符编码
    什么是字符编码字符编码中的编码指的是翻译或者转换的意思即将人能理解的字符翻译成计算机能识别的数字字符编码的发展史一家独大计算机是美国人发明的,美国人想更方便的掌控计算机中的语言,于是就发明了ASCII码表这张表存储了英文字符及特殊标点和数字之间的一一对应关......
  • Arcgis分割图斑编码工具
    一、分割图斑编码:分割图斑在原图斑编码的基础上_1、_2................的续编。二、代码:#coding:utf-8importarcpyfromcollectionsimportCounterdefget_repeat_values(in_table,field):fields_values=[]witharcpy.da.SearchCursor(in_table,field)as......
  • 宗地从上到下从左到右西北角顺时针界址点编码、宗地界址点成果表、宗地四至情况说明、
    一、宗地界址点编码:从上到下从左到右每宗西北角顺时针编码,可根据界址点分类类型计算序号前面的字母。二、界址点成果表:每一宗地生成一个界址点成果表.xls,西北角界址点开始顺时针填写界址点,首先填写宗地外环界址点,最后填写宗地内环。三、宗地四至情况说明:西北角界址点开始顺时......
  • burp技术主题基本技能之使用HTML编码与前导零进行xss bypass
    使用编码对攻击进行模糊处理https://portswigger.net/web-security/all-topicsburp官网所有技术主题基础技能URLdecoded服务器端;HTMLdecoded客户端inputfilters输入过滤器:还需要对输入进行解码,检查输入安全性为什么要编码?[...]/?search=Fish+&+Chips&有特......
  • 【misc】[GFCTF 2021]重生之我在A国当间谍 --短信pdu编码
    附件下载发现只有两个文件打开flag.rar需要密码,那考虑解压密码应该是从secret.txt中获得,打开secret.txt文件试过很多加密方式都不行,考虑是短信的pdu编码PDU编码(非常经典)-CSDN博客可以使用在线短信PDU编码解码-在线工具(bugscaner.com)在线解码,这里解码第三行数据得到b......
  • Base64编码解码
    一、Base64编码技术简介Base64编码是一种广泛应用于网络传输和数据存储的编码方式。它将原始数据转换为可打印的字符形式,以便于传输和存储。Base64编码后的数据长度是原始数据长度的约3/4,具有一定的压缩效果。Base64编码解码--一个覆盖广泛主题工具的高效在线平台(amd794.co......