From 3bf7df4a5e1f46248c78e9e596cd8dab6ff57356 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 29 Dec 2017 15:39:38 +0100 Subject: sub: move all subtitle timestamp messing code to a central place It was split at least across osd.c and sd_ass.c/sd_lavc.c. sd_lavc.c actually ignored most of the more obscure subtitle timing things. There's no reason for this - just move it all to dec_sub.c (mostly from sd_ass.c, because it has some of the most complex stuff). Now timestamps are transformed as they enter or leave dec_sub.c. There appear to have been some subtle mismatches about how subtitle timestamps were transformed, e.g. sd_functions.accepts_packet didn't apply the subtitle speed to the timestamp. This patch should fix them, although it's not clear if they caused actual misbehavior. The semantics of SD_CTRL_SUB_STEP are slightly changed, which is the reason for the changes in command.c and sd_lavc.c. --- sub/dec_sub.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 3 deletions(-) (limited to 'sub/dec_sub.c') diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 11ab879211..b9fdc7adb9 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -57,6 +57,8 @@ struct dec_sub { struct sh_stream *sh; double last_pkt_pts; bool preload_attempted; + double video_fps; + double sub_speed; struct mp_codec_params *codec; double start, end; @@ -67,6 +69,44 @@ struct dec_sub { struct demux_packet *new_segment; }; +static void update_subtitle_speed(struct dec_sub *sub) +{ + struct MPOpts *opts = sub->opts; + sub->sub_speed = 1.0; + + if (sub->video_fps > 0 && sub->codec->frame_based > 0) { + MP_VERBOSE(sub, "Frame based format, dummy FPS: %f, video FPS: %f\n", + sub->codec->frame_based, sub->video_fps); + sub->sub_speed *= sub->codec->frame_based / sub->video_fps; + } + + if (opts->sub_fps && sub->video_fps) + sub->sub_speed *= opts->sub_fps / sub->video_fps; + + sub->sub_speed *= opts->sub_speed; +} + +// Return the subtitle PTS used for a given video PTS. +static double pts_to_subtitle(struct dec_sub *sub, double pts) +{ + struct MPOpts *opts = sub->opts; + + if (pts != MP_NOPTS_VALUE) + pts = (pts - opts->sub_delay) / sub->sub_speed; + + return pts; +} + +static double pts_from_subtitle(struct dec_sub *sub, double pts) +{ + struct MPOpts *opts = sub->opts; + + if (pts != MP_NOPTS_VALUE) + pts = pts * sub->sub_speed + opts->sub_delay; + + return pts; +} + void sub_lock(struct dec_sub *sub) { pthread_mutex_lock(&sub->lock); @@ -140,8 +180,10 @@ struct dec_sub *sub_create(struct mpv_global *global, struct sh_stream *sh, mpthread_mutex_init_recursive(&sub->lock); sub->sd = init_decoder(sub); - if (sub->sd) + if (sub->sd) { + update_subtitle_speed(sub); return sub; + } talloc_free(sub); return NULL; @@ -164,6 +206,7 @@ static void update_segment(struct dec_sub *sub) sub->sd->driver->uninit(sub->sd); talloc_free(sub->sd); sub->sd = new; + update_subtitle_speed(sub); } else { // We'll just keep the current decoder, and feed it possibly // invalid data (not our fault if it crashes or something). @@ -214,6 +257,7 @@ bool sub_read_packets(struct dec_sub *sub, double video_pts) { bool r = true; pthread_mutex_lock(&sub->lock); + video_pts = pts_to_subtitle(sub, video_pts); while (1) { bool read_more = true; if (sub->sd->driver->accepts_packet) @@ -272,6 +316,8 @@ void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, int format, { struct MPOpts *opts = sub->opts; + pts = pts_to_subtitle(sub, pts); + sub->last_vo_pts = pts; update_segment(sub); @@ -291,6 +337,8 @@ char *sub_get_text(struct dec_sub *sub, double pts) struct MPOpts *opts = sub->opts; char *text = NULL; + pts = pts_to_subtitle(sub, pts); + sub->last_vo_pts = pts; update_segment(sub); @@ -324,8 +372,28 @@ int sub_control(struct dec_sub *sub, enum sd_ctrl cmd, void *arg) { int r = CONTROL_UNKNOWN; pthread_mutex_lock(&sub->lock); - if (sub->sd->driver->control) - r = sub->sd->driver->control(sub->sd, cmd, arg); + switch (cmd) { + case SD_CTRL_SET_VIDEO_DEF_FPS: + sub->video_fps = *(double *)arg; + update_subtitle_speed(sub); + break; + case SD_CTRL_UPDATE_SPEED: + update_subtitle_speed(sub); + break; + case SD_CTRL_SUB_STEP: { + double *a = arg; + double arg2[2] = {a[0], a[1]}; + arg2[0] = pts_to_subtitle(sub, arg2[0]); + if (sub->sd->driver->control) + r = sub->sd->driver->control(sub->sd, cmd, arg2); + if (r == CONTROL_OK) + a[0] = pts_from_subtitle(sub, arg2[0]); + break; + } + default: + if (sub->sd->driver->control) + r = sub->sd->driver->control(sub->sd, cmd, arg); + } pthread_mutex_unlock(&sub->lock); return r; } -- cgit v1.2.3