整章目录:Android------- IjkPlayer 源码学习目录
本篇会有很多源代码,请注意阅读每行代码上面的注释。

本篇介绍的主要内容为上图红框圈起部分:
video_refresh_thread一个专注于刷新视频播放界面的线程。
不清楚IjkPlayer如何启动video_refresh_thread线程的请看:Android ---- Ijkplayer阅读native层源码之IjkMediaPlayer_prepareAsync(五)
video_refresh_thread:
static int video_refresh_thread(void *arg)
{
FFPlayer *ffp = arg;
VideoState *is = ffp->is;
double remaining_time = 0.0;
// 如果播放没退出则无限循环
while (!is->abort_request) {
// 因为还没到下一帧的显示时间,所以要延迟刷新。
if (remaining_time > 0.0)
av_usleep((int)(int64_t)(remaining_time * 1000000.0));
remaining_time = REFRESH_RATE;
// 如果有视频流,is->show_mode=SHOW_MODE_VIDEO
if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
// 刷新一下界面
video_refresh(ffp, &remaining_time);
}
return 0;
}
remaining_time:当前帧是否需要延迟播放。由于每帧的fps(刷新率)是相同的,但是在播放中会导致一些误差,如解码太快等原因,导致当前帧还未到其播放显示的时间,所以需要等待,而等待的时间就是remaining_time。默认的刷新时间1/fps
还需注意,只要没退出播放器,这个线程就是一个死循环。每次循环都会先判断:是否需要延迟刷新界面,如果要,就睡眠remaining_time,否则调用video_refresh刷新一下界面,并将remaining_time传入函数计算出当前帧需要等待刷新的时间。
video_refresh:
static void video_refresh(FFPlayer *opaque, double *remaining_time)
{
FFPlayer *ffp = opaque;
VideoState *is = ffp->is;
double time;
Frame *sp, *sp2;
// 如果同步时间参考额外时间轴或者是直播
if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)
check_external_clock_speed(is);
// 如果屏幕可以展示,但此时只播放音频,进入
if (!ffp->display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {
省略。。。
}
// 如果有视频
if (is->video_st) {
retry:
// 缓存队列中没有视频帧
if (frame_queue_nb_remaining(&is->pictq) == 0) {
// nothing to do, no picture to display in the queue
} else {
double last_duration, duration, delay;
Frame *vp, *lastvp;
/* dequeue the picture */
// 获得上一帧视频,该帧已经被展示了
lastvp = frame_queue_peek_last(&is->pictq);
// 获得当前一帧视频,如果lastvp没有被展示,则vp=lastvp
vp = frame_queue_peek(&is->pictq);
// 视频缓存队列已经更新
if (vp->serial != is->videoq.serial) {
// 丢弃上一帧
frame_queue_next(&is->pictq);
goto retry;
}
// 视频缓存队列已经更新
if (lastvp->serial != vp->serial)
// 设置已播放时间
is->frame_timer = av_gettime_relative() / 1000000.0;
if (is->paused)
goto display;
/* compute nominal last_duration */
// 计算相邻两帧之间的显示时间间隔
last_duration = vp_duration(is, lastvp, vp);
// 重要:计算相邻两帧之间实际时间间隔,(包含了同步补偿)
delay = compute_target_delay(ffp, last_duration, is);
time= av_gettime_relative()/1000000.0;
// 更新当前播放时间
if (isnan(is->frame_timer) || time < is->frame_timer)
is->frame_timer = time;
// 还未到该帧的显示,进入
if (time < is->frame_timer + delay) {
// 计算播放该帧还需等待的时间
*remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
// 去等待,注意:由于force_refresh=0,并不会去播放该帧
goto display;
}
// ------------------------------------
// 当前帧显示时间已经到达
// ------------------------------------
// 设置播放器的播放时间
is->frame_timer += delay;

最低0.47元/天 解锁文章
1550





