ffplay的FrameQueue分析

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);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市脓斩,隨后出現(xiàn)的幾起案子木西,更是在濱河造成了極大的恐慌,老刑警劉巖随静,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件八千,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡燎猛,警方通過(guò)查閱死者的電腦和手機(jī)恋捆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)重绷,“玉大人沸停,你說(shuō)我怎么就攤上這事≌炎浚” “怎么了愤钾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)候醒。 經(jīng)常有香客問(wèn)我绰垂,道長(zhǎng),這世上最難降的妖魔是什么火焰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮胧沫,結(jié)果婚禮上昌简,老公的妹妹穿的比我還像新娘占业。我一直安慰自己,他們只是感情好纯赎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布谦疾。 她就那樣靜靜地躺著,像睡著了一般犬金。 火紅的嫁衣襯著肌膚如雪念恍。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天晚顷,我揣著相機(jī)與錄音峰伙,去河邊找鬼。 笑死该默,一個(gè)胖子當(dāng)著我的面吹牛瞳氓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播栓袖,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼匣摘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了裹刮?” 一聲冷哼從身側(cè)響起音榜,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捧弃,沒(méi)想到半個(gè)月后赠叼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡塔橡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年梅割,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片葛家。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡户辞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出癞谒,到底是詐尸還是另有隱情底燎,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布弹砚,位于F島的核電站双仍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏桌吃。R本人自食惡果不足惜朱沃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逗物,春花似錦搬卒、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至失暴,卻和暖如春坯门,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背逗扒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工古戴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缴阎。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓允瞧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蛮拔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子述暂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,698評(píng)論 0 3
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,386評(píng)論 8 265
  • 這是一個(gè)跨平臺(tái)的播放器ijkplayer,iOS上集成看【如何快速的開(kāi)發(fā)一個(gè)完整的iOS直播app】(原理篇)建炫。 ...
    FindCrt閱讀 7,068評(píng)論 2 46
  • 長(zhǎng)治縣第六中學(xué)校 2018年招生告知 同學(xué)們好畦韭,遵照縣委、縣政府肛跌、縣教科局有關(guān)文件會(huì)議精神要求艺配,我校特向有志就讀我...
    巖棟閱讀 2,255評(píng)論 0 0
  • 記得羅曼羅蘭曾經(jīng)說(shuō)過(guò)一句話:世界上不是沒(méi)有美,而是沒(méi)有發(fā)現(xiàn)美的眼睛衍慎。 今天學(xué)生考試转唉,每次的語(yǔ)文閱讀理解都是極美的文...
    唐人生閱讀 1,114評(píng)論 0 3