RV1126视频编码增强模块:RV1126的QP代码实战

目录

一.RV1126多线程分别获取QP的VENC数据和普通VENC数据的流程

1.1初始化VI模块:

1.2 普通VENC模块初始化、 QP量化VENC模块初始化:

1.3设置QP的VENC模块QP量化参数:

1.4VI模块绑定普通VENC模块和QP量化的VENC模块:

1.5多线程获取普通VENC模块数据:

1.6多线程获取QP的VENC模块数据:

二.代码实战

三.播放效果对比


一.RV1126多线程分别获取QP的VENC数据和普通VENC数据的流程

RV1126利用多线程同时获取普通VENC数据和QP量化的VENC数据,需要上面8个步骤,分别是:VI模块的初始化、普通VENC模块的初始化、量化QP的VENC模块的初始化、绑定VI模块和普通VENC模块、设置QP的VENC模块QP量化参数、绑定VI模块和QP量化VENC模块、多线程获取每一帧普通VENC编码数据、多线程获取每一帧QP量化后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 普通VENC模块初始化、 QP量化VENC模块初始化:

//普通的VENC模块初始化

VENC_CHN_ATTR_S common_venc_attr;

。。。。。。。。。。。。。。。。。。。。。。。

RK_MPI_VENC_CreateChn(COMMON_VENC_CHN, &common_venc_attr);

//QP的VENC模块初始化

VENC_CHN_ATTR_S qp_venc_attr;

。。。。。。。。。。。。。。。。。。。。。。。

RK_MPI_VENC_CreateChn(QP_VENC_CHN, &qp_venc_attr);

这里需要创建两个VENC层,一个是普通的VENC层、另外一个是QP的VENC层

1.3设置QP的VENC模块QP量化参数:

VENC_RC_PARAM_S venc_rc_params;

venc_rc_params.s32FirstFrameStartQp = -1;

venc_rc_params.stParamH264.u32StepQp = 1;

venc_rc_params.stParamH264.u32MaxQp = 30;

venc_rc_params.stParamH264.u32MinQp = 10;

venc_rc_params.stParamH264.u32MinIQp = 10;

venc_rc_params.stParamH264.u32MaxIQp = 30;

ret = RK_MPI_VENC_SetRcParam(QP_VENC_CHN, &venc_rc_params);

上面的代码主要是设置的QP调节的参数,设置完成之后调用 RK_MPI_VENC_SetRcParam

1.4VI模块绑定普通VENC模块和QP量化的VENC模块:

//VI模块节点

MPP_CHN_S vi_chn_s;

vi_chn_s.enModId = RK_ID_VI;

vi_chn_s.s32ChnId = VI_CHN_ID;

//普通VENC模块节点

MPP_CHN_S common_venc_chn_s;

common_venc_chn_s.enModId = RK_ID_VENC;

common_venc_chn_s.s32ChnId = COMMON_VENC_CHN;

ret = RK_MPI_SYS_Bind(&vi_chn_s, &common_venc_chn_s);

//QP的VENC模块节点

MPP_CHN_S qp_venc_chn_s;

qp_venc_chn_s.enModId = RK_ID_VENC;

qp_venc_chn_s.s32ChnId = QP_VENC_CHN;

ret = RK_MPI_SYS_Bind(&vi_chn_s, &qp_venc_chn_s);

注意:VI模块分别绑定普通VENC模块和QP量化的VENC模块

​​​​​​​1.5多线程获取普通VENC模块数据:

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

while(1)

{

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

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

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

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

}

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

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

while(1)

{

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

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

  fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, qp_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 "common/sample_common.h"
#include "rkmedia_api.h"

#define PIPE_ID 0
#define VI_CHN_ID 0

#define COMMON_VENC_CHN 0
#define QP_VENC_CHN 1




//获取每一帧COMMON_VENC的编码数据
void * get_common_venc_thread(void * args)
{
    pthread_detach(pthread_self());
    FILE  * origin_h264 = fopen("test_origin.h264", "w+");
    MEDIA_BUFFER mb = NULL;

    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, COMMON_VENC_CHN, -1);
        if(!mb)
        {
            printf("Get Origin Venc break....\n");
            break;
        }

        printf("Get Origin File Venc Success....\n");
        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, origin_h264);
        RK_MPI_MB_ReleaseBuffer(mb);
    }
    
    return NULL;
}


//获取每一帧QP_VENC的编码数据
void * get_qp_venc_thread(void * args)
{
    pthread_detach(pthread_self());
    FILE  * origin_h264 = fopen("test_qp.h264", "w+");
    MEDIA_BUFFER mb = NULL;

    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, QP_VENC_CHN, -1);
        if(!mb)
        {
            printf("Get QP Venc break....\n");
            break;
        }

        printf("Get QP File Venc Success....\n");
        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, origin_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 Venc Parameter
    VENC_CHN_ATTR_S common_venc_attr;
    common_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;  // 设置编码器类型
    common_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;  // 设置编码图像类型
    common_venc_attr.stVencAttr.u32PicWidth = 1920;           // 设置编码分辨率宽度
    common_venc_attr.stVencAttr.u32PicHeight = 1080;          // 设置编码分辨率高度
    common_venc_attr.stVencAttr.u32VirWidth = 1920;           // 设置编码分辨率虚宽
    common_venc_attr.stVencAttr.u32VirHeight = 1080;          // 设置编码分辨率虚高
    common_venc_attr.stVencAttr.u32Profile = 66;              // 设置编码等级
    common_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0; // 设置编码的旋转角度

    //********* 设置码率控制属性  *******************//
    common_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;    // 设置H264的CBR码率控制模式
    common_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;              // 设置GOP关键帧间隔
    common_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;  // 设置源帧率分子
    common_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;   // 设置源帧率分母
    common_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25; // 设置目标帧率分子
    common_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;  // 设置目标帧率分母
    common_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;     // 设置码率大小
    ret = RK_MPI_VENC_CreateChn(COMMON_VENC_CHN, &common_venc_attr);
    if (ret)
    {
        printf("Set Common Venc Attr Failed.....\n");
    }
    else
    {
        printf("Set Common Venc Attr Success.....\n");
    }

    // QP Venc Parameter
    VENC_CHN_ATTR_S qp_venc_attr;
    qp_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;  // 设置编码器类型
    qp_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;  // 设置编码图像类型
    qp_venc_attr.stVencAttr.u32PicWidth = 1920;           // 设置编码分辨率宽度
    qp_venc_attr.stVencAttr.u32PicHeight = 1080;          // 设置编码分辨率高度
    qp_venc_attr.stVencAttr.u32VirWidth = 1920;           // 设置编码分辨率虚宽
    qp_venc_attr.stVencAttr.u32VirHeight = 1080;          // 设置编码分辨率虚高
    qp_venc_attr.stVencAttr.u32Profile = 66;              // 设置编码等级
    qp_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0; // 设置编码的旋转角度

    //********* 设置码率控制属性  *******************//
    qp_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;    // 设置H264的CBR码率控制模式
    qp_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;              // 设置GOP关键帧间隔
    qp_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;  // 设置源帧率分子
    qp_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;   // 设置源帧率分母
    qp_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25; // 设置目标帧率分子
    qp_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;  // 设置目标帧率分母
    qp_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;     // 设置码率大小
    ret = RK_MPI_VENC_CreateChn(QP_VENC_CHN, &qp_venc_attr);
    if (ret)
    {
        printf("Set QP Venc Attr Failed.....\n");
    }
    else
    {
        printf("Set QP Venc Attr Success.....\n");
    }

    //QP Set
    VENC_RC_PARAM_S venc_rc_params;
    venc_rc_params.s32FirstFrameStartQp = -1;//初始化StartQP的值,-1
    venc_rc_params.stParamH264.u32StepQp = 1; //QStep Set
    venc_rc_params.stParamH264.u32MaxQp = 30; //设置MAXQP的值 
    venc_rc_params.stParamH264.u32MinQp = 10; //设置MINQP的值
    venc_rc_params.stParamH264.u32MaxIQp = 30;//设置MAXIQP的值
    venc_rc_params.stParamH264.u32MinIQp = 10;//设置MINIQP的值
    ret = RK_MPI_VENC_SetRcParam(QP_VENC_CHN, &venc_rc_params);
    if(ret)
    {
        printf("Set RC_PARAM Failed.....\n");
    }
    else
    {
        printf("Set RC_PARAM 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_venc_chn_s;
    common_venc_chn_s.enModId = RK_ID_VENC;
    common_venc_chn_s.s32ChnId = COMMON_VENC_CHN;

    MPP_CHN_S qp_venc_chn_s;
    qp_venc_chn_s.enModId = RK_ID_VENC;
    qp_venc_chn_s.s32ChnId = QP_VENC_CHN;

    ret = RK_MPI_SYS_Bind(&vi_chn_s, &common_venc_chn_s); 绑定VI模块和COMMON_VENC模块
    if(ret)
    {
        printf("Bind Vi Chn And Common Venc Chn Failed.....\n");
    }
    else
    {
        printf("Bind Vi Chn And Common Venc Chn Success.....\n");
    }

    ret = RK_MPI_SYS_Bind(&vi_chn_s, &qp_venc_chn_s); 绑定VI模块和QP_VENC模块
    if(ret)
    {
        printf("Bind Vi Chn And QP Venc Chn Failed.....\n");
    }
    else
    {
        printf("Bind Vi Chn And QP Venc Chn Success.....\n");
    }

    pthread_t common_pid, qp_pid;
    pthread_create(&common_pid, NULL, get_common_venc_thread, NULL);
    pthread_create(&qp_pid, NULL, get_qp_venc_thread, NULL);

    while (1)
    {
       sleep(1);
    }

    RK_MPI_SYS_UnBind(&vi_chn_s, &common_venc_chn_s);
    RK_MPI_SYS_UnBind(&vi_chn_s, &qp_venc_chn_s);
    RK_MPI_VENC_DestroyChn(COMMON_VENC_CHN);
    RK_MPI_VENC_DestroyChn(QP_VENC_CHN);
    RK_MPI_VI_DisableChn(PIPE_ID, VI_CHN_ID);
    
    return 0;
}

三.播放效果对比

分别播放两个H264文件,test_origin.h264、test_qp.h264。

ffplay test_origin.h264

ffplay test_qp.h264

然后对比两个画面的质量,test_origin.h264的画面质量低于test_qp.h264的画面质量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值