mlp, truehd: support non 1:1 channel mapping.
[libav.git] / libavcodec / mlpdec.c
index 0630428..c5a97ac 100644 (file)
@@ -58,6 +58,8 @@ typedef struct SubStream {
     uint8_t     max_channel;
     //! The number of channels input into the rematrix stage.
     uint8_t     max_matrix_channel;
+    //! For each channel output by the matrix, the output channel to map it to
+    uint8_t     ch_assign[MAX_CHANNELS];
 
     //! The left shift applied to random noise in 0x31ea substreams.
     uint8_t     noise_shift;
@@ -380,16 +382,19 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
 
     skip_bits(gbp, 16);
 
+    memset(s->ch_assign, 0, sizeof(s->ch_assign));
+
     for (ch = 0; ch <= s->max_matrix_channel; ch++) {
         int ch_assign = get_bits(gbp, 6);
         dprintf(m->avctx, "ch_assign[%d][%d] = %d\n", substr, ch,
                 ch_assign);
-        if (ch_assign != ch) {
+        if (ch_assign > s->max_matrix_channel) {
             av_log(m->avctx, AV_LOG_ERROR,
-                   "Non-1:1 channel assignments are used in this stream. %s\n",
-                   sample_message);
+                   "Assignment of matrix channel %d to invalid output channel %d. %s\n",
+                   ch, ch_assign, sample_message);
             return -1;
         }
+        s->ch_assign[ch_assign] = ch;
     }
 
     checksum = ff_mlp_restart_checksum(buf, get_bits_count(gbp) - start_count);
@@ -421,7 +426,7 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
     }
 
     if (substr == m->max_decoded_substream) {
-        m->avctx->channels = s->max_channel + 1;
+        m->avctx->channels = s->max_matrix_channel + 1;
     }
 
     return 0;
@@ -831,7 +836,7 @@ static int output_data_internal(MLPDecodeContext *m, unsigned int substr,
                                 uint8_t *data, unsigned int *data_size, int is32)
 {
     SubStream *s = &m->substream[substr];
-    unsigned int i, ch = 0;
+    unsigned int i, out_ch = 0;
     int32_t *data_32 = (int32_t*) data;
     int16_t *data_16 = (int16_t*) data;
 
@@ -839,15 +844,17 @@ static int output_data_internal(MLPDecodeContext *m, unsigned int substr,
         return -1;
 
     for (i = 0; i < s->blockpos; i++) {
-        for (ch = 0; ch <= s->max_channel; ch++) {
-            int32_t sample = m->sample_buffer[i][ch] << s->output_shift[ch];
-            s->lossless_check_data ^= (sample & 0xffffff) << ch;
+        for (out_ch = 0; out_ch <= s->max_matrix_channel; out_ch++) {
+            int mat_ch = s->ch_assign[out_ch];
+            int32_t sample = m->sample_buffer[i][mat_ch]
+                          << s->output_shift[mat_ch];
+            s->lossless_check_data ^= (sample & 0xffffff) << mat_ch;
             if (is32) *data_32++ = sample << 8;
             else      *data_16++ = sample >> 8;
         }
     }
 
-    *data_size = i * ch * (is32 ? 4 : 2);
+    *data_size = i * out_ch * (is32 ? 4 : 2);
 
     return 0;
 }