ffplay FrameQueue 源碼分析
一、FrameQueue結構
typedef struct FrameQueue {
Frame queue[FRAME_QUEUE_SIZE];
int rindex;//隊頭索引
int windex;//隊尾索引
int size;//隊列元素個數
int max_size;//隊列最大容量
int keep_last;//保留最後一幀數據
int rindex_shown;
SDL_mutex *mutex;
SDL_cond *cond;
PacketQueue *pktq;
} FrameQueue;
原理示意圖
二、操作函數
包含如圖所示的方法
主要分析隊列添加和移除元素功能
1、添加元素到隊列
- 調用frame_queue_peek_writable(…)獲取隊列中的可用的Frame
- 調用frame_queue_push(…)將隊尾索引++,元素個數++
static Frame *frame_queue_peek_writable(FrameQueue *f)
{
/* wait until we have space to put a new frame */
SDL_LockMutex(f->mutex);
while (f->size >= f->max_size &&
!f->pktq->abort_request) {// !f->pktq->abort_request條件讓隊列可被終止添加數據
SDL_CondWait(f->cond, f->mutex);//渲染線程取走數據後,負責喚醒
}
SDL_UnlockMutex(f->mutex);
if (f->pktq->abort_request)
return NULL;
return &f->queue[f->windex];
}
static void frame_queue_push(FrameQueue *f)
{
if (++f->windex == f->max_size)
f->windex = 0;//隊列尾索引大於等於max_size時重新回到0
SDL_LockMutex(f->mutex);
f->size++;//隊列中元素個數++,解碼線程和渲染線程均會操作,加鎖保護
SDL_CondSignal(f->cond);//通知因隊列空而阻塞的渲染線程,隊列中有數據了
SDL_UnlockMutex(f->mutex);
}
2、獲取隊列中的元素
- 調用frame_queue_peek_readable(…)獲取當前隊頭的元素,隊列爲空將阻塞
- frame_queue_next(…)將隊頭索引++,隊列元素個數–
static Frame *frame_queue_peek_readable(FrameQueue *f)
{
/* wait until we have a readable a new frame */
SDL_LockMutex(f->mutex);
while (f->size - f->rindex_shown <= 0 &&
!f->pktq->abort_request) {
SDL_CondWait(f->cond, f->mutex);
}
SDL_UnlockMutex(f->mutex);
if (f->pktq->abort_request)
return NULL;
return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
}
static void frame_queue_next(FrameQueue *f)
{
if (f->keep_last && !f->rindex_shown) {
f->rindex_shown = 1;
return;
}
frame_queue_unref_item(&f->queue[f->rindex]);
if (++f->rindex == f->max_size)
f->rindex = 0;
SDL_LockMutex(f->mutex);
f->size--;//解碼線程和渲染線程均會操作,加鎖保護
SDL_CondSignal(f->cond);//通知因隊列滿而阻塞的解碼線程,隊列有空間了
SDL_UnlockMutex(f->mutex);
}
線程均會操作,加鎖保護
SDL_CondSignal(f->cond);//通知因隊列滿而阻塞的解碼線程,隊列有空間了
SDL_UnlockMutex(f->mutex);
}