summaryrefslogtreecommitdiffstats
path: root/sub/sd_lavc.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-04-02 17:39:49 +0200
committerwm4 <wm4@nowhere>2016-04-02 17:41:12 +0200
commit7089175d8d45d7c75621e56d2a3623fe02e38960 (patch)
treea03553c843dd648a6ceb8b08145893e5ccc95276 /sub/sd_lavc.c
parenteb740673b8a110f5d18879ba0080e9d3f13387d0 (diff)
downloadmpv-7089175d8d45d7c75621e56d2a3623fe02e38960.tar.bz2
mpv-7089175d8d45d7c75621e56d2a3623fe02e38960.tar.xz
sd_lavc: use decoder-reordered PTS for PGS
There is an obscure feature which requires essentially reordering PTS from different packets. Unfortunately, libavcodec introduced a ridiculously shitty API for this, which works very much unlike the audio/video API. Instead of simply passing through the PTS, it wants to fuck with it for no reason, and even worse, fucks with other fields and changes their semantivcs (??????). This affects AVSubtitle.end_display_time. This probably will cause issues for us, and I have no desire to find out whether it will. Since only PGS requires this, and it happens not to use end_display_time, do it for PGS only. Fixes #3016.
Diffstat (limited to 'sub/sd_lavc.c')
-rw-r--r--sub/sd_lavc.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c
index f0c51ceaa6..56377b213e 100644
--- a/sub/sd_lavc.c
+++ b/sub/sd_lavc.c
@@ -54,6 +54,7 @@ struct seekpoint {
struct sd_lavc_priv {
AVCodecContext *avctx;
+ AVRational pkt_timebase;
struct sub subs[MAX_QUEUE]; // most recent event first
struct sub_bitmap *outbitmaps;
int64_t displayed_id;
@@ -117,6 +118,22 @@ static int init(struct sd *sd)
if (!ctx)
goto error;
mp_lavc_set_extradata(ctx, sd->codec->extradata, sd->codec->extradata_size);
+ if (cid == AV_CODEC_ID_HDMV_PGS_SUBTITLE) {
+ // We don't always want to set this, because the ridiculously shitty
+ // libavcodec API will mess with certain fields (end_display_time)
+ // when setting it. On the other hand, PGS in particular needs PTS
+ // mangling. While the PGS decoder doesn't modify the timestamps (just
+ // reorder it), the ridiculously shitty libavcodec wants a timebase
+ // anyway and for no good reason. It always sets end_display_time to
+ // UINT32_MAX (which is a broken and undocumented way to say "unknown"),
+ // which coincidentally won't be overridden by the ridiculously shitty
+ // pkt_timebase code. also, Libav doesn't have the pkt_timebase field,
+ // because Libav tends to avoid _adding_ ridiculously shitty APIs.
+#if LIBAVCODEC_VERSION_MICRO >= 100
+ priv->pkt_timebase = (AVRational){1, AV_TIME_BASE};
+ ctx->pkt_timebase = priv->pkt_timebase;
+#endif
+ }
if (avcodec_open2(ctx, sub_codec, NULL) < 0)
goto error;
priv->avctx = ctx;
@@ -177,14 +194,15 @@ static void decode(struct sd *sd, struct demux_packet *packet)
if (pts == MP_NOPTS_VALUE)
MP_WARN(sd, "Subtitle with unknown start time.\n");
- av_init_packet(&pkt);
- pkt.data = packet->buffer;
- pkt.size = packet->len;
+ mp_set_av_packet(&pkt, packet, &priv->pkt_timebase);
int got_sub;
int res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt);
if (res < 0 || !got_sub)
return;
+ if (sub.pts != AV_NOPTS_VALUE)
+ pts = sub.pts / (double)AV_TIME_BASE;
+
if (pts != MP_NOPTS_VALUE) {
if (sub.end_display_time > sub.start_display_time &&
sub.end_display_time != UINT32_MAX)