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

RV1126画面质量三:QP调节

一.什么是 QP 调节?
        QP 参数调节,指的是量化参数调节。它主要是来调节图像的细节,最终达到调节画面质量的作用。QP 值和比特率成反比QP值越小画面质量越高;反之 QP 值越大,画面质量越低。而且随着视频源复杂度,这种反比的关系会更加明显。QP 调节是改变画面质量最常用的手段之一。

        QP调节H264和H265画面最常用的一个手段。

二.QP 调节的基本概念:
        QP 调节一般由 QStep、MinQp、MaxQp 这三个参数进行调节。下面我们来看看,这三个参数的作用。下面这个是QP值和QStep对应的一个关键值。假设我的Qset是1,QP值就是4,在开发的时候,一个是直接调Qset就可以了

        前面说了QP值越小,画面越好,反之画面越差。 因为QP值和QStep对应的一个关键值。所以我们通过调Qset来设置QP值。

2.2. minqp 最小量化步长(调节禁止画面)
        设置最小量化器,限制最好的图像质量(重点在静止画面比如建筑,植物......),当 QP 达到这个值的时候,数值不会变。这就会使得在静止场景下,码率到达一定数量后不会进行调整。minqp 越小,静止时候码率越大,质量越好,建议值[8,20]。简单说就是解决禁止画面的异常,比如呼吸效应。这个值是经验值来的,是经过多调试才能得出一个比较不错的值,8是最好,但是有代价就是码率比较大。20画面质量也还行,但是码效率小。感根据实际情况取舍。如果我填8,这个植物是没有任何呼吸效应和马赛克情况。

        比如下面这写球员站着的球员用minqp 最小量化步长,因为画面相对禁止。

2.3. maxqp 最大量化步长(调节运动画面)

        设置最大量化器,最大 QP 值,限制最差的画面(重点在运动的时候),在运动画面把宏块和马赛克去掉,maxQp 越小,2同样道理,当运动情况下到达一定码率后就不会调整。建议值[20,50],一样要多试。

        比如踢球,因为是运动的,就要调maxqp

        QSet调整体画面,minQp调禁止的画面,maxqp调运动画面。

        QP调节的有一个数据结构体rvVENC_RC_PARAM_S数据结构

         u32ThrdI、u32ThrdP:分别衡量 I 帧、P 帧宏块复杂的一组阈值。这组阈值是从小到大依次排序,每个阈值的取值是[0,255]。这组阈值主要用于宏块级别的码率控制,并根据图像复杂程度对每个宏块进行 QP 调节。这部分大部分也用在 CBR 上面。
u32ThrdI 默认值:[0,0,0,0,3,3,5,5,8,8,8,15,15,20,25,25]
u32ThrdP 默认值:[0,0,0,0,3,3,5,5,8,8,8,15,15,20,25,25]
注意:u32ThrdI、u32ThrdP 在一般情况下不需要设置        

        下面解析一下:

        我们知道每一帧都是一张图片,图片又是是一个一个像素点组成,16X16的像素点,为一个宏快,u32ThrdI、u32ThrdP是对这些宏块调节,可以说是微观调节,但是用处不大,不如整体调节

        u32RowQpDeltaI: 基于行的宏块级别码率控制,每一行的宏块的起始 QP 相对于 I 帧的 QP 波动幅度值,主要用在 CBR 控制模式。对于码率波动比较严格的场景下,可以通过调节这个参数使得码率控制更加精确。在高码率时,该值推荐为 0;中码率时推荐该值为 0 或 1;低码率时推荐 该值为 2~5。

        意思是每一个小宏块的QP 相对于 I 帧的 QP 波动幅度值,宏块的QP  - I 帧的 QP = 码率的幅度


        u32RowQpDeltaP: 基于行的宏块级别码率控制,每一行的宏块的起始 QP 相对于 P 帧的 QP 波动幅度值,主要用在 CBR 控制模式。对于码率波动比较严格的场景下,可以通过调节这个参数使得码率控制更加精确。在高码率时,该值推荐为 0;中码率时推荐该值为 0 或 1;低码率时推荐 该值为 2~5。 

        意思是每一个小宏块的QP 相对于 I 帧的 QP 波动幅度值,宏块的QP  - I 帧的 QP = 码率的幅度

       

        下面的表格就是来解释哪些范围是高码率,中码率,低码率 

        s32FirstFrameStartQp:第一帧 QP 值,默认-1。-1 代表的是第一帧的起始 QP 由编码器内部进行计算。若是其他值,则由用户指定该合法值为第一帧起始 QP。 

在数据结果里面,这三个才是重点,实际开发的时候也是调这个

  1. stParamH264:主要是调节 H264 的 QP 参数
  2. stParamH265:主要是调节 H265 的 QP 参数
  3. stParamMjpeg:主要是调节 Mjpeg 的 QP 参数

stParamH264:主要是调节 H264 的 QP 参数:

  1. u32StepQp: QP 的 STEP 步长,STEP 步长去调节 QP 值,要想画面最好直接填1
  2. u32MaxQp:QP 的最大值调节非I帧的,对运动画面进行限制,若忽视码率则建议 51;若对质量讲究,则建议设置[20,51]。
  3. u32MinQp:QP 的最小值,希望在静止画面的时候节省码率,取值范围[0,48]。VBR 建议设置为[24,32],CBR 建议设置[10,20]
  4. u32MaxIQp: I 帧的 QP 最大值,取值范围[8,51],图像运动的时候节省码率,默认和 u32MaxQP 的值是一致。
  5. u32MinIQp: I 帧的 QP 最小值,取值范围[0,48],图像静止或小运动的时候节省码率,默认和 u32MinIQp 是一致。

u32MaxQp和u32MinQp还是基于I帧P帧B帧直接整体调整,u32RowQpDeltaI和u32RowQpDeltaP:基于宏块调整。宏块调整的效果远远低于整体调整

stParamH265:主要是调节 H265 的 QP 参数:和264差不多

  1. u32StepQp: QP 的 STEP 步长
  2. u32MaxQp:QP 的最大值,对运动画面进行限制,若忽视码率则建议 51;若对质量讲究,则建议设置[40,51]。取值范围[8,51]。
  3. u32MinQp:QP 的最小值,希望在静止画面的时候节省码率,取值范围[0,48]。VBR 建议设置为[24,32],CBR 建议设置[10,20]
  4. u32MaxIQp: I 帧的 QP 最大值,取值范围[8,51],图像运动的时候节省码率,默认和 u32MaxQP 的值是一致。
  5. u32MinIQp: I 帧的 QP 最小值,取值范围[0,48],图像静止或小运动的时候节省码率,默认和 u32MinIQp 是一致。

编码 :

#include <stdio.h>
#include "rkmedia_config.h"

void * collect_venc_thread(void * args)
{
   pthread_detach(pthread_self());
   MEDIA_BUFFER mb;
   FILE * h264_file = fopen("./test_output_smart.h264", "w+");

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

       printf("mmmmmm\n");
       fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, h264_file);
       RK_MPI_MB_ReleaseBuffer(mb);
   }
   return NULL;
}

int main()
{
    RK_U32 u32Width = 1920;
    RK_U32 u32Height = 1080;
    RK_CHAR *pDeviceName = "rkispp_scale0";
    RK_CHAR *pOutPath = NULL;
    RK_CHAR *pIqfilesPath = NULL;
    CODEC_TYPE_E enCodecType = RK_CODEC_TYPE_H264;
    RK_CHAR *pCodecName = "H264";
    RK_S32 s32CamId = 0;
    RK_U32 u32BufCnt = 3;

    rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
    SAMPLE_COMM_ISP_Init(hdr_mode, RK_FALSE);
    SAMPLE_COMM_ISP_Run();
    SAMPLE_COMM_ISP_SetFrameRate(30);

    int ret;
    RK_MPI_SYS_Init();
    VI_CHN_ATTR_S vi_chn_attr;
    vi_chn_attr.pcVideoNode = pDeviceName;
    vi_chn_attr.u32BufCnt = u32BufCnt;
    vi_chn_attr.u32Width = u32Width;
    vi_chn_attr.u32Height = u32Height;
    vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;
    vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;
    vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
    ret = RK_MPI_VI_SetChnAttr(s32CamId, 1, &vi_chn_attr);
    ret |= RK_MPI_VI_EnableChn(s32CamId, 1);
    if (ret)
    {
        printf("ERROR: create VI[0] error! ret=%d\n", ret);
        return 0;
    }

    VENC_CHN_ATTR_S venc_chn_attr;
    memset(&venc_chn_attr, 0, sizeof(venc_chn_attr));
    venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;
    venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 30 * 4;
    venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = u32Width * u32Height;
    // frame rate: in 30/1, out 30/1.
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 30;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 30;
    venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;
    venc_chn_attr.stVencAttr.u32PicWidth = u32Width;
    venc_chn_attr.stVencAttr.u32PicHeight = u32Height;
    venc_chn_attr.stVencAttr.u32VirWidth = u32Width;
    venc_chn_attr.stVencAttr.u32VirHeight = u32Height;
    venc_chn_attr.stVencAttr.u32Profile = 77;
    ret = RK_MPI_VENC_CreateChn(0, &venc_chn_attr);
    if (ret)
    {
        printf("ERROR: create VENC[0] error! ret=%d\n", ret);
        return 0;
    }

    RK_U32 u32StepQp = 1; //因为是一个整形,我们尽量填整型
    RK_U32 u32MaxQp = 24; //这个只能说一个经验值,可能24还会一点点马赛克的情况,只能说多调试
    RK_U32 u32MinQp = 10; //禁止的时候我们把画面质量提高,10是比较高的了
    RK_U32 u32MaxIQp = 24; 
    RK_U32 u32MinIQp = 10;
    VENC_RC_PARAM_S venc_rc_param;

    venc_rc_param.u32RowQpDeltaI = 1; //因为是中码率所以填1
    venc_rc_param.u32RowQpDeltaP = 1; //因为是中码率所以填1
    venc_rc_param.s32FirstFrameStartQp = -1; //默认-1
    //把值设置进去
    venc_rc_param.stParamH264.u32StepQp = u32StepQp;
    venc_rc_param.stParamH264.u32MaxQp = u32MaxQp;
    venc_rc_param.stParamH264.u32MinQp = u32MinQp;
    venc_rc_param.stParamH264.u32MinIQp = u32MinIQp;
    venc_rc_param.stParamH264.u32MaxIQp = u32MaxIQp;
    ret = RK_MPI_VENC_SetRcParam(0, &venc_rc_param);
    if (ret != 0)
    {
        printf("venc_params failed....\n");
    }
    else
    {
        printf("venc_params success....\n");
    }


    MPP_CHN_S stSrcChn;
    stSrcChn.enModId = RK_ID_VI;
    stSrcChn.s32DevId = 0;
    stSrcChn.s32ChnId = 1;
    
    MPP_CHN_S stDestChn;
    stDestChn.enModId = RK_ID_VENC;
    stDestChn.s32DevId = 0;
    stDestChn.s32ChnId = 0;
    ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if (ret)
    {
        printf("ERROR: Bind VI[0] and VENC[0] error! ret=%d\n", ret);
        return 0;
    }

    pthread_t pid;
    ret = pthread_create(&pid, NULL, collect_venc_thread, NULL);
    if(ret != 0)
    {
        printf("Create Venc Thread Failed....\n");
    }

    while (1)
    {
       sleep(20);
    }
    

    return 0;
}


http://www.kler.cn/a/517480.html

相关文章:

  • 【动态规划】--- 斐波那契数模型
  • Qt中QVariant的使用
  • 【模拟集成电路】锁相环(phase-locked loops,PLL)设计_环形振荡器相关(简)
  • 浏览器hid 和蓝牙bluetooth技术区别
  • 计算机视觉-卷积
  • WPF基础 | WPF 基础概念全解析:布局、控件与事件
  • 实现GD32F470作为高速USB主机与USB鼠标通信的功能
  • uart、iic、spi通信总线
  • npm:升级自身时报错:EBADENGINE
  • 微前端架构在前端开发中的实践与挑战
  • 基于微信小程序的校园失物招领系统设计与实现(LW+源码+讲解)
  • 批量修改图片资源的属性。
  • 完全二叉树的节点个数(力扣222)
  • unity 粒子系统设置触发
  • dfs专题五:FloodFill算法
  • react中hooks之 React 19 新 Hooks useOptimistic
  • linux系统下的磁盘扩容
  • 前端知识——HTML基础
  • ⚡C++ 中 std::transform 函数深度解析:解锁容器元素转换的奥秘⚡【AI 润色】
  • 低代码开发中的开源与闭源之争
  • 分数之和(题解)
  • 无人机的应用场景有哪些?
  • gesp(C++六级)(1)洛谷:P10250:[GESP样题 六级] 下楼梯
  • Java面试题2025-Spring
  • 【C语言】结构体与共用体深入解析
  • Django创建纯净版项目并启动