summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-08-10 18:40:16 +0200
committerwm4 <wm4@nowhere>2015-08-10 18:40:16 +0200
commitfedaad8250b9c9e262da3cda2114ccf5b62703a3 (patch)
treeffd35bcfbb0b50f828ecb7e78756478248311395
parent3d1cc17ab27b98294f5710e69250e95347d84598 (diff)
downloadmpv-fedaad8250b9c9e262da3cda2114ccf5b62703a3.tar.bz2
mpv-fedaad8250b9c9e262da3cda2114ccf5b62703a3.tar.xz
player: separate controls for user and video controlled speed
For video sync, we want separate playback speed controls for user- requested speed and the "correction" speed for video timing. Further, we use this separation to make sure only a resampler is inserted if playback speed is only changed for video sync correction. As of this commit, this is basically inactive code. It's just preparation for the video sync code (the following commit).
-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;