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

RV1126 NO.22:多线程获取SMARTP的GOP模式数据和普通GOP模式数据

前言:通过编程方式同步获取SMARTP模式和常规GOP模式的VENC码流数据,并对其画质表现进行对比分析。

一.RV1126 VI采集摄像头数据并同时编码SMARTP模式和普通GOP模式的编码码流流程

RV1126利用多线程同时获取普通GOP的VENC码流数据和SMARTP的码流数据一般如上图,分为8个步骤:分别是VI模块初始化、普通GOP的VENC模块初始化、智能SMARTP_GOP的VENC模块初始化、VI绑定普通GOP的VENC编码器节点、设置GOP属性为SMARTP属性、VI绑定SMARTP_GOP的VENC编码器节点、创建多线程获取普通GOP的VENC码流数据并保存、创建多线程获取SMART_GOP的VENC码流数据并保存。

1.1.初始化VI模块

VI模块的初始化实际上就是对VI_CHN_ATTR_S的参数进行设置、然后调用RK_MPI_VI_SetChnAttr设置VI模块并使能RK_MPI_VI_EnableChn,伪代码如下:

VI_CHN_ATTR_S  vi_chn_attr;

。。。。。。。。。。。。。。。(这里是设置VI的属性)

ret = RK_MPI_VI_SetChnAttr(CAMERA_ID, 0, &vi_chn_attr);

ret |= RK_MPI_VI_EnableChn(CAMERA_ID, 0);

1.2.​​​​​​​两种GOP模式VENC模块初始化

VENC_CHN_ATTR_S  common_gop_venc_chn_attr;

..................................

RK_MPI_VENC_CreateChn(COMMON_GOP_VENC_CHN, &common_gop_venc_chn_attr);

VENC_CHN_ATTR_S  smartp_gop_venc_chn_attr;

..................................

RK_MPI_VENC_CreateChn(SMARTP_VENC_CHN, &smartp_gop_venc_chn_attr);

注意:这里需要创建两个编码器层,分别是普通GOP模式编码器和SMART的GOP模式编码器。

1.3.​​​​​​​​​​​​​​设置SMARTP的VENC模块GOP参数调节

VENC_GOP_ATTR_S venc_gop_attr;

venc_gop_attr.enGopMode = VENC_GOPMODE_SMARTP; //设置GOP模式为SMARTP模式

venc_gop_attr.u32GopSize = 25; //设置短参考帧间隔是25

venc_gop_attr.s32IPQpDelta = 6; //设置I帧和P帧的差值是6

venc_gop_attr.s32ViQpDelta = 6;//设置虚拟I帧和P帧的差值是6

venc_gop_attr.u32BgInterval = 25 * 5; //设置长参考帧的长度是短参考帧的5倍

ret = RK_MPI_VENC_SetGopMode(SMARTP_GOP_VENC_CHN, &venc_gop_attr);

上面是SMARTP的GOP模式一些参数的设置,设置完成调用RK_MPI_VENC_SetGopMode去调用

1.4.​​​​​​​VI模块绑定普通GOP的VENC模块和SMARTP_GOP的VENC模块,下面是伪代码

//VI模块节点

MPP_CHN_S vi_chn_s;

vi_chn_s.enModId = RK_ID_VI;

vi_chn_s.s32ChnId = VI_CHN_ID;

//普通GOP的VENC模块节点

MPP_CHN_S common_gop_venc_chn_s;

common_gop_venc_chn_s.enModId = RK_ID_VENC;

common_gop_venc_chn_s.s32ChnId = COMMON_GOP_VENC_CHN;

ret = RK_MPI_SYS_Bind(&vi_chn_s, &common_gop_venc_chn_s);

//SMARTP_GOP的VENC模块

MPP_CHN_S smartp_gop_venc_chn_s;

smartp_gop_venc_chn_s_s.enModId = RK_ID_VENC;

smartp_gop_venc_chn_s.s32ChnId = SMARTP_GOP_VENC_CHN;

ret = RK_MPI_SYS_Bind(&vi_chn_s, &smartp_gop_venc_chn_s);

1.5.​​​​​​​​​​​​​​创建多线程获取普通GOP的VENC码流数据并保存

开启一个线程去采集每一帧普通GOP的VENC模块数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是普通GOP的 VENC创建ID号。这个API伪代码如下:

while(1)

{

  .........................

  mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, COMMON_GOP_VENC_CHN, -1);

  fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, common_gop_h264_file);

.......................

}

1.6.​​​​​​​​​​​​​​多线程获取SMARTP_GOP的VENC模块数据:

开启一个线程去采集每一帧SMARTP_GOP的VENC模块数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是SMARTP_GOP的VENC层。这个API伪代码如下:

while(1)

{

  .........................

  mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, SMARTP_GOP_VENC_CHN, -1);

  fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, smartp_gop_h264_file);

.......................

}

好的,接下来我们进行完整的代码

#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "rkmedia_api.h"#define PIPE_ID 0
#define VI_CHN_ID 0#define COMMON_GOP_VENC_CHN 0
#define SMARTP_GOP_VENC_CHN 1//获取每一帧COMMON_GOP的编码数据
void  * get_common_gop_thread(void * args)
{pthread_detach(pthread_self());FILE * common_gop_h264 = fopen("test_common_gop.h264", "w+");MEDIA_BUFFER mb = NULL;while (1){mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, COMMON_GOP_VENC_CHN, -1);if(!mb){printf("Get COMMON_GOP VENC break.......\n");break;}printf("Get COMMON_GOP VENC Success.......\n");fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, common_gop_h264);RK_MPI_MB_ReleaseBuffer(mb);}return NULL;
}//获取每一帧SMARTP_GOP的编码数据
void  * get_smartp_gop_thread(void * args)
{pthread_detach(pthread_self());FILE * smartp_gop_h264 = fopen("test_smartp_gop.h264", "w+");MEDIA_BUFFER mb = NULL;while (1){mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, SMARTP_GOP_VENC_CHN, -1);if(!mb){printf("Get SMARTP_GOP VENC break.......\n");break;}printf("Get SMARTP_GOP VENC Success.......\n");fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, smartp_gop_h264);RK_MPI_MB_ReleaseBuffer(mb);}return NULL;
}int main()
{int ret;RK_MPI_SYS_Init();// VI Init......VI_CHN_ATTR_S vi_chn_attr;vi_chn_attr.pcVideoNode = "rkispp_scale0";    // 设置视频设备节点路径vi_chn_attr.u32Width = 1920;                  // 设置分辨率的宽度vi_chn_attr.u32Height = 1080;                 // 设置分辨率的高度vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;       // 设置图像类型vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP; // 设置VI获取类型vi_chn_attr.u32BufCnt = 3;                    // 设置缓冲数量vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL; // 设置VI工作类型ret = RK_MPI_VI_SetChnAttr(PIPE_ID, VI_CHN_ID, &vi_chn_attr);if (ret){printf("VI_CHN_ATTR Set Failed.....\n");return -1;}else{printf("VI_CHN_ATTR Set Success.....\n");}ret |= RK_MPI_VI_EnableChn(PIPE_ID, VI_CHN_ID);if (ret){printf("VI_CHN_ATTR Enable Failed.....\n");return -1;}else{printf("VI_CHN_ATTR Enable Success.....\n");}// Common_Gop Venc ParameterVENC_CHN_ATTR_S common_gop_venc_attr;common_gop_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;  // 设置编码器类型common_gop_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;  // 设置编码图像类型common_gop_venc_attr.stVencAttr.u32PicWidth = 1920;           // 设置编码分辨率宽度common_gop_venc_attr.stVencAttr.u32PicHeight = 1080;          // 设置编码分辨率高度common_gop_venc_attr.stVencAttr.u32VirWidth = 1920;           // 设置编码分辨率虚宽common_gop_venc_attr.stVencAttr.u32VirHeight = 1080;          // 设置编码分辨率虚高common_gop_venc_attr.stVencAttr.u32Profile = 66;              // 设置编码等级common_gop_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0; // 设置编码的旋转角度//********* 设置码率控制属性  *******************//common_gop_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;    // 设置H264的CBR码率控制模式common_gop_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;              // 设置GOP关键帧间隔common_gop_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;  // 设置源帧率分子common_gop_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;   // 设置源帧率分母common_gop_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25; // 设置目标帧率分子common_gop_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;  // 设置目标帧率分母common_gop_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;     // 设置码率大小ret = RK_MPI_VENC_CreateChn(COMMON_GOP_VENC_CHN, &common_gop_venc_attr);if (ret){printf("Set Common_Gop Venc Attr Failed.....\n");}else{printf("Set Common_Gop Venc Attr Success.....\n");}// smart_Gop Venc ParameterVENC_CHN_ATTR_S smartp_gop_venc_attr;smartp_gop_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;  // 设置编码器类型smartp_gop_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;  // 设置编码图像类型smartp_gop_venc_attr.stVencAttr.u32PicWidth = 1920;           // 设置编码分辨率宽度smartp_gop_venc_attr.stVencAttr.u32PicHeight = 1080;          // 设置编码分辨率高度smartp_gop_venc_attr.stVencAttr.u32VirWidth = 1920;           // 设置编码分辨率虚宽smartp_gop_venc_attr.stVencAttr.u32VirHeight = 1080;          // 设置编码分辨率虚高smartp_gop_venc_attr.stVencAttr.u32Profile = 66;              // 设置编码等级smartp_gop_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0; // 设置编码的旋转角度//********* 设置码率控制属性  *******************//smartp_gop_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;    // 设置H264的CBR码率控制模式smartp_gop_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;              // 设置GOP关键帧间隔smartp_gop_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;  // 设置源帧率分子smartp_gop_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;   // 设置源帧率分母smartp_gop_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25; // 设置目标帧率分子smartp_gop_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;  // 设置目标帧率分母smartp_gop_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;     // 设置码率大小ret = RK_MPI_VENC_CreateChn(SMARTP_GOP_VENC_CHN, &smartp_gop_venc_attr);if (ret){printf("Set SMARTP_Gop Venc Attr Failed.....\n");}else{printf("Set SMARTP_Gop Venc Attr Success.....\n");}VENC_GOP_ATTR_S venc_gop_attr_s;venc_gop_attr_s.enGopMode = VENC_GOPMODE_SMARTP;//设置GOP模式为SMARTP模式venc_gop_attr_s.u32GopSize = 25;//设置短参考帧间隔是25venc_gop_attr_s.u32BgInterval = 25 * 5;//长期参考帧的间隔venc_gop_attr_s.s32IPQpDelta = 6;//设置I帧和P帧的差值是6venc_gop_attr_s.s32ViQpDelta = 6;//设置虚拟I帧和P帧的差值是6ret = RK_MPI_VENC_SetGopMode(SMARTP_GOP_VENC_CHN,&venc_gop_attr_s);if (ret){printf("Set SMARTP_GOP_MODE Failed.....\n");}else{printf("Set SMARTP_GOP_MODE Success.....\n");}MPP_CHN_S vi_chn_s;vi_chn_s.enModId = RK_ID_VI;vi_chn_s.s32ChnId = VI_CHN_ID;MPP_CHN_S common_gop_venc_chn_s;common_gop_venc_chn_s.enModId = RK_ID_VENC;common_gop_venc_chn_s.s32ChnId = COMMON_GOP_VENC_CHN;MPP_CHN_S smartp_gop_venc_chn_s;smartp_gop_venc_chn_s.enModId = RK_ID_VENC;smartp_gop_venc_chn_s.s32ChnId = SMARTP_GOP_VENC_CHN;ret = RK_MPI_SYS_Bind(&vi_chn_s, &common_gop_venc_chn_s); //绑定VI和COMMON_GOP的VENC节点if (ret){printf("Bind Vi And Common_Gop Failed.....\n");}else{printf("Bind Vi And Common_Gop Success.....\n");}ret = RK_MPI_SYS_Bind(&vi_chn_s, &smartp_gop_venc_chn_s);  //绑定VI和SMARTP_GOP的VENC节点if (ret){printf("Bind Vi And Smartp_Gop Failed.....\n");}else{printf("Bind Vi And Smartp_Gop Success.....\n");}pthread_t common_gop_pid, smartp_gop_pid;pthread_create(&common_gop_pid, NULL, get_common_gop_thread, NULL);pthread_create(&smartp_gop_pid, NULL, get_smartp_gop_thread, NULL);while (1){sleep(2);}RK_MPI_SYS_UnBind(&vi_chn_s, &common_gop_venc_chn_s);RK_MPI_SYS_UnBind(&vi_chn_s, &smartp_gop_venc_chn_s);RK_MPI_VENC_DestroyChn(COMMON_GOP_VENC_CHN);RK_MPI_VENC_DestroyChn(SMARTP_GOP_VENC_CHN);RK_MPI_VI_DisableChn(PIPE_ID, VI_CHN_ID);return 0;
}

疑问:

这段代码中RV1126这里的GOP, 一个是普通GOP, 一个是 smart GOP 就是这里只是设置了smart GOP, 普通GOP就并没有没设置, 是默认还是?

关键点分析:

  1. 默认 GOP 模式:
    • 在 Rockchip 的 RKMEDIA 库中,如果未显式设置 GOP 模式,编码器通常会使用 默认的普通 GOP 模式(可能是 VENC_GOPMODE_NORMALP 或类似模式,具体取决于实现)。
    • 默认的 GOP 结构通常是简单的 I-P-P-P... 序列,GOP 大小由 u32Gop 参数(在 stH264Cbr 中设置为 25)决定,即每 25 帧一个 I 帧,其余为 P 帧。
  2. 代码中的显式设置:
    • 只有 SMARTP_GOP_VENC_CHN 调用了 RK_MPI_VENC_SetGopMode,明确配置了 SMARTP 模式的参数(如 u32GopSize=25u32BgInterval=125 等)。
    • COMMON_GOP_VENC_CHN 未调用此函数,因此会使用默认配置。

文章转载自:

http://3S9xFkZ5.ctbjr.cn
http://64Zz3B4F.ctbjr.cn
http://bGLnZOSC.ctbjr.cn
http://cE4OA4K2.ctbjr.cn
http://wf2yIIDs.ctbjr.cn
http://qkSwQYyg.ctbjr.cn
http://Cuf3trDT.ctbjr.cn
http://NBMOXQHX.ctbjr.cn
http://JcvGHxV9.ctbjr.cn
http://SeRFN98v.ctbjr.cn
http://lYenl4na.ctbjr.cn
http://6TgYPeAJ.ctbjr.cn
http://iRdYpw7X.ctbjr.cn
http://ipafrBOG.ctbjr.cn
http://CZzOjL0J.ctbjr.cn
http://s3a5hokh.ctbjr.cn
http://Bs73uCAX.ctbjr.cn
http://eO3hO3JY.ctbjr.cn
http://MTWWC7Kq.ctbjr.cn
http://VmzYaZ8I.ctbjr.cn
http://vJWLcpVg.ctbjr.cn
http://P71irHkx.ctbjr.cn
http://0zfVp1up.ctbjr.cn
http://oQM45nkn.ctbjr.cn
http://ZiU6XjHY.ctbjr.cn
http://3Fynf4KM.ctbjr.cn
http://q6xNdYTF.ctbjr.cn
http://gUVxE91f.ctbjr.cn
http://Y4s1jzDe.ctbjr.cn
http://BlkqL9Tq.ctbjr.cn
http://www.dtcms.com/a/382423.html

相关文章:

  • 数据的读多写少和读多写多解决方案
  • 0基础Java学习过程记录——异常
  • 几种网络IO模型
  • 文章阅读与实践 - OOM/时间精度/步数排行实现/故障复盘
  • 第七章:AI进阶之------输入与输出函数(二)
  • html列表总结补充
  • 系统软中间件:连接软件与硬件的桥梁
  • 关于Bug排查日记的技术文章大纲
  • 【Ambari监控】— API请求逻辑梳理
  • Deepseek构建本地知识库
  • DAY 29 复习日:类的装饰器-2025.9.16
  • 2025.9.14英语红宝书【必背16-20】
  • 【CMake】环境变量
  • 贪心算法应用:广告投放优化问题详解
  • VSCode AI编程插件
  • 题解:P4711 「化学」相对分子质量
  • QGIS构建问题
  • 【飞书多维表格插件】
  • 云原生与多云策略:构建弹性、开放的数据底座
  • Java接口入门:从零掌握行为规范
  • Java基础常见知识点
  • Linux epoll 事件模型终极指南:深入解析 epoll_event 与事件类型
  • 简单学习HTML+CSS+JavaScript
  • 4 Python开发环境准备
  • 人源化抗体:从临床应用到未来趋势,3 大领域突破 + 4 大发展方向全解析
  • Scrapy框架入门:快速掌握爬虫精髓
  • 2.1线性表
  • Java 21 虚拟线程高并发落地:中间件适配、场景匹配与细节优化的技术实践
  • 炒股进阶理论知识
  • 07_Softmax回归、损失函数、分类