FFmpeg
Loading...
Searching...
No Matches
webvttdec.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012 Clément Bœsch
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * WebVTT subtitle demuxer
24 * @see https://www.w3.org/TR/webvtt1/
25 */
26
27#include "avformat.h"
28#include "demux.h"
29#include "internal.h"
30#include "subtitles.h"
31#include "libavutil/bprint.h"
33#include "libavutil/opt.h"
34
35typedef struct {
36 const AVClass *class;
38 int kind;
40
41static int webvtt_probe(const AVProbeData *p)
42{
43 const uint8_t *ptr = p->buf;
44
45 if (AV_RB24(ptr) == 0xEFBBBF)
46 ptr += 3; /* skip UTF-8 BOM */
47 if (!strncmp(ptr, "WEBVTT", 6) &&
48 (!ptr[6] || strchr("\n\r\t ", ptr[6])))
49 return AVPROBE_SCORE_MAX;
50 return 0;
51}
52
53static int64_t read_ts(const char *s)
54{
55 int hh, mm, ss, ms;
56 if (sscanf(s, "%u:%u:%u.%u", &hh, &mm, &ss, &ms) == 4) return (hh*3600LL + mm*60LL + ss) * 1000LL + ms;
57 if (sscanf(s, "%u:%u.%u", &mm, &ss, &ms) == 3) return ( mm*60LL + ss) * 1000LL + ms;
58 return AV_NOPTS_VALUE;
59}
60
62{
63 WebVTTContext *webvtt = s->priv_data;
64 AVBPrint cue;
65 int res = 0;
67
68 if (!st)
69 return AVERROR(ENOMEM);
70 avpriv_set_pts_info(st, 64, 1, 1000);
73 st->disposition |= webvtt->kind;
74
76
77 for (;;) {
78 int i;
80 AVPacket *sub;
81 const char *p, *identifier, *settings;
82 size_t identifier_len, settings_len;
83 int64_t ts_start, ts_end;
84
85 res = ff_subtitles_read_chunk(s->pb, &cue);
86 if (res < 0)
87 goto end;
88
89 if (!cue.len)
90 break;
91
92 p = identifier = cue.str;
93 pos = avio_tell(s->pb);
94
95 /* ignore header chunk */
96 if (!strncmp(p, "\xEF\xBB\xBFWEBVTT", 9) ||
97 !strncmp(p, "WEBVTT", 6) ||
98 !strncmp(p, "STYLE", 5) ||
99 !strncmp(p, "REGION", 6) ||
100 !strncmp(p, "NOTE", 4))
101 continue;
102
103 /* optional cue identifier (can be a number like in SRT or some kind of
104 * chaptering id) */
105 for (i = 0; p[i] && p[i] != '\n' && p[i] != '\r'; i++) {
106 if (!strncmp(p + i, "-->", 3)) {
107 identifier = NULL;
108 break;
109 }
110 }
111 if (!identifier)
112 identifier_len = 0;
113 else {
114 identifier_len = strcspn(p, "\r\n");
115 p += identifier_len;
116 if (*p == '\r')
117 p++;
118 if (*p == '\n')
119 p++;
120 }
121
122 /* cue timestamps */
123 if ((ts_start = read_ts(p)) == AV_NOPTS_VALUE)
124 break;
125 if (!(p = strstr(p, "-->")))
126 break;
127 p += 2;
128 do p++; while (*p == ' ' || *p == '\t');
129 if ((ts_end = read_ts(p)) == AV_NOPTS_VALUE)
130 break;
131
132 /* optional cue settings */
133 p += strcspn(p, "\n\r\t ");
134 while (*p == '\t' || *p == ' ')
135 p++;
136 settings = p;
137 settings_len = strcspn(p, "\r\n");
138 p += settings_len;
139 if (*p == '\r')
140 p++;
141 if (*p == '\n')
142 p++;
143
144 /* create packet */
145 sub = ff_subtitles_queue_insert(&webvtt->q, p, strlen(p), 0);
146 if (!sub) {
147 res = AVERROR(ENOMEM);
148 goto end;
149 }
150 sub->pos = pos;
151 sub->pts = ts_start;
152 sub->duration = ts_end - ts_start;
153
154#define SET_SIDE_DATA(name, type) do { \
155 if (name##_len) { \
156 uint8_t *buf = av_packet_new_side_data(sub, type, name##_len); \
157 if (!buf) { \
158 res = AVERROR(ENOMEM); \
159 goto end; \
160 } \
161 memcpy(buf, name, name##_len); \
162 } \
163} while (0)
164
167 }
168
170
171end:
173 return res;
174}
175
177{
178 WebVTTContext *webvtt = s->priv_data;
179 return ff_subtitles_queue_read_packet(&webvtt->q, pkt);
180}
181
182static int webvtt_read_seek(AVFormatContext *s, int stream_index,
183 int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
184{
185 WebVTTContext *webvtt = s->priv_data;
186 return ff_subtitles_queue_seek(&webvtt->q, s, stream_index,
187 min_ts, ts, max_ts, flags);
188}
189
191{
192 WebVTTContext *webvtt = s->priv_data;
193 ff_subtitles_queue_clean(&webvtt->q);
194 return 0;
195}
196
197#define OFFSET(x) offsetof(WebVTTContext, x)
198#define KIND_FLAGS AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_DECODING_PARAM
199
200static const AVOption options[] = {
201 { "kind", "Set kind of WebVTT track", OFFSET(kind), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, KIND_FLAGS, .unit = "webvtt_kind" },
202 { "subtitles", "WebVTT subtitles kind", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, KIND_FLAGS, .unit = "webvtt_kind" },
203 { "captions", "WebVTT captions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, INT_MIN, INT_MAX, KIND_FLAGS, .unit = "webvtt_kind" },
204 { "descriptions", "WebVTT descriptions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, INT_MIN, INT_MAX, KIND_FLAGS, .unit = "webvtt_kind" },
205 { "metadata", "WebVTT metadata kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, INT_MIN, INT_MAX, KIND_FLAGS, .unit = "webvtt_kind" },
206 { NULL }
207};
208
210 .class_name = "WebVTT demuxer",
211 .item_name = av_default_item_name,
212 .option = options,
213 .version = LIBAVUTIL_VERSION_INT,
214};
215
217 .p.name = "webvtt",
218 .p.long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
219 .p.mime_type = "text/vtt",
220 .p.extensions = "vtt,webvtt",
221 .p.priv_class = &webvtt_demuxer_class,
222 .priv_data_size = sizeof(WebVTTContext),
223 .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
227 .read_seek2 = webvtt_read_seek,
229};
const FFInputFormat ff_webvtt_demuxer
Definition webvttdec.c:216
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition avformat.c:834
Main libavformat public API header.
#define AVPROBE_SCORE_MAX
maximum score
Definition avformat.h:483
#define AV_DISPOSITION_CAPTIONS
The subtitle stream contains captions, providing a transcription and possibly a translation of audio.
Definition avformat.h:710
#define AV_DISPOSITION_METADATA
The subtitle stream contains time-aligned metadata that is not intended to be directly presented to t...
Definition avformat.h:721
#define AV_DISPOSITION_DESCRIPTIONS
The subtitle stream contains a textual description of the video content.
Definition avformat.h:716
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition avio.h:494
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
AVBPrint public header.
#define AV_BPRINT_SIZE_UNLIMITED
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define ss(width, name, subs,...)
Definition cbs_vp9.c:202
#define s(width, name)
Definition cbs_vp9.c:198
static int read_probe(const AVProbeData *p)
Definition cdg.c:30
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
#define FF_INFMT_FLAG_INIT_CLEANUP
For an FFInputFormat with this flag set read_close() needs to be called by the caller upon read_heade...
Definition demux.h:35
static AVPacket * pkt
static int read_header(FFV1Context *f, RangeCoder *c)
Definition ffv1dec.c:578
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_CODEC_ID_WEBVTT
Definition codec_id.h:584
@ AV_PKT_DATA_WEBVTT_SETTINGS
The optional settings (rendering instructions) that immediately follow the timestamp specifier of a W...
Definition packet.h:199
@ AV_PKT_DATA_WEBVTT_IDENTIFIER
The optional first identifier line of a WebVTT cue.
Definition packet.h:193
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:235
#define AVERROR(e)
Definition error.h:45
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
@ AVMEDIA_TYPE_SUBTITLE
Definition avutil.h:203
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define AV_RB24(x)
#define KIND_FLAGS
Definition webvttdec.c:198
static int webvtt_read_seek(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
Definition webvttdec.c:182
#define SET_SIDE_DATA(name, type)
static int webvtt_probe(const AVProbeData *p)
Definition webvttdec.c:41
static int64_t read_ts(const char *s)
Definition webvttdec.c:53
static const AVClass webvtt_demuxer_class
Definition webvttdec.c:209
static int webvtt_read_header(AVFormatContext *s)
Definition webvttdec.c:61
static int webvtt_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition webvttdec.c:176
static int webvtt_read_close(AVFormatContext *s)
Definition webvttdec.c:190
#define OFFSET(x)
Definition webvttdec.c:197
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
static av_cold int read_close(AVFormatContext *ctx)
Definition libcdio.c:143
AVOptions.
unsigned int pos
Definition spdifenc.c:431
Describe the class of an AVClass context structure.
Definition log.h:76
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
Format I/O context.
Definition avformat.h:1333
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition packet.h:621
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition packet.h:596
int64_t pos
byte position in stream, -1 if unknown
Definition packet.h:623
This structure contains the data a format has to probe a file.
Definition avformat.h:471
Stream structure.
Definition avformat.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:789
int disposition
Stream disposition - a combination of AV_DISPOSITION_* flags.
Definition avformat.h:835
FFDemuxSubtitlesQueue q
Definition webvttdec.c:37
int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
Update current_sub_idx to emulate a seek.
Definition subtitles.c:269
AVPacket * ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q, const uint8_t *event, size_t len, int merge)
Insert a new subtitle event.
Definition subtitles.c:111
int ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf)
Same as ff_subtitles_read_text_chunk(), but read from an AVIOContext.
Definition subtitles.c:445
int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt)
Generic read_packet() callback for subtitles demuxers using this queue system.
Definition subtitles.c:230
void ff_subtitles_queue_finalize(void *log_ctx, FFDemuxSubtitlesQueue *q)
Set missing durations, sort subtitles by PTS (and then byte position), and drop duplicated events.
Definition subtitles.c:212
void ff_subtitles_queue_clean(FFDemuxSubtitlesQueue *q)
Remove and destroy all the subtitles packets.
Definition subtitles.c:321