LINUX学习之通过多线程分别获取两个不同分辨率的码流数据

目录

一。前置知识

1.1 VENC 知识

1.2 RGA知识

1.3 RK_MPI_SYS_SendMediaBuffer函数

二。程序框架

三。编码实战

3.1 VI,RGA,两个VENC(HIGH和LOW)初始化配置

3.2 模块绑定

3.3 pthread_t 建立多线程分别处理

3.4 编译

3.5结果


一。前置知识

1.1 VENC 知识

https://blog.youkuaiyun.com/ALIANG2000/article/details/154291390?spm=1011.2124.3001.6209https://blog.youkuaiyun.com/ALIANG2000/article/details/154291390?spm=1011.2124.3001.6209

1.2 RGA知识

https://blog.youkuaiyun.com/ALIANG2000/article/details/154291390?spm=1011.2124.3001.6209https://blog.youkuaiyun.com/ALIANG2000/article/details/154291390?spm=1011.2124.3001.6209

1.3 RK_MPI_SYS_SendMediaBuffer函数

RK_S32 RK_MPI_SYS_SendMediaBuffer(MOD_ID_E enModID, RK_S32 s32ChnID, MEDIA_BUFFER buffer);

1.3.1函数概述:

用于在不同的模块通道 之间传递多媒体数据(即 MEDIA_BUFFER),实现 MPP 内部数据流的“手动”连接,允许开发者将数据从一个处理单元发送到另一个处理单元。

1.3.2参数详解

  1. enModID: 目标模块标识符
    常用模块:RK_ID_VI(视频输入)、RK_ID_VPSS(视频处理)、RK_ID_VENC(视频编码)、RK_ID_RGA(图形处理)

  2. s32ChnID: 目标模块的通道号,从0开始

  3. buffer: 多媒体数据缓冲区句柄,可来自其他模块或应用程序创建

返回值

  • 类型: RK_S32 (有符号32位整数)

  • 含义: 函数执行状态。

    • 成功: 返回 RK_SUCCESS (通常值为0)。

    • 失败: 返回一个错误码(非0值),用于指示失败的原因。例如:

      • RK_ERR_SYS_NOTREADY: 系统未初始化。

      • RK_ERR_SYS_NOT_PERM: 操作不允许(如格式不匹配)。

      • RK_ERR_SYS_TIMEOUT: 操作超时(目标模块的输入缓冲区已满)

1.3.3 重要注意事项

  1. 绑定关系: 在发送数据之前,必须确保目标模块和通道已经创建并初始化成功。通常需要在系统初始化(RK_MPI_SYS_Init)之后,分别对各个模块进行初始化。

  2. 数据格式匹配: 发送的 MEDIA_BUFFER 的数据格式(如图像宽度、高度、像素格式)必须与目标通道所期望的输入格式兼容,否则发送会失败。

  3. 缓冲区管理:MEDIA_BUFFER 被成功发送后,你不应该再继续使用或修改这个缓冲区,因为它已经交由目标模块管理。目标模块处理完毕后,通常会通过相应的 Get 函数返回一个新的 MEDIA_BUFFER 句柄,或者释放该缓冲区。

  4. 阻塞与非阻塞: 这个函数通常是阻塞的。如果目标模块的输入缓冲区已满,函数会等待直到有空间可以写入或超时。超时时间可以在创建通道时进行配置。

  5. 与 Bind 的区别: MPP 还提供了 RK_MPI_SYS_Bind 函数,可以自动将两个模块连接起来,数据会自动流动,无需手动 SendSendMediaBuffer 提供了更灵活的控制,适用于 Bind 无法满足的复杂场景或需要应用程序介入处理的场景

二。程序框架

使用VENC对视频进行码流处理,支持不同分辨率的编码,但是VI输出原始分辨率为1920*1080,不能直接通过设置VENC的分辨率进行降分辨率。需要通过RGA进行处理,将分辨率降低,在用过VENC编码输出。

三。编码实战

3.1 VI,RGA,两个VENC(HIGH和LOW)初始化配置

3.2 模块绑定

主要是两个:

VI直接绑定到HIGH_VENC,因为二者的分辨率一致都是1920*1080

    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 bind the high-resolution VENC module **/
    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");
    }

VI与RGA绑定,将1920*1080通过RGA进行分辨率处理程序1280*720,。

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

 /**vi bind the RGA module **/
    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");
    }

3.3 pthread_t 建立多线程分别处理

    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(&high_venc_pid, NULL, rga_handle_thread, NULL);//创建多线程获取RGA码流并发送到低分辨率编码器
    pthread_create(&high_venc_pid, NULL, get_low_venc_thread, NULL);//创建多线程获取低分辨率编码码流
//创建多线程获取高分辨率的编码码流
void *get_high_venc_thread(void * args)
{
    pthread_detach(pthread_self());
    /*
     pthread_detach(pthread_self());
    作用:
    将调用此代码的线程设置为分离状态(detached state)
    分离状态的线程在结束时会自动释放资源,不需要其他线程调用 pthread_join() 来回收
    */
    FILE * high_venc_file = fopen("test_high_venc_20251118.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");
            break;

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



void *rga_handle_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;
    while(1)
    {
        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);
    }

}



void *get_low_venc_thread(void * args)
{
    pthread_detach(pthread_self());
    /*
     pthread_detach(pthread_self());
    作用:
    将调用此代码的线程设置为分离状态(detached state)
    分离状态的线程在结束时会自动释放资源,不需要其他线程调用 pthread_join() 来回收
    */
    FILE * low_venc_file = fopen("test_low_venc_20251118.h264","w+");
    MEDIA_BUFFER mb;

    while(1)
    {
        
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC,LOW_VENC_CHN,-1);
        if(!mb)
        {
            printf(" Get LOW Venc break .....\n");
            break;

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

需要注意的是:低分辨率的数据是通过RGA获取,然后再传递给VENC进行编码处理,需要用到

        RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC,LOW_VENC_CHN,mb);

功能:用于在不同的模块通道 之间传递多媒体数据

实现不同线程之间信息传递

3.4 编译

第一次编译:

问题:VENC 缓冲区溢出问题,存储buffer数据没有及时提取走

VENC的获取缓冲数据失败,错误状态为0编码

错误分析:

  • Mode[AENC]:Chn[0] in status[0]:音频编码通道 0 状态为 0(未就绪)

  • this operation is not allowed!:不允许执行获取缓冲区操作

  • 通道 0 和通道 1 都出现相同问题

问题定位:

模块ID拼写错误:应该为RK_ID_VENC才是视频的数据,而我使用了RK_ID_AENC为音频模块数据

第二次编译:

3.5结果

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值