欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > ffplay音视频同步处理

ffplay音视频同步处理

2025/1/6 14:19:04 来源:https://blog.csdn.net/cai742925624/article/details/144073516  浏览:    关键词:ffplay音视频同步处理

1、ffplay音视频同步的选项参数:sync=audio/video/ext

static int av_sync_type = AV_SYNC_AUDIO_MASTER; //默认音频
static int opt_sync(void *optctx, const char *opt, const char *arg)
{if (!strcmp(arg, "audio"))      //音频av_sync_type = AV_SYNC_AUDIO_MASTER;else if (!strcmp(arg, "video")) //视频av_sync_type = AV_SYNC_VIDEO_MASTER;else if (!strcmp(arg, "ext"))   //外部时间av_sync_type = AV_SYNC_EXTERNAL_CLOCK;else {av_log(NULL, AV_LOG_ERROR, "Unknown value for %s: %s\n", opt, arg);exit(1);}return 0;
}

2、以视频或者外部时钟为基准,控制采样点播放的数量

// 如果 sync_type 是视频或外部主时钟,则返回所需的样本数以获得更好的同步
static int synchronize_audio(VideoState *is, int nb_samples)
{int wanted_nb_samples = nb_samples;// 如果不是主时钟,那么我们会尝试删除或添加样本来纠正时钟if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) {double diff, avg_diff;int min_nb_samples, max_nb_samples;diff = get_clock(&is->audclk) - get_master_clock(is);if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {/* not enough measures to have a correct estimate */is->audio_diff_avg_count++;} else {/* estimate the A-V difference */avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);if (fabs(avg_diff) >= is->audio_diff_threshold) {wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));wanted_nb_samples = av_clip(wanted_nb_samples, min_nb_samples, max_nb_samples);}av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\n", diff, avg_diff, wanted_nb_samples - nb_samples, is->audio_clock, is->audio_diff_threshold);}} else {/* too big difference : may be initial PTS errors, so reset A-V filter */is->audio_diff_avg_count = 0;is->audio_diff_cum       = 0;}}return wanted_nb_samples;
}

3、以音频或者外部时钟为基准,计算remaining_time

static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) 
{double remaining_time = 0.0;SDL_PumpEvents();while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {if (!cursor_hidden && av_gettime_relative() - cursor_last_shown > CURSOR_HIDE_DELAY) {SDL_ShowCursor(0);cursor_hidden = 1;}if (remaining_time > 0.0)av_usleep((int64_t)(remaining_time * 1000000.0));remaining_time = REFRESH_RATE;if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))video_refresh(is, &remaining_time);SDL_PumpEvents();}
}/* called to display each frame */
static void video_refresh(void *opaque, double *remaining_time)
{VideoState *is = opaque;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 (!display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {time = av_gettime_relative() / 1000000.0;if (is->force_refresh || is->last_vis_time + rdftspeed < time) {video_display(is);is->last_vis_time = time;}*remaining_time = FFMIN(*remaining_time, is->last_vis_time + rdftspeed - time);}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);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(last_duration, is);time= av_gettime_relative()/1000000.0;if (time < is->frame_timer + delay) {*remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);goto display;}is->frame_timer += delay;if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX)is->frame_timer = time;SDL_LockMutex(is->pictq.mutex);if (!isnan(vp->pts))update_video_pts(is, vp->pts, vp->serial);SDL_UnlockMutex(is->pictq.mutex);if (frame_queue_nb_remaining(&is->pictq) > 1) {Frame *nextvp = frame_queue_peek_next(&is->pictq);duration = vp_duration(is, vp, nextvp);if(!is->step && (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){is->frame_drops_late++;frame_queue_next(&is->pictq);goto retry;}}if (is->subtitle_st) {while (frame_queue_nb_remaining(&is->subpq) > 0) {sp = frame_queue_peek(&is->subpq);if (frame_queue_nb_remaining(&is->subpq) > 1)sp2 = frame_queue_peek_next(&is->subpq);elsesp2 = NULL;if (sp->serial != is->subtitleq.serial|| (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))|| (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000)))){if (sp->uploaded) {int i;for (i = 0; i < sp->sub.num_rects; i++) {AVSubtitleRect *sub_rect = sp->sub.rects[i];uint8_t *pixels;int pitch, j;if (!SDL_LockTexture(is->sub_texture, (SDL_Rect *)sub_rect, (void **)&pixels, &pitch)) {for (j = 0; j < sub_rect->h; j++, pixels += pitch)memset(pixels, 0, sub_rect->w << 2);SDL_UnlockTexture(is->sub_texture);}}}frame_queue_next(&is->subpq);} else {break;}}}frame_queue_next(&is->pictq);is->force_refresh = 1;if (is->step && !is->paused)stream_toggle_pause(is);}display:/* display picture */if (!display_disable && is->force_refresh && is->show_mode == SHOW_MODE_VIDEO && is->pictq.rindex_shown)video_display(is);}is->force_refresh = 0;if (show_status) {AVBPrint buf;static int64_t last_time;int64_t cur_time;int aqsize, vqsize, sqsize;double av_diff;cur_time = av_gettime_relative();if (!last_time || (cur_time - last_time) >= 30000) {aqsize = 0;vqsize = 0;sqsize = 0;if (is->audio_st)aqsize = is->audioq.size;if (is->video_st)vqsize = is->videoq.size;if (is->subtitle_st)sqsize = is->subtitleq.size;av_diff = 0;if (is->audio_st && is->video_st)av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk);else if (is->video_st)av_diff = get_master_clock(is) - get_clock(&is->vidclk);else if (is->audio_st)av_diff = get_master_clock(is) - get_clock(&is->audclk);av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);av_bprintf(&buf,"%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",get_master_clock(is),(is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : "   ")),av_diff,is->frame_drops_early + is->frame_drops_late,aqsize / 1024,vqsize / 1024,sqsize,is->video_st ? is->viddec.avctx->pts_correction_num_faulty_dts : 0,is->video_st ? is->viddec.avctx->pts_correction_num_faulty_pts : 0);if (show_status == 1 && AV_LOG_INFO > av_log_get_level())fprintf(stderr, "%s", buf.str);elseav_log(NULL, AV_LOG_INFO, "%s", buf.str);fflush(stderr);av_bprint_finalize(&buf, NULL);last_time = cur_time;}}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com