ffplay的FrameQueue
先簡(jiǎn)單介紹以下FrameQueue, FrameQueue是一個(gè)隊(duì)列,它是用來(lái)存儲(chǔ)解碼后的數(shù)據(jù)突雪, 像視頻驰贷, 就是一幀的YUV或者RGB數(shù)據(jù), 音頻,就是pcm數(shù)據(jù)棵帽,還有字幕。每一種媒體類(lèi)型都會(huì)有FrameQueue這樣一個(gè)隊(duì)列渣玲, 一般視頻有最多三種媒體類(lèi)型逗概,視頻、音頻還有字幕忘衍,所以
ffplay
會(huì)創(chuàng)建三個(gè)FrameQueue逾苫,分別用來(lái)存儲(chǔ)視頻卿城、音頻和字幕。
下面貼下FrameQueue的結(jié)構(gòu)體
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;
-
queue
是存儲(chǔ)Frame
的數(shù)組 -
rindex
是讀幀數(shù)據(jù)索引铅搓, 相當(dāng)于是隊(duì)列的隊(duì)首 -
windex
是寫(xiě)幀數(shù)據(jù)索引瑟押, 相當(dāng)于是隊(duì)列的隊(duì)尾 -
size
是存儲(chǔ)在這個(gè)隊(duì)列的Frame
的數(shù)量 -
max_size
是可以存儲(chǔ)Frame
的最大數(shù)量 -
keep_last
,這個(gè)變量的含義狸吞,據(jù)我分析勉耀, 是用來(lái)判斷隊(duì)列是否保留正在顯示的幀(Frame
) -
rindex_shown
表示當(dāng)前是否有幀在顯示 -
pktq
指向各自數(shù)據(jù)包(ES包)
的隊(duì)列
下面分析以下與FrameQueue的操作函數(shù)
FrameQueue的初始化函數(shù)frame_queue_init
:
static int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)
{
int i;
memset(f, 0, sizeof(FrameQueue));
// 創(chuàng)建互斥量
if (!(f->mutex = SDL_CreateMutex())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
}
// 創(chuàng)建條件變量
if (!(f->cond = SDL_CreateCond())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
}
// 使pktq指向相應(yīng)的ES流隊(duì)列
f->pktq = pktq;
f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);
f->keep_last = !!keep_last;
// 為幀隊(duì)列中的各個(gè)Frame創(chuàng)建AvFrame
for (i = 0; i < f->max_size; i++)
if (!(f->queue[i].frame = av_frame_alloc()))
return AVERROR(ENOMEM);
return 0;
}
frame_queue_peek_last
:獲取當(dāng)前播放器顯示的幀
static Frame *frame_queue_peek_last(FrameQueue *f)
{
return &f->queue[f->rindex];
}
frame_queue_peek
:獲取待顯示的第一個(gè)幀
static Frame *frame_queue_peek(FrameQueue *f)
{
return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
}
frame_queue_peek_next
:獲取待顯示的第二個(gè)幀
static Frame *frame_queue_peek_next(FrameQueue *f)
{
return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];
}
frame_queue_peek_writable
:獲取queue
中一塊Frame
大小的可寫(xiě)內(nèi)存
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) {
SDL_CondWait(f->cond, f->mutex);
}
SDL_UnlockMutex(f->mutex);
if (f->pktq->abort_request)
return NULL;
return &f->queue[f->windex];
}
frame_queue_peek_readable
:這方法和frame_queue_peek
的作用一樣, 都是獲取待顯示的第一幀
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];
}
frame_queue_push
:推入一幀數(shù)據(jù)蹋偏, 其實(shí)數(shù)據(jù)已經(jīng)在調(diào)用這個(gè)方法前填充進(jìn)去了便斥, 這個(gè)方法的作用是將隊(duì)列的寫(xiě)索引(也就是隊(duì)尾)向后移, 還有將這個(gè)隊(duì)列中的Frame
的數(shù)量加一威始。
static void frame_queue_push(FrameQueue *f)
{
if (++f->windex == f->max_size)
f->windex = 0;
SDL_LockMutex(f->mutex);
f->size++;
SDL_CondSignal(f->cond);
SDL_UnlockMutex(f->mutex);
}
frame_queue_next
:將讀索引(隊(duì)頭)后移一位枢纠, 還有將這個(gè)隊(duì)列中的Frame
的數(shù)量減一
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);
}
frame_queue_nb_remaining
:返回隊(duì)列中待顯示幀的數(shù)目
/* return the number of undisplayed frames in the queue */
static int frame_queue_nb_remaining(FrameQueue *f)
{
return f->size - f->rindex_shown;
}
frame_queue_last_pos
:返回正在顯示的幀的position
/* return last shown position */
static int64_t frame_queue_last_pos(FrameQueue *f)
{
Frame *fp = &f->queue[f->rindex];
if (f->rindex_shown && fp->serial == f->pktq->serial)
return fp->pos;
else
return -1;
}
frame_queue_destory
:釋放Frame
,釋放互斥鎖和互斥量
static void frame_queue_destory(FrameQueue *f)
{
int i;
for (i = 0; i < f->max_size; i++) {
Frame *vp = &f->queue[i];
frame_queue_unref_item(vp);
av_frame_free(&vp->frame);
}
SDL_DestroyMutex(f->mutex);
SDL_DestroyCond(f->cond);
}
frame_queue_unref_item
:取消引用幀引用的所有緩沖區(qū)并重置幀字段黎棠,釋放給定字幕結(jié)構(gòu)中的所有已分配數(shù)據(jù)晋渺。
static void frame_queue_unref_item(Frame *vp)
{
av_frame_unref(vp->frame);
avsubtitle_free(&vp->sub);
}