1.RV1126中GOP模式的分类
在RV1126中GOP模式,一般分为三大类,分别是普通GOP模式、智能SMARTP的GOP模式、TSVC的GOP模式。这三种不同的GOP模式,分别对应不同的视频场景。下面我们来一一介绍这三种GOP模式的特点。
1.普通GOP模式
普通GOP模式是最常见的GOP模式,它的特点就是两个I帧间隔固定的GOPSIZE,而GOPSIZE里面都是P帧或者B帧。比方说上图,GOPSIZE=5,相当于每隔5个P帧或者B帧插入一个I帧;普通的GOP模式通常适用于普通场景,比方说视频场景比较单一,没有那种运动画面、静止画面频繁切换的场景。
2.智能编码SMARTP的GOP模式
在SMART的GOP模式下,会分成两种I帧,一种是普通的I帧、另外一种是虚拟I帧。普通的I帧主要是检测画面的静止区域,当检测到视频里面有静止画面的时候,编码器会利用长参考帧大幅度降低码率,静止画面降低码率能够有效防止画面的呼吸效应出现。
而在运动区域,则利用短参考帧进行运动估计,并插入Virtual I帧(虚拟I帧就是SMARTP)。在插入虚拟I帧的时候,可以最大拉长I帧间隔让它其提高在运动场景下的码率能够得到足够的提高,画面质量能够得到很好的改善;SMARTP模式常使用在静止画面和运动画面经常切换的场景,尤其是体育赛事。
3.多层时域参考模型
多层时域指的是编码层可以划分为多个层级,RV1126提供了RK_MPI_MB_GetTsvcLevel获取层数,并通过层数来定制码流。举个例子,TSVC技术可以将一个普通的H264码流分割成不同的帧率、分辨率和视频质量的层数。一般而言,TSVC技术会根据目前的编码的网络情况把视频码流分割成一个基础层和多个视频增强层,基础层为开发者提供最基本的视频质量、帧率和分辨率。基础层可以作为一个独立的层进行解码,而增强层的信息则依赖于基础层进行解码;总体来说,解码端接受的增强层数量越大,解码的视频质量就会越好。TSVC模式主要运用在网络环境不好的情况,如弱网环境、或者移动场景下比较多。
2.RV1126中设置GOP模式的结构体和API:
1.RV1126的GOP属性结构体
上图就是RV1126设置GOP属性的结构体,下面我们来分别介绍它的成员变量:
1.enGopMode:
编码GOP类型的设置,RV1126中分别提供了三种GOP类型的设置,分别是:VENC_GOPMODE_NORMALP(普通GOP模式)VENC_GOPMODE_SMARTP(智能SMARTP模式)、VENC_GOPMODE_TSVC(多层时域参考模型)
2. u32GopSize:编码GOP的长度大小,在普通的GOP模式下这个值就是I帧关键帧间隔。在SMARTP模式下,它是短期参考帧的间隔。
3. s32IPQpDelta:I帧相对于P帧的差值,这个值主要是调节I帧过大或者呼吸效应的场景,默认值为6, 取值范围是[-10, 30]
4. u32BgInterval:长期参考帧的间隔, 主要运用在SMARTP模式下, 普通GOP模式不起作用。一般而言,长参考帧是短参考帧的整数倍。
5. s32ViQpDelta:虚拟I帧相对于P帧的差值,这个值主要是调节虚拟I帧过大默认值为6,这个值主要使用在SMARTP模式下调节运动画面的场景,取值范围是[-10, 30]。
2.RV1126设置GOP属性的API
上面这个就是设置VENC GOP模式的API:
第一个传参数:VeChn编码通道号
第二个传参数:VENC_GOP_ATTR_S结构体指针
3.代码
同时获取SMARTP模式的VENC码流数据和普通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码流数据并保存。
#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 "include/rkmedia/rkmedia_api.h" #define CAMERA_PATH "rkispp_scale0" #define PIPE_TD 0 #define VI_CHN 0 #define COMMON_GOP_CHN 0 #define SMART_GOP_CHN 1 void *get_common_gop_thread(void*args) { pthread_detach(pthread_self()); FILE* common_gop_file = fopen("test_common_gop.h264","w+"); MEDIA_BUFFER mb; while (1) { mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC,COMMON_GOP_CHN,-1); if(!mb) { printf("COMMON GOP RK_MPI_SYS_GetMediaBuffer Failed\n"); break; } printf("COMMON GOP RK_MPI_SYS_GetMediaBuffer Success\n"); fwrite(RK_MPI_MB_GetPtr(mb),RK_MPI_MB_GetSize(mb),1,common_gop_file); RK_MPI_MB_ReleaseBuffer(mb); } return NULL; } void *get_smart_gop_thread(void*args) { pthread_detach(pthread_self()); FILE* smart_gop_file = fopen("test_smart_gop.h264","w+"); MEDIA_BUFFER mb; while (1) { mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC,SMART_GOP_CHN,-1); if(!mb) { printf("SMART GOP RK_MPI_SYS_GetMediaBuffer Failed\n"); break; } printf("SMART GOP RK_MPI_SYS_GetMediaBuffer Success\n"); fwrite(RK_MPI_MB_GetPtr(mb),RK_MPI_MB_GetSize(mb),1,smart_gop_file); RK_MPI_MB_ReleaseBuffer(mb); } return NULL; } int main() { int ret; RK_MPI_SYS_Init(); VI_CHN_ATTR_S vi_chn_attr; vi_chn_attr.pcVideoNode = CAMERA_PATH; vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12; vi_chn_attr.u32Width = 1920; vi_chn_attr.u32Height = 1080; vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP; vi_chn_attr.u32BufCnt = 3; vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL; ret = RK_MPI_VI_SetChnAttr(PIPE_TD,VI_CHN,&vi_chn_attr); if(ret) { printf("RK_MPI_VI_SetChnAttr Failed\n"); return 0; } else { printf("RK_MPI_VI_SetChnAttr Success\n"); } ret = RK_MPI_VI_EnableChn(PIPE_TD,VI_CHN); if(ret) { printf("RK_MPI_VI_EnableChn Failed\n"); return 0; } else { printf("RK_MPI_VI_EnableChn Success\n"); } VENC_CHN_ATTR_S commom_venc_chn_attr; commom_venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264; commom_venc_chn_attr.stVencAttr.bByFrame = RK_FALSE; commom_venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12; commom_venc_chn_attr.stVencAttr.enRotation = VENC_ROTATION_0; commom_venc_chn_attr.stVencAttr.u32PicWidth = 1920; commom_venc_chn_attr.stVencAttr.u32PicHeight = 1080; commom_venc_chn_attr.stVencAttr.u32Profile = 66; commom_venc_chn_attr.stVencAttr.u32VirWidth = 1920; commom_venc_chn_attr.stVencAttr.u32VirHeight = 1080; commom_venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR; commom_venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25; commom_venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1; commom_venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25; commom_venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1; commom_venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608; commom_venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 25; ret = RK_MPI_VENC_CreateChn(COMMON_GOP_CHN,&commom_venc_chn_attr); if(ret) { printf("COMMON RK_MPI_VENC_CreateChn Failed\n"); return 0; } else { printf("COMMON RK_MPI_VENC_CreateChn Success\n"); } VENC_CHN_ATTR_S smart_gop_chn_attr; smart_gop_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264; smart_gop_chn_attr.stVencAttr.bByFrame = RK_FALSE; smart_gop_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12; smart_gop_chn_attr.stVencAttr.enRotation = VENC_ROTATION_0; smart_gop_chn_attr.stVencAttr.u32PicWidth = 1920; smart_gop_chn_attr.stVencAttr.u32PicHeight = 1080; smart_gop_chn_attr.stVencAttr.u32Profile = 66; smart_gop_chn_attr.stVencAttr.u32VirWidth = 1920; smart_gop_chn_attr.stVencAttr.u32VirHeight = 1080; smart_gop_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR; smart_gop_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25; smart_gop_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1; smart_gop_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25; smart_gop_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1; smart_gop_chn_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608; smart_gop_chn_attr.stRcAttr.stH264Cbr.u32Gop = 25; ret = RK_MPI_VENC_CreateChn(SMART_GOP_CHN,&smart_gop_chn_attr); if(ret) { printf("SMART GOP RK_MPI_VENC_CreateChn Failed\n"); return 0; } else { printf("SMART GOOP RK_MPI_VENC_CreateChn Success\n"); } rkVENC_GOP_ATTR_S smart_gop_attr; smart_gop_attr.enGopMode = VENC_GOPMODE_SMARTP; smart_gop_attr.u32GopSize = 25; smart_gop_attr.u32BgInterval = 25*5; smart_gop_attr.s32IPQpDelta = 6; smart_gop_attr.s32ViQpDelta = 6; RK_MPI_VENC_SetGopMode(SMART_GOP_CHN,&smart_gop_attr); MPP_CHN_S vi_chn_s; vi_chn_s.enModId = RK_ID_VI; vi_chn_s.s32ChnId = VI_CHN; MPP_CHN_S common_gop_chn_s; common_gop_chn_s.enModId = RK_ID_VENC; common_gop_chn_s.s32ChnId = COMMON_GOP_CHN; MPP_CHN_S smart_gop_chn_s; smart_gop_chn_s.enModId = RK_ID_VENC; smart_gop_chn_s.s32ChnId = SMART_GOP_CHN; ret = RK_MPI_SYS_Bind(&vi_chn_s,&common_gop_chn_s); if(ret) { printf("VI BIND COMMON GOP Failed\n"); return 0; } else { printf("VI BIND COMMON GOP Success\n"); } ret = RK_MPI_SYS_Bind(&vi_chn_s,&smart_gop_chn_s); if(ret) { printf("VI BIND SMART GOP Failed\n"); return 0; } else { printf("VI BIND SMART GOP Success\n"); } pthread_t common_pid,smart_pid; pthread_create(&common_pid,NULL,get_common_gop_thread,NULL); pthread_create(&smart_pid,NULL,get_smart_gop_thread,NULL); while(1) { sleep(2); } RK_MPI_SYS_UnBind(&vi_chn_s,&common_gop_chn_s); RK_MPI_SYS_UnBind(&vi_chn_s,&smart_gop_chn_s); RK_MPI_VENC_DestroyChn(COMMON_GOP_CHN); RK_MPI_VENC_DestroyChn(SMART_GOP_CHN); RK_MPI_VI_DisableChn(PIPE_TD,VI_CHN); return 0; }