在開發過程當中常常會遇到須要使用環形緩衝的地方,好比在流媒體方面,對於接收到的音視頻數據的存儲、以及音頻解碼後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; }
使用該緩衝區時,初始化一塊大小合適的內存,並在外部進行加鎖,同時須要讀寫操做保持基本一致,便可;若是用戶設置的緩衝區太小,或者讀寫速率差距較大,則會形成用戶數據的丟失。ide
以上代碼使用純C寫的,固然也能夠使用C++進行編寫,寫一個類,藉助string類能開發出一套更簡潔的緩衝緩衝代碼,只要注意邏輯實現不出問題便可。
ui