X-Git-Url: http://git.ieval.ro/?p=fdkaac.git;a=blobdiff_plain;f=src%2Fpcm_readhelper.c;h=5a2b037b49a5cc2c71319e44b220518aa737e2a8;hp=70b47f57dc0317e5ac5339d1616018501cb51a74;hb=1af8624b009faf5bc6b9b8dfa76676483da5f6cf;hpb=29a8f73fafe37beb8048316cca06ac83dfd1f2e1 diff --git a/src/pcm_readhelper.c b/src/pcm_readhelper.c index 70b47f5..5a2b037 100644 --- a/src/pcm_readhelper.c +++ b/src/pcm_readhelper.c @@ -12,9 +12,12 @@ #endif #include +#include +#include #include #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; +}