• RKMEDIA--VENC/VDEC使用


    前面两篇已经介绍了VI和VO的使用,本章节来介绍rkmedia且也是瑞芯微平台重点部分:编解码

    目录

    一、简介

    二、编解码能力

    三、编码

    编码初始化:

    在初始化VENC时需要注意几点:

    venc编码帧率控制:

     编码添加osd位图:

    四、解码

    解码初始化:

    五、编解码常见问题及调试

    1、调试命令

    2、编码常见问题

    3、解码常见问题


    一、简介

    rkmedia编解码部分是对mpp接口进行封装提供给用户使用。

    mpp是瑞芯微提供的媒体处理软件平台(Media Process Platform, 简称 MPP)是适用于瑞芯微芯片系列的通用媒体处理软件平台。只要是rk平台的的编解码都是用的mpp,区别在于编解码能力不同以及不同芯片支持的格式等不同。编解码都是硬件编解码,编解码资源是分开的。

    MPP 提供的功能包括:
    视频解码:
            H.265 / H.264 / H.263 / VP9 / VP8 / MPEG-4 / MPEG-2 / MPEG-1 / VC1 / MJPEG
    视频编码:
            H.264 / VP8 / MJPEG

    二、编解码能力

    rv1126编解码能力如下:

     

    rv1109编解码能力如下:

     以上编解码能力是总的编解码能力,如需多路编解码,可以自行换算。

    三、编码

    VENC 模块,即视频编码模块。此模块支持多路实时编码,且每路编码独立,编码协议和编码 profile 可以不同。支持视频编码同时,调度 Region 模块对编码图像内容进行叠加和遮挡。支持
    H264/H265/MJPEG/JPEG编码,支持的码控类型为CBR和VBR。

    编码初始化:

            以H264 CBR为例:

    1. venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;
    2. venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    3. venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 30;
    4. venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = u32Width * u32Height;
    5. // frame rate: in 30/1, out 30/1.
    6. venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
    7. venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 30;
    8. venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
    9. venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 30;
    10. venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;
    11. venc_chn_attr.stVencAttr.u32PicWidth = u32Width;
    12. venc_chn_attr.stVencAttr.u32PicHeight = u32Height;
    13. venc_chn_attr.stVencAttr.u32VirWidth = u32Width;
    14. venc_chn_attr.stVencAttr.u32VirHeight = u32Height;
    15. venc_chn_attr.stVencAttr.u32Profile = 77;
    16. ret = RK_MPI_VENC_CreateChn(0, &venc_chn_attr);
    17. if (ret) {
    18. printf("ERROR: create VENC[0] error! ret=%d\n", ret);
    19. return 0;
    20. }

            设置jpeg/mjpeg编码时,可以设置zoom宽高,实际上是经过rga进行缩放后再送去编码:

    1. VENC_CHN_ATTR_S venc_chn_attr;
    2. memset(&venc_chn_attr, 0, sizeof(venc_chn_attr));
    3. venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_JPEG;
    4. venc_chn_attr.stVencAttr.imageType = enPixFmt;
    5. venc_chn_attr.stVencAttr.u32PicWidth = u32SrcWidth;
    6. venc_chn_attr.stVencAttr.u32PicHeight = u32SrcHeight;
    7. venc_chn_attr.stVencAttr.u32VirWidth = u32SrcWidth;
    8. venc_chn_attr.stVencAttr.u32VirHeight = u32SrcHeight;
    9. /*********************************************************************/
    10. venc_chn_attr.stVencAttr.stAttrJpege.u32ZoomWidth = u32DstWidth;
    11. venc_chn_attr.stVencAttr.stAttrJpege.u32ZoomHeight = u32DstHeight;
    12. venc_chn_attr.stVencAttr.stAttrJpege.u32ZoomVirWidth = u32DstWidth;
    13. venc_chn_attr.stVencAttr.stAttrJpege.u32ZoomVirHeight = u32DstHeight;
    14. /*********************************************************************/
    15. venc_chn_attr.stVencAttr.enRotation = enRotation;
    16. venc_chn_attr.stVencAttr.stAttrJpege.bSupportDCF = RK_TRUE;
    17. venc_chn_attr.stVencAttr.stAttrJpege.stMPFCfg.u8LargeThumbNailNum = 2;
    18. venc_chn_attr.stVencAttr.stAttrJpege.stMPFCfg.astLargeThumbNailSize[0]
    19. .u32Width = 164;
    20. venc_chn_attr.stVencAttr.stAttrJpege.stMPFCfg.astLargeThumbNailSize[0]
    21. .u32Height = 128;
    22. venc_chn_attr.stVencAttr.stAttrJpege.stMPFCfg.astLargeThumbNailSize[1]
    23. .u32Width = 128;
    24. venc_chn_attr.stVencAttr.stAttrJpege.stMPFCfg.astLargeThumbNailSize[1]
    25. .u32Height = 164;
    26. ret = RK_MPI_VENC_CreateChn(0, &venc_chn_attr);
    27. if (ret) {
    28. printf("Create Venc failed! ret=%d\n", ret);
    29. return -1;
    30. }

    在初始化VENC时需要注意几点:

            1、编码是没有缩放功能的,输入的分辨率要和配置的分辨率一样,否则执行过程会报错。如需要动态切换分分辨率,需要disable venc、解绑、重新配置vi分辨率、重新配置venc分辨率、绑定。

            2、帧率控制参数是比例关系。比如默认配置的是1 30 1 30,实际比例是1:1。所以代表输入多少帧率就编码多少帧率。很多人会错误的认为是实际帧率的关系,觉得帧率控制有问题。

            3、编码h26x视频编码协议都是基于YUV420的,所以如果是yuv422输入编码出来的数据会有色彩偏差,这一点一般用hdmi作为输入的时候容易遇到。因为mpp内部会把输入的非yuv420格式(yuv422、argb8888)转换成yuv420,造成色彩丢失。

            4、编码jpeg时会多样一些,因为是图像。图像和视频还是有区别的。

    venc编码帧率控制:

    默认情况下编码的qp值已经设置成

    qpMin:8, qpMax:48, qpMinI:8, qpMaxI:48

    如果对码率控制的比较严格的情况下需要自行修改qp值,至于qp值具体配置成什么,那要根据自己的实际情况自己慢慢去调整。

    1. RK_MPI_VENC_GetRcParam(0,&stRcParam);
    2. printf("pstRcParam->s32FirstFrameStartQp=%d\n",stRcParam.s32FirstFrameStartQp);
    3. stRcParam.stParamH264.u32StepQp = 4;
    4. stRcParam.stParamH264.u32MaxQp = 50;
    5. stRcParam.stParamH264.u32MinQp = 23;
    6. stRcParam.stParamH264.u32MaxIQp = 48;
    7. stRcParam.stParamH264.u32MinIQp = 18;
    8. RK_MPI_VENC_SetRcParam(0, &stRcParam);

     对于编码高级参数在rkmedia的手册中描述的不多,这边截取海思手册中的描述,总体使用都差不多。

    在学习/使用编码高级参数还是需要多多去动手,多修改对应参数将保存的编码数据对比,这样才可以深入了解各个参数设置的意思。

     编码添加osd位图:

    rkmedia的venc中添加位图,使用的是RK_MPI_VENC_RGN_SetBitMap 接口去实现。位图只支持ARGB8888的格式,且最多支持8个区域优先级从REGION_ID_0~REGION_ID_7递增。

    1. #define TEST_ARGB32_YELLOW 0xFFFFFF00
    2. #define TEST_ARGB32_RED 0xFFFF0000
    3. #define TEST_ARGB32_GREEN 0xFF00FF00
    4. #define TEST_ARGB32_BLUE 0xFF0000FF
    5. #define TEST_ARGB32_TRANS 0x00000000
    6. #define TEST_ARGB32_WHITE 0xF0FFFFFF
    7. static void set_argb8888_buffer(RK_U32 *buf, RK_U32 size, RK_U32 color) {
    8. for (RK_U32 i = 0; buf && (i < size); i++)
    9. *(buf + i) = color;
    10. }
    11. RK_MPI_VENC_RGN_Init(0, NULL);
    12. BITMAP_S BitMap;
    13. BitMap.enPixelFormat = PIXEL_FORMAT_ARGB_8888;
    14. BitMap.u32Width = 160;
    15. BitMap.u32Height = 160;
    16. BitMap.pData = malloc(BitMap.u32Width * 4 * BitMap.u32Height);
    17. RK_U8 *ColorData = (RK_U8 *)BitMap.pData;
    18. RK_U16 ColorBlockSize = BitMap.u32Height * BitMap.u32Width;
    19. set_argb8888_buffer((RK_U32 *)ColorData, ColorBlockSize / 4,
    20. TEST_ARGB32_WHITE);
    21. set_argb8888_buffer((RK_U32 *)(ColorData + ColorBlockSize),
    22. ColorBlockSize / 4, TEST_ARGB32_TRANS);
    23. set_argb8888_buffer((RK_U32 *)(ColorData + 2 * ColorBlockSize),
    24. ColorBlockSize / 4, TEST_ARGB32_RED);
    25. set_argb8888_buffer((RK_U32 *)(ColorData + 3 * ColorBlockSize),
    26. ColorBlockSize / 4, TEST_ARGB32_BLUE);
    27. // Case 1: Canvas and bitmap are equal in size
    28. OSD_REGION_INFO_S RngInfo;
    29. RngInfo.enRegionId = REGION_ID_0;
    30. RngInfo.u32PosX = 160;
    31. RngInfo.u32PosY = 160;
    32. RngInfo.u32Width = 160;
    33. RngInfo.u32Height = 160;
    34. RngInfo.u8Enable = 1;
    35. RngInfo.u8Inverse = 0;
    36. RK_MPI_VENC_RGN_SetBitMap(0, &RngInfo, &BitMap);

     注意点:

            1、编码的位图只支持256色,所以如果是叠加彩色图片会出现色彩有偏差的问题,可以换成RGA的位图叠加函数去实现。

            2、每次更新数据的时候,需要重新调用RK_MPI_VENC_RGN_SetBitMap接口去刷一遍数据

            3、想要显示文字osd,还是需要把文字的类型转成argb的数据,送进去显示。给个链接可以参考:海思3516a实现OSD叠加水印_烫手的热山药的博客-CSDN博客

    四、解码

    VDEC 模块,即视频解码模块。此模块支持多路实时解码,且每路解码独立,支持
    H264/H265/MJPEG/JPEG解码。


    解码初始化:

    1. VDEC_CHN_ATTR_S stVdecAttr;
    2. memset(&stVdecAttr, 0, sizeof(stVdecAttr));
    3. stVdecAttr.enCodecType = enCodecType;
    4. stVdecAttr.enMode = VIDEO_MODE_FRAME;
    5. if (stVdecAttr.enCodecType == RK_CODEC_TYPE_MJPEG)
    6. stVdecAttr.enMode = VIDEO_MODE_FRAME;
    7. else
    8. stVdecAttr.enMode = VIDEO_MODE_STREAM;
    9. stVdecAttr.enDecodecMode = VIDEO_DECODEC_HADRWARE;
    10. ret = RK_MPI_VDEC_CreateChn(0, &stVdecAttr);
    11. if (ret)
    12. {
    13. printf("Create Vdec[0] failed! ret=%d\n", ret);
    14. return -1;
    15. }

    解码的初始化比较简单。解码的方式分为两种:帧模式流模式

    帧模式需要在送数据前已经分好帧,流模式则是在内部分帧

    注意:

            1、jpeg和mjpeg解码只支持帧模式,没有流模式。

            2、在解码中送数据的时间延时要自己控制,送的太快或者太慢都会导致解码器报错。

            3、解码时需要收到第一个I帧才会解码

    五、编解码常见问题及调试

    1、调试命令

    编码:

    查看编码信息cat /proc/mpp_service/session_summary
    查看硬件编解码时间echo 0x100 > /sys/module/rk_vcodec/parameters/mpp_dev_debug

    查看h26x编码频率

    cat /sys/kernel/debug/clk/clk_summary | grep enc
    查看mjpeg编码频率cat /sys/kernel/debug/clk/clk_summary | grep vepu
    设置26x编码频率echo 600000000 > /proc/mpp_service/rkvenc/clk_core(594000000是最高频率)

    解码:

    查看jpeg解码频率cat /sys/kernel/debug/clk/clk_summary | grep jpeg

    2、编码常见问题

    1、jpeg的旋转不支持缩放旋转,只能单独旋转

    2、jpeg编码不支持rgb格式,支持argb格式

    3、不管是输入格式是i还是p  编码出来的都是p(P代表逐行扫描,i代表隔行扫描)

    4、编码帧率达不到预期

    原因:可能达到编码能力的瓶颈。

    解决:以下步骤挨个测试

    (1)抬高编码频率

    (2)DDR定频 修改 rkbin/RKBOOT/RV1126MINIALL.ini 所有924改成1056

    (3)cpu定频 

            echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
            echo 1512000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed

    (4)提高cpu优先级

            io -4 0xfe830008 0x202

     (5)关闭温控

            echo user_space > /sys/class/thermal/thermal_zone0/policy
            echo 0 > /sys/class/thermal/thermal_zone0/cdev0/cur_state

            echo 0 > /sys/class/thermal/thermal_zone0/cdev0/cur_state

    3、解码常见问题

    1、在获取vdec的yuv数据时,将获取的数据直接写入到文件中,打开后会出现一部分绿色的情况

       解决:主要是写文件的方式有问题

    1. int width,height,h_stride,v_stride;
    2. RK_U8 *base_y;
    3. RK_U8 *base_c;
    4. while (!quit) {
    5. mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VDEC, 0, 500);
    6. if (!mb) {
    7. printf("RK_MPI_SYS_GetMediaBuffer get null buffer in 500ms...\n");
    8. return NULL;
    9. }
    10. sprintf(picname, "/userdata/rv1126_dec_%d", ccount++);
    11. vdec_file_save = fopen(picname, "w");
    12. base_y = RK_MPI_MB_GetPtr(mb);
    13. base_c = RK_MPI_MB_GetPtr(mb) + h_stride * v_stride;
    14. for (i = 0; i < height; i++, base_y += h_stride)
    15. {
    16. fwrite(base_y, 1, width, vdec_file_save);
    17. }
    18. for (i = 0; i < height / 2; i++, base_c += h_stride)
    19. {
    20. fwrite(base_c, 1, width, vdec_file_save);
    21. }
    22. fclose(vdec_file_save);
    23. memset(picname, 0 ,64);
    24. RK_MPI_MB_ReleaseBuffer(mb);
    25. }

    2、在使用vdec解码jpeg时,会导致缓存逐渐增大。

    解决:需要配置 /proc/mpp_service/vdpu/session_buffers 这个值,默认是40,可以将其改小

    3、解码时出现

    [ 669.352997] mpp_rkvdec2 fdf80200.rkvdec: resetting...

    [ 669.353460] mpp_rkvdec2 fdf80200.rkvdec: reset done 打印

    原因:mpp吧数据丢给硬件解码后设定了一个200ms的等待时间,如果超时硬件认为有异常,所以复位了。

    解决:增加延时时间( kernel/drivers/video/rockchip/mpp)

    暂时关于VENC/VENC部分写这么多,有新的建议后续加上来

     文章汇总:RKMEDIA使用简介_未_定的博客-CSDN博客

  • 相关阅读:
    2022年湖北省文化产业示范园(基地)发展专项资金申报条件以及奖励补贴情况!
    MVCC的执行原理
    第4章 决策树
    python 基础知识点(蓝桥杯python科目个人复习计划56)
    【左程云算法全讲11】贪心算法 & 并查集
    大数据学习技术栈及书籍推荐
    RN 事件穿透pointerEvents属性
    Oracle 创建和操作表
    VLC 21年,重新审视低延迟直播
    Python爬虫之续Urllib && Jsonpath库的使用
  • 原文地址:https://blog.csdn.net/qq_36769014/article/details/128128760