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 Parameter
    VENC_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 Parameter
    VENC_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;//设置短参考帧间隔是25
    venc_gop_attr_s.u32BgInterval = 25 * 5;//长期参考帧的间隔
    venc_gop_attr_s.s32IPQpDelta = 6;//设置I帧和P帧的差值是6
    venc_gop_attr_s.s32ViQpDelta = 6;//设置虚拟I帧和P帧的差值是6
    ret = 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 未调用此函数,因此会使用默认配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值