通过多线程分别获取高分辨率和低分辨率的H264码流

打印 上一主题 下一主题

主题 823|帖子 823|积分 2469

目录
一.RV1126 VI收罗摄像头数据并同时获取高分辨率码流和低分辨率码流流程
​编辑
1.1初始化VI模块:
1.2初始化RGA模块:
1.3初始化高分辨率VENC编码器、 低分辨率VENC编码器:
1.4 VI绑定高分辨率VENC编码器,VI绑定RGA模块,伪代码如下:
1.5 创建多线程获取高分辨率编码数据:
1.6 创建多线程获取低分辨率数据并传输到编码器:
1.7.创建多线程获取低分辨率编码数据:
三.运行的结果:



一.RV1126 VI收罗摄像头数据并同时获取高分辨率码流和低分辨率码流流程



RV1126使用多线程同时获取高分辨率编码文件、低分辨率编码文件,一样平常要分为上图8个步骤:VI模块初始化RGA图像模块初始化、高分辨率编码器的初始化、低分辨率编码器的初始化、VI绑定高分辨率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初始化RGA模块:

RGA重要的作用是缩放VI模块的分辨率,比方说:VI模块的分辨率1920 * 1080,经过RGA缩放后分辨率为1280 * 720,并使用RK_MPI_RGA_CreateChn创建RGA模块,伪代码如下:
RGA_ATTR_S rga_attr;
rga_attr.stImgIn.u32Width = 1920;
rga_attr.stImgIn.u32Height = 1080;
。。。。。。。。。
rga_attr.stImgOut.u32Width = 1280;
rga_attr.stImgOut.u32Height = 720;
。。。。。。。。。。。
RK_MPI_RGA_CreateChn(RGA_CHN_ID, &rga_attr);
这段代码的焦点是输入图像(输入分辨率是原分辨率和VI模块同等)和输出分辨率(输出分辨率是自己设置的分辨率)的设置。比方说输入的分辨率是 : 1920*1080,那stImgIn.u32Width = 1920 、stImgIn.u32Height = 1080,输出图像成:1280 * 720,stImgOut.u32Width = 1280、stImgOut.u32Height = 720。

1.3初始化高分辨率VENC编码器、 低分辨率VENC编码器:

高分辨率编码器的初始化
VENC_CHN_ATTR_S high_venc_chn_attr;
high_venc_chn_attr.stVencAttr.u32PicWidth = 1920;
high_venc_chn_attr.stVencAttr.u32PicHeight = 1080;
high_venc_chn_attr.stVencAttr.u32VirWidth = 1920;
high_venc_chn_attr.stVencAttr.u32VirHeight = 1080;
................................
RK_MPI_VENC_CreateChn(HIGH_VENC_CHN, &high_venc_chn_attr);

低分辨率编码器的初始化
VENC_CHN_ATTR_S low_venc_chn_attr;
low_venc_chn_attr.stVencAttr.u32PicWidth = 1280;
low_venc_chn_attr.stVencAttr.u32PicHeight = 720;
low_venc_chn_attr.stVencAttr.u32VirWidth = 1280;
low_venc_chn_attr.stVencAttr.u32VirHeight = 720;
................................
RK_MPI_VENC_CreateChn(HIGH_VENC_CHN, &low_venc_chn_attr);
高分辨率和低分辨率最焦点的设置就是分辨率的设置,高分辨率u32PicWidth = 1920、u32PicHeight = 1920,低分辨率u32PicWidth = 1280、u32PicHeight = 720

1.4 VI绑定高分辨率VENC编码器,VI绑定RGA模块,伪代码如下:


//VI模块绑定RGA模块
MPP_CHN_S vi_chn_s;
vi_chn_s.enModId = RK_ID_VI;
vi_chn_s.s32ChnId = CAMERA_CHN;

MPP_CHN_S rga_chn_s;
rga_chn_s.enModId = RK_ID_RGA;
rga_chn_s.s32ChnId = RGA_CHN_ID;
RK_MPI_SYS_Bind(&vi_chn_s, &rga_chn_s);

//VI模块绑定高分辨率VENC模块
MPP_CHN_S high_venc_chn_s;
high_venc_chn_s_s.enModId = RK_ID_VENC;
high_venc_chn_s_s.s32ChnId = HIGH_VENC_ID;
RK_MPI_SYS_Bind(&vi_chn_s, &high_venc_chn_s);

1.5 创建多线程获取高分辨率编码数据:

开启一个线程去收罗每一帧高分辨率的VENC模块数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是高分辨率VENC创建的ID号:
while(1)
{
  .........................
  mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, HIGH_VENC_ID, -1);
  fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1,high_venc_id);
.......................
}

1.6 创建多线程获取低分辨率数据并传输到编码器:

开启一个线程去收罗每一帧RGA低分辨率的数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_RGA,通道号ID是RGA的通道ID,收罗完每一帧RGA数据则使用RK_MPI_SYS_SendMediaBuffer传输到低分辨率编码器这个API伪代码如下
while (1)
{
.........................................
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, 0, -1);
    RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, LOW_VENC_ID, mb);
................................
}
下面我们来看看RK_MPI_SYS_SendMediaBuffer的具体实现
RK_S32 RK_MPI_SYS_SendMediaBuffer(MOD_ID_E enModID, RK_S32 s32ChnID, MEDIA_BUFFER buffer);

enModID:开发者需要传输的目标模块的ID号,比方说VI模块的数据传输到VENC模块,那么目标模块就是VENC,ID号就是RK_ID_VENC;比方说VI模块的数据传输到RGA模块,那么目标模块就是RGA,ID号就是RK_ID_RGA。
s32ChnID:目标模块的通道号
buffer:缓冲区数据MediaBuffer

1.7.创建多线程获取低分辨率编码数据:

开启一个线程去收罗每一帧低分辨率的编码数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是低分辨率VENC创建的ID号这个API伪代码如下
while (1)
{
.........................................
mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, LOW_VENC_ID, -1);
fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, low_venc_file);
................................
}

二.代码实战
  1. #include <assert.h>
  2. #include <fcntl.h>
  3. #include <getopt.h>
  4. #include <pthread.h>
  5. #include <signal.h>
  6. #include <stdbool.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <time.h>
  10. #include <unistd.h>
  11. // #include "common/sample_common.h"
  12. #include "rkmedia_api.h"
  13. #define PIPE_ID 0
  14. #define VI_CHN_ID 0
  15. #define RGA_CHN_ID 0
  16. #define HIGH_VENC_CHN 0
  17. #define LOW_VENC_CHN 1
  18. //创建多线程获取高分辨率的编码码流
  19. void *get_high_venc_thread(void *args)
  20. {
  21.     pthread_detach(pthread_self());
  22.     FILE *high_venc_file = fopen("test_high_venc.h264", "w+");
  23.     MEDIA_BUFFER mb;
  24.     while (1)
  25.     {
  26.         //获取每一帧高分辨率编码码流数据
  27.         mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, HIGH_VENC_CHN, -1);
  28.         if (!mb)
  29.         {
  30.             printf("Get High Venc break.....\n");
  31.         }
  32.         printf("Get High Venc Success.....\n");
  33.         fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, high_venc_file);
  34.         RK_MPI_MB_ReleaseBuffer(mb);
  35.     }
  36.     return NULL;
  37. }
  38. //创建多线程获取RGA码流并发送到低分辨率编码器
  39. void *rga_handle_thread(void *args)
  40. {
  41.     pthread_detach(pthread_self());
  42.     MEDIA_BUFFER mb;
  43.     while (1)
  44.     {
  45.          //获取每一帧RGA码流数据
  46.         mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, RGA_CHN_ID, -1);
  47.         if (!mb)
  48.         {
  49.             printf("Get RGA break.....\n");
  50.         }
  51.         printf("Get RGA Success.....\n");
  52.         //发送每一帧RGA数据到低分辨率编码器
  53.         RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, LOW_VENC_CHN, mb);
  54.         RK_MPI_MB_ReleaseBuffer(mb);
  55.     }
  56.     return NULL;
  57. }
  58. //创建多线程获取低分辨率编码码流
  59. void *get_low_venc_thread(void *args)
  60. {
  61.     pthread_detach(pthread_self());
  62.     MEDIA_BUFFER mb;
  63.     FILE * low_venc_file = fopen("test_low_venc.h264", "w+");
  64.     while (1)
  65.     {
  66.         //获取每一帧低分辨率编码码流
  67.         mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, LOW_VENC_CHN, -1);
  68.         if (!mb)
  69.         {
  70.             printf("Get LOW VENC break.....\n");
  71.         }
  72.         printf("Get LOW VENC Success.....\n");
  73.         fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, low_venc_file);
  74.         RK_MPI_MB_ReleaseBuffer(mb);
  75.     }
  76.     return NULL;
  77. }
  78. int main(int argc, char *argv[])
  79. {
  80.     int ret;
  81.     RK_MPI_SYS_Init();
  82.     // VI Init......
  83.     VI_CHN_ATTR_S vi_chn_attr;
  84.     vi_chn_attr.pcVideoNode = "rkispp_scale0";//设置视频设备节点路径
  85.     vi_chn_attr.u32Width = 1920;//设置分辨率的宽度
  86.     vi_chn_attr.u32Height = 1080;//设置分辨率的高度
  87.     vi_chn_attr.enPixFmt = IMAGE_TYPE_NV12;//设置图像类型
  88.     vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;//设置VI获取类型
  89.     vi_chn_attr.u32BufCnt = 3;//设置缓冲数量
  90.     vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;//设置VI工作类型
  91.     ret = RK_MPI_VI_SetChnAttr(PIPE_ID, VI_CHN_ID, &vi_chn_attr);
  92.     if (ret)
  93.     {
  94.         printf("VI_CHN_ATTR Set Failed.....\n");
  95.         return -1;
  96.     }
  97.     else
  98.     {
  99.         printf("VI_CHN_ATTR Set Success.....\n");
  100.     }
  101.     ret = RK_MPI_VI_EnableChn(PIPE_ID, VI_CHN_ID);
  102.     if (ret)
  103.     {
  104.         printf("VI_CHN_ATTR Enable Failed.....\n");
  105.         return -1;
  106.     }
  107.     else
  108.     {
  109.         printf("VI_CHN_ATTR Enable Success.....\n");
  110.     }
  111.     // RGA
  112.     RGA_ATTR_S rga_info;
  113.     /**Image Input ..............*/
  114.     rga_info.stImgIn.u32Width = 1920;//设置RGA输入分辨率宽度
  115.     rga_info.stImgIn.u32Height = 1080;//设置RGA输入分辨率高度
  116.     rga_info.stImgIn.u32HorStride = 1920;//设置RGA输入分辨率虚宽
  117.     rga_info.stImgIn.u32VirStride = 1080;//设置RGA输入分辨率虚高
  118.     rga_info.stImgIn.imgType = IMAGE_TYPE_NV12;//设置ImageType图像类型
  119.     rga_info.stImgIn.u32X = 0;//设置X坐标
  120.     rga_info.stImgIn.u32Y = 0;//设置Y坐标
  121.     /**Image Output......................*/
  122.     rga_info.stImgOut.u32Width = 1280;//设置RGA输出分辨率宽度
  123.     rga_info.stImgOut.u32Height = 720;//设置RGA输出分辨率高度
  124.     rga_info.stImgOut.u32HorStride = 1280;//设置RGA输出分辨率虚宽
  125.     rga_info.stImgOut.u32VirStride = 720;//设置RGA输出分辨率虚高
  126.     rga_info.stImgOut.imgType = IMAGE_TYPE_NV12;//设置输出ImageType图像类型
  127.     rga_info.stImgOut.u32X = 0;//设置X坐标
  128.     rga_info.stImgOut.u32Y = 0;//设置Y坐标
  129.     // RGA Public Parameter
  130.     rga_info.u16BufPoolCnt = 3;//缓冲池计数
  131.     rga_info.u16Rotaion = 0;//
  132.     rga_info.enFlip = RGA_FLIP_H;//水平翻转
  133.     rga_info.bEnBufPool = RK_TRUE;
  134.     ret = RK_MPI_RGA_CreateChn(RGA_CHN_ID, &rga_info);
  135.     if (ret)
  136.     {
  137.         printf("RGA Set Failed.....\n");
  138.     }
  139.     else
  140.     {
  141.         printf("RGA Set Success.....\n");
  142.     }
  143.     // High Venc Parameter
  144.     VENC_CHN_ATTR_S high_venc_attr;
  145.     high_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;//设置编码器类型
  146.     high_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型
  147.     high_venc_attr.stVencAttr.u32PicWidth = 1920;//设置编码分辨率宽度
  148.     high_venc_attr.stVencAttr.u32PicHeight = 1080;//设置编码分辨率高度
  149.     high_venc_attr.stVencAttr.u32VirWidth = 1920;//设置编码分辨率虚宽
  150.     high_venc_attr.stVencAttr.u32VirHeight = 1080;//设置编码分辨率虚高
  151.     high_venc_attr.stVencAttr.u32Profile = 66;//设置编码等级
  152.     high_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度
  153.     //********* 设置码率控制属性  *******************//
  154.     high_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;//设置H264的CBR码率控制模式
  155.     high_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔
  156.     high_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子
  157.     high_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;//设置源帧率分母
  158.     high_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子
  159.     high_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母
  160.     high_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;//设置码率大小
  161.     ret = RK_MPI_VENC_CreateChn(HIGH_VENC_CHN, &high_venc_attr);
  162.     if (ret)
  163.     {
  164.         printf("Set High Venc Attr Failed.....\n");
  165.     }
  166.     else
  167.     {
  168.         printf("Set High Venc Attr Success.....\n");
  169.     }
  170.     // Low Venc Parameter
  171.     VENC_CHN_ATTR_S low_venc_attr;
  172.     low_venc_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;//设置编码器类型
  173.     low_venc_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型
  174.     low_venc_attr.stVencAttr.u32PicWidth = 1280;//设置编码分辨率宽度
  175.     low_venc_attr.stVencAttr.u32PicHeight = 720;//设置编码分辨率高度
  176.     low_venc_attr.stVencAttr.u32VirWidth = 1280;//设置编码分辨率虚宽
  177.     low_venc_attr.stVencAttr.u32VirHeight = 720;//设置编码分辨率虚高
  178.     low_venc_attr.stVencAttr.u32Profile = 66;//设置编码等级
  179.     low_venc_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度
  180.      //********* 设置码率控制属性  *******************//
  181.     low_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;//设置H264的CBR码率控制模式
  182.     low_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔
  183.     low_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子
  184.     low_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;//设置源帧率分母
  185.     low_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子
  186.     low_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母
  187.     low_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;//设置码率大小
  188.     ret = RK_MPI_VENC_CreateChn(LOW_VENC_CHN, &low_venc_attr);
  189.     if (ret)
  190.     {
  191.         printf("Set Low Venc Attr Failed.....\n");
  192.     }
  193.     else
  194.     {
  195.         printf("Set Low Venc Attr Success.....\n");
  196.     }
  197.     MPP_CHN_S vi_chn_s;
  198.     vi_chn_s.enModId = RK_ID_VI;
  199.     vi_chn_s.s32ChnId = VI_CHN_ID;
  200.     MPP_CHN_S high_chn_s;
  201.     high_chn_s.enModId = RK_ID_VENC;
  202.     high_chn_s.s32ChnId = HIGH_VENC_CHN;
  203.     //VI绑定高分辨率VENC模块
  204.     ret = RK_MPI_SYS_Bind(&vi_chn_s, &high_chn_s);
  205.     if (ret)
  206.     {
  207.         printf("VI Bind High Venc Failed.....\n");
  208.         return -1;
  209.     }
  210.     else
  211.     {
  212.         printf("VI Bind High Venc Success.....\n");
  213.     }
  214.     MPP_CHN_S rga_chn_s;
  215.     rga_chn_s.enModId = RK_ID_RGA;
  216.     rga_chn_s.s32ChnId = RGA_CHN_ID;
  217.     //VI绑定RGA模块
  218.     ret = RK_MPI_SYS_Bind(&vi_chn_s, &rga_chn_s);
  219.     if (ret)
  220.     {
  221.         printf("VI Bind RGA Failed.....\n");
  222.         return -1;
  223.     }
  224.     else
  225.     {
  226.         printf("VI Bind RGA Success.....\n");
  227.     }
  228.     pthread_t high_venc_pid;
  229.     pthread_t rga_pid;
  230.     pthread_t low_venc_pid;
  231.     pthread_create(&high_venc_pid, NULL, get_high_venc_thread, NULL); //创建多线程获取高分辨率的编码码流 
  232.     pthread_create(&rga_pid, NULL, rga_handle_thread, NULL);//创建多线程获取RGA码流并发送到低分辨率编码器
  233.     pthread_create(&low_venc_pid, NULL, get_low_venc_thread, NULL);//创建多线程获取低分辨率编码码流
  234.     while (1)
  235.     {
  236.         sleep(1);
  237.     }
  238.     RK_MPI_SYS_UnBind(&vi_chn_s, &high_chn_s);
  239.     RK_MPI_SYS_UnBind(&vi_chn_s, &rga_chn_s);
  240.     RK_MPI_RGA_DestroyChn(RGA_CHN_ID);
  241.     RK_MPI_VENC_DestroyChn(HIGH_VENC_CHN);
  242.     RK_MPI_VENC_DestroyChn(LOW_VENC_CHN);
  243.     RK_MPI_VI_DisableChn(PIPE_ID, VI_CHN_ID);
  244.     return 0;
  245. }
复制代码

三.运行的结果:

分别用ffplay播放器分别播出高分辨率H264文件(test_high_venc.h264),低分辨率(test_rga_venc.h264)
ffplay test_high_venc.h264
ffplay test_rga_venc.h264


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张国伟

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表