一种多媒体框架中的零buffer拷贝实现机制

BUFFER管理是多媒体框架设计实现中的核心任务,在常见的多媒体框架,比如FFMPEG,GST等中,BUFFER管理的代码实现都是复杂且代码量非常大的部分。从某种意义上说,多媒体应用的核心在于BUFFER管理,一个高效易用的BUFFER管理框架不但可以提供友好的开发模型,而且还可以最大限度的挖掘VPU的计算能力,提高多媒体应用的效率。

为什么可以通过零拷贝来优化多媒体框架?一个典型的多媒体解码架构如下图所示:

 数据路径可以理解成 下图所示:

如果我们按照数据的性质再进行细分,会发现这样一个现象,在数据传输的前半段,数据的存在的形态都是VBV 数据,也就是原始的编码数据,而在传输的后半段,数据变成了贞数据。

 既然是数据的性质相同,那么我们就可以用同一个BUFFER去管理他,不同的组建之间传递数据时,只需要传递这个BUFFER管理池的指针就好了,不用每次组件之间传递数据时,都进行内存拷贝。这种实现方式就是零拷贝。

那么,在GST或FFMPEG以及OMX上有没有实现零拷贝呢?很遗憾,零拷贝是和实现相关的,默认的GST,FFMPEG,以及OMX都没有实现支持零拷贝的底层机制。

OMX组件的非Tunnel模型:

 FFMPEG的工作模型:

GST仅仅是一套框架,具体的实现依赖于具体的插件。

一个基于msgget/msgsnd进程异步通信机制的零BUFFER拷贝实现:

根据零BUFFER拷贝的需求,本文设计了一种零Buffer拷贝的实现机制,原理如下:

 在生产者和消费者之间,建立起两条管道,一个管道名称为send pipe,用于传递VBV数据,另一个管道叫做return pipe,用于返回使用完毕的空的VBV buffer,这样,这样,生产者发送帧以及消费者消费帧之间,以及消费者还帧和生产者要空帧之间构成了逻辑循环的闭环,可以一直进行下去。的

 使用MSTBOX或者其他系统进程间通信机制,可以实现上图中的pipeline,如下图所示的代码实现:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <pthread.h>

//消息的数据结构
struct msg_st
{
    long int msg_type;
    char text[1024];
};

void *read_msg_server(void *param)
{
    int ret=-1;
    struct msg_st data;
    int msgid=-1, msgid1;
    int msgtype = 0;

    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
    if(msgid==-1)
    {
        perror("msgget create fail!");
        return NULL;
    }

    msgid1 = msgget((key_t)4321, 0666 | IPC_CREAT);
    if(msgid1==-1)
    {
        perror("msgget create fail!");
        return NULL;
    }

    while(1)
    {
        //从队列中获取消息,直到遇到quit为止
        ret=msgrcv(msgid,(void*)&data,1024,msgtype,0);
        if(ret==-1)
        {
            perror("msgrcv fail");
            break;
        }
        
        printf("%s line %d, msg receive:%s\n", __func__, __LINE__, data.text);
        
        data.msg_type=1;
        strcpy(data.text,"return");
        
        //向队列发送数据
        ret=msgsnd(msgid1,(void*)&data, 1024, 0);
        if(ret==-1)
        {
            perror("msgsnd fail!");
            break;
        }
    }

    return NULL;
}

void *write_msg_server(void *param)
{
    int ret=-1;
    struct msg_st data;
    int msgid=-1, msgid1;
    int msgtype = 0;

    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
    if(msgid==-1)
    {
        perror("msgget create fail!");
        return NULL;
    }

    msgid1 = msgget((key_t)4321, 0666 | IPC_CREAT);
    if(msgid1==-1)
    {
        perror("msgget create fail!");
        return NULL;
    }

    while(1)
    {
        data.msg_type=1;
        strcpy(data.text,"send");
        
        //向队列发送数据
        ret=msgsnd(msgid,(void*)&data, 1024, 0);
        if(ret==-1)
        {
            perror("msgsnd fail!");
            break;
        }

        sleep(1);

        ret=msgrcv(msgid1,(void*)&data,1024,msgtype,0);
        if(ret==-1)
        {
            perror("msgrcv fail");
            break;
        }

        printf("%s line %d msg receive:%s\n", __func__, __LINE__, data.text);
    }

    return NULL;
}

int main()
{
    int ret;
    int msgid=-1;
    long int msgtype = 0;     //接收为0,发送为1
    pthread_t pthread_read;
    pthread_t pthread_write;
    
    //建立消息队列
    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
    if(msgid==-1)
    {
        perror("msgget create fail!");
        return -1;
    }

    int err = pthread_create(&pthread_read, NULL, read_msg_server, &msgid);
    if(err != 0)
    {
        perror("create pthread failure.");
        return -1;
    }

    err = pthread_create(&pthread_write, NULL, write_msg_server, &msgid);
    if(err != 0)
    {
        perror("create pthread failure.");
        return -1;
    }

    pthread_join(pthread_write, NULL);
    pthread_join(pthread_read, NULL);
    
    //删除消息队列
    ret=msgctl(msgid,IPC_RMID,0);
    if(ret==-1)
    {
        perror("msgctl delete fail!");
        return -1;
    }
    
    return 0;
}

运行结果:

对两个管道进行一次封装,封装为一个pipeline对象

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <pthread.h>

//消息的数据结构
struct msg_st
{
    long int msg_type;
    char text[1024];
};

typedef struct _pipeline_
{
    int msgid_pro;
    int msgid_con;
}pipeline_t;

void skt_create(pipeline_t *skt)
{
    skt->msgid_pro = msgget((key_t)1234, 0666 | IPC_CREAT);
    if(skt->msgid_pro ==-1)
    {
        perror("msgget create fail!");
        return;
    }

    skt->msgid_con = msgget((key_t)4321, 0666 | IPC_CREAT);
    
  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值