音視頻環(huán)形緩沖區(qū) 介紹與實(shí)現(xiàn)
一、什么是環(huán)形緩沖區(qū)
環(huán)形緩沖區(qū)(也稱為循環(huán)緩沖區(qū))是固定大小的緩沖區(qū),工作原理就像內(nèi)存是連續(xù)的且可循環(huán)的一樣。在生成和使用內(nèi)存時(shí),不需將原來(lái)的數(shù)據(jù)全部重新清理掉,只要調(diào)整head/tail 指針即可。當(dāng)添加數(shù)據(jù)時(shí),head 指針前進(jìn)。當(dāng)使用數(shù)據(jù)時(shí),tail 指針向前移動(dòng)。當(dāng)?shù)竭_(dá)緩沖區(qū)的尾部時(shí),指針又回到緩沖區(qū)的起始位置。

二、為什么使用環(huán)形緩沖區(qū)
環(huán)形緩沖區(qū)是嵌入式系統(tǒng)中十分重要的一種數(shù)據(jù)結(jié)構(gòu),比如在一個(gè)音視頻處理的機(jī)制中,環(huán)形緩沖區(qū)就可以理解為數(shù)據(jù)碼流的通道,每一個(gè)通道都對(duì)應(yīng)著一個(gè)環(huán)形緩沖區(qū),這樣數(shù)據(jù)在讀取和寫入的時(shí)候都可以在這個(gè)緩沖區(qū)里循環(huán)進(jìn)行,程序員可以根據(jù)自己需要的數(shù)據(jù)大小來(lái)決定自己使用的緩沖區(qū)大小。
環(huán)形緩沖區(qū)通常用作固定大小的隊(duì)列。固定大小的隊(duì)列對(duì)于嵌入式系統(tǒng)的開(kāi)發(fā)非常友好,因?yàn)殚_(kāi)發(fā)人員通常會(huì)嘗試使用靜態(tài)數(shù)據(jù)存儲(chǔ)的方法而不是動(dòng)態(tài)分配。
環(huán)形緩沖區(qū)對(duì)于數(shù)據(jù)寫入和讀出以不同速率發(fā)生的情況也是非常有用的結(jié)構(gòu):最新數(shù)據(jù)始終可用。如果讀取數(shù)據(jù)的速度跟不上寫入數(shù)據(jù)的速度,舊的數(shù)據(jù)將被新寫入的數(shù)據(jù)覆蓋。通過(guò)使用循環(huán)緩沖區(qū),能夠保證我們始終使用最新的數(shù)據(jù)。
三、代碼實(shí)現(xiàn)
1. 環(huán)形緩存區(qū)結(jié)構(gòu)體RING_BUFFER
typedef struct
{
//緩存空間指針
char* buffer;
//緩存空間容量
int size;
//緩存讀序號(hào),范圍:0 - (size -1)
int rdIdx;
//緩存寫序號(hào),范圍:0 - (size -1)
int wrIdx;
//緩存滿標(biāo)志
int isFull;
}RING_BUFFER;
2. 創(chuàng)建環(huán)形緩存區(qū)
void* ringBufferCreate(int size)
{
RING_BUFFER* rb;
if(NULL == (rb = malloc(sizeof(RING_BUFFER) + size)))
{
printf("內(nèi)存不足!\n");
return NULL;
}
memset(rb, 0, sizeof(RING_BUFFER));
rb->buffer = (char*)rb + sizeof(RING_BUFFER);
rb->size = size;
return (void*)rb;
}
3. 獲取環(huán)形緩存區(qū)中有效數(shù)據(jù)大小
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. 獲取環(huán)形緩存區(qū)中空閑空間字節(jié)大小
int ringBufferFreeLen(RING_BUFFER* rb)
{
return ((rb->size - 1) - __ringBufferGetSize(rb));
}
5. 寫環(huán)形緩存區(qū)
int ringBufferWrite(void* handle, const char* ptr, int len)
{
RING_BUFFER* rb = (void*)handle;
int size;
if(0 >= len)
{
printf("rb寫參數(shù)[%lu]非法!\n", len);
return 0;
}
//獲取空閑空間大小
size = ringBufferFreeLen(rb);
if(size < len)
{
//空閑空間不足
printf("rb寫溢出!<%d, %d>\n", len, size);
return 0;
}
//計(jì)算"寫序號(hào)"后部還允許寫入的數(shù)據(jù)字節(jié)數(shù)
size = rb->size - rb->wrIdx;
if(size >= len)
{
//當(dāng)前待寫入全部數(shù)據(jù)可一次寫入后部
memcpy(rb->buffer + rb->wrIdx, ptr, len);
rb->wrIdx = (size > len) ? (rb->wrIdx + len) : 0;
return len;
}
//先寫一部分?jǐn)?shù)據(jù)到后部
memcpy(rb->buffer + rb->wrIdx, ptr, size);
//再寫剩余數(shù)據(jù)到前部
memcpy(rb->buffer, ptr + size, len - size);
rb->wrIdx = len - size;
return len;
}
6. 讀環(huán)形緩存區(qū)
int ringBufferRead(void* handle, char* ptr, int len)
{
RING_BUFFER* rb = (void*)handle;
int size;
if(0 >= len)
{
printf("rb讀參數(shù)[%lu]非法!\n", len);
return 0;
}
//獲取有效數(shù)據(jù)大小
size = ringBufferGetSize(rb);
if(0 == size)
{
return 0;//沒(méi)有數(shù)據(jù)
}
if(0 != rb->isFull)
{
//之前已標(biāo)記 緩存滿,全清 緩存內(nèi)容
rb->rdIdx = rb->wrIdx;
rb->isFull = 0;
return 0;
}
if(size < len)
{
//有效數(shù)據(jù)不足,只能返回填充一部分
len = size;
}
//計(jì)算"讀序號(hào)"后部可讀空間大小
size = rb->size - rb->rdIdx;
if(size >= len)
{
//當(dāng)前待讀出全部數(shù)據(jù)全存在于"讀序號(hào)"后部
memcpy(ptr, rb->buffer + rb->rdIdx, len);
rb->rdIdx = (size > len) ? (rb->rdIdx + len) : 0;
return len;
}
//先從"讀序號(hào)"后部讀出一部分?jǐn)?shù)據(jù)
memcpy(ptr, rb->buffer + rb->rdIdx, size);
//再?gòu)那安孔x出剩余數(shù)據(jù)
memcpy(ptr + size, rb->buffer, len - size);
rb->rdIdx = len - size;
return len;
}
7. 銷毀環(huán)形緩存區(qū)
int ringBufferDestroy(void* handle)
{
RING_BUFFER* rb = (void*)handle;
ctFree(rb);
return 0;
}來(lái)源:https://blog.csdn.net/u012478275/article/details/122101925
最后歡迎大家加入 音視頻開(kāi)發(fā)進(jìn)階 知識(shí)星球 ,這里有知識(shí)干貨、編程答疑、開(kāi)發(fā)教程,還有很多精彩分享。
更多內(nèi)容可以在星球菜單中找到,隨著時(shí)間推移,干貨也會(huì)越來(lái)越多?。。?/span>

給出 10元 優(yōu)惠券,漲價(jià)在即,目前還是白菜價(jià),基本上提幾個(gè)問(wèn)題就回本,投資自己就是最好的投資?。?!

加我微信 ezglumes ,拉你進(jìn)技術(shù)交流群
推薦閱讀:
音視頻開(kāi)發(fā)工作經(jīng)驗(yàn)分享 || 視頻版
開(kāi)通專輯 | 細(xì)數(shù)那些年寫過(guò)的技術(shù)文章專輯
Android NDK 免費(fèi)視頻在線學(xué)習(xí)?。?!
你想要的音視頻開(kāi)發(fā)資料庫(kù)來(lái)了
推薦幾個(gè)堪稱教科書級(jí)別的 Android 音視頻入門項(xiàng)目
覺(jué)得不錯(cuò),點(diǎn)個(gè)在看唄~

