通过多线程同时获取H264和H265码流

目录

一.RV1126 VI采集摄像头数据并同时编码H264、H265的大概流程​编辑​编辑

1.1初始化VI模块:

1.2H264、H265的VENC模块初始化:

1.3VI分别绑定H264的VENC层和H265的VENC层:

​​​​​​​1.4开启H264线程采集H264的VENC数据:

​​​​​​​1.5开启H265线程采集H265的VENC数据:

二.代码实战:


一.RV1126 VI采集摄像头数据并同时编码H264、H265的大概流程

RV1126利用多线程同时获取H264文件、H265文件的过程一般分为上图的7步骤,分别是:VI模块的初始化、H264的VENC模块初始化、H265的VENC模块初始化、VI绑定H264的VENC模块、VI绑定H265的VENC模块,开启H264线程获取H264码流并保存、开启H265线程获取H265码流并保存。

​​​​​​​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.2H264、H265的VENC模块初始化:

VENC_CHN_ATTR_S  h264_venc_chn_attr;

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

RK_MPI_VENC_CreateChn(H264_VENC_CHN, &h264_venc_chn_attr);

VENC_CHN_ATTR_S  h265_venc_chn_attr;

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

RK_MPI_VENC_CreateChn(H265_VENC_CHN, &h265_venc_chn_attr);

注意:这里需要创建两个编码器层,分别是H264编码器和H265编码器。

​​​​​​​1.3VI分别绑定H264的VENC层和H265的VENC层:

VI节点分别绑定H264的VENC节点和H265节点,伪代码如下:

//VI模块节点的设置

MPP_CHN_S vi_chn_s;

vi_chn_s.enModId = RK_ID_VI;

vi_chn_s.s32ChnId = 0;

//H264的VENC模块节点设置

MPP_CHN_S h264_venc_chn_s;

h264_venc_chn_s.enModId = RK_ID_VENC;

h264_venc_chn_s.s32ChnId = H264_VENC_CHN;

ret = RK_MPI_SYS_Bind(&vi_chn_s, &h264_venc_chn_s);

//H265的VENC模块节点设置

MPP_CHN_S h265_venc_chn_s;

h265_venc_chn_s.enModId = RK_ID_VENC;

h265_venc_chn_s.s32ChnId = H265_VENC_CHN;

ret = RK_MPI_SYS_Bind(&vi_chn_s, &h265_venc_chn_s);

​​​​​​​1.4开启H264线程采集H264的VENC数据:

开启一个线程去采集每一帧H264的VENC模块数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是H264 VENC创建的ID号这个API伪代码如下

while(1)

{

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

  mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, H264_VENC_CHN, -1);

  fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, h264_file);

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

}

​​​​​​​1.5开启H265线程采集H265的VENC数据:

开启一个线程去采集每一帧H265的VENC模块数据,使用的API是RK_MPI_SYS_GetMediaBuffer, 模块ID是RK_ID_VENC,通道号ID是H265 VENC创建的ID号这个API伪代码如下

while(1)

{

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

  mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, H265_VENC_CHN, -1);

  fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, h265_file);

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

}

二.代码实战:

#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 CAMERA_PATH "rkispp_scale0"
#define CAMERA_ID 0
#define CAMERA_CHN 0
#define H264_VENC_CHN 0
#define H265_VENC_CHN 1

//创建线程获取H264码流数据并保存
void * get_h264_stream_thread(void * args)
{
    pthread_detach(pthread_self());
    FILE * h264_file = fopen("test_camera.h264", "w+");
    MEDIA_BUFFER mb ;

    while (1)
    {
        //获取每一帧H264编码码流
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, H264_VENC_CHN, -1);
        if(!mb)
        {
            printf("Get H264_Venc Buffer break....\n");
            break;
        }

        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, h264_file);
        RK_MPI_MB_ReleaseBuffer(mb);
    }
    
    return NULL;
}

//创建线程获取H265码流数据并保存
void * get_h265_stream_thread(void * args)
{
    pthread_detach(pthread_self());
    FILE * h265_file = fopen("test_camera.h265", "w+");
    MEDIA_BUFFER mb ;

    while (1)
    {
        //获取每一帧H265编码码流
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, H265_VENC_CHN , -1);
        if(!mb)
        {
            printf("Get H265_VENC Buffer break...\n");
            break;
        }

        fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, h265_file);
        RK_MPI_MB_ReleaseBuffer(mb);
    }

    return NULL;
}

int main(int argc, char *argv[])
{
    int ret;
    VI_CHN_ATTR_S vi_chn_attr;
    vi_chn_attr.pcVideoNode = CAMERA_PATH; //设置视频设备节点路径
    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(CAMERA_ID, CAMERA_CHN, &vi_chn_attr);
    if(ret)
    {
        printf("Vi Set Attr Failed.....\n");
        return 0;
    }
    else
    {
        printf("Vi Set Attr Success.....\n");
    }

    ret = RK_MPI_VI_EnableChn(CAMERA_ID, CAMERA_CHN);
    if(ret)
    {
        printf("Vi Enable Attr Failed.....\n");
        return 0;
    }
    else
    {
        printf("Vi Enable Attr Success.....\n");
    }

    VENC_CHN_ATTR_S h264_venc_chn_attr;
    //******   H264  设置VENC基础属性   ************************//
    h264_venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264; //设置编码器类型
    h264_venc_chn_attr.stVencAttr.u32PicWidth = 1920;//设置编码分辨率宽度
    h264_venc_chn_attr.stVencAttr.u32PicHeight = 1080;//设置编码分辨率高度
    h264_venc_chn_attr.stVencAttr.u32VirWidth = 1920;//设置编码分辨率虚宽
    h264_venc_chn_attr.stVencAttr.u32VirHeight = 1080;//设置编码分辨率虚高
    h264_venc_chn_attr.stVencAttr.u32Profile = 66;//设置编码等级
    h264_venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型
    h264_venc_chn_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度

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

    VENC_CHN_ATTR_S h265_venc_chn_attr;
    //******   H265  设置VENC基础属性   ************************//
    h265_venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H265;//设置编码器类型
    h265_venc_chn_attr.stVencAttr.u32PicWidth = 1920;//设置编码分辨率宽度
    h265_venc_chn_attr.stVencAttr.u32PicHeight = 1080;//设置编码分辨率高度
    h265_venc_chn_attr.stVencAttr.u32VirWidth = 1920;//设置编码分辨率虚宽
    h265_venc_chn_attr.stVencAttr.u32VirHeight = 1080;//设置编码分辨率虚高
    h265_venc_chn_attr.stVencAttr.u32Profile = 77;//设置编码等级
    h265_venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_NV12;//设置编码图像类型
    h265_venc_chn_attr.stVencAttr.enRotation = VENC_ROTATION_0;//设置编码的旋转角度
    //********* H265 VENC RCMODE Set  *******************//
    h265_venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H265CBR;//设置H265的CBR码率控制模式
    h265_venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 25;//设置GOP关键帧间隔
    //25/1 NUM/DEN == FrameRate
    h265_venc_chn_attr.stRcAttr.stH265Cbr.u32SrcFrameRateDen = 1; //设置源帧率分母
    h265_venc_chn_attr.stRcAttr.stH265Cbr.u32SrcFrameRateNum = 25;//设置源帧率分子
    h265_venc_chn_attr.stRcAttr.stH265Cbr.fr32DstFrameRateDen = 1;//设置目标帧率分母
    h265_venc_chn_attr.stRcAttr.stH265Cbr.fr32DstFrameRateNum = 25;//设置目标帧率分子
    h265_venc_chn_attr.stRcAttr.stH265Cbr.u32BitRate = 8388608; //设置码率大小
    ret = RK_MPI_VENC_CreateChn(H265_VENC_CHN, &h265_venc_chn_attr);
    if(ret)
    {
        printf("Create H265 Venc Failed .....\n");
        return 0;
    }
    else
    {
        printf("Create H265 Venc Success .....\n");
    }

    //VI_CHN
    MPP_CHN_S vi_chn_s;
    vi_chn_s.enModId = RK_ID_VI;
    vi_chn_s.s32ChnId = CAMERA_CHN;

    //H264_VENC_CHN
    MPP_CHN_S h264_chn_s;
    h264_chn_s.enModId = RK_ID_VENC;
    h264_chn_s.s32ChnId = H264_VENC_CHN;

    //H265_VENC_CHN
    MPP_CHN_S h265_chn_s;
    h265_chn_s.enModId = RK_ID_VENC;
    h265_chn_s.s32ChnId = H265_VENC_CHN;


    //VI Bind H264_VENC
    ret = RK_MPI_SYS_Bind(&vi_chn_s, &h264_chn_s);
    if(ret)
    {
        printf("Vi Bind H264_Venc Failed .....\n");
    }
    else
    {
        printf("Vi Bind H264_Venc Success .....\n");
    }


    //VI Bind H265_VENC
    ret = RK_MPI_SYS_Bind(&vi_chn_s, &h265_chn_s);
    if(ret)
    {
        printf("Vi Bind H265_Venc Failed .....\n");
    }
    else
    {
        printf("Vi Bind H265_Venc Success .....\n");
    }

    pthread_t h264_pid, h265_pid;

    pthread_create(&h264_pid, NULL, get_h264_stream_thread, NULL);//创建线程获取H264码流数据并保存
    pthread_create(&h265_pid, NULL, get_h265_stream_thread, NULL);//创建线程获取H265码流数据并保存

    while (1)
    {
        sleep(1);
    }

    RK_MPI_SYS_UnBind(&vi_chn_s, &h264_chn_s);
    RK_MPI_SYS_UnBind(&vi_chn_s, &h265_chn_s);
    RK_MPI_VI_DisableChn(0, 0);
    RK_MPI_VENC_DestroyChn(0);
    RK_MPI_VENC_DestroyChn(1);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/982065.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot为什么要禁止循环依赖?

大家好&#xff0c;我是锋哥。今天分享关于【SpringBoot为什么要禁止循环依赖?】面试题。希望对大家有帮助&#xff1b; SpringBoot为什么要禁止循环依赖? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring Boot 和 Spring 框架之所以要避免循环依赖&#xf…

The Rust Programming Language 学习 (三)

所有权 所有权&#xff08;系统&#xff09;是 Rust 最为与众不同的特性&#xff0c;它让 Rust 无需垃圾回收器&#xff08;garbage collector&#xff09;即可保证内存安全。因此&#xff0c;理解 Rust 中所有权的运作方式非常重要。 这里是非常重非常重的一个知识点,这里一…

基于物联网技术的电动车防盗系统设计(论文+源码)

1总体设计 本课题为基于物联网技术的电动车防盗系统&#xff0c;在此将整个系统架构设计如图2.1所示&#xff0c;其采用STM32F103单片机为控制器&#xff0c;通过NEO-6M实现GPS定位功能&#xff0c;通过红外传感器检测电瓶是否离开位&#xff0c;通过Air202 NBIOT模块将当前的数…

雷池WAF的为什么选择基于Docker

Docker 是一种开源的容器化平台&#xff0c;可以帮助开发人员将应用程序及其所有依赖项打包到一个称为容器的独立、可移植的环境中。Docker 的核心概念包括以下几点&#xff1a; 容器&#xff1a;Docker 使用容器来封装应用程序及其依赖项&#xff0c;使其能够在任何环境中都能…

解决docker认证问题 failed to authorize: failed to fetch oauth token

报错信息[bash1]解决方案 全局代理打开“buildkit”: false &#xff0c;见[图1] [bash1] >docker build -t ffpg . [] Building 71.8s (3/3) FINISHED docker:desktop-linux> [internal] load bui…

LINUX网络基础 [一] - 初识网络,理解网络协议

目录 前言 一. 计算机网络背景 1.1 发展历程 1.1.1 独立模式 1.1.2 网络互联 1.1.3 局域网LAN 1.1.4 广域网WAN 1.2 总结 二. "协议" 2.1 什么是协议 2.2 网络协议的理解 2.3 网络协议的分层结构 三. OSI七层模型&#xff08;理论标准&#xff09; …

【Docker】容器安全之非root用户运行

【Docker】容器安全之非root用户运行 1. 场景2. 原 Dockerfile 内容3. 整改结果4. 非 root 用户带来的潜在问题4.1 文件夹读写权限异常4.2 验证文件夹权限 1. 场景 最近有个项目要交付&#xff0c;第三方测试对项目源码扫描后发现一个问题&#xff0c;服务的 Dockerfile 都未指…

亚马逊云科技Marketplace(中国区)上架专业服务产品, “云生态连接器”价值凸显

近日&#xff0c;由西云数据运营的亚马逊云科技Marketplace&#xff08;中国区&#xff09;正式支持专业服务产品。此次发布将大幅简化企业对云专业服务的采购流程&#xff0c;实现云软件从规划、部署到支持的全生命周期管理&#xff0c;同时也为合作伙伴提供了更多的销售机会。…

鸿蒙启动页开发

鸿蒙启动页开发 1.1 更改应用名称和图标 1.更改应用图标 找到moudle.json5文件&#xff0c;找到应用启动的EntryAbility下面的icon,将原来的图标改成自己设置的即可 2.更改应用名称 3.效果展示 2.1 广告页面开发 3.1 详细介绍 3.1.1 启动页面 import { PrivacyDialog } fr…

HCIA—IP路由静态

一、概念及作用 1、概念&#xff1a;IP路由是指在IP网络中&#xff0c;数据从源节点到目的节点所经过的路径选择和数据转发的过程。 2、作用 ①实现网络互联&#xff1a;使不同网段的设备能够相互通信&#xff0c;构建大规模的互联网络 ②优化网络拓扑&#xff1a;根据网络…

【计算机网络入门】初学计算机网络(十一)重要

目录 1. CIDR无分类编址 1.1 CIDR的子网划分 1.1.1 定长子网划分 1.1.2 变长子网划分 2. 路由聚合 2.1 最长前缀匹配原则 3. 网络地址转换NAT 3.1 端口号 3.2 IP地址不够用&#xff1f; 3.3 公网IP和内网IP 3.4 NAT作用 4. ARP协议 4.1 如何利用IP地址找到MAC地址…

机器视觉开发教程——封装Halcon通用模板匹配工具【含免费教程源码】

目录 引言前期准备Step1 设计可序列化的输入输出集合【不支持多线程】Step2 设计程序框架1、抽象层【IProcess】2、父类【HAlgorithm】3、子类【HFindModelTool】 Step3 设计UI结果展示 引言 通过仿照VisionPro软件二次开发Halcon的模板匹配工具&#xff0c;便于在客户端软件中…

【Linux跬步积累】—— 线程池详解(有源代码)

文章目录 一、如何实现一个线程1、基本结构2、实现成员函数3、演示4、代码总汇Thread.hppMain.cc 二、如何封装线程池1、设计成员变量2、构造函数与析构函数3、初始化4、启动与回收5、主线程放入任务6、子线程读取任务7、终止线程池 三、测试四、线程池总代码1、ThreadPool.hpp…

【Linux】自定协议和序列化与反序列化

目录 一、序列化与反序列化概念 二、自定协议实现一个加法网络计算器 &#xff08;一&#xff09;TCP如何保证接收方的接收到数据是完整性呢&#xff1f; &#xff08;二&#xff09;自定义协议 &#xff08;三&#xff09;自定义协议的实现 1、基础类 2、序列化与反序列…

hive之LEAD 函数详解

1. 函数概述 LEAD 是 Hive 中的窗口函数&#xff0c;用于获取当前行之后指定偏移量处的行的值。常用于分析时间序列数据、计算相邻记录的差异或预测趋势。 2. 语法 LEAD(column, offset, default) OVER ([PARTITION BY partition_column] [ORDER BY order_column [ASC|DESC]…

ZYNQ-PL学习实践(二)按键和定时器控制LED闪烁灯

ZYNQ-PL学习实践&#xff08;二&#xff09;按键和定时器控制LED闪烁灯&#xff09; 1 创建工程2 verilog 代码3 约束4 综合5 生成bit总结 1 创建工程 2 verilog 代码 添加key_led.v 文件&#xff0c; module key_led(input sys_clk , //系统时钟50MHzinput …

【Python爬虫】利用代理IP爬取跨境电商AI选品分析

引言 随着DeepSeek的流行&#xff0c;越来越多的用户开始尝试将AI工具融入到日常工作当中&#xff0c;借助AI的强大功能提高工作效率。最近又掀起了一波企业出海的小高潮&#xff0c;那么如果是做跨境电商业务&#xff0c;怎么将AI融入工作流中呢&#xff1f;在做跨境电商的时候…

设计一个SVF下载器之一:整体思路

CPLD或者FPGA开发工具会生成SVF文件用以通过JTAG口配置CPLD或者FPGA。这里有些基本控制JTAG状态机的指令&#xff0c;其实就是主要两条SIR和SDR分别实现对IR寄存器和DR寄存器的写。 这样我们的这个下载器的基本工作变成了解析SVF文件之后对JTAG的TAP状态机进行操作实现对IR和D…

计算机视觉算法实战——图像配准(主页有源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​ 1. 领域简介 图像配准&#xff08;Image Registration&#xff09;是计算机视觉中的一个重要研究方向&#xff0c;旨在将两幅或多幅…

ArcGIS操作:07 绘制矢量shp面

1、点击目录 2、右侧显示目录 3、选择要存储的文件夹&#xff0c;新建shp 4、定义名称、要素类型、坐标系 5、点击开始编辑 6、点击创建要素 7、右侧选择图层、创建面 8、开始绘制&#xff0c;双击任意位置结束绘制