diff options
author | wm4 <wm4@mplayer2.org> | 2012-04-01 22:52:33 +0200 |
---|---|---|
committer | wm4 <wm4@mplayer2.org> | 2012-04-01 22:52:33 +0200 |
commit | 1aa2e36122e6e664e42170f47d6db82873bef5aa (patch) | |
tree | 39e13f93bcb606da9e365c7cd379132bdf53c20b /mplayer.c | |
parent | fea8c85c8595b797fc839b113c1db252fc55c798 (diff) | |
parent | 8cd71527ade21ea27ea24cdcc66dc71dca460f85 (diff) | |
download | mpv-1aa2e36122e6e664e42170f47d6db82873bef5aa.tar.bz2 mpv-1aa2e36122e6e664e42170f47d6db82873bef5aa.tar.xz |
Merge remote-tracking branch 'origin/master'
Conflicts:
bstr.c
bstr.h
etc/input.conf
input/input.c
input/input.h
libao2/ao_pulse.c
libmpcodecs/vf_ass.c
libmpcodecs/vf_vo.c
libvo/gl_common.c
libvo/x11_common.c
mixer.c
mixer.h
mplayer.c
Diffstat (limited to 'mplayer.c')
-rw-r--r-- | mplayer.c | 661 |
1 files changed, 322 insertions, 339 deletions
@@ -1229,6 +1229,8 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame) if (mpctx->time_frame > 0) mpctx->last_av_difference += mpctx->time_frame * opts->playback_speed; + if (a_pos == MP_NOPTS_VALUE || mpctx->video_pts == MP_NOPTS_VALUE) + mpctx->last_av_difference = MP_NOPTS_VALUE; if (mpctx->last_av_difference > 0.5 && drop_frame_cnt > 50 && !mpctx->drop_message_shown) { mp_tmsg(MSGT_AVSYNC, MSGL_WARN, SystemTooSlow); @@ -1238,9 +1240,6 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame) if (opts->quiet) return; - if (a_pos == MP_NOPTS_VALUE) - a_pos = -9; // don't print a huge negative number - int width; char *line; unsigned pos = 0; @@ -1258,8 +1257,11 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame) // Audio time if (mpctx->sh_audio) { - saddf(line, &pos, width, "A:%6.1f ", a_pos); - if (!sh_video) { + if (a_pos != MP_NOPTS_VALUE) + saddf(line, &pos, width, "A:%6.1f ", a_pos); + else + saddf(line, &pos, width, "A: ??? "); + if (!sh_video && a_pos != MP_NOPTS_VALUE) { float len = get_time_length(mpctx); saddf(line, &pos, width, "("); sadd_hhmmssf(line, &pos, width, a_pos); @@ -1270,13 +1272,22 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame) } // Video time - if (sh_video) - saddf(line, &pos, width, "V:%6.1f ", mpctx->video_pts); + if (sh_video) { + if (mpctx->video_pts != MP_NOPTS_VALUE) + saddf(line, &pos, width, "V:%6.1f ", mpctx->video_pts); + else + saddf(line, &pos, width, "V: ??? ", mpctx->video_pts); + } // A-V sync - if (mpctx->sh_audio && sh_video) - saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ", - mpctx->last_av_difference, mpctx->total_avsync_change); + if (mpctx->sh_audio && sh_video) { + if (mpctx->last_av_difference != MP_NOPTS_VALUE) + saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ", + mpctx->last_av_difference, mpctx->total_avsync_change); + else + saddf(line, &pos, width, "A-V: ??? ct:%7.3f ", + mpctx->total_avsync_change); + } // Video stats if (sh_video) @@ -1770,7 +1781,7 @@ void reinit_audio_chain(struct MPContext *mpctx) current_module = "af_preinit"; if (!(mpctx->initialized_flags & INITIALIZED_AO)) { mpctx->initialized_flags |= INITIALIZED_AO; - mpctx->ao = ao_create(); + mpctx->ao = ao_create(opts, mpctx->input); mpctx->ao->samplerate = force_srate; mpctx->ao->format = opts->audio_output_format; } @@ -1818,6 +1829,8 @@ void reinit_audio_chain(struct MPContext *mpctx) } mpctx->mixer.ao = ao; mpctx->mixer.volstep = volstep; + mpctx->mixer.softvol = opts->softvol; + mpctx->mixer.softvol_max = opts->softvol_max; mixer_reinit(&mpctx->mixer); mpctx->syncing_audio = true; return; @@ -1898,13 +1911,14 @@ static bool is_av_sub(int type) return type == 'b' || type == 'p' || type == 'x'; } -void update_subtitles(struct MPContext *mpctx, double refpts, - double sub_offset, bool reset) +void update_subtitles(struct MPContext *mpctx, double refpts_tl, bool reset) { + mpctx->osd->sub_offset = mpctx->video_offset; struct MPOpts *opts = &mpctx->opts; struct sh_video *sh_video = mpctx->sh_video; struct demux_stream *d_sub = mpctx->d_sub; - double curpts = refpts + sub_delay; + double refpts_s = refpts_tl - mpctx->osd->sub_offset; + double curpts_s = refpts_s + sub_delay; unsigned char *packet = NULL; int len; struct sh_sub *sh_sub = d_sub->sh; @@ -1929,7 +1943,7 @@ void update_subtitles(struct MPContext *mpctx, double refpts, if (sub_fps == 0) sub_fps = sh_video ? sh_video->fps : 25; current_module = "find_sub"; - find_sub(mpctx, mpctx->subdata, curpts * + find_sub(mpctx, mpctx->subdata, curpts_s * (mpctx->subdata->sub_uses_time ? 100. : sub_fps)); if (vo_sub) mpctx->vo_sub_last = vo_sub; @@ -1944,13 +1958,13 @@ void update_subtitles(struct MPContext *mpctx, double refpts, // Vobsub len = 0; if (vo_vobsub) { - if (curpts >= 0) { - len = vobsub_get_packet(vo_vobsub, curpts, + if (curpts_s >= 0) { + len = vobsub_get_packet(vo_vobsub, curpts_s, (void **)&packet, ×tamp); if (len > 0) mp_dbg(MSGT_CPLAYER, MSGL_V, "\rVOB sub: len=%d " "v_pts=%5.3f v_timer=%5.3f sub=%5.3f ts=%d \n", - len, refpts, sh_video->timer, + len, refpts_s, sh_video->timer, timestamp / 90000.0, timestamp); } } else { @@ -1962,14 +1976,14 @@ void update_subtitles(struct MPContext *mpctx, double refpts, // d_video->pts which would have been the simplest // improvement doesn't work because mpeg specific hacks // in video.c set d_video->pts to 0. - float x = d_sub->pts - refpts; + float x = d_sub->pts - refpts_s; if (x > -20 && x < 20) // prevent missing subs on pts reset timestamp = 90000 * d_sub->pts; else - timestamp = 90000 * curpts; + timestamp = 90000 * curpts_s; mp_dbg(MSGT_CPLAYER, MSGL_V, "\rDVD sub: len=%d " "v_pts=%5.3f s_pts=%5.3f ts=%d \n", len, - refpts, d_sub->pts, timestamp); + refpts_s, d_sub->pts, timestamp); } } if (len <= 0 || !packet) @@ -1995,19 +2009,19 @@ void update_subtitles(struct MPContext *mpctx, double refpts, ds_get_next_pts(d_sub); while (d_sub->first) { - double subpts = ds_get_next_pts(d_sub) + sub_offset; - if (subpts > curpts) { + double subpts_s = ds_get_next_pts(d_sub); + if (subpts_s > curpts_s) { // Libass handled subs can be fed to it in advance if (!opts->ass_enabled || !is_text_sub(type)) break; // Try to avoid demuxing whole file at once - if (d_sub->non_interleaved && subpts > curpts + 1) + if (d_sub->non_interleaved && subpts_s > curpts_s + 1) break; } double duration = d_sub->first->duration; len = ds_get_packet_sub(d_sub, &packet); if (is_av_sub(type)) { - int ret = decode_avsub(sh_sub, packet, len, subpts, duration); + int ret = decode_avsub(sh_sub, packet, len, subpts_s, duration); if (ret < 0) mp_msg(MSGT_SPUDEC, MSGL_WARN, "lavc failed decoding " "subtitle\n"); @@ -2036,10 +2050,10 @@ void update_subtitles(struct MPContext *mpctx, double refpts, continue; } if (sh_sub && sh_sub->active) { - sub_decode(sh_sub, mpctx->osd, packet, len, subpts, duration); + sub_decode(sh_sub, mpctx->osd, packet, len, subpts_s, duration); continue; } - if (subpts != MP_NOPTS_VALUE) { + if (subpts_s != MP_NOPTS_VALUE) { if (duration < 0) sub_clear_text(&subs, MP_NOPTS_VALUE); if (type == 'a') { // ssa/ass subs without libass => convert to plaintext @@ -2053,21 +2067,21 @@ void update_subtitles(struct MPContext *mpctx, double refpts, len -= p - packet; packet = p; } - double endpts = MP_NOPTS_VALUE; - if (subpts != MP_NOPTS_VALUE && duration >= 0) - endpts = subpts + duration; - sub_add_text(&subs, packet, len, endpts); + double endpts_s = MP_NOPTS_VALUE; + if (subpts_s != MP_NOPTS_VALUE && duration >= 0) + endpts_s = subpts_s + duration; + sub_add_text(&subs, packet, len, endpts_s); set_osd_subtitle(mpctx, &subs); } if (d_sub->non_interleaved) ds_get_next_pts(d_sub); } if (!opts->ass_enabled) - if (sub_clear_text(&subs, curpts)) + if (sub_clear_text(&subs, curpts_s)) set_osd_subtitle(mpctx, &subs); } if (vo_spudec) { - spudec_heartbeat(vo_spudec, 90000 * curpts); + spudec_heartbeat(vo_spudec, 90000 * curpts_s); if (spudec_changed(vo_spudec)) vo_osd_changed(OSDTYPE_SPU); } @@ -2500,7 +2514,7 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize) return decode_audio(sh_audio, &ao->buffer, playsize); } -static int fill_audio_out_buffers(struct MPContext *mpctx) +static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) { struct MPOpts *opts = &mpctx->opts; struct ao *ao = mpctx->ao; @@ -2562,8 +2576,7 @@ static int fill_audio_out_buffers(struct MPContext *mpctx) t = GetTimer() - t; tt = t * 0.000001f; audio_time_usage += tt; - if (mpctx->timeline && modifiable_audio_format) { - double endpts = mpctx->timeline[mpctx->timeline_part + 1].start; + if (endpts != MP_NOPTS_VALUE && modifiable_audio_format) { double bytes = (endpts - written_audio_pts(mpctx) + audio_delay) * ao->bps / opts->playback_speed; if (playsize > bytes) { @@ -2605,65 +2618,6 @@ static int fill_audio_out_buffers(struct MPContext *mpctx) return -partial_fill; } -static int sleep_until_near_frame(struct MPContext *mpctx, float *time_frame, - bool sync_to_audio, float *aq_sleep_time) -{ - struct MPOpts *opts = &mpctx->opts; - double audio_limit = 2; - current_module = "calc_sleep_time"; - - if (mpctx->restart_playback) - return 0; - - *time_frame -= get_relative_time(mpctx); // reset timer - - if (sync_to_audio) { - float delay = ao_get_delay(mpctx->ao); - mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "delay=%f\n", delay); - - if (opts->autosync) { - /* - * Adjust this raw delay value by calculating the expected - * delay for this frame and generating a new value which is - * weighted between the two. The higher autosync is, the - * closer to the delay value gets to that which "-nosound" - * would have used, and the longer it will take for A/V - * sync to settle at the right value (but it eventually will.) - * This settling time is very short for values below 100. - */ - float predicted = mpctx->delay / opts->playback_speed + *time_frame; - float difference = delay - predicted; - delay = predicted + difference / (float)opts->autosync; - } - - *time_frame = delay - mpctx->delay / opts->playback_speed; - - // delay = amount of audio buffered in soundcard/driver - delay = FFMIN(delay, 0.5); - delay = FFMAX(delay, 0.1); - audio_limit = delay; - } else { - // If we're lagging more than 200 ms behind the right playback rate, - // don't try to "catch up". - // If benchmark is set always output frames as fast as possible - // without sleeping. - if (*time_frame < -0.2 || opts->benchmark) - *time_frame = 0; - } - - double t = *time_frame - mpctx->video_out->flip_queue_offset; - - if (t <= 0.05) - return 0; - - t -= 0.05; - if (t > audio_limit * 0.6) - t = audio_limit * 0.5; - *aq_sleep_time += t; - mp_input_get_cmd(mpctx->input, t * 1000 + 1, 1); - return 1; -} - int reinit_video_chain(struct MPContext *mpctx) { struct MPOpts *opts = &mpctx->opts; @@ -3070,7 +3024,7 @@ static int redraw_osd(struct MPContext *mpctx) return -1; if (vo_redraw_frame(mpctx->video_out) < 0) return -1; - mpctx->osd->pts = mpctx->video_pts; + mpctx->osd->pts = mpctx->video_pts - mpctx->osd->sub_offset; if (!(sh_video->output_flags & VFCAP_EOSD_FILTER)) vf->control(vf, VFCTRL_DRAW_EOSD, mpctx->osd); vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd); @@ -3086,39 +3040,7 @@ void add_step_frame(struct MPContext *mpctx) unpause_player(mpctx); } -static void pause_loop(struct MPContext *mpctx) -{ - mp_cmd_t *cmd; - - update_pause_message(mpctx); - - while ((cmd = mp_input_get_cmd(mpctx->input, 20, 1)) == NULL - || cmd->id == MP_CMD_SET_MOUSE_POS || cmd->pausing == 4) { - if (cmd) { - cmd = mp_input_get_cmd(mpctx->input, 0, 0); - run_command(mpctx, cmd); - mp_cmd_free(cmd); - continue; - } - if (mpctx->sh_video && mpctx->video_out) - vo_check_events(mpctx->video_out); - update_osd_msg(mpctx); - int hack = vo_osd_changed(0); - vo_osd_changed(hack); - if (hack || mpctx->sh_video && mpctx->video_out->want_redraw) - break; - update_pause_message(mpctx); - } -} - -static void reinit_decoders(struct MPContext *mpctx) -{ - reinit_video_chain(mpctx); - reinit_audio_chain(mpctx); - mp_property_do("sub", M_PROPERTY_SET, &(int){mpctx->global_sub_pos}, mpctx); -} - -static void seek_reset(struct MPContext *mpctx, bool reset_ao) +static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac) { if (mpctx->sh_video) { current_module = "seek_video_reset"; @@ -3130,18 +3052,16 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao) mpctx->sh_video->last_pts = MP_NOPTS_VALUE; mpctx->delay = 0; mpctx->time_frame = 0; - mpctx->restart_playback = true; // Not all demuxers set d_video->pts during seek, so this value // (which is used by at least vobsub code below) may be completely // wrong (probably 0). mpctx->sh_video->pts = mpctx->d_video->pts + mpctx->video_offset; mpctx->video_pts = mpctx->sh_video->pts; - update_subtitles(mpctx, mpctx->sh_video->pts, mpctx->video_offset, - true); + update_subtitles(mpctx, mpctx->sh_video->pts, true); update_teletext(mpctx->sh_video, mpctx->demuxer, 1); } - if (mpctx->sh_audio) { + if (mpctx->sh_audio && reset_ac) { current_module = "seek_audio_reset"; resync_audio_stream(mpctx->sh_audio); if (reset_ao) @@ -3149,8 +3069,7 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao) mpctx->ao->buffer.len = mpctx->ao->buffer_playable_size; mpctx->sh_audio->a_buffer_len = 0; if (!mpctx->sh_video) - update_subtitles(mpctx, mpctx->sh_audio->pts, - mpctx->video_offset, true); + update_subtitles(mpctx, mpctx->sh_audio->pts, true); } if (vo_vobsub && mpctx->sh_video) { @@ -3158,6 +3077,7 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao) vobsub_seek(vo_vobsub, mpctx->sh_video->pts); } + mpctx->restart_playback = true; mpctx->hrseek_active = false; mpctx->hrseek_framedrop = false; mpctx->total_avsync_change = 0; @@ -3249,13 +3169,19 @@ static int seek(MPContext *mpctx, struct seek_params seek, if (demuxer_amount == -1) { mpctx->stop_play = AT_END_OF_FILE; // Clear audio from current position - if (mpctx->sh_audio) { + if (mpctx->sh_audio && !timeline_fallthrough) { ao_reset(mpctx->ao); mpctx->sh_audio->a_buffer_len = 0; } return -1; } } + if (need_reset) { + reinit_video_chain(mpctx); + mp_property_do("sub", M_PROPERTY_SET, &(int){mpctx->global_sub_pos}, + mpctx); + } + int demuxer_style = 0; switch (seek.type) { case MPSEEK_FACTOR: @@ -3272,12 +3198,19 @@ static int seek(MPContext *mpctx, struct seek_params seek, demuxer_amount -= opts->hr_seek_demuxer_offset; int seekresult = demux_seek(mpctx->demuxer, demuxer_amount, audio_delay, demuxer_style); - if (need_reset) - reinit_decoders(mpctx); - if (seekresult == 0) + if (seekresult == 0) { + if (need_reset) { + reinit_audio_chain(mpctx); + seek_reset(mpctx, !timeline_fallthrough, false); + } return -1; + } - seek_reset(mpctx, !timeline_fallthrough); + if (need_reset) + reinit_audio_chain(mpctx); + /* If we just reinitialized audio it doesn't need to be reset, + * and resetting could lose audio some decoders produce during init. */ + seek_reset(mpctx, !timeline_fallthrough, !need_reset); /* Use the target time as "current position" for further relative * seeks etc until a new video frame has been decoded */ @@ -3368,9 +3301,11 @@ double get_current_time(struct MPContext *mpctx) struct demuxer *demuxer = mpctx->demuxer; if (demuxer->stream_pts != MP_NOPTS_VALUE) return demuxer->stream_pts; - struct sh_video *sh_video = demuxer->video->sh; - if (sh_video) - return mpctx->video_pts; + if (mpctx->sh_video) { + double pts = mpctx->video_pts; + if (pts != MP_NOPTS_VALUE) + return pts; + } double apts = playing_audio_pts(mpctx); if (apts != MP_NOPTS_VALUE) return apts; @@ -3463,7 +3398,7 @@ int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts) int res = demuxer_seek_chapter(mpctx->demuxer, chapter, seek_pts); if (res >= 0) { if (*seek_pts == -1) - seek_reset(mpctx, true); + seek_reset(mpctx, true, true); else { mpctx->last_chapter_seek = res; mpctx->last_chapter_pts = *seek_pts; @@ -3486,8 +3421,20 @@ int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts) static void run_playloop(struct MPContext *mpctx) { struct MPOpts *opts = &mpctx->opts; - float aq_sleep_time = 0; bool full_audio_buffers = false; + bool audio_left = false, video_left = false; + double endpts = end_at.type == END_AT_TIME ? end_at.pos : MP_NOPTS_VALUE; + bool end_is_chapter = false; + double sleeptime = 0.5; + bool was_restart = mpctx->restart_playback; + + if (mpctx->timeline) { + double end = mpctx->timeline[mpctx->timeline_part + 1].start; + if (endpts == MP_NOPTS_VALUE || end < endpts) { + endpts = end; + end_is_chapter = true; + } + } if (opts->chapterrange[1] > 0) { int cur_chapter = get_current_chapter(mpctx); @@ -3501,79 +3448,27 @@ static void run_playloop(struct MPContext *mpctx) reinit_audio_chain(mpctx); } - /*========================== PLAY AUDIO ============================*/ - - if (!mpctx->sh_video) - mpctx->restart_playback = false; + if (mpctx->step_frames && !mpctx->sh_video) { + mpctx->step_frames = 0; + pause_player(mpctx); + } if (mpctx->sh_audio && !mpctx->restart_playback) { - int status = fill_audio_out_buffers(mpctx); + int status = fill_audio_out_buffers(mpctx, endpts); full_audio_buffers = status >= 0 && !mpctx->ao->untimed; - if (status == -2) - // at eof, all audio at least written to ao - if (!mpctx->sh_video) - mpctx->stop_play = AT_END_OF_FILE; + // Not at audio stream EOF yet + audio_left = status > -2; } - - if (!mpctx->sh_video) { - if (mpctx->step_frames) { - mpctx->step_frames = 0; - pause_player(mpctx); - } - // handle audio-only case: - double a_pos = 0, a_buf = 0; - // sh_audio can be NULL due to video stream switching - // TODO: handle this better - if (mpctx->sh_audio) { - a_buf = ao_get_delay(mpctx->ao); - a_pos = written_audio_pts(mpctx) - mpctx->opts.playback_speed * - a_buf; - } - - print_status(mpctx, a_pos, false); - - update_subtitles(mpctx, a_pos, mpctx->video_offset, false); - update_osd_msg(mpctx); - if (end_at.type == END_AT_TIME && end_at.pos < a_pos) - mpctx->stop_play = AT_END_OF_FILE; - else if (mpctx->timeline && mpctx->stop_play == AT_END_OF_FILE - && mpctx->timeline_part + 1 < mpctx->num_timeline_parts - && mpctx->sh_audio) { - struct timeline_part *p = mpctx->timeline + mpctx->timeline_part; - if (!opts->gapless_audio && p->source != (p + 1)->source - && a_buf > 0.05) { - mpctx->stop_play = KEEP_PLAYING; - mp_input_get_cmd(mpctx->input, (a_buf - .05) * 1000, true); - } else { - seek(mpctx, (struct seek_params){ .type = MPSEEK_ABSOLUTE, - .amount = (p + 1)->start }, - true); - } - } else if (!mpctx->stop_play) { - int sleep_time = 100; - if (mpctx->sh_audio) { - if (mpctx->ao->untimed) - sleep_time = 0; - else if (full_audio_buffers) - sleep_time = FFMAX(20, a_buf * 1000 - 50); - else - sleep_time = 20; - sleep_time = FFMIN(sleep_time, 100); - } - mp_input_get_cmd(mpctx->input, sleep_time, true); - } - } else { - - /*========================== PLAY VIDEO ============================*/ - + double buffered_audio = -1; + while (mpctx->sh_video) { // never loops, for "break;" only vo_pts = mpctx->sh_video->timer * 90000.0; vo_fps = mpctx->sh_video->fps; - bool blit_frame = mpctx->video_out->frame_loaded; - if (!blit_frame) { + video_left = mpctx->video_out->hasframe; + if (!mpctx->video_out->frame_loaded + && (!mpctx->paused || mpctx->restart_playback)) { double frame_time = update_video(mpctx); - blit_frame = mpctx->video_out->frame_loaded; mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "*** ftime=%5.3f ***\n", frame_time); if (mpctx->sh_video->vf_initialized < 0) { mp_tmsg(MSGT_CPLAYER, MSGL_FATAL, @@ -3582,25 +3477,14 @@ static void run_playloop(struct MPContext *mpctx) mpctx->stop_play = PT_NEXT_ENTRY; return; } - if (frame_time < 0) - mpctx->stop_play = AT_END_OF_FILE; - else if (!mpctx->restart_playback) { + video_left = frame_time >= 0; + if (endpts != MP_NOPTS_VALUE) + video_left &= mpctx->sh_video->pts < endpts; + if (video_left && !mpctx->restart_playback) { mpctx->time_frame += frame_time / opts->playback_speed; adjust_sync(mpctx, frame_time); } } - if (mpctx->timeline) { - struct timeline_part *next = - mpctx->timeline + mpctx->timeline_part + 1; - if (mpctx->sh_video->pts >= next->start - || mpctx->stop_play == AT_END_OF_FILE - && mpctx->timeline_part + 1 < mpctx->num_timeline_parts) { - seek(mpctx, (struct seek_params){ .type = MPSEEK_ABSOLUTE, - .amount = next->start }, - true); - return; - } - } // ================================================================ @@ -3622,78 +3506,116 @@ static void run_playloop(struct MPContext *mpctx) } } - bool frame_time_remaining = sleep_until_near_frame(mpctx, - &mpctx->time_frame, - full_audio_buffers, - &aq_sleep_time); + if (!video_left || (mpctx->paused && !mpctx->restart_playback)) + break; + if (!mpctx->video_out->frame_loaded) { + sleeptime = 0; + break; + } + + mpctx->time_frame -= get_relative_time(mpctx); + if (full_audio_buffers && !mpctx->restart_playback) { + buffered_audio = ao_get_delay(mpctx->ao); + mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "delay=%f\n", buffered_audio); + + if (opts->autosync) { + /* Smooth reported playback position from AO by averaging + * it with the value expected based on previus value and + * time elapsed since then. May help smooth video timing + * with audio output that have inaccurate position reporting. + * This is badly implemented; the behavior of the smoothing + * now undesirably depends on how often this code runs + * (mainly depends on video frame rate). */ + float predicted = (mpctx->delay / opts->playback_speed + + mpctx->time_frame); + float difference = buffered_audio - predicted; + buffered_audio = predicted + difference / opts->autosync; + } + + mpctx->time_frame = (buffered_audio - + mpctx->delay / opts->playback_speed); + } else { + /* If we're more than 200 ms behind the right playback + * position, don't try to speed up display of following + * frames to catch up; continue with default speed from + * the current frame instead. + * If benchmark is set always output frames immediately + * without sleeping. + */ + if (mpctx->time_frame < -0.2 || opts->benchmark) + mpctx->time_frame = 0; + } + + double vsleep = mpctx->time_frame - mpctx->video_out->flip_queue_offset; + if (vsleep > 0.050) { + sleeptime = FFMIN(sleeptime, vsleep - 0.040); + break; + } + sleeptime = 0; //=================== FLIP PAGE (VIDEO BLT): ====================== current_module = "flip_page"; - if (!frame_time_remaining && blit_frame) { - vo_new_frame_imminent(mpctx->video_out); - struct sh_video *sh_video = mpctx->sh_video; - mpctx->video_pts = sh_video->pts; - update_subtitles(mpctx, sh_video->pts, mpctx->video_offset, false); - update_teletext(sh_video, mpctx->demuxer, 0); - update_osd_msg(mpctx); - struct vf_instance *vf = sh_video->vfilter; - mpctx->osd->pts = mpctx->video_pts; - vf->control(vf, VFCTRL_DRAW_EOSD, mpctx->osd); - vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd); - vo_osd_changed(0); - - mpctx->time_frame -= mpctx->video_out->flip_queue_offset; - aq_sleep_time += mpctx->time_frame; - // flag 256 means: libvo driver does its timing (dvb card) - if (mpctx->time_frame > 0.001 - && !(mpctx->sh_video->output_flags & VFCAP_TIMER)) - mpctx->time_frame = timing_sleep(mpctx, mpctx->time_frame); - mpctx->time_frame += mpctx->video_out->flip_queue_offset; - - unsigned int t2 = GetTimer(); - /* Playing with playback speed it's possible to get pathological - * cases with mpctx->time_frame negative enough to cause an - * overflow in pts_us calculation, thus the FFMAX. */ - double time_frame = FFMAX(mpctx->time_frame, -1); - unsigned int pts_us = mpctx->last_time + time_frame * 1e6; - int duration = -1; - double pts2 = mpctx->video_out->next_pts2; - if (pts2 != MP_NOPTS_VALUE && opts->correct_pts - && !mpctx->restart_playback) { - // expected A/V sync correction is ignored - double diff = (pts2 - mpctx->video_pts); - diff /= opts->playback_speed; - if (mpctx->time_frame < 0) - diff += mpctx->time_frame; - if (diff < 0) - diff = 0; - if (diff > 10) - diff = 10; - duration = diff * 1e6; - } - vo_flip_page(mpctx->video_out, pts_us | 1, duration); - - mpctx->last_vo_flip_duration = (GetTimer() - t2) * 0.000001; - vout_time_usage += mpctx->last_vo_flip_duration; - if (mpctx->video_out->driver->flip_page_timed) { - // No need to adjust sync based on flip speed - mpctx->last_vo_flip_duration = 0; - // For print_status - VO call finishing early is OK for sync - mpctx->time_frame -= get_relative_time(mpctx); - } - if (mpctx->restart_playback) { - mpctx->syncing_audio = true; - if (mpctx->sh_audio) - fill_audio_out_buffers(mpctx); - mpctx->restart_playback = false; - mpctx->time_frame = 0; - get_relative_time(mpctx); - } - print_status(mpctx, MP_NOPTS_VALUE, true); - screenshot_flip(mpctx); - } else - print_status(mpctx, MP_NOPTS_VALUE, false); + vo_new_frame_imminent(mpctx->video_out); + struct sh_video *sh_video = mpctx->sh_video; + mpctx->video_pts = sh_video->pts; + update_subtitles(mpctx, sh_video->pts, false); + update_teletext(sh_video, mpctx->demuxer, 0); + update_osd_msg(mpctx); + struct vf_instance *vf = sh_video->vfilter; + mpctx->osd->pts = mpctx->video_pts - mpctx->osd->sub_offset; + vf->control(vf, VFCTRL_DRAW_EOSD, mpctx->osd); + vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd); + vo_osd_changed(0); + + mpctx->time_frame -= mpctx->video_out->flip_queue_offset; + float aq_sleep_time = mpctx->time_frame; + if (mpctx->time_frame > 0.001 + && !(mpctx->sh_video->output_flags & VFCAP_TIMER)) + mpctx->time_frame = timing_sleep(mpctx, mpctx->time_frame); + mpctx->time_frame += mpctx->video_out->flip_queue_offset; + + unsigned int t2 = GetTimer(); + /* Playing with playback speed it's possible to get pathological + * cases with mpctx->time_frame negative enough to cause an + * overflow in pts_us calculation, thus the FFMAX. */ + double time_frame = FFMAX(mpctx->time_frame, -1); + unsigned int pts_us = mpctx->last_time + time_frame * 1e6; + int duration = -1; + double pts2 = mpctx->video_out->next_pts2; + if (pts2 != MP_NOPTS_VALUE && opts->correct_pts && + !mpctx->restart_playback) { + // expected A/V sync correction is ignored + double diff = (pts2 - mpctx->video_pts); + diff /= opts->playback_speed; + if (mpctx->time_frame < 0) + diff += mpctx->time_frame; + if (diff < 0) + diff = 0; + if (diff > 10) + diff = 10; + duration = diff * 1e6; + } + vo_flip_page(mpctx->video_out, pts_us | 1, duration); + + mpctx->last_vo_flip_duration = (GetTimer() - t2) * 0.000001; + vout_time_usage += mpctx->last_vo_flip_duration; + if (mpctx->video_out->driver->flip_page_timed) { + // No need to adjust sync based on flip speed + mpctx->last_vo_flip_duration = 0; + // For print_status - VO call finishing early is OK for sync + mpctx->time_frame -= get_relative_time(mpctx); + } + if (mpctx->restart_playback) { + mpctx->syncing_audio = true; + if (mpctx->sh_audio) + fill_audio_out_buffers(mpctx, endpts); + mpctx->restart_playback = false; + mpctx->time_frame = 0; + get_relative_time(mpctx); + } + print_status(mpctx, MP_NOPTS_VALUE, true); + screenshot_flip(mpctx); if (opts->auto_quality > 0) { current_module = "autoq"; @@ -3706,25 +3628,18 @@ static void run_playloop(struct MPContext *mpctx) set_video_quality(mpctx->sh_video, output_quality); } - if (!frame_time_remaining && blit_frame) { - if (play_n_frames >= 0) { - --play_n_frames; - if (play_n_frames <= 0) - mpctx->stop_play = PT_NEXT_ENTRY; - } - if (mpctx->step_frames > 0) { - mpctx->step_frames--; - if (mpctx->step_frames == 0) - pause_player(mpctx); - } + if (play_n_frames >= 0) { + --play_n_frames; + if (play_n_frames <= 0) + mpctx->stop_play = PT_NEXT_ENTRY; } - - // FIXME: add size based support for -endpos - if (end_at.type == END_AT_TIME && - !frame_time_remaining && end_at.pos <= mpctx->sh_video->pts) - mpctx->stop_play = PT_NEXT_ENTRY; - - } // end if(mpctx->sh_video) + if (mpctx->step_frames > 0) { + mpctx->step_frames--; + if (mpctx->step_frames == 0) + pause_player(mpctx); + } + break; + } // video #ifdef CONFIG_DVDNAV if (mpctx->stream->type == STREAMTYPE_DVDNAV) { @@ -3750,48 +3665,116 @@ static void run_playloop(struct MPContext *mpctx) } #endif - //================= Keyboard events, SEEKing ==================== + if (mpctx->restart_playback && !video_left) { + if (mpctx->sh_audio) { + int status = fill_audio_out_buffers(mpctx, endpts); + full_audio_buffers = status >= 0 && !mpctx->ao->untimed; + // Not at audio stream EOF yet + audio_left = status > -2; + } + mpctx->restart_playback = false; + } + if (mpctx->sh_audio && buffered_audio == -1) + buffered_audio = mpctx->paused ? 0 : ao_get_delay(mpctx->ao); - current_module = "key_events"; + update_osd_msg(mpctx); + if (mpctx->paused) + update_pause_message(mpctx); + if (!video_left && (!mpctx->paused || was_restart)) { + double a_pos = 0; + if (mpctx->sh_audio) { + a_pos = (written_audio_pts(mpctx) - + mpctx->opts.playback_speed * buffered_audio); + } + print_status(mpctx, a_pos, false); - while (1) { - mp_cmd_t *cmd; - while |