From 5181275d0474aadc420da46f3a1c9044900aa36d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Krzciuk?= <lkrzciuk@vewd.com>
Date: Fri, 13 Apr 2018 14:57:57 +0200
Subject: [PATCH] avformat/mpegts: set AV_DISPOSITION_DESCRIPTIONS for OIPF
cases
1. an audio component with an ISO_639_language_descriptor in the PMT with the
audio_type field set to 0x03
2. a supplementary_audio_descriptor with the editorial_classification field set
to 0x01
3. an ac-3_descriptor or an enhanced_ac-3_descriptor with a component_type field
with the service_type flags set to Visually Impaired
---
libavformat/Makefile | 1 +
libavformat/mpegts.c | 30 +++++
libavformat/tests/descriptor.c | 265 +++++++++++++++++++++++++++++++++++++++++
tests/fate/libavformat.mak | 4 +
tests/ref/fate/descriptor | 5 +
5 files changed, 305 insertions(+)
create mode 100644 libavformat/tests/descriptor.c
create mode 100644 tests/ref/fate/descriptor
@@ -635,6 +635,7 @@ TESTPROGS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh
TESTPROGS-$(CONFIG_MOV_MUXER) += movenc
TESTPROGS-$(CONFIG_NETWORK) += noproxy
TESTPROGS-$(CONFIG_SRTP) += srtp
+TESTPROGS-$(CONFIG_NETWORK) += descriptor
TOOLS = aviocat \
ismindex \
@@ -1835,6 +1835,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
break;
case 0x03:
st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
+ st->disposition |= AV_DISPOSITION_DESCRIPTIONS;
break;
}
}
@@ -1910,6 +1911,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
switch ((flags >> 2) & 0x1F) { /* editorial_classification */
case 0x01:
st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
+ st->disposition |= AV_DISPOSITION_DESCRIPTIONS;
break;
case 0x02:
st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
@@ -1934,6 +1936,34 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
}
}
break;
+ case 0x6a: /* ac-3_descriptor */
+ {
+ int component_type_flag = get8(pp, desc_end) & (1 << 7);
+ if (component_type_flag) {
+ int component_type = get8(pp, desc_end);
+ int service_type_mask = 0x38; // 0b00111000
+ int service_type = ((component_type & service_type_mask) >> 3);
+ if (service_type == 0x02 /* 0b010 */) {
+ st->disposition |= AV_DISPOSITION_DESCRIPTIONS;
+ av_log(ts->stream, AV_LOG_DEBUG, "New track disposition for id %u: %u\n", st->id, st->disposition);
+ }
+ }
+ }
+ break;
+ case 0x7a: /* enhanced_ac-3_descriptor */
+ {
+ int component_type_flag = get8(pp, desc_end) & (1 << 7);
+ if (component_type_flag) {
+ int component_type = get8(pp, desc_end);
+ int service_type_mask = 0x38; // 0b00111000
+ int service_type = ((component_type & service_type_mask) >> 3);
+ if (service_type == 0x02 /* 0b010 */) {
+ st->disposition |= AV_DISPOSITION_DESCRIPTIONS;
+ av_log(ts->stream, AV_LOG_DEBUG, "New track disposition for id %u: %u\n", st->id, st->disposition);
+ }
+ }
+ }
+ break;
default:
break;
}
new file mode 100644
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2018 Łukasz Krzciuk
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/md5.h"
+
+#include "libavformat/avformat.h"
+#include "libavformat/mpegts.h"
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if !HAVE_GETOPT
+#include "compat/getopt.c"
+#endif
+
+#define HASH_SIZE 16
+
+static const uint8_t aac_extradata[] = {
+ 0x12, 0x10
+};
+static const uint8_t pmt_editorial_classification[] = {
+ 0x02, 0xb0, 0x22, 0x00, 0x02, 0xc1, 0x00, 0x00, 0xe0, 0x21, 0xf0, 0x00,
+ 0x1b, 0xe0, 0x21, 0xf0, 0x00, 0x11, 0xe0, 0x24, 0xf0, 0x0b, 0x7f, 0x05,
+ 0x06, 0x87, 0x65, 0x6e, 0x67, 0x7c, 0x02, 0x60, 0x00, 0x6f, 0xe1, 0x92,
+ 0xf7
+};
+
+static const char *format = "mp4";
+AVFormatContext *ctx;
+uint8_t iobuf[32768];
+AVDictionary *opts;
+
+const char *cur_name;
+int out_size;
+struct AVMD5* md5;
+uint8_t hash[HASH_SIZE];
+
+AVStream *audio_st;
+int64_t audio_dts;
+
+int64_t audio_duration;
+int force_iobuf_size;
+
+static inline int get8(const uint8_t **pp, const uint8_t *p_end)
+{
+ const uint8_t *p;
+ int c;
+
+ p = *pp;
+ if (p >= p_end)
+ return AVERROR_INVALIDDATA;
+ c = *p++;
+ *pp = p;
+ return c;
+}
+
+static inline int get16(const uint8_t **pp, const uint8_t *p_end)
+{
+ const uint8_t *p;
+ int c;
+
+ p = *pp;
+ if (1 >= p_end - p)
+ return AVERROR_INVALIDDATA;
+ c = AV_RB16(p);
+ p += 2;
+ *pp = p;
+ return c;
+}
+
+static void parse_section_header(const uint8_t **pp, const uint8_t *p_end)
+{
+ get8(pp, p_end);
+ get8(pp, p_end);
+ get8(pp, p_end);
+ get8(pp, p_end);
+ get8(pp, p_end);
+ get8(pp, p_end);
+
+ get8(pp, p_end); // tid
+ get16(pp, p_end); // id
+ get8(pp, p_end); // version
+ get8(pp, p_end); // sec_num
+ get8(pp, p_end); // last_sec_num
+}
+
+static int io_write(void *opaque, uint8_t *buf, int size)
+{
+ out_size += size;
+ av_md5_update(md5, buf, size);
+ return size;
+}
+
+static int io_write_data_type(void *opaque, uint8_t *buf, int size,
+ enum AVIODataMarkerType type, int64_t time)
+{
+ char timebuf[30], content[5] = { 0 };
+ const char *str;
+ switch (type) {
+ case AVIO_DATA_MARKER_HEADER: str = "header"; break;
+ case AVIO_DATA_MARKER_SYNC_POINT: str = "sync"; break;
+ case AVIO_DATA_MARKER_BOUNDARY_POINT: str = "boundary"; break;
+ case AVIO_DATA_MARKER_UNKNOWN: str = "unknown"; break;
+ case AVIO_DATA_MARKER_TRAILER: str = "trailer"; break;
+ default: str = "unknown"; break;
+ }
+ if (time == AV_NOPTS_VALUE)
+ snprintf(timebuf, sizeof(timebuf), "nopts");
+ else
+ snprintf(timebuf, sizeof(timebuf), "%"PRId64, time);
+ // There can be multiple header/trailer callbacks, only log the box type
+ // for header at out_size == 0
+ if (type != AVIO_DATA_MARKER_UNKNOWN &&
+ type != AVIO_DATA_MARKER_TRAILER &&
+ (type != AVIO_DATA_MARKER_HEADER || out_size == 0) &&
+ size >= 8)
+ memcpy(content, &buf[4], 4);
+ else
+ snprintf(content, sizeof(content), "-");
+ printf("write_data len %d, time %s, type %s atom %s\n", size, timebuf, str, content);
+ return io_write(opaque, buf, size);
+}
+
+static void init_out(const char *name)
+{
+ char buf[100];
+ cur_name = name;
+ snprintf(buf, sizeof(buf), "%s.%s", cur_name, format);
+
+ av_md5_init(md5);
+ out_size = 0;
+}
+
+static void close_out(void)
+{
+ int i;
+ av_md5_final(md5, hash);
+ for (i = 0; i < HASH_SIZE; i++)
+ printf("%02x", hash[i]);
+ printf(" %d %s\n", out_size, cur_name);
+}
+
+static void init_fps(int bf, int audio_preroll, int fps)
+{
+ AVStream *st;
+ int iobuf_size = force_iobuf_size ? force_iobuf_size : sizeof(iobuf);
+ ctx = avformat_alloc_context();
+ if (!ctx)
+ exit(1);
+ ctx->oformat = av_guess_format(format, NULL, NULL);
+ if (!ctx->oformat)
+ exit(1);
+ ctx->pb = avio_alloc_context(iobuf, iobuf_size, AVIO_FLAG_WRITE, NULL, NULL, io_write, NULL);
+ if (!ctx->pb)
+ exit(1);
+ ctx->pb->write_data_type = io_write_data_type;
+ ctx->flags |= AVFMT_FLAG_BITEXACT;
+
+ st = avformat_new_stream(ctx, NULL);
+ if (!st)
+ exit(1);
+ st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codecpar->codec_id = AV_CODEC_ID_AAC;
+ st->codecpar->sample_rate = 44100;
+ st->codecpar->channels = 2;
+ st->time_base.num = 1;
+ st->time_base.den = 44100;
+ st->codecpar->extradata_size = sizeof(aac_extradata);
+ st->codecpar->extradata = av_mallocz(st->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codecpar->extradata)
+ exit(1);
+ memcpy(st->codecpar->extradata, aac_extradata, sizeof(aac_extradata));
+ audio_st = st;
+
+ if (avformat_write_header(ctx, &opts) < 0)
+ exit(1);
+ av_dict_free(&opts);
+
+ audio_duration = 1024LL * audio_st->time_base.den / audio_st->codecpar->sample_rate;
+ if (audio_preroll)
+ audio_preroll = 2048LL * audio_st->time_base.den / audio_st->codecpar->sample_rate;
+
+ audio_dts = -audio_preroll;
+}
+
+static void init(int bf, int audio_preroll)
+{
+ init_fps(bf, audio_preroll, 30);
+}
+
+static void finish(void)
+{
+ av_write_trailer(ctx);
+ avio_context_free(&ctx->pb);
+ avformat_free_context(ctx);
+ ctx = NULL;
+}
+
+static void pmt_cb(const uint8_t *p, int p_size)
+{
+ int pid, desc_list_len;
+ const uint8_t *desc_list_end;
+ const uint8_t *p_end = p + p_size - 4;
+ parse_section_header(&p, p_end);
+
+ for (;;) {
+ int stream_type = get8(&p, p_end);
+ if (stream_type < 0)
+ break;
+ pid = get16(&p, p_end);
+ if (pid < 0)
+ break;
+ desc_list_len = get16(&p, p_end);
+ desc_list_len &= 0xfff;
+ desc_list_end = p + desc_list_len;
+ if (desc_list_end > p_end)
+ break;
+ for (;;) {
+ if (ff_parse_mpeg2_descriptor(ctx, audio_st, 0, &p, desc_list_end, NULL, 0, 0, NULL))
+ break;
+ }
+ p = desc_list_end;
+ }
+ printf("disposition:%d\n", audio_st->disposition);
+}
+
+int main(int argc, char **argv)
+{
+ md5 = av_md5_alloc();
+ if (!md5)
+ return 1;
+
+ // Test
+ init_out("pmt with editorial_classification");
+ av_dict_set(&opts, "movflags", "frag_keyframe", 0);
+ init(0, 0);
+ pmt_cb(pmt_editorial_classification, sizeof(pmt_editorial_classification));
+ finish();
+ close_out();
+
+ av_free(md5);
+
+ return 0;
+}
@@ -22,6 +22,10 @@ FATE_LIBAVFORMAT-$(CONFIG_MOV_MUXER) += fate-movenc
fate-movenc: libavformat/tests/movenc$(EXESUF)
fate-movenc: CMD = run libavformat/tests/movenc
+FATE_LIBAVFORMAT-yes += fate-descriptor
+fate-descriptor: libavformat/tests/descriptor$(EXESUF)
+fate-descriptor: CMD = run libavformat/tests/descriptor
+
FATE_LIBAVFORMAT += $(FATE_LIBAVFORMAT-yes)
FATE-$(CONFIG_AVFORMAT) += $(FATE_LIBAVFORMAT)
fate-libavformat: $(FATE_LIBAVFORMAT)
new file mode 100644
@@ -0,0 +1,5 @@
+write_data len 32, time nopts, type header atom ftyp
+disposition:131328
+write_data len 649, time nopts, type header atom -
+write_data len 24, time nopts, type trailer atom -
+1da78d265861b40de21f6ec205d48ea4 705 pmt with editorial_classification
--
2.8.3