Merge remote-tracking branch 'qatar/master'
[ffmpeg.git] / libavcodec / mlpdec.c
index 9a2496d..9909a71 100644 (file)
@@ -2,20 +2,20 @@
  * MLP decoder
  * Copyright (c) 2007-2008 Ian Caulfield
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * 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.
  *
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -41,7 +41,7 @@
 
 static const char* sample_message =
     "Please file a bug report following the instructions at "
-    "http://libav.org/bugreports.html and include "
+    "http://ffmpeg.org/bugreports.html and include "
     "a sample of this file.";
 
 typedef struct SubStream {
@@ -134,6 +134,9 @@ typedef struct MLPDecodeContext {
     /// Index of the last substream to decode - further substreams are skipped.
     uint8_t     max_decoded_substream;
 
+    /// Stream needs channel reordering to comply with FFmpeg's channel order
+    uint8_t     needs_reordering;
+
     /// number of PCM samples contained in each frame
     int         access_unit_size;
     /// next power of two above the number of samples in each frame
@@ -330,6 +333,26 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb)
     for (substr = 0; substr < MAX_SUBSTREAMS; substr++)
         m->substream[substr].restart_seen = 0;
 
+    if (mh.stream_type == 0xbb) {
+        /* MLP stream */
+        m->avctx->channel_layout = ff_mlp_layout[mh.channels_mlp];
+    } else { /* mh.stream_type == 0xba */
+        /* TrueHD stream */
+        if (mh.channels_thd_stream2) {
+            m->avctx->channel_layout = ff_truehd_layout(mh.channels_thd_stream2);
+        } else {
+            m->avctx->channel_layout = ff_truehd_layout(mh.channels_thd_stream1);
+        }
+        if (m->avctx->channels &&
+            !m->avctx->request_channels && !m->avctx->request_channel_layout &&
+            av_get_channel_layout_nb_channels(m->avctx->channel_layout) != m->avctx->channels) {
+            m->avctx->channel_layout = 0;
+            av_log_ask_for_sample(m->avctx, "Unknown channel layout.");
+        }
+    }
+
+    m->needs_reordering = mh.channels_mlp >= 18 && mh.channels_mlp <= 20;
+
     return 0;
 }
 
@@ -440,6 +463,33 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
         s->ch_assign[ch_assign] = ch;
     }
 
+    if (m->avctx->codec_id == CODEC_ID_MLP && m->needs_reordering) {
+        if (m->avctx->channel_layout == (AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY) ||
+            m->avctx->channel_layout == AV_CH_LAYOUT_5POINT0_BACK) {
+            int i = s->ch_assign[4];
+            s->ch_assign[4] = s->ch_assign[3];
+            s->ch_assign[3] = s->ch_assign[2];
+            s->ch_assign[2] = i;
+        } else if (m->avctx->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) {
+            FFSWAP(int, s->ch_assign[2], s->ch_assign[4]);
+            FFSWAP(int, s->ch_assign[3], s->ch_assign[5]);
+        }
+    }
+    if (m->avctx->codec_id == CODEC_ID_TRUEHD &&
+        (m->avctx->channel_layout == AV_CH_LAYOUT_7POINT1 ||
+        m->avctx->channel_layout == AV_CH_LAYOUT_7POINT1_WIDE)) {
+        FFSWAP(int, s->ch_assign[4], s->ch_assign[6]);
+        FFSWAP(int, s->ch_assign[5], s->ch_assign[7]);
+    } else if (m->avctx->codec_id == CODEC_ID_TRUEHD &&
+        (m->avctx->channel_layout == AV_CH_LAYOUT_6POINT1 ||
+        m->avctx->channel_layout == (AV_CH_LAYOUT_6POINT1 | AV_CH_TOP_CENTER) ||
+        m->avctx->channel_layout == (AV_CH_LAYOUT_6POINT1 | AV_CH_TOP_FRONT_CENTER))) {
+        int i = s->ch_assign[6];
+        s->ch_assign[6] = s->ch_assign[5];
+        s->ch_assign[5] = s->ch_assign[4];
+        s->ch_assign[4] = i;
+    }
+
     checksum = ff_mlp_restart_checksum(buf, get_bits_count(gbp) - start_count);
 
     if (checksum != get_bits(gbp, 8))