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類能開發出一套更簡潔的緩衝緩衝代碼,只要注意邏輯實現不出問題即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章