summaryrefslogtreecommitdiffstats
path: root/sub
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-12-29 15:39:38 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-01-02 14:27:37 -0800
commit3bf7df4a5e1f46248c78e9e596cd8dab6ff57356 (patch)
tree1b49e9e053e063b397552038c7f3309878d65c86 /sub
parent828bd2963cd10a851e0a977809687aed4d377dc3 (diff)
downloadmpv-3bf7df4a5e1f46248c78e9e596cd8dab6ff57356.tar.bz2
mpv-3bf7df4a5e1f46248c78e9e596cd8dab6ff57356.tar.xz
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.
Diffstat (limited to 'sub')
-rw-r--r--sub/dec_sub.c74
-rw-r--r--sub/osd.c8
-rw-r--r--sub/sd_ass.c35
-rw-r--r--sub/sd_lavc.c2
4 files changed, 76 insertions, 43 deletions
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;
}
diff --git a/sub/osd.c b/sub/osd.c
index 0d594cd24d..d2351b7213 100644
--- a/sub/osd.c
+++ b/sub/osd.c
@@ -273,12 +273,8 @@ static void render_object(struct osd_state *osd, struct osd_object *obj,
check_obj_resize(osd, res, obj);
if (obj->type == OSDTYPE_SUB || obj->type == OSDTYPE_SUB2) {
- if (obj->sub) {
- double sub_pts = video_pts;
- if (sub_pts != MP_NOPTS_VALUE)
- sub_pts -= opts->sub_delay;
- sub_get_bitmaps(obj->sub, obj->vo_res, format, sub_pts, out_imgs);
- }
+ if (obj->sub)
+ sub_get_bitmaps(obj->sub, obj->vo_res, format, video_pts, out_imgs);
} else if (obj->type == OSDTYPE_EXTERNAL2) {
if (obj->external2 && obj->external2->format) {
*out_imgs = *obj->external2;
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index 4bc9e15f8a..74d500be8d 100644
--- a/sub/sd_ass.c
+++ b/sub/sd_ass.c
@@ -49,7 +49,6 @@ struct sd_ass_priv {
char last_text[500];
struct mp_image_params video_params;
struct mp_image_params last_params;
- double sub_speed, video_fps, frame_fps;
int64_t *seen_packets;
int num_seen_packets;
bool duration_unknown;
@@ -147,24 +146,6 @@ static void enable_output(struct sd *sd, bool enable)
}
}
-static void update_subtitle_speed(struct sd *sd)
-{
- struct MPOpts *opts = sd->opts;
- struct sd_ass_priv *ctx = sd->priv;
- ctx->sub_speed = 1.0;
-
- if (ctx->video_fps > 0 && ctx->frame_fps > 0) {
- MP_VERBOSE(sd, "Frame based format, dummy FPS: %f, video FPS: %f\n",
- ctx->frame_fps, ctx->video_fps);
- ctx->sub_speed *= ctx->frame_fps / ctx->video_fps;
- }
-
- if (opts->sub_fps && ctx->video_fps)
- ctx->sub_speed *= opts->sub_fps / ctx->video_fps;
-
- ctx->sub_speed *= opts->sub_speed;
-}
-
static int init(struct sd *sd)
{
struct MPOpts *opts = sd->opts;
@@ -212,9 +193,6 @@ static int init(struct sd *sd)
ass_set_check_readorder(ctx->ass_track, sd->opts->sub_clear_on_seek ? 0 : 1);
#endif
- ctx->frame_fps = sd->codec->frame_based;
- update_subtitle_speed(sd);
-
enable_output(sd, true);
ctx->packer = mp_ass_packer_alloc(ctx);
@@ -387,8 +365,6 @@ static long long find_timestamp(struct sd *sd, double pts)
if (pts == MP_NOPTS_VALUE)
return 0;
- pts /= priv->sub_speed;
-
long long ts = llrint(pts * 1000);
if (!sd->opts->sub_fix_timing || sd->opts->ass_style_override == 0)
@@ -679,11 +655,11 @@ static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
switch (cmd) {
case SD_CTRL_SUB_STEP: {
double *a = arg;
- long long ts = llrint(a[0] * (1000.0 / ctx->sub_speed));
+ long long ts = llrint(a[0] * 1000.0);
long long res = ass_step_sub(ctx->ass_track, ts, a[1]);
if (!res)
return false;
- a[0] = res / (1000.0 / ctx->sub_speed);
+ a[0] += res / 1000.0;
return true;
}
case SD_CTRL_SET_VIDEO_PARAMS:
@@ -692,13 +668,6 @@ static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
case SD_CTRL_SET_TOP:
ctx->on_top = *(bool *)arg;
return CONTROL_OK;
- case SD_CTRL_SET_VIDEO_DEF_FPS:
- ctx->video_fps = *(double *)arg;
- update_subtitle_speed(sd);
- return CONTROL_OK;
- case SD_CTRL_UPDATE_SPEED:
- update_subtitle_speed(sd);
- return CONTROL_OK;
default:
return CONTROL_UNKNOWN;
}
diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c
index e805d5c34c..81d8ccfa7d 100644
--- a/sub/sd_lavc.c
+++ b/sub/sd_lavc.c
@@ -561,7 +561,7 @@ static double step_sub(struct sd *sd, double now, int movement)
movement -= direction;
} while (movement);
- return best < 0 ? 0 : priv->seekpoints[best].pts - now;
+ return best < 0 ? now : priv->seekpoints[best].pts;
}
static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)