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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容