rindex_shown为1时,队列中总是保留了最后一帧lastvp(灰色方框)。按照这样的设计思路,如果rindex_shown为2,队列中就会保留最后2帧。
但keep_last机制有什么用途呢?希望知道的同学指点一下。
注意,在TX时刻,无新帧可显示,保留的一帧是已经显示过的。那么最后一帧什么时候被清掉呢?在播放结束或用户中途取消播放时,会调用frame_queue_destory()清空播放队列。
rindex_shown的引入增加了读队列操作的理解难度。大多数读操作函数都会用到这个变量。
通过FrameQueue.keep_last和FrameQueue.rindex_shown两个变量实现了保留最后一次播放帧的机制。
是否启用keep_last机制是由全局变量keep_last值决定的,在队列初始化函数frame_queue_init()中有f->keep_last = !!keep_last;,而在更新读指针函数frame_queue_next()中如果启用keep_last机制,则f->rindex_shown值为1。如果rindex_shown对理解代码造成了困扰,可以先将全局变量keep_last值赋为0,这样f->rindex_shown值为0,代码看起来会清晰很多。理解了读队列的基本方法后,再看f->rindex_shown值为1时代码是如何运行的。
先看frame_queue_next()函数:
frame_queue_next()
三个动作:删除rindex节点(lastvp),更新f->rindex和f->size。
frame_queue_peek_readable()
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]; }从队列头部读取一帧(vp),只读取不删除,若无帧可读则等待。这个函数和frame_queue_peek()的区别仅仅是多了不可读时等待的操作。
frame_queue_peek()
static Frame *frame_queue_peek(FrameQueue *f) { return &f->queue[(f->rindex + f->rindex_shown) % f->max_size]; } static Frame *frame_queue_peek_next(FrameQueue *f) { return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size]; } // 取出此帧进行播放,只读取不删除,不删除是因为此帧需要缓存下来供下一次使用。播放后,此帧变为上一帧 static Frame *frame_queue_peek_last(FrameQueue *f) { return &f->queue[f->rindex]; }从队列头部读取一帧(vp),只读取不删除。