summaryrefslogtreecommitdiff
path: root/libavformat/matroskadec.c
diff options
context:
space:
mode:
authorMatthew Heaney <matthewjheaney@google.com>2013-08-08 15:40:03 -0700
committerMichael Niedermayer <michaelni@gmx.at>2013-08-19 22:34:57 +0200
commit818ebe930fa426ac73368f8aaccf4782fcbf3f92 (patch)
treeacbc90b829843686dadf9b5434f96973fbdf3436 /libavformat/matroskadec.c
parent23b3141261b7ffed5f512eebbd8d82001ebf8523 (diff)
avformat/matroskadec: add WebVTT support
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. Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/matroskadec.c')
-rw-r--r--libavformat/matroskadec.c135
1 files changed, 134 insertions, 1 deletions
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index a857630d7e..60f7a5a87c 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);
@@ -1862,6 +1863,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
@@ -2228,6 +2239,120 @@ 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, *q;
+ int err;
+
+ if (data_len <= 0)
+ return AVERROR_INVALIDDATA;
+
+ p = data;
+ q = data + data_len;
+
+ id = p;
+ id_len = -1;
+ while (p < q) {
+ if (*p == '\r' || *p == '\n') {
+ id_len = p - id;
+ if (*p == '\r')
+ p++;
+ break;
+ }
+ p++;
+ }
+
+ if (p >= q || *p != '\n')
+ return AVERROR_INVALIDDATA;
+ p++;
+
+ settings = p;
+ settings_len = -1;
+ while (p < q) {
+ if (*p == '\r' || *p == '\n') {
+ settings_len = p - settings;
+ if (*p == '\r')
+ p++;
+ break;
+ }
+ p++;
+ }
+
+ if (p >= q || *p != '\n')
+ return AVERROR_INVALIDDATA;
+ p++;
+
+ 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;
+ }
+
+ if (text_len <= 0)
+ return AVERROR_INVALIDDATA;
+
+ pkt = av_mallocz(sizeof(*pkt));
+ err = av_new_packet(pkt, text_len);
+ if (err < 0) {
+ av_free(pkt);
+ return AVERROR(err);
+ }
+
+ 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,
@@ -2456,6 +2581,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,