From 7aa8580cabb85345d75e1e579ddffbe4e84b3f84 Mon Sep 17 00:00:00 2001 From: Mohammad AlSaleh Date: Wed, 1 Jul 2026 09:03:31 +0300 Subject: [PATCH] options: store audio/sub delay in doubles instead of floats An `--audio-file` could be sourced from a stream. A stream could be using timestamps that match unix time in their segments. In that case, setting `audio-delay` will lead to a big unexpected A/V desync due to the limited precision of floats. This commit changes `--audio-delay` (and --sub-delay while at it) to be stored in `double` instead of `float`. `audio_delay` was already up-casted to `double` wherever it was evaluated. Same for `sub-delay`, except its own value was getting adjusted based on `double` values in one place (bad!): player/command.c:6297 mpctx->opts->subs_shared->sub_delay[track_ind] -= a[0] - refpts; A showcase: mkfifo /tmp/mpv date=$(date +'%s') Before: mpv --input-ipc-server=/tmp/mpv - echo 'print-text '"${date}" | socat - /tmp/mpv # 1782890841 echo 'set audio-delay '"${date}" | socat - /tmp/mpv echo 'set sub-delay '"${date}" | socat - /tmp/mpv echo 'print-text ${=audio-delay}' | socat - /tmp/mpv # 1782890880.000000 echo 'print-text ${=sub-delay}' | socat - /tmp/mpv # 1782890880.000000 After: mpv --input-ipc-server=/tmp/mpv - echo 'print-text '"${date}" | socat - /tmp/mpv # 1782890841 echo 'set audio-delay '"${date}" | socat - /tmp/mpv echo 'set sub-delay '"${date}" | socat - /tmp/mpv echo 'print-text ${=audio-delay}' | socat - /tmp/mpv # 1782890841.000000 echo 'print-text ${=sub-delay}' | socat - /tmp/mpv # 1782890841.000000 Signed-off-by: Mohammad AlSaleh --- options/options.c | 6 +++--- options/options.h | 4 ++-- sub/dec_sub.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/options/options.c b/options/options.c index 48baef13ff..bab7e324ca 100644 --- a/options/options.c +++ b/options/options.c @@ -381,8 +381,8 @@ const struct m_sub_options mp_subtitle_sub_opts = { const struct m_sub_options mp_subtitle_shared_sub_opts = { .opts = (const struct m_option[]){ - {"sub-delay", OPT_FLOAT(sub_delay[0])}, - {"secondary-sub-delay", OPT_FLOAT(sub_delay[1])}, + {"sub-delay", OPT_DOUBLE(sub_delay[0])}, + {"secondary-sub-delay", OPT_DOUBLE(sub_delay[1])}, {"sub-pos", OPT_FLOAT(sub_pos[0]), M_RANGE(0.0, 150.0)}, {"secondary-sub-pos", OPT_FLOAT(sub_pos[1]), M_RANGE(0.0, 150.0)}, {"sub-visibility", OPT_BOOL(sub_visibility[0])}, @@ -692,7 +692,7 @@ static const m_option_t mp_opts[] = { {"audio-pitch-correction", OPT_BOOL(pitch_correction)}, // set a-v distance - {"audio-delay", OPT_FLOAT(audio_delay)}, + {"audio-delay", OPT_DOUBLE(audio_delay)}, // ------------------------- codec/vfilter options -------------------- diff --git a/options/options.h b/options/options.h index 014e41de6d..d7b9542e27 100644 --- a/options/options.h +++ b/options/options.h @@ -139,7 +139,7 @@ struct mp_subtitle_opts { // Options for both primary and secondary subs. struct mp_subtitle_shared_opts { - float sub_delay[2]; + double sub_delay[2]; float sub_pos[2]; bool sub_visibility[2]; int ass_style_override[2]; @@ -263,7 +263,7 @@ typedef struct MPOpts { int hr_seek; float hr_seek_demuxer_offset; bool hr_seek_framedrop; - float audio_delay; + double audio_delay; float default_max_pts_correction; int autosync; int frame_dropping; diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 2cd3f453dc..33b3878660 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -107,7 +107,7 @@ static void update_subtitle_speed(struct dec_sub *sub) static double pts_to_subtitle(struct dec_sub *sub, double pts) { struct mp_subtitle_shared_opts *opts = sub->shared_opts; - float delay = sub->order < 0 ? 0.0f : opts->sub_delay[sub->order]; + double delay = sub->order < 0 ? 0.0 : opts->sub_delay[sub->order]; if (pts != MP_NOPTS_VALUE) pts = (pts * sub->play_dir - delay) / sub->sub_speed; @@ -118,7 +118,7 @@ static double pts_to_subtitle(struct dec_sub *sub, double pts) static double pts_from_subtitle(struct dec_sub *sub, double pts) { struct mp_subtitle_shared_opts *opts = sub->shared_opts; - float delay = sub->order < 0 ? 0.0f : opts->sub_delay[sub->order]; + double delay = sub->order < 0 ? 0.0 : opts->sub_delay[sub->order]; if (pts != MP_NOPTS_VALUE) pts = (pts * sub->sub_speed + delay) * sub->play_dir; @@ -365,7 +365,7 @@ void sub_read_packets(struct dec_sub *sub, double video_pts, bool force, break; // (Use this mechanism only if sub_delay matters to avoid corner cases.) - float delay = sub->order < 0 ? 0.0f : sub->shared_opts->sub_delay[sub->order]; + double delay = sub->order < 0 ? 0.0 : sub->shared_opts->sub_delay[sub->order]; double min_pts = delay < 0 || force ? video_pts : MP_NOPTS_VALUE; struct demux_packet *pkt;