[FFmpeg-devel] [PATCH]Reorder channels for some mov channel layouts

Carl Eugen Hoyos cehoyos at ag.or.at
Wed Jun 22 19:21:03 CEST 2011


On Friday 17 June 2011 06:46:41 pm Michael Niedermayer wrote:
> On Mon, Jun 13, 2011 at 10:01:51PM +0200, Carl Eugen Hoyos wrote:

> > Attached patch fixes ticket 98.
> >
> > Please comment, Carl Eugen
> >
> >  libavcodec/avcodec.h |    7 +++
> >  libavcodec/pcm.c     |   99
> > +++++++++++++++++++++++++++++++++++++++++++++++++++ libavformat/isom.c  
> > |    3 -
> 
> missing entry in the AVOption array

Updated patch attached.

Please comment, Carl Eugen
-------------- next part --------------
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 90c389b..dd7e249 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2903,6 +2903,13 @@ typedef struct AVCodecContext {
     int64_t pts_correction_last_dts;       /// DTS of the last frame
 
 
+    /**
+     * mov channel layout tag as described in the CAF specification.
+     * - decoding: Set by user.
+     * - encoding: unused
+     */
+    uint32_t mov_channel_layout;
+
 } AVCodecContext;
 
 /**
diff --git a/libavcodec/options.c b/libavcodec/options.c
index b6ad5d8..341d5dc 100644
--- a/libavcodec/options.c
+++ b/libavcodec/options.c
@@ -418,6 +418,7 @@ static const AVOption options[]={
 {"mbtree", "use macroblock tree ratecontrol (x264 only)", 0, FF_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_MBTREE }, INT_MIN, INT_MAX, V|E, "flags2"},
 {"bits_per_raw_sample", NULL, OFFSET(bits_per_raw_sample), FF_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX},
 {"channel_layout", NULL, OFFSET(channel_layout), FF_OPT_TYPE_INT64, {.dbl = DEFAULT }, 0, INT64_MAX, A|E|D, "channel_layout"},
+{"mov_channel_layout", "mov channel layout as used in mov/aif/caf files", OFFSET(mov_channel_layout), FF_OPT_TYPE_INT, {.dbl = DEFAULT }, 0, INT_MAX, A|D},
 {"request_channel_layout", NULL, OFFSET(request_channel_layout), FF_OPT_TYPE_INT64, {.dbl = DEFAULT }, 0, INT64_MAX, A|D, "request_channel_layout"},
 {"rc_max_vbv_use", NULL, OFFSET(rc_max_available_vbv_use), FF_OPT_TYPE_FLOAT, {.dbl = 1.0/3 }, 0.0, FLT_MAX, V|E},
 {"rc_min_vbv_use", NULL, OFFSET(rc_min_vbv_overflow_use),  FF_OPT_TYPE_FLOAT, {.dbl = 3 },     0.0, FLT_MAX, V|E},
diff --git a/libavcodec/pcm.c b/libavcodec/pcm.c
index 111ce61..5329c56 100644
--- a/libavcodec/pcm.c
+++ b/libavcodec/pcm.c
@@ -204,13 +204,63 @@ static int pcm_encode_frame(AVCodecContext *avctx,
     return dst - frame;
 }
 
+typedef struct Channel_maps {
+    uint32_t layout_tag;
+    int64_t channel_layout;
+    uint8_t channel_map[8];
+} Channel_maps;
+
+static const Channel_maps channel_maps[] = {
+    /* kCAFChannelLayoutTag_Pentagonal */
+    { (109 << 16) | 5, AV_CH_LAYOUT_5POINT0_BACK, { 0, 1, 4, 2, 3 } },
+    /* kCAFChannelLayoutTag_Hexagonal */
+    { (110 << 16) | 6, AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER, { 0, 1, 4, 2, 3, 5 } },
+    /* kCAFChannelLayoutTag_MPEG_3_0_B */
+    { (114 << 16) | 3, AV_CH_LAYOUT_SURROUND, { 1, 2, 0 } },
+    /* kCAFChannelLayoutTag_MPEG_4_0_B */
+    { (116 << 16) | 4, AV_CH_LAYOUT_4POINT0, { 1, 2, 0, 3 } },
+    /* kCAFChannelLayoutTag_MPEG_5_0_B */
+    { (118 << 16) | 5, AV_CH_LAYOUT_5POINT0_BACK, { 0, 1, 4, 2, 3 } },
+    /* kCAFChannelLayoutTag_MPEG_5_0_C */
+    { (119 << 16) | 5, AV_CH_LAYOUT_5POINT0_BACK, { 0, 2, 1, 3, 4 } },
+    /* kCAFChannelLayoutTag_MPEG_5_0_D */
+    { (120 << 16) | 5, AV_CH_LAYOUT_5POINT0_BACK, { 1, 2, 0, 3, 4 } },
+    /* kCAFChannelLayoutTag_MPEG_5_1_B */
+    { (122 << 16) | 6, AV_CH_LAYOUT_5POINT1_BACK, { 0, 1, 4, 5, 2, 3 } },
+    /* kCAFChannelLayoutTag_MPEG_5_1_C */
+    { (123 << 16) | 6, AV_CH_LAYOUT_5POINT1_BACK, { 0, 2, 1, 5, 3, 4 } },
+    /* kCAFChannelLayoutTag_MPEG_5_1_D */
+    { (124 << 16) | 6, AV_CH_LAYOUT_5POINT1_BACK, { 1, 2, 0, 5, 3, 4 } },
+    /* kCAFChannelLayoutTag_MPEG_7_1_B */
+    { (127 << 16) | 8, AV_CH_LAYOUT_7POINT1_WIDE, { 3, 4, 0, 7, 5, 6, 1, 2 } },
+    /* kCAFChannelLayoutTag_Emagic_Default_7_1 */
+    { (129 << 16) | 8, AV_CH_LAYOUT_7POINT1_WIDE, { 0, 1, 4, 5, 2, 3, 6, 7 } },
+    /* kCAFChannelLayoutTag_AudioUnit_6_0 */
+    { (139 << 16) | 6, AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER, { 0, 1, 4, 2, 3, 5 } },
+    /* kCAFChannelLayoutTag_AudioUnit_7_0 */
+    { (140 << 16) | 7, AV_CH_LAYOUT_7POINT0, { 0, 1, 4, 5, 6, 2, 3 } },
+    /* kCAFChannelLayoutTag_AAC_6_0 */
+    { (141 << 16) | 6, AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER, { 1, 2, 0, 3, 4, 5 } },
+    /* kCAFChannelLayoutTag_AAC_6_1 */
+    { (142 << 16) | 7, AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER, { 1, 2, 0, 6, 3, 4, 5 } },
+    /* kCAFChannelLayoutTag_AAC_7_0 */
+    { (143 << 16) | 7, AV_CH_LAYOUT_7POINT0, { 1, 2, 0, 5, 6, 3, 4 } },
+    /* kCAFChannelLayoutTag_AAC_Octagonal */
+    { (144 << 16) | 8, AV_CH_LAYOUT_7POINT0|AV_CH_BACK_CENTER, { 1, 2, 0, 5, 6, 7, 3, 4 } },
+    { 0 },
+};
+
 typedef struct PCMDecode {
     short table[256];
+    const uint8_t *channel_map;
+    uint8_t *reorder_buf;
+    unsigned int buf_size;
 } PCMDecode;
 
 static av_cold int pcm_decode_init(AVCodecContext * avctx)
 {
     PCMDecode *s = avctx->priv_data;
+    const Channel_maps *channel_map = channel_maps;
     int i;
 
     switch(avctx->codec->id) {
@@ -231,6 +281,19 @@ static av_cold int pcm_decode_init(AVCodecContext * avctx)
     if (avctx->sample_fmt == AV_SAMPLE_FMT_S32)
         avctx->bits_per_raw_sample = av_get_bits_per_sample(avctx->codec->id);
 
+    if(avctx->mov_channel_layout) {
+        while(channel_map->layout_tag) {
+            if(channel_map->layout_tag == avctx->mov_channel_layout &&
+                (channel_map->layout_tag & 0xF) == avctx->channels) {
+                s->channel_map = channel_map->channel_map;
+                avctx->channel_layout = channel_map->channel_layout;
+                break;
+            }
+            channel_map++;
+        }
+    if (!avctx->channel_layout)
+        av_log_ask_for_sample(s, "Unknown channel layout.\n");
+    }
     return 0;
 }
 
@@ -468,9 +531,47 @@ static int pcm_decode_frame(AVCodecContext *avctx,
         return -1;
     }
     *data_size = (uint8_t *)samples - (uint8_t *)data;
+
+    if (s->channel_map) {
+        s->reorder_buf = av_fast_realloc(s->reorder_buf, &s->buf_size, *data_size);
+        memcpy(s->reorder_buf, data, *data_size);
+        for (i = 0; i < buf_size/sample_size / avctx->channels; i++)
+            for (c = 0; c < avctx->channels; c++)
+                switch (avctx->sample_fmt) {
+                case AV_SAMPLE_FMT_U8:
+                    ((uint8_t *)data)[i * avctx->channels + c] =
+                        s->reorder_buf[i * avctx->channels + s->channel_map[c]];
+                    break;
+                case AV_SAMPLE_FMT_S16:
+                    ((int16_t *)data)[i * avctx->channels + c] =
+                        ((int16_t *)s->reorder_buf)[i * avctx->channels + s->channel_map[c]];
+                    break;
+                case AV_SAMPLE_FMT_S32:
+                    ((int32_t *)data)[i * avctx->channels + c] =
+                        ((int32_t *)s->reorder_buf)[i * avctx->channels + s->channel_map[c]];
+                    break;
+                case AV_SAMPLE_FMT_FLT:
+                    ((float *)data)[i * avctx->channels + c] =
+                        ((float *)s->reorder_buf)[i * avctx->channels + s->channel_map[c]];
+                    break;
+                case AV_SAMPLE_FMT_DBL:
+                    ((double *)data)[i * avctx->channels + c] =
+                        ((double *)s->reorder_buf)[i * avctx->channels + s->channel_map[c]];
+                    break;
+                }
+    }
+
     return src - buf;
 }
 
+static av_cold int pcm_decode_close(AVCodecContext *avctx)
+{
+    PCMDecode *s = avctx->priv_data;
+    av_freep(&s->reorder_buf);
+
+    return 0;
+}
+
 #if CONFIG_ENCODERS
 #define PCM_ENCODER(id_,sample_fmt_,name_,long_name_) \
 AVCodec ff_ ## name_ ## _encoder = {            \
@@ -496,6 +597,7 @@ AVCodec ff_ ## name_ ## _decoder = {            \
     .priv_data_size = sizeof(PCMDecode),        \
     .init           = pcm_decode_init,          \
     .decode         = pcm_decode_frame,         \
+    .close          = pcm_decode_close,         \
     .sample_fmts = (const enum AVSampleFormat[]){sample_fmt_,AV_SAMPLE_FMT_NONE}, \
     .long_name = NULL_IF_CONFIG_SMALL(long_name_), \
 }
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 100c06d..e4888d9 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -21,7 +21,7 @@
 #define AVCODEC_VERSION_H
 
 #define LIBAVCODEC_VERSION_MAJOR 53
-#define LIBAVCODEC_VERSION_MINOR  7
+#define LIBAVCODEC_VERSION_MINOR  8
 #define LIBAVCODEC_VERSION_MICRO  0
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavformat/isom.c b/libavformat/isom.c
index 09ee23b..12cee67 100644
--- a/libavformat/isom.c
+++ b/libavformat/isom.c
@@ -476,6 +476,7 @@ void ff_mov_read_chan(AVFormatContext *s, int64_t size, AVCodecContext *codec)
         avio_skip(pb, size);
         return;
     }
+    codec->mov_channel_layout = layout_tag;
     while (layouts->channel_layout) {
         if (layout_tag == layouts->layout_tag) {
             codec->channel_layout = layouts->channel_layout;
@@ -483,8 +484,6 @@ void ff_mov_read_chan(AVFormatContext *s, int64_t size, AVCodecContext *codec)
         }
         layouts++;
     }
-    if (!codec->channel_layout)
-        av_log(s, AV_LOG_WARNING, "Unknown container channel layout.\n");
     avio_skip(pb, size);
 }
 


More information about the ffmpeg-devel mailing list