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

Carl Eugen Hoyos cehoyos at ag.or.at
Mon Jun 13 22:01:51 CEST 2011


Hi!

Attached patch fixes ticket 98.

Please comment, Carl Eugen
-------------- next part --------------
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index ef539a2..e651bd9 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2899,6 +2899,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
+     */
+    int32_t mov_channel_layout;
+
 } AVCodecContext;
 
 /**
diff --git a/libavcodec/pcm.c b/libavcodec/pcm.c
index 111ce61..9835582 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,16 @@ 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++;
+        }
     return 0;
 }
 
@@ -468,9 +528,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 +594,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/libavformat/isom.c b/libavformat/isom.c
index 45ccdd2..8ed15ea 100644
--- a/libavformat/isom.c
+++ b/libavformat/isom.c
@@ -471,6 +471,7 @@ void ff_mov_read_chan(AVFormatContext *s, int64_t size, AVCodecContext *codec)
         avio_skip(pb, 4);
         return;
     }
+    codec->mov_channel_layout = layout_tag;
     while (layouts->channel_layout) {
         if (layout_tag == layouts->layout_tag) {
             codec->channel_layout = layouts->channel_layout;
@@ -478,8 +479,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, 8);
 }
 


More information about the ffmpeg-devel mailing list