From dea512ea38605b6e203e98c1684f819e4aa465f1 Mon Sep 17 00:00:00 2001 From: Ripose Date: Wed, 22 Nov 2023 20:13:57 -0700 Subject: [PATCH] options: add secondary-sub-delay Add --secondary-sub-delay option and decouple --sub-delay from secondary subtitles. This produces desirable behavior in most cases as secondary and primary subtitles tracks tend to be timed independently of one another. This feature is implemented by turning the sub_delay field in mp_subtitle_opts into an array of 2 floats. From here the track index is either passed around or derived when sub_delay is needed. There are some cases in dec_sub.c where it is possible for dec_sub.order (equivalent to track index) to be -1. In these cases, sub_delay is inferred as 0. --- DOCS/interface-changes.rst | 2 ++ DOCS/man/options.rst | 5 ++++- options/options.c | 3 ++- options/options.h | 2 +- player/command.c | 17 ++++++++++++----- player/misc.c | 7 ++++++- sub/dec_sub.c | 9 ++++++--- 7 files changed, 33 insertions(+), 12 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 53975f2a3a..94bc6772f2 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -28,6 +28,8 @@ Interface changes --- mpv 0.38.0 --- - remove shared-script-properties (user-data is a replacement) + - add `--secondary-sub-delay`, decouple secondary subtitles from + `--sub-delay` --- mpv 0.37.0 --- - `--save-position-on-quit` and its associated commands now store state files in %LOCALAPPDATA% instead of %APPDATA% directory by default on Windows. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 6025705a99..f80fc77904 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2312,7 +2312,10 @@ Subtitles printed by ``--sub-demuxer=help``. ``--sub-delay=`` - Delays subtitles by ```` seconds. Can be negative. + Delays primary subtitles by ```` seconds. Can be negative. + +``--secondary-sub-delay=`` + Delays secondary subtitles by ```` seconds. Can be negative. ``--sub-files=``, ``--sub-file=`` Add a subtitle file to the list of external subtitles. diff --git a/options/options.c b/options/options.c index 7c6ffa5ccd..526ef7d634 100644 --- a/options/options.c +++ b/options/options.c @@ -281,7 +281,8 @@ const struct m_sub_options mp_sub_filter_opts = { const struct m_sub_options mp_subtitle_sub_opts = { .opts = (const struct m_option[]){ - {"sub-delay", OPT_FLOAT(sub_delay)}, + {"sub-delay", OPT_FLOAT(sub_delay[0])}, + {"secondary-sub-delay", OPT_FLOAT(sub_delay[1])}, {"sub-fps", OPT_FLOAT(sub_fps)}, {"sub-speed", OPT_FLOAT(sub_speed)}, {"sub-visibility", OPT_BOOL(sub_visibility)}, diff --git a/options/options.h b/options/options.h index aa071b28f6..9f55d5b8b1 100644 --- a/options/options.h +++ b/options/options.h @@ -85,7 +85,7 @@ struct mp_subtitle_opts { bool sub_visibility; bool sec_sub_visibility; float sub_pos; - float sub_delay; + float sub_delay[2]; float sub_fps; float sub_speed; bool sub_forced_events_only; diff --git a/player/command.c b/player/command.c index 84cda39adb..4ec0b5277d 100644 --- a/player/command.c +++ b/player/command.c @@ -2874,9 +2874,10 @@ static int mp_property_sub_delay(void *ctx, struct m_property *prop, { MPContext *mpctx = ctx; struct MPOpts *opts = mpctx->opts; + int track_ind = *(int *)prop->priv; switch (action) { case M_PROPERTY_PRINT: - *(char **)arg = format_delay(opts->subs_rend->sub_delay); + *(char **)arg = format_delay(opts->subs_rend->sub_delay[track_ind]); return M_PROPERTY_OK; } return mp_property_generic_option(mpctx, prop, action, arg); @@ -3929,7 +3930,9 @@ static const struct m_property mp_properties_base[] = { {"sid", property_switch_track, .priv = (void *)(const int[]){0, STREAM_SUB}}, {"secondary-sid", property_switch_track, .priv = (void *)(const int[]){1, STREAM_SUB}}, - {"sub-delay", mp_property_sub_delay}, + {"sub-delay", mp_property_sub_delay, .priv = (void *)&(const int){0}}, + {"secondary-sub-delay", mp_property_sub_delay, + .priv = (void *)&(const int){1}}, {"sub-speed", mp_property_sub_speed}, {"sub-pos", mp_property_sub_pos}, {"sub-ass-extradata", mp_property_sub_ass_extradata}, @@ -4246,6 +4249,7 @@ static const struct property_osd_display { {"secondary-sid", "Secondary subtitles"}, {"sub-pos", "Sub position"}, {"sub-delay", "Sub delay"}, + {"secondary-sub-delay", "Secondary sub delay"}, {"sub-speed", "Sub speed"}, {"sub-visibility", .msg = "Subtitles ${!sub-visibility==yes:hidden}" @@ -5380,10 +5384,13 @@ static void cmd_sub_step_seek(void *p) a[1] = cmd->args[0].v.i; if (sub_control(sub, SD_CTRL_SUB_STEP, a) > 0) { if (step) { - mpctx->opts->subs_rend->sub_delay -= a[0] - refpts; + mpctx->opts->subs_rend->sub_delay[track_ind] -= a[0] - refpts; m_config_notify_change_opt_ptr_notify(mpctx->mconfig, - &mpctx->opts->subs_rend->sub_delay); - show_property_osd(mpctx, "sub-delay", cmd->on_osd); + &mpctx->opts->subs_rend->sub_delay[track_ind]); + show_property_osd( + mpctx, + track_ind == 0 ? "sub-delay" : "secondary-sub-delay", + cmd->on_osd); } else { // We can easily seek/step to the wrong subtitle line (because // video frame PTS and sub PTS rarely match exactly). Add an diff --git a/player/misc.c b/player/misc.c index b91d52a607..d267c51906 100644 --- a/player/misc.c +++ b/player/misc.c @@ -147,7 +147,12 @@ double get_track_seek_offset(struct MPContext *mpctx, struct track *track) if (track->type == STREAM_AUDIO) return -opts->audio_delay; if (track->type == STREAM_SUB) - return -opts->subs_rend->sub_delay; + { + for (int n = 0; n < num_ptracks[STREAM_SUB]; n++) { + if (mpctx->current_track[n][STREAM_SUB] == track) + return -opts->subs_rend->sub_delay[n]; + } + } } return 0; } diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 18d826e8b5..195a14abea 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -92,9 +92,10 @@ static void update_subtitle_speed(struct dec_sub *sub) static double pts_to_subtitle(struct dec_sub *sub, double pts) { struct mp_subtitle_opts *opts = sub->opts; + float delay = sub->order < 0 ? 0.0f : opts->sub_delay[sub->order]; if (pts != MP_NOPTS_VALUE) - pts = (pts * sub->play_dir - opts->sub_delay) / sub->sub_speed; + pts = (pts * sub->play_dir - delay) / sub->sub_speed; return pts; } @@ -102,9 +103,10 @@ 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_opts *opts = sub->opts; + float delay = sub->order < 0 ? 0.0f : opts->sub_delay[sub->order]; if (pts != MP_NOPTS_VALUE) - pts = (pts * sub->sub_speed + opts->sub_delay) * sub->play_dir; + pts = (pts * sub->sub_speed + delay) * sub->play_dir; return pts; } @@ -291,7 +293,8 @@ bool 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.) - double min_pts = sub->opts->sub_delay < 0 || force ? video_pts : MP_NOPTS_VALUE; + float delay = sub->order < 0 ? 0.0f : sub->opts->sub_delay[sub->order]; + double min_pts = delay < 0 || force ? video_pts : MP_NOPTS_VALUE; struct demux_packet *pkt; int st = demux_read_packet_async_until(sub->sh, min_pts, &pkt);