[FFmpeg-devel] [PATCH] Matroska demuxer adds WebVTT support
Matthew Heaney
matthewjheaney at google.com
Mon Jul 15 23:08:24 CEST 2013
WebM files now support inband text tracks, as described in the
following specification:
http://wiki.webmproject.org/webm-metadata/temporal-metadata/webvtt-in-webm
The Matroska demuxer now detects the presence of WebVTT tracks,
synthesizing WebVTT packets (having codec id AV_CODEC_ID_WEBVTT) and
pushing them downstream in the normal way.
---
libavformat/matroska.c | 5 ++
libavformat/matroskadec.c | 130 +++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 134 insertions(+), 1 deletion(-)
diff --git a/libavformat/matroska.c b/libavformat/matroska.c
index ee57c18..953c572 100644
--- a/libavformat/matroska.c
+++ b/libavformat/matroska.c
@@ -57,6 +57,11 @@ const CodecTags ff_mkv_codec_tags[]={
{"A_VORBIS" , AV_CODEC_ID_VORBIS},
{"A_WAVPACK4" , AV_CODEC_ID_WAVPACK},
+ {"D_WEBVTT/SUBTITLES" , AV_CODEC_ID_WEBVTT},
+ {"D_WEBVTT/CAPTIONS" , AV_CODEC_ID_WEBVTT},
+ {"D_WEBVTT/DESCRIPTIONS", AV_CODEC_ID_WEBVTT},
+ {"D_WEBVTT/METADATA" , AV_CODEC_ID_WEBVTT},
+
{"S_TEXT/UTF8" , AV_CODEC_ID_SUBRIP},
{"S_TEXT/UTF8" , AV_CODEC_ID_TEXT},
{"S_TEXT/UTF8" , AV_CODEC_ID_SRT},
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 9a15a2b..3f8eabc 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -1566,7 +1566,8 @@ static int matroska_read_header(AVFormatContext *s)
/* Apply some sanity checks. */
if (track->type != MATROSKA_TRACK_TYPE_VIDEO &&
track->type != MATROSKA_TRACK_TYPE_AUDIO &&
- track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
+ track->type != MATROSKA_TRACK_TYPE_SUBTITLE &&
+ track->type != MATROSKA_TRACK_TYPE_METADATA) {
av_log(matroska->ctx, AV_LOG_INFO,
"Unknown or unsupported track type %"PRIu64"\n",
track->type);
@@ -1860,6 +1861,16 @@ static int matroska_read_header(AVFormatContext *s)
st->codec->bits_per_coded_sample = track->audio.bitdepth;
if (st->codec->codec_id != AV_CODEC_ID_AAC)
st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ } else if (codec_id == AV_CODEC_ID_WEBVTT) {
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+
+ if (!strcmp(track->codec_id, "D_WEBVTT/CAPTIONS")) {
+ st->disposition |= AV_DISPOSITION_CAPTIONS;
+ } else if (!strcmp(track->codec_id, "D_WEBVTT/DESCRIPTIONS")) {
+ st->disposition |= AV_DISPOSITION_DESCRIPTIONS;
+ } else if (!strcmp(track->codec_id, "D_WEBVTT/METADATA")) {
+ st->disposition |= AV_DISPOSITION_METADATA;
+ }
} else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) {
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
#if FF_API_ASS_SSA
@@ -2226,6 +2237,115 @@ fail:
return ret;
}
+static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
+ MatroskaTrack *track,
+ AVStream *st,
+ uint8_t *data, int data_len,
+ uint64_t timecode,
+ uint64_t duration,
+ int64_t pos)
+{
+ AVPacket *pkt;
+ uint8_t *id, *settings, *text, *buf;
+ int id_len, settings_len, text_len;
+
+ uint8_t *p = data;
+ uint8_t *q = data + data_len;
+
+ if (p >= q)
+ return AVERROR_INVALIDDATA;
+
+ id = p;
+ id_len = strcspn(p, "\r\n");
+
+ p += id_len;
+ if (p >= q)
+ return AVERROR_INVALIDDATA;
+
+ if (*p == '\r')
+ p++;
+ if (p >= q || *p != '\n')
+ return AVERROR_INVALIDDATA;
+ p++;
+
+ if (p >= q)
+ return AVERROR_INVALIDDATA;
+
+ settings = p;
+ settings_len = strcspn(p, "\r\n");
+
+ p += settings_len;
+ if (p >= q)
+ return AVERROR_INVALIDDATA;
+
+ if (*p == '\r')
+ p++;
+ if (p >= q || *p != '\n')
+ return AVERROR_INVALIDDATA;
+ p++;
+
+ if (p >= q)
+ return AVERROR_INVALIDDATA;
+
+ text = p;
+ text_len = q - p;
+
+ while (text_len > 0) {
+ const int len = text_len - 1;
+ const uint8_t c = p[len];
+ if (c != '\r' && c != '\n')
+ break;
+ text_len = len;
+ }
+
+ pkt = av_mallocz(sizeof(AVPacket));
+ if (av_new_packet(pkt, text_len) < 0) {
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+
+ memcpy(pkt->data, text, text_len);
+
+ if (id_len > 0) {
+ buf = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_WEBVTT_IDENTIFIER,
+ id_len);
+ if (buf == NULL) {
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(buf, id, id_len);
+ }
+
+ if (settings_len > 0) {
+ buf = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_WEBVTT_SETTINGS,
+ settings_len);
+ if (buf == NULL) {
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(buf, settings, settings_len);
+ }
+
+ // Do we need this for subtitles?
+ // pkt->flags = AV_PKT_FLAG_KEY;
+
+ pkt->stream_index = st->index;
+ pkt->pts = timecode;
+
+ // Do we need this for subtitles?
+ // pkt->dts = timecode;
+
+ pkt->duration = duration;
+ pkt->pos = pos;
+
+ dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
+ matroska->prev_pkt = pkt;
+
+ return 0;
+}
+
static int matroska_parse_frame(MatroskaDemuxContext *matroska,
MatroskaTrack *track,
AVStream *st,
@@ -2454,6 +2574,14 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
if (res)
goto end;
+ } else if (st->codec->codec_id == AV_CODEC_ID_WEBVTT) {
+ res = matroska_parse_webvtt(matroska, track, st,
+ data, lace_size[n],
+ timecode, lace_duration,
+ pos);
+ if (res)
+ goto end;
+
} else {
res = matroska_parse_frame(matroska, track, st, data, lace_size[n],
timecode, lace_duration,
--
1.8.3
More information about the ffmpeg-devel
mailing list