diff options
-rw-r--r-- | DOCS/interface-changes.rst | 1 | ||||
-rw-r--r-- | DOCS/man/input.rst | 4 | ||||
-rw-r--r-- | player/audio.c | 38 | ||||
-rw-r--r-- | player/command.c | 23 | ||||
-rw-r--r-- | player/core.h | 8 | ||||
-rw-r--r-- | player/loadfile.c | 2 | ||||
-rw-r--r-- | player/video.c | 10 |
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; |