summaryrefslogtreecommitdiffstats
path: root/sub
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-12-05 23:55:35 +0100
committerwm4 <wm4@nowhere>2015-12-05 23:55:35 +0100
commit9a240dc82e442a2f1d3d383c4b32f3eaab0a1f6a (patch)
treef785e15828be5a0146553686cf8b7c54c8bf3bc7 /sub
parenta7cf0915191f6f01f6d66534aba98d6cbf7996f5 (diff)
downloadmpv-9a240dc82e442a2f1d3d383c4b32f3eaab0a1f6a.tar.bz2
mpv-9a240dc82e442a2f1d3d383c4b32f3eaab0a1f6a.tar.xz
sd_lavc: discard empty subtitles and improve sub_seek behavior
Image subtitles often use a "signaling" packet to set the end time of the previous subtitle. As far as the libavcodec API is concerned, such packets decode to empty AVSubtitles. Discard these after the end time of the previous subtitle has been set. Keep track of the per-subtitle end time better. This is for the sake of improving sub_step/sub_seek. Without this, it would seek to the sub before the previous sub, if the current sub has ended displaying.
Diffstat (limited to 'sub')
-rw-r--r--sub/sd_lavc.c76
1 files changed, 49 insertions, 27 deletions
diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c
index e46ffc02ab..d6f6bf8e48 100644
--- a/sub/sd_lavc.c
+++ b/sub/sd_lavc.c
@@ -46,6 +46,11 @@ struct sub {
int64_t id;
};
+struct seekpoint {
+ double pts;
+ double endpts;
+};
+
struct sd_lavc_priv {
AVCodecContext *avctx;
struct sub subs[MAX_QUEUE]; // most recent event first
@@ -54,8 +59,8 @@ struct sd_lavc_priv {
int64_t new_id;
struct mp_image_params video_params;
double current_pts;
- double *timestamps;
- int num_timestamps;
+ struct seekpoint *seekpoints;
+ int num_seekpoints;
};
static bool supports_format(const char *format)
@@ -158,6 +163,7 @@ static void decode(struct sd *sd, struct demux_packet *packet)
struct sd_lavc_priv *priv = sd->priv;
AVCodecContext *ctx = priv->avctx;
double pts = packet->pts;
+ double endpts = MP_NOPTS_VALUE;
double duration = packet->duration;
AVSubtitle sub;
AVPacket pkt;
@@ -186,14 +192,30 @@ static void decode(struct sd *sd, struct demux_packet *packet)
duration = (sub.end_display_time - sub.start_display_time) / 1000.0;
}
pts += sub.start_display_time / 1000.0;
- }
- double endpts = MP_NOPTS_VALUE;
- if (pts != MP_NOPTS_VALUE && duration >= 0)
- endpts = pts + duration;
- // set end time of previous sub
- if (priv->subs[0].endpts == MP_NOPTS_VALUE || priv->subs[0].endpts > pts)
- priv->subs[0].endpts = pts;
+ if (duration >= 0)
+ endpts = pts + duration;
+
+ // set end time of previous sub
+ struct sub *prev = &priv->subs[0];
+ if (prev->valid) {
+ if (prev->endpts == MP_NOPTS_VALUE || prev->endpts > pts)
+ prev->endpts = pts;
+
+ for (int n = 0; n < priv->num_seekpoints; n++) {
+ if (priv->seekpoints[n].pts == prev->pts) {
+ priv->seekpoints[n].endpts = prev->endpts;
+ break;
+ }
+ }
+ }
+
+ // This subtitle packet only signals the end of subtitle display.
+ if (!sub.num_rects) {
+ avsubtitle_free(&sub);
+ return;
+ }
+ }
alloc_sub(priv);
struct sub *current = &priv->subs[0];
@@ -238,15 +260,16 @@ static void decode(struct sd *sd, struct demux_packet *packet)
current->count++;
}
- if (pts != MP_NOPTS_VALUE && current->count) {
- for (int n = 0; n < priv->num_timestamps; n++) {
- if (priv->timestamps[n] == pts)
+ if (pts != MP_NOPTS_VALUE) {
+ for (int n = 0; n < priv->num_seekpoints; n++) {
+ if (priv->seekpoints[n].pts == pts)
goto skip;
}
// Set arbitrary limit as safe-guard against insane files.
- if (priv->num_timestamps >= 10000)
- MP_TARRAY_REMOVE_AT(priv->timestamps, priv->num_timestamps, 0);
- MP_TARRAY_APPEND(priv, priv->timestamps, priv->num_timestamps, pts);
+ if (priv->num_seekpoints >= 10000)
+ MP_TARRAY_REMOVE_AT(priv->seekpoints, priv->num_seekpoints, 0);
+ MP_TARRAY_APPEND(priv, priv->seekpoints, priv->num_seekpoints,
+ (struct seekpoint){.pts = pts, .endpts = endpts});
skip: ;
}
}
@@ -363,10 +386,10 @@ static void uninit(struct sd *sd)
talloc_free(priv);
}
-static int compare_double(const void *pa, const void *pb)
+static int compare_seekpoint(const void *pa, const void *pb)
{
- double diff = *(double *)pa - *(double *)pb;
- return diff == 0 ? 0 : (diff < 0 ? -1 : +1);
+ const struct seekpoint *a = pa, *b = pb;
+ return a->pts == b->pts ? 0 : (a->pts < b->pts ? -1 : +1);
}
// taken from ass_step_sub(), libass (ISC)
@@ -377,21 +400,20 @@ static double step_sub(struct sd *sd, double now, int movement)
double target = now;
int direction = movement > 0 ? 1 : -1;
- if (movement == 0 || priv->num_timestamps == 0)
+ if (movement == 0 || priv->num_seekpoints == 0)
return MP_NOPTS_VALUE;
- qsort(priv->timestamps, priv->num_timestamps, sizeof(priv->timestamps[0]),
- compare_double);
+ qsort(priv->seekpoints, priv->num_seekpoints, sizeof(priv->seekpoints[0]),
+ compare_seekpoint);
while (movement) {
int closest = -1;
double closest_time = 0;
- for (int i = 0; i < priv->num_timestamps; i++) {
- double start = priv->timestamps[i];
+ for (int i = 0; i < priv->num_seekpoints; i++) {
+ struct seekpoint *p = &priv->seekpoints[i];
+ double start = p->pts;
if (direction < 0) {
- double end = start;
- if (i + 1 < priv->num_timestamps)
- end = priv->timestamps[i + 1];
+ double end = p->endpts == MP_NOPTS_VALUE ? INFINITY : p->endpts;
if (end < target) {
if (closest < 0 || end > closest_time) {
closest = i;
@@ -414,7 +436,7 @@ static double step_sub(struct sd *sd, double now, int movement)
movement -= direction;
}
- return best < 0 ? 0 : priv->timestamps[best] - now;
+ return best < 0 ? 0 : priv->seekpoints[best].pts - now;
}
static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)