出处见链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
https://blog.csdn.net/myvest/article/details/97416415

{
video->frameq.deQueue(&video->frame);

double current_pts = *(double *)video->frame->opaque;//当前帧的pts
double delay = current_pts - video->frame_last_pts;//相减之后 就是前帧默认的时间
if (delay <= 0 || delay >= 1.0)
{
delay = video->frame_last_delay;//数据波动太大 特殊处理
}

double ref_clock = audio->get_audio_clock();//参考时间
double diff = current_pts - ref_clock;//应该播放时间-当前时间 = 偏差时间 diff < 0 :video slow,diff > 0 :video fast

double sync_threshold = FFMAX(MIN_SYNC_THRESHOLD, FFMIN(MAX_SYNC_THRESHOLD, delay)) ;//规定帧播放时间在一定范围内

audio->audio_wait_video(current_pts,false);//更新时钟
video->video_drop_frame(ref_clock,false);

if (!isnan(diff) && fabs(diff) < NOSYNC_THRESHOLD) // 不同步
{
if (diff <= -sync_threshold)//视频比音频慢,加快
{
delay = FFMAX(0, delay + diff);//表示直接覆盖上一帧
static int last_delay_zero_counts = 0;
if(video->frame_last_delay <= 0)
{
last_delay_zero_counts++;
}
else
{
last_delay_zero_counts = 0;
}
if(diff < -1.0 && last_delay_zero_counts >= 10)//连续缓慢 视频解码跟不上
{
printf("maybe video codec too slow, adjust video&audio\n");
#ifndef DORP_PACK
audio->audio_wait_video(current_pts,true);//差距较大,需要反馈音频等待视频
#endif
video->video_drop_frame(ref_clock,true);//差距较大,需要视频丢帧追上
}
}//视频比音频快,减慢
else if (diff >= sync_threshold && delay > SYNC_FRAMEDUP_THRESHOLD)//快了一帧以上 该帧与前帧相差了不少
delay = delay + diff;//直接跳过去
else if (diff >= sync_threshold)
delay = 2 * delay;//音视频差距较小,加倍延迟,逐渐缩小
}
video->frame_last_delay = delay;//该帧从current_pts播放了delay时长
video->frame_last_pts = current_pts;

double curr_time = static_cast<double>(av_gettime()) / 1000000.0;
if(video->frame_timer == 0)
{
video->frame_timer = curr_time;//第一次
}

double actual_delay = video->frame_timer + delay - curr_time;//应该为curr_time-video->frame_timer + delay
if (actual_delay <= MIN_REFRSH_S)
{
actual_delay = MIN_REFRSH_S;
}
usleep(static_cast<int>(actual_delay * 1000 * 1000));
//printf("actual_delay[%lf] delay[%lf] diff[%lf]\n",actual_delay,delay,diff);
// Display
SDL_UpdateTexture(video->texture, &(video->rect), video->frame->data[0], video->frame->linesize[0]);
SDL_RenderClear(video->renderer);
SDL_RenderCopy(video->renderer, video->texture, &video->rect, &video->rect);
SDL_RenderPresent(video->renderer);
video->frame_timer = static_cast<double>(av_gettime()) / 1000000.0 ;//刷新一帧显示时间

av_frame_unref(video->frame);

//update next frame
schedule_refresh(media, 1);
}