aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--DOCS/interface-changes.rst1
-rw-r--r--DOCS/man/input.rst4
-rw-r--r--player/audio.c38
-rw-r--r--player/command.c23
-rw-r--r--player/core.h8
-rw-r--r--player/loadfile.c2
-rw-r--r--player/video.c10
7 files changed, 64 insertions, 22 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst
index d2f186d6d7..20b9664e59 100644
--- a/DOCS/interface-changes.rst
+++ b/DOCS/interface-changes.rst
@@ -20,6 +20,7 @@ Interface changes
::
--- mpv 0.10.0 will be released ---
+ - add "audio-speed-correction" and "video-speed-correction" properties
- remove --demuxer-readahead-packets and --demuxer-readahead-bytes
add --demuxer-max-packets and --demuxer-max-bytes
(the new options are not replacement and have very different semantics)
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst
index c8ea211fdf..10be785ec5 100644
--- a/DOCS/man/input.rst
+++ b/DOCS/man/input.rst
@@ -826,6 +826,10 @@ Property list
``speed`` (RW)
See ``--speed``.
+``audio-speed-correction``, ``video-speed-correction``
+ Factor multiplied with ``speed`` at which the player attempts to play the
+ file. Usually it's exactly 1. (Display sync mode will make this useful.)
+
``filename``
Currently played file, with path stripped. If this is an URL, try to undo
percent encoding as well. (The result is not necessarily correct, but
diff --git a/player/audio.c b/player/audio.c
index 5b19e2fc0c..ab4e50b1b9 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -45,9 +45,14 @@
static int update_playback_speed_filters(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
- double speed = opts->playback_speed;
+ double speed = mpctx->audio_speed;
struct af_stream *afs = mpctx->d_audio->afilter;
+ // Use pitch correction only for speed adjustments by the user, not minor
+ // sync correction ones.
+ bool use_pitch_correction = opts->pitch_correction &&
+ opts->playback_speed != 1.0;
+
// Make sure only exactly one filter changes speed; resetting them all
// and setting 1 filter is the easiest way to achieve this.
af_control_all(afs, AF_CONTROL_SET_PLAYBACK_SPEED, &(double){1});
@@ -63,7 +68,7 @@ static int update_playback_speed_filters(struct MPContext *mpctx)
return 0;
int method = AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE;
- if (opts->pitch_correction)
+ if (use_pitch_correction)
method = AF_CONTROL_SET_PLAYBACK_SPEED;
if (!af_control_any_rev(afs, method, &speed)) {
@@ -88,6 +93,8 @@ static int recreate_audio_filters(struct MPContext *mpctx)
if (update_playback_speed_filters(mpctx) < 0) {
mpctx->opts->playback_speed = 1.0;
+ mpctx->speed_factor_a = 1.0;
+ mpctx->audio_speed = 1.0;
mp_notify(mpctx, MP_EVENT_CHANGE_ALL, NULL);
}
@@ -117,11 +124,20 @@ int reinit_audio_filters(struct MPContext *mpctx)
return 1;
}
-void set_playback_speed(struct MPContext *mpctx, double new_speed)
+// Call this if opts->playback_speed or mpctx->speed_correction changes.
+void update_playback_speed(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
- opts->playback_speed = new_speed;
+ double old_speed_factor_a = mpctx->speed_factor_a;
+ double old_audio_speed = mpctx->audio_speed;
+
+ mpctx->audio_speed = opts->playback_speed * mpctx->speed_factor_a;
+ mpctx->video_speed = opts->playback_speed * mpctx->speed_factor_v;
+
+ if (mpctx->speed_factor_a == old_speed_factor_a &&
+ mpctx->audio_speed == old_audio_speed)
+ return;
if (!mpctx->d_audio || mpctx->d_audio->afilter->initialized < 1)
return;
@@ -300,7 +316,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
if (recreate_audio_filters(mpctx) < 0)
goto init_error;
- set_playback_speed(mpctx, opts->playback_speed);
+ update_playback_speed(mpctx);
return;
@@ -349,9 +365,9 @@ double written_audio_pts(struct MPContext *mpctx)
// accept everything to internal buffers yet
buffered_output += mp_audio_buffer_seconds(mpctx->ao_buffer);
- // Filters divide audio length by playback_speed, so multiply by it
+ // Filters divide audio length by audio_speed, so multiply by it
// to get the length in original units without speedup or slowdown
- a_pts -= buffered_output * mpctx->opts->playback_speed;
+ a_pts -= buffered_output * mpctx->audio_speed;
return a_pts +
get_track_video_offset(mpctx, mpctx->current_track[0][STREAM_AUDIO]);
@@ -363,7 +379,7 @@ double playing_audio_pts(struct MPContext *mpctx)
double pts = written_audio_pts(mpctx);
if (pts == MP_NOPTS_VALUE || !mpctx->ao)
return pts;
- return pts - mpctx->opts->playback_speed * ao_get_delay(mpctx->ao);
+ return pts - mpctx->audio_speed * ao_get_delay(mpctx->ao);
}
static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags)
@@ -378,7 +394,7 @@ static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags
#endif
if (data->samples == 0)
return 0;
- double real_samplerate = out_format.rate / mpctx->opts->playback_speed;
+ double real_samplerate = out_format.rate / mpctx->audio_speed;
int played = ao_play(mpctx->ao, data->planes, data->samples, flags);
assert(played <= data->samples);
if (played > 0) {
@@ -406,7 +422,7 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip)
struct mp_audio out_format = {0};
ao_get_format(mpctx->ao, &out_format);
- double play_samplerate = out_format.rate / opts->playback_speed;
+ double play_samplerate = out_format.rate / mpctx->audio_speed;
if (!opts->initial_audio_sync) {
mpctx->audio_status = STATUS_FILLING;
@@ -483,7 +499,7 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
struct mp_audio out_format = {0};
ao_get_format(mpctx->ao, &out_format);
- double play_samplerate = out_format.rate / opts->playback_speed;
+ double play_samplerate = out_format.rate / mpctx->audio_speed;
// If audio is infinitely fast, somehow try keeping approximate A/V sync.
if (mpctx->audio_status == STATUS_PLAYING && ao_untimed(mpctx->ao) &&
diff --git a/player/command.c b/player/command.c
index c87d9378b7..486c7262b8 100644
--- a/player/command.c
+++ b/player/command.c
@@ -279,9 +279,8 @@ static int mp_property_playback_speed(void *ctx, struct m_property *prop,
double speed = mpctx->opts->playback_speed;
switch (action) {
case M_PROPERTY_SET: {
- double new_speed = *(double *)arg;
- if (speed != new_speed)
- set_playback_speed(mpctx, new_speed);
+ mpctx->opts->playback_speed = *(double *)arg;
+ update_playback_speed(mpctx);
return M_PROPERTY_OK;
}
case M_PROPERTY_PRINT:
@@ -291,6 +290,18 @@ static int mp_property_playback_speed(void *ctx, struct m_property *prop,
return mp_property_generic_option(mpctx, prop, action, arg);
}
+static int mp_property_av_speed_correction(void *ctx, struct m_property *prop,
+ int action, void *arg)
+{
+ MPContext *mpctx = ctx;
+ char *type = prop->priv;
+ switch (type[0]) {
+ case 'a': return m_property_double_ro(action, arg, mpctx->speed_factor_a);
+ case 'v': return m_property_double_ro(action, arg, mpctx->speed_factor_v);
+ }
+ abort();
+}
+
/// filename with path (RO)
static int mp_property_path(void *ctx, struct m_property *prop,
int action, void *arg)
@@ -639,7 +650,7 @@ static int mp_property_playtime_remaining(void *ctx, struct m_property *prop,
if (!time_remaining(mpctx, &remaining))
return M_PROPERTY_UNAVAILABLE;
- double speed = mpctx->opts->playback_speed;
+ double speed = mpctx->video_speed;
return property_time(action, arg, remaining / speed);
}
@@ -3305,6 +3316,8 @@ static const struct m_property mp_properties[] = {
{"loop", mp_property_generic_option},
{"loop-file", mp_property_generic_option},
{"speed", mp_property_playback_speed},
+ {"audio-speed-correction", mp_property_av_speed_correction, .priv = "a"},
+ {"video-speed-correction", mp_property_av_speed_correction, .priv = "v"},
{"filename", mp_property_filename},
{"stream-open-filename", mp_property_stream_open_filename},
{"file-size", mp_property_file_size},
@@ -3536,7 +3549,7 @@ static const char *const *const mp_event_property_change[] = {
E(MPV_EVENT_TICK, "time-pos", "stream-pos", "stream-time-pos", "avsync",
"percent-pos", "time-remaining", "playtime-remaining", "playback-time",
"estimated-vf-fps", "drop-frame-count", "vo-drop-frame-count",
- "total-avsync-change"),
+ "total-avsync-change", "audio-speed-correction", "video-speed-correction"),
E(MPV_EVENT_VIDEO_RECONFIG, "video-out-params", "video-params",
"video-format", "video-codec", "video-bitrate", "dwidth", "dheight",
"width", "height", "fps", "aspect", "vo-configured", "current-vo",
diff --git a/player/core.h b/player/core.h
index 75dd2edec7..092775f40e 100644
--- a/player/core.h
+++ b/player/core.h
@@ -238,6 +238,12 @@ typedef struct MPContext {
enum playback_status video_status, audio_status;
bool restart_complete;
+ // Factors to multiply with opts->playback_speed to get the total audio or
+ // video speed (usually 1.0, but can be set to by the sync code).
+ double speed_factor_v, speed_factor_a;
+ // Redundant values set from opts->playback_speed and speed_factor_*.
+ // update_playback_speed() updates them from the other fields.
+ double audio_speed, video_speed;
bool broken_fps_header;
/* Set if audio should be timed to start with video frame after seeking,
* not set when e.g. playing cover art */
@@ -362,7 +368,7 @@ double playing_audio_pts(struct MPContext *mpctx);
void fill_audio_out_buffers(struct MPContext *mpctx, double endpts);
double written_audio_pts(struct MPContext *mpctx);
void clear_audio_output_buffers(struct MPContext *mpctx);
-void set_playback_speed(struct MPContext *mpctx, double new_speed);
+void update_playback_speed(struct MPContext *mpctx);
void uninit_audio_out(struct MPContext *mpctx);
void uninit_audio_chain(struct MPContext *mpctx);
diff --git a/player/loadfile.c b/player/loadfile.c
index 6d94c13bd3..23ffafc1b9 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -1018,6 +1018,8 @@ static void play_current_file(struct MPContext *mpctx)
mpctx->playing_msg_shown = false;
mpctx->backstep_active = false;
mpctx->max_frames = -1;
+ mpctx->video_speed = mpctx->audio_speed = opts->playback_speed;
+ mpctx->speed_factor_a = mpctx->speed_factor_v = 1.0;
mpctx->broken_fps_header = false;
mpctx->seek = (struct seek_params){ 0 };
diff --git a/player/video.c b/player/video.c
index 539a75c08e..13f40430de 100644
--- a/player/video.c
+++ b/player/video.c
@@ -581,7 +581,7 @@ static void handle_new_frame(struct MPContext *mpctx)
mpctx->video_next_pts = pts;
mpctx->delay -= frame_time;
if (mpctx->video_status >= STATUS_PLAYING) {
- mpctx->time_frame += frame_time / mpctx->opts->playback_speed;
+ mpctx->time_frame += frame_time / mpctx->video_speed;
adjust_sync(mpctx, pts, frame_time);
}
mpctx->dropped_frames = 0;
@@ -711,7 +711,7 @@ static void update_avsync_before_frame(struct MPContext *mpctx)
{
double buffered_audio = ao_get_delay(mpctx->ao);
- double predicted = mpctx->delay / opts->playback_speed +
+ double predicted = mpctx->delay / mpctx->video_speed +
mpctx->time_frame;
double difference = buffered_audio - predicted;
MP_STATS(mpctx, "value %f audio-diff", difference);
@@ -727,7 +727,7 @@ static void update_avsync_before_frame(struct MPContext *mpctx)
buffered_audio = predicted + difference / opts->autosync;
}
- mpctx->time_frame = buffered_audio - mpctx->delay / opts->playback_speed;
+ mpctx->time_frame = buffered_audio - mpctx->delay / mpctx->video_speed;
} else {
/* If we're more than 200 ms behind the right playback
* position, don't try to speed up display of following
@@ -756,7 +756,7 @@ static void update_avsync_after_frame(struct MPContext *mpctx)
mpctx->last_av_difference = a_pos - mpctx->video_pts + opts->audio_delay;
if (mpctx->time_frame > 0)
- mpctx->last_av_difference += mpctx->time_frame * opts->playback_speed;
+ mpctx->last_av_difference += mpctx->time_frame * mpctx->video_speed;
if (a_pos == MP_NOPTS_VALUE || mpctx->video_pts == MP_NOPTS_VALUE) {
mpctx->last_av_difference = 0;
} else if (fabs(mpctx->last_av_difference) > 0.5 && !mpctx->drop_message_shown) {
@@ -968,7 +968,7 @@ void write_video(struct MPContext *mpctx, double endpts)
double diff = get_frame_duration(mpctx, 0);
if (diff >= 0) {
// expected A/V sync correction is ignored
- diff /= opts->playback_speed;
+ diff /= mpctx->video_speed;
if (mpctx->time_frame < 0)
diff += mpctx->time_frame;
frame->duration = MPCLAMP(diff, 0, 10) * 1e6;