caf input support
[fdkaac.git] / src / pcm_readhelper.c
index 70b47f57dc0317e5ac5339d1616018501cb51a74..5a2b037b49a5cc2c71319e44b220518aa737e2a8 100644 (file)
 #endif
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <stdarg.h>
 #include "pcm_reader.h"
 #include "m4af_endian.h"
+#include "catypes.h"
 
 int pcm_read(pcm_io_context_t *io, void *buffer, uint32_t size)
 {
@@ -152,3 +155,202 @@ FAIL:
     va_end(ap);
     return count;
 }
+
+static
+int channel_compare(const void *a, const void *b)
+{
+    return (*(const uint8_t **)a)[0] - (*(const uint8_t **)b)[0];
+}
+
+void apple_translate_channel_labels(uint8_t *channels, unsigned n)
+{
+    unsigned i;
+    char *has_side = strpbrk((char*)channels, "\x0A\x0B");
+
+    for (i = 0; i < n; ++i) {
+        switch (channels[i]) {
+        case kAudioChannelLabel_LeftSurround:
+        case kAudioChannelLabel_RightSurround:
+            if (!has_side) channels[i] += 5; // map to SL/SR
+            break;
+        case kAudioChannelLabel_RearSurroundLeft:
+        case kAudioChannelLabel_RearSurroundRight:
+            if (!has_side) channels[i] -= 28; // map to BL/BR
+            break;
+        case kAudioChannelLabel_Mono:
+            channels[i] = kAudioChannelLabel_Center;
+            break;
+        }
+    }
+}
+
+int apple_chan_chunk(pcm_io_context_t *io, uint32_t chunk_size,
+                     pcm_sample_description_t *fmt, uint8_t *mapping)
+{
+    /*
+     * Although FDK encoder supports upto 5.1ch, we handle upto
+     * 8 channels here.
+     */
+    uint32_t i, mChannelLayoutTag, mChannelBitmap, mNumberChannelDescriptions;
+    uint32_t mask = 0;
+    const uint32_t nchannels = fmt->channels_per_frame;
+    uint8_t channels[9] = { 0 };
+    uint8_t *index[8] = { 0 };
+    const char *layout = 0;
+
+    ENSURE(chunk_size >= 12);
+    TRY_IO(pcm_scanb(io, "LLL", &mChannelLayoutTag, &mChannelBitmap,
+                     &mNumberChannelDescriptions) != 3);
+
+    switch (mChannelLayoutTag) {
+    case kAudioChannelLayoutTag_UseChannelBitmap:
+        ENSURE(bitcount(mask) == nchannels);
+        TRY_IO(pcm_skip(io, chunk_size - 12));
+        fmt->channel_mask = mChannelBitmap;
+        for (i = 0; i < nchannels; ++i)
+            mapping[i] = i;
+        return 0;
+    case kAudioChannelLayoutTag_UseChannelDescriptions:
+        ENSURE(mNumberChannelDescriptions == nchannels);
+        ENSURE(chunk_size >= 12 + nchannels * 20);
+        for (i = 0; i < mNumberChannelDescriptions; ++i) {
+            uint32_t mChannelLabel;
+            TRY_IO(pcm_read32be(io, &mChannelLabel));
+            ENSURE(mChannelLabel && mChannelLabel <= 0xff);
+            channels[i] = mChannelLabel;
+            TRY_IO(pcm_skip(io, 16));
+        }
+        TRY_IO(pcm_skip(io, chunk_size - 12 - nchannels * 20));
+        apple_translate_channel_labels(channels, nchannels);
+        for (i = 0; i < nchannels; ++i)
+            if (channels[i] > kAudioChannelLabel_TopBackLeft)
+                goto FAIL;
+        break;
+    default:
+        ENSURE((mChannelLayoutTag & 0xffff) == nchannels);
+        TRY_IO(pcm_skip(io, chunk_size - 12));
+
+        switch (mChannelLayoutTag) {
+        /* 1ch */
+        case kAudioChannelLayoutTag_Mono:
+            layout = "\x03"; break;
+        /* 1.1ch */
+        case kAudioChannelLayoutTag_AC3_1_0_1:
+            layout = "\x03\x04"; break;
+        /* 2ch */
+        case kAudioChannelLayoutTag_Stereo:
+        case kAudioChannelLayoutTag_MatrixStereo:
+        case kAudioChannelLayoutTag_Binaural:
+            layout = "\x01\x02"; break;
+        /* 2.1ch */
+        case kAudioChannelLayoutTag_DVD_4:
+            layout = "\x01\x02\x04"; break;
+        /* 3ch */
+        case kAudioChannelLayoutTag_MPEG_3_0_A:
+            layout = "\x01\x02\x03"; break;
+        case kAudioChannelLayoutTag_AC3_3_0:
+            layout = "\x01\x03\x02"; break;
+        case kAudioChannelLayoutTag_MPEG_3_0_B:
+            layout = "\x03\x01\x02"; break;
+        case kAudioChannelLayoutTag_ITU_2_1:
+            layout = "\x01\x02\x09"; break;
+        /* 3.1ch */
+        case kAudioChannelLayoutTag_DVD_10:
+            layout = "\x01\x02\x03\x04"; break;
+        case kAudioChannelLayoutTag_AC3_3_0_1:
+            layout = "\x01\x03\x02\x04"; break;
+        case kAudioChannelLayoutTag_DVD_5:
+            layout = "\x01\x02\x04\x09"; break;
+        case kAudioChannelLayoutTag_AC3_2_1_1:
+            layout = "\x01\x02\x09\x04"; break;
+        /* 4ch */
+        case kAudioChannelLayoutTag_Quadraphonic:
+        case kAudioChannelLayoutTag_ITU_2_2:
+            layout = "\x01\x02\x0A\x0B"; break;
+        case kAudioChannelLayoutTag_MPEG_4_0_A:
+            layout = "\x01\x02\x03\x09"; break;
+        case kAudioChannelLayoutTag_MPEG_4_0_B:
+            layout = "\x03\x01\x02\x09"; break;
+        case kAudioChannelLayoutTag_AC3_3_1:
+            layout = "\x01\x03\x02\x09"; break;
+        /* 4.1ch */
+        case kAudioChannelLayoutTag_DVD_6:
+            layout = "\x01\x02\x04\x0A\x0B"; break;
+        case kAudioChannelLayoutTag_DVD_18:
+            layout = "\x01\x02\x0A\x0B\x04"; break;
+        case kAudioChannelLayoutTag_DVD_11:
+            layout = "\x01\x02\x03\x04\x09"; break;
+        case kAudioChannelLayoutTag_AC3_3_1_1:
+            layout = "\x01\x03\x02\x09\x04"; break;
+        /* 5ch */
+        case kAudioChannelLayoutTag_MPEG_5_0_A:
+            layout = "\x01\x02\x03\x0A\x0B"; break;
+        case kAudioChannelLayoutTag_Pentagonal:
+        case kAudioChannelLayoutTag_MPEG_5_0_B:
+            layout = "\x01\x02\x0A\x0B\x03"; break;
+        case kAudioChannelLayoutTag_MPEG_5_0_C:
+            layout = "\x01\x03\x02\x0A\x0B"; break;
+        case kAudioChannelLayoutTag_MPEG_5_0_D:
+            layout = "\x03\x01\x02\x0A\x0B"; break;
+        /* 5.1ch */
+        case kAudioChannelLayoutTag_MPEG_5_1_A:
+            layout = "\x01\x02\x03\x04\x0A\x0B"; break;
+        case kAudioChannelLayoutTag_MPEG_5_1_B:
+            layout = "\x01\x02\x0A\x0B\x03\x04"; break;
+        case kAudioChannelLayoutTag_MPEG_5_1_C:
+            layout = "\x01\x03\x02\x0A\x0B\x04"; break;
+        case kAudioChannelLayoutTag_MPEG_5_1_D:
+            layout = "\x03\x01\x02\x0A\x0B\x04"; break;
+        /* 6ch */
+        case kAudioChannelLayoutTag_Hexagonal:
+        case kAudioChannelLayoutTag_AudioUnit_6_0:
+            layout = "\x01\x02\x0A\x0B\x03\x09"; break;
+        case kAudioChannelLayoutTag_AAC_6_0:
+            layout = "\x03\x01\x02\x0A\x0B\x09"; break;
+        /* 6.1ch */
+        case kAudioChannelLayoutTag_MPEG_6_1_A:
+            layout = "\x01\x02\x03\x04\x0A\x0B\x09"; break;
+        case kAudioChannelLayoutTag_AAC_6_1:
+            layout = "\x03\x01\x02\x0A\x0B\x09\x04"; break;
+        /* 7ch */
+        case kAudioChannelLayoutTag_AudioUnit_7_0:
+            layout = "\x01\x02\x0A\x0B\x03\x05\x06"; break;
+        case kAudioChannelLayoutTag_AudioUnit_7_0_Front:
+            layout = "\x01\x02\x0A\x0B\x03\x07\x08"; break;
+        case kAudioChannelLayoutTag_AAC_7_0:
+            layout = "\x03\x01\x02\x0A\x0B\x05\x06"; break;
+        /* 7.1ch */
+        case kAudioChannelLayoutTag_MPEG_7_1_A:
+            layout = "\x01\x02\x03\x04\x0A\x0B\x07\x08"; break;
+        case kAudioChannelLayoutTag_MPEG_7_1_B:
+            layout = "\x03\x07\x08\x01\x02\x05\x06\x04"; break;
+        case kAudioChannelLayoutTag_MPEG_7_1_C:
+            layout = "\x01\x02\x03\x04\x0A\x0B\x05\x06"; break;
+        case kAudioChannelLayoutTag_Emagic_Default_7_1:
+            layout = "\x01\x02\x0A\x0B\x03\x04\x07\x08"; break;
+        /* 8ch */
+        case kAudioChannelLayoutTag_Octagonal:
+            layout = "\x01\x02\x05\x06\x03\x09\x0A\x0B"; break;
+        case kAudioChannelLayoutTag_AAC_Octagonal:
+            layout = "\x03\x01\x02\x0A\x0B\x05\x06\x09"; break;
+        default:
+            goto FAIL;
+        }
+        strcpy((char*)channels, layout);
+    }
+
+    for (i = 0; i < nchannels; ++i)
+        mask |= 1 << (channels[i] - 1);
+    fmt->channel_mask = mask;
+    ENSURE(bitcount(mask) == nchannels);
+
+    for (i = 0; i < nchannels; ++i) 
+        index[i] = channels + i;
+    qsort(index, nchannels, sizeof(char*), channel_compare);
+    for (i = 0; i < nchannels; ++i) 
+        mapping[i] = index[i] - channels;
+
+    return 0;
+FAIL:
+    return -1;
+}
This page took 0.012347 seconds and 4 git commands to generate.