From patchwork Fri Dec 30 20:10:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Franklin Phillips X-Patchwork-Id: 1996 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.89.21 with SMTP id n21csp2995067vsb; Fri, 30 Dec 2016 12:10:36 -0800 (PST) X-Received: by 10.28.214.133 with SMTP id n127mr46910525wmg.28.1483128636103; Fri, 30 Dec 2016 12:10:36 -0800 (PST) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id b19si59799432wma.105.2016.12.30.12.10.35; Fri, 30 Dec 2016 12:10:36 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B86A2689C39; Fri, 30 Dec 2016 22:10:28 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mout.gmx.net (mout.gmx.net [212.227.17.22]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 8129868998B for ; Fri, 30 Dec 2016 22:10:21 +0200 (EET) Received: from localhost.localdomain ([59.26.118.28]) by mail.gmx.com (mrgmx103 [212.227.17.174]) with ESMTPSA (Nemesis) id 0Lq9Ma-1d0Uzk0KDQ-00djq7; Fri, 30 Dec 2016 21:10:21 +0100 From: Franklin Phillips To: ffmpeg-devel@ffmpeg.org Date: Fri, 30 Dec 2016 20:10:04 +0000 Message-Id: <20161230201005.7097-1-franklinphillips@gmx.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20161216171350.3a4f064b@debian> References: <20161216171350.3a4f064b@debian> X-Provags-ID: V03:K0:nEyP/6gSYlHM4EWUzFCibuzwoRXLtwUaDP7CqQoklkaADOTqnLR fUOuvtYoz4STZ79yOS4AjBIeO/8+4jEHlRxZrPLSLiRuc5ZHHoQyDrLdVe9eKRXt9oQKWZ8 7CHmaeAmybtaY1AWzngyCs/9wevPvmfgAmQxA6t/ueSGk/5Oh6DTAQXewxzHtewV4Byp9hq guiNbAfwn/QhDbdrFQIkw== X-UI-Out-Filterresults: notjunk:1; V01:K0:beZrGjuuQLw=:Q0SXLy2zrT78w34+Ex1xy9 RjbPepi7q5hQL6tj+KVYwtVeH28geLjhOl05AuWHwP/pWykeBcEUq2Mloz4SJ8Q6lj6PfnMMc lnHgFdRD1cuoMYOC9WP0PUP2F+iqPqYjPYRip24i2uJ3r9vRcoxRHr4YvJ4uZ7qzEIawoBKDg kpaPd6yqG1p3dBUE3APKEWtEzIsS+qrwEEF1I4kwRk7aesLXYUyuMEvejAfg2UObkwjoXb5uW gI0+dMXt4p5k0swshEgamxgJwOKAV36aA4nE+DMjOvB6WCAn9DSsiT/Lpg0OLB1r2DRvQ2yB8 l/ASrM+5tZZX55VS26Ge4TFdtlDAa2ZQfC/Vdg0hJG7ADsZFyMpYP0u3yQGhGz4LrhjnG5uPK 4PQZEJ4fmXi079DbTBduEju9OVagDEQDGNbOG9ojby4b30a7XIpPEkp4qz7qfaCpndN/wEJsw KYAolEKaquXd1oTbo5LZYPENukV1GbDI+9xvdOPtznf+7ZxbVlOdXqskq1V7uCmW7zBAkGF84 5aONB12HgC3UWzy5yW3HGgVuEkD1PbjShgqRinGA0feuJadI381IiJ+YUN9pABnU4ooj4ile+ Jl7Yx0L3G6DQGC+/tR0JowaWCWRy21Y68fruSCZxhpCcZQYB88mF7ho7B/1CmgAsTYS94+N6p r6WADHHMXDEpxYq40LGStlBE37MPHzcJOX7OnvcD6TAiSRq2LbpBTZSvwPTOtr39MeSdASggn oPVC5TzdGF758oxRcNWz+ezzFme88/Ptx0Adw8aID46jAbeu8CeLQ30vzRm8MMmtihy+Kn4jO OuhcgAVv5IBh6vI171RWFpbliHd1TWL1AWF9WejBglNCpAtrinYUOyNPiLeKPmgnkNsjRQjrc ECN2lpmJHxnmL5pNvsRw+BBLECZg7VaIZlmlAPCqubug7hAopC3iEXqmVuzr2WWsyCajC6Ric xCspgJAOZ4GyTl95gnpisfxBsDFhC4bNp+P3zZSPoatYyJzrk9Cs2n4euPFBv5dWaA70gKDem mg== Subject: [FFmpeg-devel] [PATCH 1/2] avformat/webvttdec: Add support for HLS WebVTT MPEG timestamp map X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Franklin Phillips MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" WebVTT subtitle files in HLS streams contain a header to synchronize the subtitles with the MPEG TS timestamps of the HLS stream. Add an AVOption to prefer MPEG TS style timestamps generated according to the mapping header, if available. Signed-off-by: Franklin Phillips --- libavformat/webvttdec.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/libavformat/webvttdec.c b/libavformat/webvttdec.c index 0aeb8a6..329b25e 100644 --- a/libavformat/webvttdec.c +++ b/libavformat/webvttdec.c @@ -35,6 +35,7 @@ typedef struct { const AVClass *class; FFDemuxSubtitlesQueue q; int kind; + int prefer_hls_mpegts_pts; } WebVTTContext; static int webvtt_probe(AVProbeData *p) @@ -57,12 +58,19 @@ static int64_t read_ts(const char *s) return AV_NOPTS_VALUE; } +static int64_t convert_to_hls_mpegts_ts(int64_t timestamp, int64_t offset) +{ + return (timestamp * 90 + offset) & ((1LL << 33) - 1); +} + static int webvtt_read_header(AVFormatContext *s) { WebVTTContext *webvtt = s->priv_data; AVBPrint header, cue; int res = 0; AVStream *st = avformat_new_stream(s, NULL); + int has_hls_timestamp_map = 0; + int64_t hls_ts_offset; if (!st) return AVERROR(ENOMEM); @@ -93,8 +101,36 @@ static int webvtt_read_header(AVFormatContext *s) /* ignore header chunk */ if (!strncmp(p, "\xEF\xBB\xBFWEBVTT", 9) || !strncmp(p, "WEBVTT", 6) || - !strncmp(p, "NOTE", 4)) + !strncmp(p, "NOTE", 4)) { + + if (webvtt->prefer_hls_mpegts_pts) { + /* + * WebVTT files in HLS streams contain a timestamp offset for + * syncing with the main stream: + * + * X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000 + * (LOCAL and MPEGTS can be reversed even though HLS spec + * does not say so) + */ + + char *hls_timestamp_map = strstr(p, "\nX-TIMESTAMP-MAP="); + if (hls_timestamp_map) { + char *native_str = strstr(hls_timestamp_map, "LOCAL:"); + char *mpegts_str = strstr(hls_timestamp_map, "MPEGTS:"); + if (native_str && mpegts_str) { + int64_t native_ts = read_ts(native_str + 6); + int64_t mpegts_ts = strtoll(mpegts_str + 7, NULL, 10); + + if (native_ts != AV_NOPTS_VALUE) { + hls_ts_offset = mpegts_ts - native_ts * 90; + has_hls_timestamp_map = 1; + avpriv_set_pts_info(st, 33, 1, 90000); + } + } + } + } continue; + } /* optional cue identifier (can be a number like in SRT or some kind of * chaptering id) */ @@ -125,6 +161,12 @@ static int webvtt_read_header(AVFormatContext *s) if ((ts_end = read_ts(p)) == AV_NOPTS_VALUE) break; + if (has_hls_timestamp_map) { + /* convert and truncate to MPEG TS timestamps */ + ts_start = convert_to_hls_mpegts_ts(ts_start, hls_ts_offset); + ts_end = convert_to_hls_mpegts_ts(ts_end, hls_ts_offset); + } + /* optional cue settings */ p += strcspn(p, "\n\t "); while (*p == '\t' || *p == ' ') @@ -200,6 +242,7 @@ static const AVOption options[] = { { "captions", "WebVTT captions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, { "descriptions", "WebVTT descriptions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, { "metadata", "WebVTT metadata kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, + { "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 }, { NULL } };