前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >音视频环形缓冲区 介绍与实现

音视频环形缓冲区 介绍与实现

作者头像
音视频开发进阶
发布2022-10-31 11:12:17
7510
发布2022-10-31 11:12:17
举报

一、什么是环形缓冲区

环形缓冲区(也称为循环缓冲区)是固定大小的缓冲区,工作原理就像内存是连续的且可循环的一样。在生成和使用内存时,不需将原来的数据全部重新清理掉,只要调整head/tail 指针即可。当添加数据时,head 指针前进。当使用数据时,tail 指针向前移动。当到达缓冲区的尾部时,指针又回到缓冲区的起始位置。

二、为什么使用环形缓冲区

环形缓冲区是嵌入式系统中十分重要的一种数据结构,比如在一个音视频处理的机制中,环形缓冲区就可以理解为数据码流的通道,每一个通道都对应着一个环形缓冲区,这样数据在读取和写入的时候都可以在这个缓冲区里循环进行,程序员可以根据自己需要的数据大小来决定自己使用的缓冲区大小。

环形缓冲区通常用作固定大小的队列。固定大小的队列对于嵌入式系统的开发非常友好,因为开发人员通常会尝试使用静态数据存储的方法而不是动态分配。

环形缓冲区对于数据写入和读出以不同速率发生的情况也是非常有用的结构:最新数据始终可用。如果读取数据的速度跟不上写入数据的速度,旧的数据将被新写入的数据覆盖。通过使用循环缓冲区,能够保证我们始终使用最新的数据。

三、代码实现

1. 环形缓存区结构体RING_BUFFER

代码语言:javascript
复制
typedef struct
{
    //缓存空间指针
    char*                           buffer;
    //缓存空间容量
    int                             size;
    //缓存读序号,范围:0 - (size -1)
    int                             rdIdx;
    //缓存写序号,范围:0 - (size -1)
    int                             wrIdx;
    //缓存满标志
    int                             isFull;
}RING_BUFFER;

2. 创建环形缓存区

代码语言:javascript
复制
void* ringBufferCreate(int size)
{
    RING_BUFFER*    rb;
    if(NULL == (rb = malloc(sizeof(RING_BUFFER) + size)))
    {
        printf("内存不足!\n");
        return NULL;
    }
    memset(rb, 0, sizeof(RING_BUFFER));
    rb->buffer = (char*)rb + sizeof(RING_BUFFER);
    rb->size = size;
    return (void*)rb;
}

3. 获取环形缓存区中有效数据大小

代码语言:javascript
复制
int ringBufferGetSize(RING_BUFFER* rb)
{
    if(rb->wrIdx == rb->rdIdx)
    {
        return 0;
    }
    if(rb->wrIdx > rb->rdIdx)
    {
        return (rb->wrIdx - rb->rdIdx);
    }
    return ((rb->size - rb->rdIdx) + rb->wrIdx);
}

4. 获取环形缓存区中空闲空间字节大小

代码语言:javascript
复制
int ringBufferFreeLen(RING_BUFFER* rb)
{
    return ((rb->size - 1) - __ringBufferGetSize(rb));
}

5. 写环形缓存区

代码语言:javascript
复制
int ringBufferWrite(void* handle, const char* ptr, int len)
{
    RING_BUFFER*    rb = (void*)handle;
    int          size;
    if(0 >= len)
    {
        printf("rb写参数[%lu]非法!\n", len);
        return 0;
    }
    //获取空闲空间大小
    size = ringBufferFreeLen(rb);
    if(size < len)
    {
        //空闲空间不足
        printf("rb写溢出!<%d, %d>\n", len, size);
        return 0;
    }
    //计算"写序号"后部还允许写入的数据字节数
    size = rb->size - rb->wrIdx;
    if(size >= len)
    {
        //当前待写入全部数据可一次写入后部
        memcpy(rb->buffer + rb->wrIdx, ptr, len);
        rb->wrIdx = (size > len) ? (rb->wrIdx + len) : 0;
        return len;
    }
    //先写一部分数据到后部
    memcpy(rb->buffer + rb->wrIdx, ptr, size);
    //再写剩余数据到前部
    memcpy(rb->buffer, ptr + size, len - size);
    rb->wrIdx = len - size;
    return len;
}

6. 读环形缓存区

代码语言:javascript
复制
int ringBufferRead(void* handle, char* ptr, int len)
{
    RING_BUFFER*    rb = (void*)handle;
    int         size;
    if(0 >= len)
    {
        printf("rb读参数[%lu]非法!\n", len);
        return 0;
    }
    //获取有效数据大小
    size = ringBufferGetSize(rb);
    if(0 == size)
    {
        return 0;//没有数据
    }
    if(0 != rb->isFull)
    {
        //之前已标记 缓存满,全清 缓存内容
        rb->rdIdx = rb->wrIdx;
        rb->isFull = 0;
        return 0;
    }
    if(size < len)
    {
        //有效数据不足,只能返回填充一部分
        len = size;
    }
    //计算"读序号"后部可读空间大小
    size = rb->size - rb->rdIdx;
    if(size >= len)
    {
        //当前待读出全部数据全存在于"读序号"后部
        memcpy(ptr, rb->buffer + rb->rdIdx, len);
        rb->rdIdx = (size > len) ? (rb->rdIdx + len) : 0;
        return len;
    }
    //先从"读序号"后部读出一部分数据
    memcpy(ptr, rb->buffer + rb->rdIdx, size);
    //再从前部读出剩余数据
    memcpy(ptr + size, rb->buffer, len - size);
    rb->rdIdx = len - size;
    return len;
}

7. 销毁环形缓存区

代码语言:javascript
复制
int ringBufferDestroy(void* handle)
{
    RING_BUFFER*    rb = (void*)handle;
    ctFree(rb);
    return 0;
}

来源:https://blog.csdn.net/u012478275/article/details/122101925

最后欢迎大家加入 音视频开发进阶 知识星球 ,这里有知识干货、编程答疑、开发教程,还有很多精彩分享。

更多内容可以在星球菜单中找到,随着时间推移,干货也会越来越多!!!

给出 10元 优惠券,涨价在即,目前还是白菜价,基本上提几个问题就回本,投资自己就是最好的投资!!!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-07-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 音视频开发进阶 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、什么是环形缓冲区
  • 二、为什么使用环形缓冲区
  • 三、代码实现
相关产品与服务
媒体处理
媒体处理(Media Processing Service,MPS)是一种云端音视频处理服务。基于腾讯多年音视频领域的深耕,为您提供极致的编码能力,大幅节约存储及带宽成本、实现全平台播放,同时提供视频截图、音视频增强、内容理解、内容审核等能力,满足您在各种场景下对视频的处理需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档