summaryrefslogtreecommitdiffstats
path: root/player/playloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'player/playloop.c')
-rw-r--r--player/playloop.c113
1 files changed, 73 insertions, 40 deletions
diff --git a/player/playloop.c b/player/playloop.c
index 87c8b6390c..3118d391ea 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -23,7 +23,6 @@
#include "client.h"
#include "command.h"
-#include "config.h"
#include "core.h"
#include "mpv_talloc.h"
#include "screenshot.h"
@@ -33,7 +32,6 @@
#include "common/encode.h"
#include "common/msg.h"
#include "common/playlist.h"
-#include "common/recorder.h"
#include "common/stats.h"
#include "demux/demux.h"
#include "filters/f_decoder_wrapper.h"
@@ -77,7 +75,7 @@ void mp_set_timeout(struct MPContext *mpctx, double sleeptime)
{
if (mpctx->sleeptime > sleeptime) {
mpctx->sleeptime = sleeptime;
- int64_t abstime = mp_add_timeout(mp_time_us(), sleeptime);
+ int64_t abstime = mp_time_ns_add(mp_time_ns(), sleeptime);
mp_dispatch_adjust_timeout(mpctx->dispatch, abstime);
}
}
@@ -125,10 +123,10 @@ static void mp_process_input(struct MPContext *mpctx)
double get_relative_time(struct MPContext *mpctx)
{
- int64_t new_time = mp_time_us();
+ int64_t new_time = mp_time_ns();
int64_t delta = new_time - mpctx->last_time;
mpctx->last_time = new_time;
- return delta * 0.000001;
+ return delta * 1e-9;
}
void update_core_idle_state(struct MPContext *mpctx)
@@ -163,8 +161,10 @@ void set_pause_state(struct MPContext *mpctx, bool user_pause)
if (internal_paused != mpctx->paused) {
mpctx->paused = internal_paused;
- if (mpctx->ao)
- ao_set_paused(mpctx->ao, internal_paused);
+ if (mpctx->ao) {
+ bool eof = mpctx->audio_status == STATUS_EOF;
+ ao_set_paused(mpctx->ao, internal_paused, eof);
+ }
if (mpctx->video_out)
vo_set_paused(mpctx->video_out, internal_paused);
@@ -180,10 +180,6 @@ void set_pause_state(struct MPContext *mpctx, bool user_pause)
} else {
(void)get_relative_time(mpctx); // ignore time that passed during pause
}
-
- // For some reason, these events are supposed to be sent even if only
- // the internal pause state changed (and "pause" property didn't)... OK.
- mp_notify(mpctx, opts->pause ? MPV_EVENT_PAUSE : MPV_EVENT_UNPAUSE, 0);
}
update_core_idle_state(mpctx);
@@ -201,7 +197,8 @@ void update_screensaver_state(struct MPContext *mpctx)
if (!mpctx->video_out)
return;
- bool saver_state = !mpctx->playback_active || !mpctx->opts->stop_screensaver;
+ bool saver_state = (!mpctx->playback_active || !mpctx->opts->stop_screensaver) &&
+ mpctx->opts->stop_screensaver != 2;
vo_control_async(mpctx->video_out, saver_state ? VOCTRL_RESTORE_SCREENSAVER
: VOCTRL_KILL_SCREENSAVER, NULL);
}
@@ -239,6 +236,10 @@ void reset_playback_state(struct MPContext *mpctx)
sub_set_play_dir(t->d_sub, mpctx->play_dir);
}
+ // May need unpause first
+ if (mpctx->paused_for_cache)
+ update_internal_pause_state(mpctx);
+
mpctx->hrseek_active = false;
mpctx->hrseek_lastframe = false;
mpctx->hrseek_backstep = false;
@@ -264,6 +265,13 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
if (!mpctx->demuxer || !seek.type || seek.amount == MP_NOPTS_VALUE)
return;
+ if (seek.type == MPSEEK_CHAPTER) {
+ mpctx->last_chapter_flag = false;
+ seek.type = MPSEEK_ABSOLUTE;
+ } else {
+ mpctx->last_chapter_seek = -2;
+ }
+
bool hr_seek_very_exact = seek.exact == MPSEEK_VERY_EXACT;
double current_time = get_playback_time(mpctx);
if (current_time == MP_NOPTS_VALUE && seek.type == MPSEEK_RELATIVE)
@@ -290,7 +298,7 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
if (len >= 0)
seek_pts = seek.amount * len;
break;
- default: abort();
+ default: MP_ASSERT_UNREACHABLE();
}
double demux_pts = seek_pts;
@@ -300,10 +308,6 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
(opts->hr_seek >= 0 && seek.type == MPSEEK_ABSOLUTE) ||
(opts->hr_seek == 2 && (!mpctx->vo_chain || mpctx->vo_chain->is_sparse)));
- if (seek.type == MPSEEK_FACTOR || seek.amount < 0 ||
- (seek.type == MPSEEK_ABSOLUTE && seek.amount < mpctx->last_chapter_pts))
- mpctx->last_chapter_seek = -2;
-
// Under certain circumstances, prefer SEEK_FACTOR.
if (seek.type == MPSEEK_FACTOR && !hr_seek &&
(mpctx->demuxer->ts_resets_possible || seek_pts == MP_NOPTS_VALUE))
@@ -371,8 +375,6 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
clear_audio_output_buffers(mpctx);
reset_playback_state(mpctx);
- if (mpctx->recorder)
- mp_recorder_mark_discontinuity(mpctx->recorder);
demux_block_reading(mpctx->demuxer, false);
for (int t = 0; t < mpctx->num_tracks; t++) {
@@ -417,6 +419,7 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek)
update_ab_loop_clip(mpctx);
mpctx->current_seek = seek;
+ redraw_subs(mpctx);
}
// This combines consecutive seek requests.
@@ -427,9 +430,6 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
mp_wakeup_core(mpctx);
- if (mpctx->stop_play == AT_END_OF_FILE)
- mpctx->stop_play = KEEP_PLAYING;
-
switch (type) {
case MPSEEK_RELATIVE:
seek->flags |= flags;
@@ -446,6 +446,7 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
case MPSEEK_ABSOLUTE:
case MPSEEK_FACTOR:
case MPSEEK_BACKSTEP:
+ case MPSEEK_CHAPTER:
*seek = (struct seek_params) {
.type = type,
.amount = amount,
@@ -457,7 +458,7 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
*seek = (struct seek_params){ 0 };
return;
}
- abort();
+ MP_ASSERT_UNREACHABLE();
}
void execute_queued_seek(struct MPContext *mpctx)
@@ -583,7 +584,8 @@ int get_current_chapter(struct MPContext *mpctx)
for (i = 0; i < mpctx->num_chapters; i++)
if (current_pts < mpctx->chapters[i].pts)
break;
- return MPMAX(mpctx->last_chapter_seek, i - 1);
+ return mpctx->last_chapter_flag ?
+ mpctx->last_chapter_seek : MPMAX(mpctx->last_chapter_seek, i - 1);
}
char *chapter_display_name(struct MPContext *mpctx, int chapter)
@@ -642,7 +644,7 @@ void update_ab_loop_clip(struct MPContext *mpctx)
static void handle_osd_redraw(struct MPContext *mpctx)
{
- if (!mpctx->video_out || !mpctx->video_out->config_ok)
+ if (!mpctx->video_out || !mpctx->video_out->config_ok || (mpctx->playing && mpctx->stop_play))
return;
// If we're playing normally, let OSD be redrawn naturally as part of
// video display.
@@ -661,6 +663,9 @@ static void handle_osd_redraw(struct MPContext *mpctx)
if (!want_redraw)
return;
vo_redraw(mpctx->video_out);
+ // Even though we just redrew, it may need to be done again for certain
+ // cases of subtitles on an image.
+ redraw_subs(mpctx);
}
static void clear_underruns(struct MPContext *mpctx)
@@ -706,7 +711,7 @@ static void handle_update_cache(struct MPContext *mpctx)
}
bool is_low = use_pause_on_low_cache && !s.idle &&
- s.ts_duration < opts->cache_pause_wait;
+ s.ts_info.duration < opts->cache_pause_wait;
// Enter buffering state only if there actually was an underrun (or if
// initial caching before playback restart is used).
@@ -746,7 +751,7 @@ static void handle_update_cache(struct MPContext *mpctx)
if (mpctx->paused_for_cache) {
cache_buffer =
- 100 * MPCLAMP(s.ts_duration / opts->cache_pause_wait, 0, 0.99);
+ 100 * MPCLAMP(s.ts_info.duration / opts->cache_pause_wait, 0, 0.99);
mp_set_timeout(mpctx, 0.2);
}
@@ -767,15 +772,15 @@ static void handle_update_cache(struct MPContext *mpctx)
if ((mpctx->cache_buffer == 100) != (cache_buffer == 100)) {
if (cache_buffer < 100) {
MP_VERBOSE(mpctx, "Enter buffering (buffer went from %d%% -> %d%%) [%fs].\n",
- mpctx->cache_buffer, cache_buffer, s.ts_duration);
+ mpctx->cache_buffer, cache_buffer, s.ts_info.duration);
} else {
double t = now - mpctx->cache_stop_time;
MP_VERBOSE(mpctx, "End buffering (waited %f secs) [%fs].\n",
- t, s.ts_duration);
+ t, s.ts_info.duration);
}
} else {
MP_VERBOSE(mpctx, "Still buffering (buffer went from %d%% -> %d%%) [%fs].\n",
- mpctx->cache_buffer, cache_buffer, s.ts_duration);
+ mpctx->cache_buffer, cache_buffer, s.ts_info.duration);
}
mpctx->cache_buffer = cache_buffer;
force_update = true;
@@ -795,6 +800,22 @@ int get_cache_buffering_percentage(struct MPContext *mpctx)
return mpctx->demuxer ? mpctx->cache_buffer : -1;
}
+static void handle_update_subtitles(struct MPContext *mpctx)
+{
+ if (mpctx->video_status == STATUS_EOF) {
+ update_subtitles(mpctx, mpctx->playback_pts);
+ return;
+ }
+
+ for (int n = 0; n < mpctx->num_tracks; n++) {
+ struct track *track = mpctx->tracks[n];
+ if (track->type == STREAM_SUB && !track->demuxer_ready) {
+ update_subtitles(mpctx, mpctx->playback_pts);
+ break;
+ }
+ }
+}
+
static void handle_cursor_autohide(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
@@ -941,13 +962,16 @@ static void handle_keep_open(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
if (opts->keep_open && mpctx->stop_play == AT_END_OF_FILE &&
- (opts->keep_open == 2 || !playlist_get_next(mpctx->playlist, 1)) &&
- opts->loop_times == 1)
+ (opts->keep_open == 2 ||
+ (!playlist_get_next(mpctx->playlist, 1) && opts->loop_times == 1)))
{
mpctx->stop_play = KEEP_PLAYING;
if (mpctx->vo_chain) {
- if (!vo_has_frame(mpctx->video_out)) // EOF not reached normally
+ if (!vo_has_frame(mpctx->video_out)) { // EOF not reached normally
seek_to_last_frame(mpctx);
+ mpctx->audio_status = STATUS_EOF;
+ mpctx->video_status = STATUS_EOF;
+ }
}
if (opts->keep_open_pause) {
if (mpctx->ao && ao_is_playing(mpctx->ao))
@@ -962,7 +986,7 @@ static void handle_chapter_change(struct MPContext *mpctx)
int chapter = get_current_chapter(mpctx);
if (chapter != mpctx->last_chapter) {
mpctx->last_chapter = chapter;
- mp_notify(mpctx, MPV_EVENT_CHAPTER_CHANGE, NULL);
+ mp_notify(mpctx, MP_EVENT_CHAPTER_CHANGE, NULL);
}
}
@@ -1023,15 +1047,22 @@ int handle_force_window(struct MPContext *mpctx, bool force)
break;
}
}
+
+ // Use a 16:9 aspect ratio so that fullscreen on a 16:9 screen will not
+ // have vertical margins, which can lead to a different size or position
+ // of subtitles than with 16:9 videos.
int w = 960;
- int h = 480;
+ int h = 540;
struct mp_image_params p = {
.imgfmt = config_format,
.w = w, .h = h,
.p_w = 1, .p_h = 1,
+ .force_window = true,
};
if (vo_reconfig(vo, &p) < 0)
goto err;
+ struct track *track = mpctx->current_track[0][STREAM_VIDEO];
+ update_content_type(mpctx, track);
update_screensaver_state(mpctx);
vo_set_paused(vo, true);
vo_redraw(vo);
@@ -1078,8 +1109,7 @@ static void handle_playback_time(struct MPContext *mpctx)
} else if (mpctx->video_status == STATUS_EOF &&
mpctx->audio_status == STATUS_EOF)
{
- double apts =
- mpctx->ao_chain ? mpctx->ao_chain->last_out_pts : MP_NOPTS_VALUE;
+ double apts = playing_audio_pts(mpctx);
double vpts = mpctx->video_pts;
double mpts = MP_PTS_MAX(apts, vpts);
if (mpts != MP_NOPTS_VALUE)
@@ -1123,6 +1153,7 @@ static void handle_playback_restart(struct MPContext *mpctx)
mpctx->hrseek_active = false;
mpctx->restart_complete = true;
mpctx->current_seek = (struct seek_params){0};
+ run_command_opts(mpctx);
handle_playback_time(mpctx);
mp_notify(mpctx, MPV_EVENT_PLAYBACK_RESTART, NULL);
update_core_idle_state(mpctx);
@@ -1138,7 +1169,9 @@ static void handle_playback_restart(struct MPContext *mpctx)
if (opts->osd_playing_msg && opts->osd_playing_msg[0]) {
char *msg =
mp_property_expand_escaped_string(mpctx, opts->osd_playing_msg);
- set_osd_msg(mpctx, 1, opts->osd_duration, "%s", msg);
+ set_osd_msg(mpctx, 1, opts->osd_playing_msg_duration ?
+ opts->osd_playing_msg_duration : opts->osd_duration,
+ "%s", msg);
talloc_free(msg);
}
}
@@ -1213,8 +1246,8 @@ void run_playloop(struct MPContext *mpctx)
handle_dummy_ticks(mpctx);
update_osd_msg(mpctx);
- if (mpctx->video_status == STATUS_EOF)
- update_subtitles(mpctx, mpctx->playback_pts);
+
+ handle_update_subtitles(mpctx);
handle_each_frame_screenshot(mpctx);