/* 可能是video,audio,local time */ static double get_master_clock(VideoState *is) { if(is->av_sync_type == AV_SYNC_VIDEO_MASTER) { return get_video_clock(is); } else { return get_external_clock(is); } }
double get_master_clock(VideoState *is) { if(is->av_sync_type == AV_SYNC_VIDEO_MASTER) { return get_video_clock(is); } else if(is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audioStream>0) { return get_audio_clock(is); } else { return get_external_clock(is); } }
double get_master_clock(VideoState *is) { double masterClock; if(is->av_sync_type == AV_SYNC_VIDEO_MASTER) { masterClock = get_video_clock(is); } else if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) { masterClock = get_audio_clock(is); } else { masterClock = get_external_clock(is); } // fprintf(stderr, "---> get_master_clock: %.8f\n", masterClock); return masterClock; }
/* Must be called from the user thread. */ static void retrieve_picture(VideoState *is) { VideoPicture *vp; int dst_pix_fmt; AVPicture pict; static struct SwsContext *img_convert_ctx; AVFrame *pFrame; if (!is->got_picture) return; vp = &is->pictq[is->pictq_windex]; pFrame = vp->frame; if (!vp->bmp || vp->width != is->video_st->codec->width || vp->height != is->video_st->codec->height) { alloc_picture(is); } /* YUV->RGB conversion. */ if (vp->bmp) { /* Don't waste CPU on an outdated frame. */ if (get_video_clock(is) >= get_external_clock(is) - 0.25) { ALLEGRO_LOCKED_REGION *lock; lock = al_lock_bitmap(vp->bmp, 0, ALLEGRO_LOCK_WRITEONLY); dst_pix_fmt = PIX_FMT_RGB24; pict.data[0] = lock->data; pict.linesize[0] = lock->pitch; if (img_convert_ctx == NULL) { int w = is->video_st->codec->width; int h = is->video_st->codec->height; img_convert_ctx = sws_getContext(w, h, is->video_st->codec->pix_fmt, w, h, dst_pix_fmt, SWS_BICUBIC, NULL, NULL, NULL); if (img_convert_ctx == NULL) { ALLEGRO_ERROR("Cannot initialize the conversion context!\n"); return; } } sws_scale(img_convert_ctx, (uint8_t const *const*)pFrame->data, pFrame->linesize, 0, is->video_st->codec->height, pict.data, pict.linesize); al_unlock_bitmap(vp->bmp); } else { vp->dropped = true; } //printf("[%d] %f %f %f %s\n", is->pictq_windex, // vp->pts, get_video_clock(is), get_external_clock(is), vp->dropped ? "dropped" : "shown"); if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) { is->pictq_windex = 0; } } al_lock_mutex(is->pictq_mutex); is->pictq_size++; is->got_picture--; vp->allocated = 1; al_signal_cond(is->pictq_cond); al_unlock_mutex(is->pictq_mutex); }
static void video_refresh_timer(void *userdata) { VideoState *is = (VideoState *) userdata; VideoPicture *vp; double actual_delay, delay, sync_threshold, ref_clock, diff; if (!is->first) return; if (!is->video_st) return; if (is->pictq_size == 0) return; if (is->paused) return; if (get_master_clock(is) < is->show_next) return; vp = &is->pictq[is->pictq_rindex]; is->video_current_pts = vp->pts; is->video_current_pts_time = av_gettime(); delay = vp->pts - is->frame_last_pts; /* the pts from last time */ if (delay <= 0 || delay >= 1.0) { /* if incorrect delay, use previous one */ delay = is->frame_last_delay; } /* save for next time */ is->frame_last_delay = delay; is->frame_last_pts = vp->pts; /* update delay to sync to audio if not master source */ if (is->av_sync_type != AV_SYNC_VIDEO_MASTER) { ref_clock = get_master_clock(is); diff = vp->pts - ref_clock; /* Skip or repeat the frame. Take delay into account */ sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; if (fabs(diff) < AV_NOSYNC_THRESHOLD) { if (diff <= -sync_threshold) { delay = 0; } else if (diff >= sync_threshold) { delay = 2 * delay; } } } is->frame_timer += delay; /* computer the REAL delay */ actual_delay = is->frame_timer - (av_gettime() / 1000000.0); if (!vp->dropped && vp->bmp) { is->video->current_frame = vp->bmp; /* Can be NULL or wrong size, will be (re-)allocated as needed. */ vp->bmp = is->shown.bmp; /* That way it won't be overwritten. */ is->shown.bmp = is->video->current_frame; is->video->position = get_master_clock(is); is->video->video_position = get_video_clock(is); is->video->audio_position = get_audio_clock(is); is->show_next = is->video->position + actual_delay; al_signal_cond(is->timer_cond); if (is->video_st->codec->sample_aspect_ratio.num == 0) { is->video->aspect_ratio = 0; } else { is->video->aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio) * is->video_st->codec->width / is->video_st->codec->height; } if (is->video->aspect_ratio <= 0.0) { is->video->aspect_ratio = (float)is->video_st->codec->width / (float)is->video_st->codec->height; } } else is->dropped_count++; //printf("[%d] %f %s\n", is->pictq_rindex, // actual_delay, vp->dropped ? "dropped" : "shown"); /* update queue for next picture! */ if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) { is->pictq_rindex = 0; } al_lock_mutex(is->pictq_mutex); is->pictq_size--; al_signal_cond(is->pictq_cond); al_unlock_mutex(is->pictq_mutex); /* We skipped a frame... let's grab more until we catch up. */ if (actual_delay < 0) video_refresh_timer(userdata); }