C/C++实现环形缓冲

    在开发过程中经常会遇到需要使用环形缓冲的地方,比如在流媒体方面,对于接收到的音视频数据的存储、以及音频解码后PCM数据的存储等问题上,最好使用一个环形缓冲,接收到,或者解码后压入该缓冲区中,在需要解码,或者需要塞入声卡时,再从该缓冲区中读取,这样压入和取出同一个缓冲区,既方便快捷,又安全有效。源码如下:

typedef char s8;
typedef unsigned char u8;
typedef short s16;
typedef unsigned short u16;
typedef int s32;
typedef unsigned int u32;
typedef unsigned   uint32_t;

typedef void *FIFOBUFFERHANDLE;    //定义一个指针,方便外部引用

#ifndef _max
#define _max(a, b) a > b ? a : b
#endif

#ifndef _min
#define _min(a, b) a > b ? b : a
#endif

//定义一个结构体,用于记录该缓冲区的开始、读取、写入、接收的内存地址
typedef struct _TFIFOBUFFER
{
    u8 *pu8Buffer, *pu8Read, *pu8Write, *pu8End;
}TFIFOBUFFER, *PTFIFOBUFFER;

//创建一个指定大小的缓冲区
FIFOBUFFERHANDLE FifoBufferCreate(s32 s32Size)
{
    PTFIFOBUFFER ptFifoBuffer = NULL;
    do
    {
        ptFifoBuffer = (PTFIFOBUFFER)malloc(sizeof(TFIFOBUFFER));
        if(NULL == ptFifoBuffer)
        {
            break;
        }
        memset(ptFifoBuffer, 0, sizeof(TFIFOBUFFER));
        ptFifoBuffer->pu8Buffer = (u8 *)malloc(s32Size);
        if(NULL == ptFifoBuffer->pu8Buffer)
        {
            break;
        }
        memset(ptFifoBuffer->pu8Buffer, 0, s32Size);
        ptFifoBuffer->pu8Write = ptFifoBuffer->pu8Read = ptFifoBuffer->pu8Buffer;
        ptFifoBuffer->pu8End = ptFifoBuffer->pu8Buffer + s32Size;
        if(NULL == ptFifoBuffer->pu8Buffer)
        {
            break;
        }
        return (FIFOBUFFERHANDLE)ptFifoBuffer;
    }while(false);
    if(NULL != ptFifoBuffer)
    {
        if(NULL != ptFifoBuffer->pu8Buffer)
        {
            free(ptFifoBuffer->pu8Buffer);
            ptFifoBuffer->pu8Buffer = NULL;
        }
        free(ptFifoBuffer);
        ptFifoBuffer = NULL;
    }
    return NULL;
}

//释放一个缓冲区
void FifoBufferDestroy(FIFOBUFFERHANDLE pHandle)
{
    PTFIFOBUFFER ptFifoBuffer = (PTFIFOBUFFER)pHandle;
    if(NULL != ptFifoBuffer)
    {
        if(NULL != ptFifoBuffer->pu8Buffer)
        {
            free(ptFifoBuffer->pu8Buffer);
            ptFifoBuffer->pu8Buffer = NULL;
        }
        free(ptFifoBuffer);
        ptFifoBuffer = NULL;
    }
}

//重置缓冲区中读写指针
void FifoBufferReset(FIFOBUFFERHANDLE pHandle)
{
    PTFIFOBUFFER ptFifoBuffer = (PTFIFOBUFFER)pHandle;
    if(NULL != ptFifoBuffer)
    {
        ptFifoBuffer->pu8Write = ptFifoBuffer->pu8Read = ptFifoBuffer->pu8Buffer;
    }
}

//获取大小
int FifoBufferSize(FIFOBUFFERHANDLE pHandle)
{
    s32 s32Size = 0;
    PTFIFOBUFFER ptFifoBuffer = (PTFIFOBUFFER)pHandle;
    if(NULL != ptFifoBuffer)
    {
        s32Size = ptFifoBuffer->pu8Write - ptFifoBuffer->pu8Read;
        if(s32Size < 0)
        {
            s32Size += ptFifoBuffer->pu8End - ptFifoBuffer->pu8Buffer;
        }
    }
    return s32Size;
}

//向缓冲区中写入数据
s32 FifoBufferWrite(FIFOBUFFERHANDLE pHandle, u8 *pu8Buffer, s32 s32Size)
{
    s32 s32Length = 0;
    PTFIFOBUFFER ptFifoBuffer = (PTFIFOBUFFER)pHandle;
    if(NULL == ptFifoBuffer)
    {
        return 0;
    }
    do
    {
        s32Length = _min(ptFifoBuffer->pu8End - ptFifoBuffer->pu8Write, s32Size);
        memcpy(ptFifoBuffer->pu8Write, pu8Buffer, s32Length);
        pu8Buffer = pu8Buffer + s32Length;
        ptFifoBuffer->pu8Write += s32Length;  //向后偏移写指针
        
        //如果缓冲区写指针到达了缓冲区尾部,则将写指针移动到缓冲区开始地址,实现真正的环         //形缓冲
        if(ptFifoBuffer->pu8Write >= ptFifoBuffer->pu8End)
        {
            ptFifoBuffer->pu8Write = ptFifoBuffer->pu8Buffer;
        }
        s32Size -= s32Length;
    }while(s32Size > 0);
    return 1;
}

//读数据
s32 FifoBufferRead(FIFOBUFFERHANDLE pHandle, u8 *pu8Buffer, s32 *ps32Size)
{
    s32 s32Length = 0, pTempSize = (*ps32Size);
    PTFIFOBUFFER ptFifoBuffer = (PTFIFOBUFFER)pHandle;
    if(NULL == ptFifoBuffer || NULL == pu8Buffer || 0 > pTempSize)
    {
        return 0;
    }
    if(0 == pTempSize)
    {
        (*ps32Size) = 0;
        return 1;
    }
    (*ps32Size) = 0;
    do
    {
        s32Length = _min(FifoBufferSize(pHandle), pTempSize);
        s32Length = _min(ptFifoBuffer->pu8End - ptFifoBuffer->pu8Read, s32Length);
        if(0 == s32Length)
        {
            break;
        }
        memcpy(pu8Buffer, ptFifoBuffer->pu8Read, s32Length);
        pu8Buffer = pu8Buffer + s32Length;
        ptFifoBuffer->pu8Read = ptFifoBuffer->pu8Read + s32Length;//向后偏移读指针
        
        //如果缓冲区读指针到达了缓冲区尾部,则将读指针移动到缓冲区开始地址,实现真正的环         //形缓冲
        if(ptFifoBuffer->pu8Read >= ptFifoBuffer->pu8End)
        {
            ptFifoBuffer->pu8Read = ptFifoBuffer->pu8Buffer;
        }
        pTempSize -= s32Length;
        (*ps32Size) += s32Length;
    }while(pTempSize > 0);
    return 1;
}

s32 FifoBufferShade(FIFOBUFFERHANDLE pHandle, s32 s32Offset)
{
    PTFIFOBUFFER ptFifoBuffer = (PTFIFOBUFFER)pHandle;
    if(NULL != ptFifoBuffer)
    {
        if((ptFifoBuffer->pu8Read + s32Offset) > ptFifoBuffer->pu8End)
        {
            return *(ptFifoBuffer->pu8Buffer + (s32Offset - (ptFifoBuffer->pu8End - ptFifoBuffer->pu8Read)));
        }
        else
        {
            return *(ptFifoBuffer->pu8Read + s32Offset);
        }
    }
    return 0;
}

    使用该缓冲区时,初始化一块大小合适的内存,并在外部进行加锁,同时需要读写操作保持基本一致,即可;如果用户设置的缓冲区过小,或者读写速率差距较大,则会造成用户数据的丢失。

    以上代码使用纯C写的,当然也可以使用C++进行编写,写一个类,借助string类能开发出一套更简洁的缓冲缓冲代码,只要注意逻辑实现不出问题即可。

本文出自 “大师兄” 博客,请务必保留此出处http://cto521.blog.51cto.com/9652841/1585962

转载于:https://my.oschina.net/superfather/blog/780222

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值