Skip to content

Commit

Permalink
sd_lavc: use decoder-reordered PTS for PGS
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
wm4 committed Apr 2, 2016
1 parent eb74067 commit 7089175
Showing 1 changed file with 21 additions and 3 deletions.
24 changes: 21 additions & 3 deletions sub/sd_lavc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 7089175

Please sign in to comment.