summaryrefslogtreecommitdiffstats
path: root/mplayer.c
diff options
context:
space:
mode:
authorwm4 <wm4@mplayer2.org>2012-04-01 22:52:33 +0200
committerwm4 <wm4@mplayer2.org>2012-04-01 22:52:33 +0200
commit1aa2e36122e6e664e42170f47d6db82873bef5aa (patch)
tree39e13f93bcb606da9e365c7cd379132bdf53c20b /mplayer.c
parentfea8c85c8595b797fc839b113c1db252fc55c798 (diff)
parent8cd71527ade21ea27ea24cdcc66dc71dca460f85 (diff)
downloadmpv-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.c661
1 files changed, 322 insertions, 339 deletions
diff --git a/mplayer.c b/mplayer.c
index 004bbc621a..05bcf26fae 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -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, &timestamp);
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 ((cmd = mp_input_get_cmd(mpctx->input, 0, 1)) != NULL) {
- /* Allow running consecutive seek commands to combine them,
- * but execute the seek before running other commands.
- * If the user seeks continuously (keeps arrow key down)
-