From fa10332596c499454cc2df440ee6d82560a45cb5 Mon Sep 17 00:00:00 2001
From: Franklin Phillips <franklinphillips@gmx.com>
Date: Tue, 5 Jan 2021 03:38:01 +0100
Subject: [PATCH 1/3] avformat/webvttdec: Add support for HLS WebVTT MPEG
timestamp map
---
libavformat/webvttdec.c | 46 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/libavformat/webvttdec.c b/libavformat/webvttdec.c
index 8d2fdfed37..3e71517509 100644
|
a
|
b
|
typedef struct {
|
| 35 | 35 | const AVClass *class; |
| 36 | 36 | FFDemuxSubtitlesQueue q; |
| 37 | 37 | int kind; |
| | 38 | int prefer_hls_mpegts_pts; |
| 38 | 39 | } WebVTTContext; |
| 39 | 40 | |
| 40 | 41 | static int webvtt_probe(const AVProbeData *p) |
| … |
… |
static int webvtt_probe(const AVProbeData *p)
|
| 49 | 50 | return 0; |
| 50 | 51 | } |
| 51 | 52 | |
| | 53 | static int64_t convert_to_hls_mpegts_ts(int64_t timestamp, int64_t offset) |
| | 54 | { |
| | 55 | return (timestamp * 90 + offset) & ((1LL << 33) - 1); |
| | 56 | } |
| | 57 | |
| 52 | 58 | static int64_t read_ts(const char *s) |
| 53 | 59 | { |
| 54 | 60 | int hh, mm, ss, ms; |
| … |
… |
static int webvtt_read_header(AVFormatContext *s)
|
| 63 | 69 | AVBPrint cue; |
| 64 | 70 | int res = 0; |
| 65 | 71 | AVStream *st = avformat_new_stream(s, NULL); |
| | 72 | int has_hls_timestamp_map = 0; |
| | 73 | int64_t hls_ts_offset; |
| 66 | 74 | |
| 67 | 75 | if (!st) |
| 68 | 76 | return AVERROR(ENOMEM); |
| … |
… |
static int webvtt_read_header(AVFormatContext *s)
|
| 92 | 100 | /* ignore header chunk */ |
| 93 | 101 | if (!strncmp(p, "\xEF\xBB\xBFWEBVTT", 9) || |
| 94 | 102 | !strncmp(p, "WEBVTT", 6) || |
| 95 | | !strncmp(p, "NOTE", 4)) |
| | 103 | !strncmp(p, "NOTE", 4)) { |
| | 104 | |
| | 105 | if (webvtt->prefer_hls_mpegts_pts) { |
| | 106 | /* |
| | 107 | * WebVTT files in HLS streams contain a timestamp offset for |
| | 108 | * syncing with the main stream: |
| | 109 | * |
| | 110 | * X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000 |
| | 111 | * (LOCAL and MPEGTS can be reversed even though HLS spec |
| | 112 | * does not say so) |
| | 113 | */ |
| | 114 | |
| | 115 | char *hls_timestamp_map = strstr(p, "\nX-TIMESTAMP-MAP="); |
| | 116 | if (hls_timestamp_map) { |
| | 117 | char *native_str = strstr(hls_timestamp_map, "LOCAL:"); |
| | 118 | char *mpegts_str = strstr(hls_timestamp_map, "MPEGTS:"); |
| | 119 | if (native_str && mpegts_str) { |
| | 120 | int64_t native_ts = read_ts(native_str + 6); |
| | 121 | int64_t mpegts_ts = strtoll(mpegts_str + 7, NULL, 10); |
| | 122 | |
| | 123 | if (native_ts != AV_NOPTS_VALUE) { |
| | 124 | hls_ts_offset = mpegts_ts - native_ts * 90; |
| | 125 | has_hls_timestamp_map = 1; |
| | 126 | avpriv_set_pts_info(st, 33, 1, 90000); |
| | 127 | } |
| | 128 | } |
| | 129 | } |
| | 130 | } |
| | 131 | |
| 96 | 132 | continue; |
| | 133 | } |
| 97 | 134 | |
| 98 | 135 | /* optional cue identifier (can be a number like in SRT or some kind of |
| 99 | 136 | * chaptering id) */ |
| … |
… |
static int webvtt_read_header(AVFormatContext *s)
|
| 124 | 161 | if ((ts_end = read_ts(p)) == AV_NOPTS_VALUE) |
| 125 | 162 | break; |
| 126 | 163 | |
| | 164 | if (has_hls_timestamp_map) { |
| | 165 | /* convert and truncate to MPEG TS timestamps */ |
| | 166 | ts_start = convert_to_hls_mpegts_ts(ts_start, hls_ts_offset); |
| | 167 | ts_end = convert_to_hls_mpegts_ts(ts_end, hls_ts_offset); |
| | 168 | } |
| | 169 | |
| 127 | 170 | /* optional cue settings */ |
| 128 | 171 | p += strcspn(p, "\n\r\t "); |
| 129 | 172 | while (*p == '\t' || *p == ' ') |
| … |
… |
static const AVOption options[] = {
|
| 200 | 243 | { "captions", "WebVTT captions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, INT_MIN, INT_MAX, KIND_FLAGS, "webvtt_kind" }, |
| 201 | 244 | { "descriptions", "WebVTT descriptions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, INT_MIN, INT_MAX, KIND_FLAGS, "webvtt_kind" }, |
| 202 | 245 | { "metadata", "WebVTT metadata kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, INT_MIN, INT_MAX, KIND_FLAGS, "webvtt_kind" }, |
| | 246 | { "prefer_hls_mpegts_pts", "Use WebVTT embedded HLS MPEGTS timestamps if available.", OFFSET(prefer_hls_mpegts_pts), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM }, |
| 203 | 247 | { NULL } |
| 204 | 248 | }; |
| 205 | 249 | |