知方号

知方号

rkmedia的视频采集、编码、推流与保存以及相关API和例程解析<编码器故障怎么处理视频讲解教程>

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; 30RK_U32 u32SrcFrameRateNum; 30RK_U32 u32SrcFrameRateDen; 1RK_FR32 fr32DstFrameRateNum; 30RK_FR32 fr32DstFrameRateDen; 1RK_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 失败 错误码 示例代码与流程 代码编写流程 初始化RKMedia系统和推流服务器。设置摄像头属性,包括分辨率、帧率等。创建VI(视频采集)通道,并使能该通道。创建VENC(视频编码)通道,配置编码器的参数。注册VENC通道的回调函数,用于处理编码后的视频帧数据。绑定VI通道和VENC通道,建立数据流传输的连接。循环采集视频帧数据,并进行推流和保存到文件的操作。解除VI通道和VENC通道的绑定。销毁VENC通道。失能VI通道。关闭文件和释放相关资源。   源码展示

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

#include #include #include #include #include #include #include #include #include #include #include #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 ", 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("打开录像文件失败 ");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通道的属性错误 ");return -1;}//使能vi通道ret = RK_MPI_VI_EnableChn(0, 0);if(ret != 0){printf("使能vi通道失败 ");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("创建编码通道失败 ");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("注册编码通道的回调函数失败 ");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通道失败 ");return -1;}while(1){usleep(60);break;}quit = 1;fclose(fp);//解除通道绑定ret = RK_MPI_SYS_UnBind(&pstSrcChn,&pstDestChn);if(ret != 0){printf("解除通道绑定失败 ");return -1;}//销毁编码通道ret = RK_MPI_VENC_DestroyChn(0);if(ret != 0){printf("销毁编码通道失败 ");return -1;}//失能vi通道ret = RK_MPI_VI_DisableChn(0, 0);if(ret != 0){printf("失能vi通道失败 ");return -1;}return 0;}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。