summaryrefslogtreecommitdiff
path: root/libavformat/mov.c
diff options
context:
space:
mode:
authorZhao Zhili <zhilizhao@tencent.com>2023-03-06 20:02:09 +0800
committerZhao Zhili <zhilizhao@tencent.com>2023-03-15 00:12:59 +0800
commitd7e864366be2c4807d6d0796177051ad32c6378d (patch)
tree7e160e9c1c5e2f9f53164778ae1dba5d6888a149 /libavformat/mov.c
parenta3dc677b9f060c08c0000503f640bc9bf6a66c51 (diff)
avformat/mov: parse ISO-14496-12 ChannelLayout
Only support chnl version 0 now. Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
Diffstat (limited to 'libavformat/mov.c')
-rw-r--r--libavformat/mov.c85
1 files changed, 84 insertions, 1 deletions
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 14528bdcaa..057fd872b1 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -940,6 +940,88 @@ static int mov_read_chan(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+static int mov_read_chnl(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int64_t end = av_sat_add64(avio_tell(pb), atom.size);
+ int stream_structure;
+ int version, flags;
+ int ret = 0;
+ AVStream *st;
+
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+
+ version = avio_r8(pb);
+ flags = avio_rb24(pb);
+ if (version != 0 || flags != 0) {
+ av_log(c->fc, AV_LOG_ERROR,
+ "Unsupported 'chnl' box with version %d, flags: %#x",
+ version, flags);
+ return AVERROR_INVALIDDATA;
+ }
+
+ stream_structure = avio_r8(pb);
+
+ // stream carries channels
+ if (stream_structure & 1) {
+ int layout = avio_r8(pb);
+
+ av_log(c->fc, AV_LOG_TRACE, "'chnl' layout %d\n", layout);
+ if (!layout) {
+ uint8_t *positions = av_malloc(st->codecpar->ch_layout.nb_channels);
+
+ if (!positions)
+ return AVERROR(ENOMEM);
+ for (int i = 0; i < st->codecpar->ch_layout.nb_channels; i++) {
+ int speaker_pos = avio_r8(pb);
+
+ av_log(c->fc, AV_LOG_TRACE, "speaker_position %d\n", speaker_pos);
+ if (speaker_pos == 126) { // explicit position
+ avpriv_request_sample(c->fc, "explicit position");
+ av_freep(&positions);
+ return AVERROR_PATCHWELCOME;
+ } else {
+ positions[i] = speaker_pos;
+ }
+ }
+
+ ret = ff_mov_get_layout_from_channel_positions(positions,
+ st->codecpar->ch_layout.nb_channels,
+ &st->codecpar->ch_layout);
+ av_freep(&positions);
+ if (ret) {
+ av_log(c->fc, AV_LOG_ERROR,
+ "get channel layout from speaker positions failed, %s\n",
+ av_err2str(ret));
+ return ret;
+ }
+ } else {
+ uint64_t omitted_channel_map = avio_rb64(pb);
+
+ if (omitted_channel_map) {
+ avpriv_request_sample(c->fc, "omitted_channel_map 0x%" PRIx64 " != 0",
+ omitted_channel_map);
+ return AVERROR_PATCHWELCOME;
+ }
+ ff_mov_get_channel_layout_from_config(layout, &st->codecpar->ch_layout);
+ }
+ }
+
+ // stream carries objects
+ if (stream_structure & 2) {
+ int obj_count = avio_r8(pb);
+ av_log(c->fc, AV_LOG_TRACE, "'chnl' with object_count %d\n", obj_count);
+ }
+
+ if (avio_tell(pb) != end) {
+ av_log(c->fc, AV_LOG_WARNING, "skip %" PRId64 " bytes of unknown data inside chnl\n",
+ end - avio_tell(pb));
+ avio_seek(pb, end, SEEK_SET);
+ }
+ return ret;
+}
+
static int mov_read_wfex(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
@@ -7817,7 +7899,8 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('w','i','d','e'), mov_read_wide }, /* place holder */
{ MKTAG('w','f','e','x'), mov_read_wfex },
{ MKTAG('c','m','o','v'), mov_read_cmov },
-{ MKTAG('c','h','a','n'), mov_read_chan }, /* channel layout */
+{ MKTAG('c','h','a','n'), mov_read_chan }, /* channel layout from quicktime */
+{ MKTAG('c','h','n','l'), mov_read_chnl }, /* channel layout from ISO-14496-12 */
{ MKTAG('d','v','c','1'), mov_read_dvc1 },
{ MKTAG('s','g','p','d'), mov_read_sgpd },
{ MKTAG('s','b','g','p'), mov_read_sbgp },