[FFmpeg-devel] [PATCH 4/7] avformat/movenc: write channel descriptions when a known layout or a bitmap can't be used

James Almer jamrial at gmail.com
Tue Mar 29 02:24:50 EEST 2022


Fixes part of ticket #2865

Signed-off-by: James Almer <jamrial at gmail.com>
---
 libavformat/mov_chan.c | 75 ++++++++++++++++++++++++++++++++----------
 libavformat/mov_chan.h |  8 +++--
 libavformat/movenc.c   | 37 +++++++++++++++------
 3 files changed, 90 insertions(+), 30 deletions(-)

diff --git a/libavformat/mov_chan.c b/libavformat/mov_chan.c
index 3c23142f35..4cb373d1b9 100644
--- a/libavformat/mov_chan.c
+++ b/libavformat/mov_chan.c
@@ -504,9 +504,29 @@ static uint64_t mov_get_channel_mask(uint32_t label)
     return 0;
 }
 
-uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
-                                       const AVChannelLayout *ch_layout,
-                                       uint32_t *bitmap)
+static uint32_t mov_get_channel_label(enum AVChannel channel)
+{
+    if (channel < 0)
+        return 0;
+    if (channel <= AV_CHAN_TOP_BACK_RIGHT)
+        return channel + 1;
+    if (channel == AV_CHAN_WIDE_LEFT)
+        return 35;
+    if (channel == AV_CHAN_WIDE_RIGHT)
+        return 36;
+    if (channel == AV_CHAN_LOW_FREQUENCY_2)
+        return 37;
+    if (channel == AV_CHAN_STEREO_LEFT)
+        return 38;
+    if (channel == AV_CHAN_STEREO_RIGHT)
+        return 39;
+    return 0;
+}
+
+int ff_mov_get_channel_layout_tag(const AVCodecParameters *par,
+                                  uint32_t *layout,
+                                  uint32_t *bitmap,
+                                  uint32_t **pchannel_desc)
 {
     int i, j;
     uint32_t tag = 0;
@@ -514,7 +534,7 @@ uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
 
     /* find the layout list for the specified codec */
     for (i = 0; mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE; i++) {
-        if (mov_codec_ch_layouts[i].codec_id == codec_id)
+        if (mov_codec_ch_layouts[i].codec_id == par->codec_id)
             break;
     }
     if (mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE)
@@ -525,7 +545,7 @@ uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
         const struct MovChannelLayoutMap *layout_map;
 
         /* get the layout map based on the channel count */
-        channels = ch_layout->nb_channels;
+        channels = par->ch_layout.nb_channels;
         if (channels > 9)
             channels = 0;
         layout_map = mov_ch_layout_map[channels];
@@ -536,8 +556,8 @@ uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
                 continue;
             for (j = 0; layout_map[j].tag != 0; j++) {
                 if (layout_map[j].tag    == layouts[i] &&
-                    (ch_layout->order == AV_CHANNEL_ORDER_NATIVE &&
-                     layout_map[j].layout == ch_layout->u.mask))
+                    (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE &&
+                     layout_map[j].layout == par->ch_layout.u.mask))
                     break;
             }
             if (layout_map[j].tag)
@@ -546,18 +566,39 @@ uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
         tag = layouts[i];
     }
 
-    /* if no tag was found, use channel bitmap as a backup if possible */
-    if (tag == 0 && av_channel_layout_check(ch_layout) &&
-        ch_layout->order == AV_CHANNEL_ORDER_NATIVE &&
-        ch_layout->u.mask < 0x40000) {
-        tag     = MOV_CH_LAYOUT_USE_BITMAP;
-        *bitmap = (uint32_t)ch_layout->u.mask;
-    } else
-        *bitmap = 0;
+    *layout = tag;
+    *bitmap = 0;
+    *pchannel_desc = NULL;
+
+    /* if no tag was found, use channel bitmap or description as a backup if possible */
+    if (tag == 0) {
+        uint32_t *channel_desc;
+        if (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE &&
+            par->ch_layout.u.mask < 0x40000) {
+            *layout = MOV_CH_LAYOUT_USE_BITMAP;
+            *bitmap = (uint32_t)par->ch_layout.u.mask;
+            return 0;
+        } else if (par->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
+            return AVERROR(ENOSYS);
+
+        channel_desc = av_malloc_array(par->ch_layout.nb_channels, sizeof(*channel_desc));
+        if (!channel_desc)
+            return AVERROR(ENOMEM);
+
+        for (i = 0; i < par->ch_layout.nb_channels; i++) {
+            channel_desc[i] =
+                mov_get_channel_label(av_channel_layout_channel_from_index(&par->ch_layout, i));
+
+            if (channel_desc[i] == 0) {
+                av_free(channel_desc);
+                return AVERROR(ENOSYS);
+            }
+        }
 
-    /* TODO: set channel descriptions as a secondary backup */
+        *pchannel_desc = channel_desc;
+    }
 
-    return tag;
+    return 0;
 }
 
 int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st,
diff --git a/libavformat/mov_chan.h b/libavformat/mov_chan.h
index 9514dfa405..2815f15f07 100644
--- a/libavformat/mov_chan.h
+++ b/libavformat/mov_chan.h
@@ -30,6 +30,7 @@
 
 #include "libavutil/channel_layout.h"
 #include "libavcodec/codec_id.h"
+#include "libavcodec/codec_par.h"
 #include "avformat.h"
 
 /**
@@ -41,9 +42,10 @@
  * @param[out] bitmap          channel bitmap
  * @return                     channel layout tag
  */
-uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
-                                       const AVChannelLayout *ch_layout,
-                                       uint32_t *bitmap);
+int ff_mov_get_channel_layout_tag(const AVCodecParameters *par,
+                                       uint32_t *layout,
+                                       uint32_t *bitmap,
+                                       uint32_t **pchannel_desc);
 
 /**
  * Read 'chan' tag from the input stream.
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 46d66c29c2..263649f1da 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -867,20 +867,27 @@ static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
 
 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
 {
-    uint32_t layout_tag, bitmap;
+    uint32_t layout_tag, bitmap, *channel_desc;
     int64_t pos = avio_tell(pb);
+    int num_desc, ret;
 
-    layout_tag = ff_mov_get_channel_layout_tag(track->par->codec_id,
-                                               &track->par->ch_layout,
-                                               &bitmap);
-    if (!layout_tag) {
-        av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
-               "lack of channel information\n");
+    if (track->multichannel_as_mono)
         return 0;
+
+    ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
+                                        &bitmap, &channel_desc);
+
+    if (ret < 0) {
+        if (ret == AVERROR(ENOSYS)) {
+            av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
+                                      "lack of channel information\n");
+            ret = 0;
+        }
+
+        return ret;
     }
 
-    if (track->multichannel_as_mono)
-        return 0;
+    num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
 
     avio_wb32(pb, 0);           // Size
     ffio_wfourcc(pb, "chan");   // Type
@@ -888,7 +895,17 @@ static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
     avio_wb24(pb, 0);           // Flags
     avio_wb32(pb, layout_tag);  // mChannelLayoutTag
     avio_wb32(pb, bitmap);      // mChannelBitmap
-    avio_wb32(pb, 0);           // mNumberChannelDescriptions
+    avio_wb32(pb, num_desc);    // mNumberChannelDescriptions
+
+    for (int i = 0; i < num_desc; i++) {
+        avio_wb32(pb, channel_desc[i]); // mChannelLabel
+        avio_wb32(pb, 0);               // mChannelFlags
+        avio_wl32(pb, 0);               // mCoordinates[0]
+        avio_wl32(pb, 0);               // mCoordinates[1]
+        avio_wl32(pb, 0);               // mCoordinates[2]
+    }
+
+    av_free(channel_desc);
 
     return update_size(pb, pos);
 }
-- 
2.35.1



More information about the ffmpeg-devel mailing list