目录

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

目录

[一.RV1126 VI采集摄像头数据并同时获取高分辨率码流和低分辨率码流流程](#一.RV1126 VI采集摄像头数据并同时获取高分辨率码流和低分辨率码流流程)

​编辑

1.1初始化VI模块:

1.2初始化RGA模块:

[1.3初始化高分辨率VENC编码器、 低分辨率VENC编码器:](#1.3初始化高分辨率VENC编码器、 低分辨率VENC编码器:)

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

[1.5 创建多线程获取高分辨率编码数据:](#1.5 创建多线程获取高分辨率编码数据:)

[1.6 创建多线程获取低分辨率数据并传输到编码器:](#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_Get Size(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_Get Size(mb), 1, low_venc_file );

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

}

二.代码实战

cpp 复制代码
#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 RGA_CHN_ID 0

#define HIGH_VENC_CHN 0
#define LOW_VENC_CHN 1

//创建多线程获取高分辨率的编码码流
void *get_high_venc_thread(void *args)
{
    pthread_detach(pthread_self());
    FILE *high_venc_file = fopen("test_high_venc.h264", "w+");
    MEDIA_BUFFER mb;

    while (1)
    {
        //获取每一帧高分辨率编码码流数据
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, HIGH_VENC_CHN, -1);
        if (!mb)
        {
            printf("Get High Venc break.....\n");
        }

        printf("Get High Venc Success.....\n");
        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, high_venc_file);
        RK_MPI_MB_ReleaseBuffer(mb);
    }

    return NULL;
}

//创建多线程获取RGA码流并发送到低分辨率编码器
void *rga_handle_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;

    while (1)
    {
         //获取每一帧RGA码流数据
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, RGA_CHN_ID, -1);
        if (!mb)
        {
            printf("Get RGA break.....\n");
        }

        printf("Get RGA Success.....\n");
        //发送每一帧RGA数据到低分辨率编码器
        RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, LOW_VENC_CHN, mb);
        RK_MPI_MB_ReleaseBuffer(mb);
    }

    return NULL;
}

//创建多线程获取低分辨率编码码流
void *get_low_venc_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;
    FILE * low_venc_file = fopen("test_low_venc.h264", "w+");

    while (1)
    {
        //获取每一帧低分辨率编码码流
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, LOW_VENC_CHN, -1);
        if (!mb)
        {
            printf("Get LOW VENC break.....\n");
        }

        printf("Get LOW VENC Success.....\n");
        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, low_venc_file);
        RK_MPI_MB_ReleaseBuffer(mb);
    }

    return NULL;
}

int main(int argc, char *argv[])
{

    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");
    }

    // RGA
    RGA_ATTR_S rga_info;
    /**Image Input ..............*/
    rga_info.stImgIn.u32Width = 1920;//设置RGA输入分辨率宽度
    rga_info.stImgIn.u32Height = 1080;//设置RGA输入分辨率高度
    rga_info.stImgIn.u32HorStride = 1920;//设置RGA输入分辨率虚宽
    rga_info.stImgIn.u32VirStride = 1080;//设置RGA输入分辨率虚高
    rga_info.stImgIn.imgType = IMAGE_TYPE_NV12;//设置ImageType图像类型
    rga_info.stImgIn.u32X = 0;//设置X坐标
    rga_info.stImgIn.u32Y = 0;//设置Y坐标

    /**Image Output......................*/
    rga_info.stImgOut.u32Width = 1280;//设置RGA输出分辨率宽度
    rga_info.stImgOut.u32Height = 720;//设置RGA输出分辨率高度
    rga_info.stImgOut.u32HorStride = 1280;//设置RGA输出分辨率虚宽
    rga_info.stImgOut.u32VirStride = 720;//设置RGA输出分辨率虚高
    rga_info.stImgOut.imgType = IMAGE_TYPE_NV12;//设置输出ImageType图像类型
    rga_info.stImgOut.u32X = 0;//设置X坐标
    rga_info.stImgOut.u32Y = 0;//设置Y坐标

    // RGA Public Parameter
    rga_info.u16BufPoolCnt = 3;//缓冲池计数
    rga_info.u16Rotaion = 0;//
    rga_info.enFlip = RGA_FLIP_H;//水平翻转
    rga_info.bEnBufPool = RK_TRUE;
    ret = RK_MPI_RGA_CreateChn(RGA_CHN_ID, &rga_info);
    if (ret)
    {
        printf("RGA Set Failed.....\n");
    }
    else
    {
        printf("RGA Set Success.....\n");
    }

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

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

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

     //********* 设置码率控制属性  *******************//
    low_venc_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;//设置H264的CBR码率控制模式
    low_venc_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔
    low_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子
    low_venc_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;//设置源帧率分母
    low_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子
    low_venc_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母
    low_venc_attr.stRcAttr.stH264Cbr.u32BitRate = 8388608;//设置码率大小
    ret = RK_MPI_VENC_CreateChn(LOW_VENC_CHN, &low_venc_attr);
    if (ret)
    {
        printf("Set Low Venc Attr Failed.....\n");
    }
    else
    {
        printf("Set Low Venc Attr 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 high_chn_s;
    high_chn_s.enModId = RK_ID_VENC;
    high_chn_s.s32ChnId = HIGH_VENC_CHN;

    //VI绑定高分辨率VENC模块
    ret = RK_MPI_SYS_Bind(&vi_chn_s, &high_chn_s);
    if (ret)
    {
        printf("VI Bind High Venc Failed.....\n");
        return -1;
    }
    else
    {
        printf("VI Bind High Venc Success.....\n");
    }

    MPP_CHN_S rga_chn_s;
    rga_chn_s.enModId = RK_ID_RGA;
    rga_chn_s.s32ChnId = RGA_CHN_ID;

    //VI绑定RGA模块
    ret = RK_MPI_SYS_Bind(&vi_chn_s, &rga_chn_s);
    if (ret)
    {
        printf("VI Bind RGA Failed.....\n");
        return -1;
    }
    else
    {
        printf("VI Bind RGA Success.....\n");
    }

    pthread_t high_venc_pid;
    pthread_t rga_pid;
    pthread_t low_venc_pid;

    pthread_create(&high_venc_pid, NULL, get_high_venc_thread, NULL); //创建多线程获取高分辨率的编码码流 
    pthread_create(&rga_pid, NULL, rga_handle_thread, NULL);//创建多线程获取RGA码流并发送到低分辨率编码器
    pthread_create(&low_venc_pid, NULL, get_low_venc_thread, NULL);//创建多线程获取低分辨率编码码流

    while (1)
    {
        sleep(1);
    }

    RK_MPI_SYS_UnBind(&vi_chn_s, &high_chn_s);
    RK_MPI_SYS_UnBind(&vi_chn_s, &rga_chn_s);
    RK_MPI_RGA_DestroyChn(RGA_CHN_ID);
    RK_MPI_VENC_DestroyChn(HIGH_VENC_CHN);
    RK_MPI_VENC_DestroyChn(LOW_VENC_CHN);
    RK_MPI_VI_DisableChn(PIPE_ID, VI_CHN_ID);

    return 0;
}

三.运行的效果:

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

ffplay test_high_venc.h264

ffplay test_rga_venc.h264

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
潘yi.4 分钟前
Shell编程之条件语句
linux·运维·服务器·网络
AI服务老曹38 分钟前
成为一种国家战略范畴的新基建的智慧园区开源了
运维·人工智能·学习·开源·能源
昂子的博客43 分钟前
热门面试题第15天|最大二叉树 合并二叉树 验证二叉搜索树 二叉搜索树中的搜索
java·数据结构·算法
林政硕(Cohen0415)1 小时前
RK3568 基于Gstreamer的多媒体调试记录
linux·rk3568·多媒体·gstreamer
ん贤1 小时前
蓝桥杯考前复盘
c语言·c++·算法·职场和发展·蓝桥杯
想成为配环境大佬1 小时前
P8697 [蓝桥杯 2019 国 C] 最长子序列
算法·蓝桥杯·双指针
陈奕迅本讯2 小时前
操作系统 4.4-从生磁盘到文件
linux·运维·服务器
麦麦Max2 小时前
STL-函数对象
开发语言·c++·算法
落笔画忧愁e2 小时前
BGP路由协议
运维·服务器
DeepLink2 小时前
🧠 AI论文精读 :《Attention is All You Need》
人工智能·算法