| 1 | /* |
| 2 | * Copyright (C) 2013 nu774 |
| 3 | * For conditions of distribution and use, see copyright notice in COPYING |
| 4 | */ |
| 5 | #if HAVE_CONFIG_H |
| 6 | # include "config.h" |
| 7 | #endif |
| 8 | |
| 9 | #if HAVE_STDINT_H |
| 10 | # include <stdint.h> |
| 11 | #endif |
| 12 | |
| 13 | #include <stdio.h> |
| 14 | #include <stdlib.h> |
| 15 | #include <string.h> |
| 16 | #include <stdarg.h> |
| 17 | #include "pcm_reader.h" |
| 18 | #include "m4af.h" |
| 19 | |
| 20 | typedef struct caf_reader_t { |
| 21 | pcm_reader_vtbl_t *vtbl; |
| 22 | pcm_sample_description_t sample_format; |
| 23 | int64_t length; |
| 24 | int64_t position; |
| 25 | int64_t data_offset; |
| 26 | pcm_io_context_t io; |
| 27 | aacenc_tag_callback_t tag_callback; |
| 28 | void *tag_ctx; |
| 29 | uint8_t chanmap[8]; |
| 30 | } caf_reader_t; |
| 31 | |
| 32 | static const pcm_sample_description_t *caf_get_format(pcm_reader_t *reader) |
| 33 | { |
| 34 | return &((caf_reader_t *)reader)->sample_format; |
| 35 | } |
| 36 | |
| 37 | static int64_t caf_get_length(pcm_reader_t *reader) |
| 38 | { |
| 39 | return ((caf_reader_t *)reader)->length; |
| 40 | } |
| 41 | |
| 42 | static int64_t caf_get_position(pcm_reader_t *reader) |
| 43 | { |
| 44 | return ((caf_reader_t *)reader)->position; |
| 45 | } |
| 46 | |
| 47 | static void caf_teardown(pcm_reader_t **reader) |
| 48 | { |
| 49 | free(*reader); |
| 50 | *reader = 0; |
| 51 | } |
| 52 | |
| 53 | static |
| 54 | uint32_t caf_next_chunk(caf_reader_t *reader, int64_t *chunk_size) |
| 55 | { |
| 56 | uint32_t fcc; |
| 57 | if (pcm_scanb(&reader->io, "LQ", &fcc, chunk_size) == 2) |
| 58 | return fcc; |
| 59 | return 0; |
| 60 | } |
| 61 | |
| 62 | static |
| 63 | int caf_desc(caf_reader_t *reader, int64_t chunk_size) |
| 64 | { |
| 65 | double mSampleRate; |
| 66 | uint32_t mFormatID, mFormatFlags, mBytesPerPacket, mFramesPerPacket, |
| 67 | mChannelsPerFrame, mBitsPerChannel; |
| 68 | pcm_sample_description_t *desc = &reader->sample_format; |
| 69 | |
| 70 | ENSURE(chunk_size >= 32); |
| 71 | TRY_IO(pcm_scanb(&reader->io, "QLLLLLL", &mSampleRate, &mFormatID, |
| 72 | &mFormatFlags, &mBytesPerPacket, &mFramesPerPacket, |
| 73 | &mChannelsPerFrame, &mBitsPerChannel) != 7); |
| 74 | |
| 75 | ENSURE(mFormatID == M4AF_FOURCC('l','p','c','m')); |
| 76 | ENSURE(mSampleRate && mBytesPerPacket && |
| 77 | mChannelsPerFrame >= 1 && mChannelsPerFrame <= 8 && |
| 78 | mBitsPerChannel && mFramesPerPacket == 1 && |
| 79 | mBytesPerPacket % mChannelsPerFrame == 0 && |
| 80 | mBytesPerPacket >= mChannelsPerFrame * ((mBitsPerChannel + 7) / 8)); |
| 81 | |
| 82 | desc->sample_rate = mSampleRate; |
| 83 | desc->bits_per_channel = mBitsPerChannel; |
| 84 | desc->bytes_per_frame = mBytesPerPacket; |
| 85 | desc->channels_per_frame = mChannelsPerFrame; |
| 86 | |
| 87 | switch (mFormatFlags) { |
| 88 | case 0: desc->sample_type = PCM_TYPE_SINT_BE; break; |
| 89 | case 1: desc->sample_type = PCM_TYPE_FLOAT_BE; break; |
| 90 | case 2: desc->sample_type = PCM_TYPE_SINT; break; |
| 91 | case 3: desc->sample_type = PCM_TYPE_FLOAT; break; |
| 92 | default: goto FAIL; |
| 93 | } |
| 94 | |
| 95 | TRY_IO(pcm_skip(&reader->io, chunk_size - 32)); |
| 96 | return 0; |
| 97 | FAIL: |
| 98 | return -1; |
| 99 | } |
| 100 | |
| 101 | static |
| 102 | int caf_info(caf_reader_t *reader, int64_t chunk_size) |
| 103 | { |
| 104 | char *buf, *key, *val, *end; |
| 105 | size_t len; |
| 106 | |
| 107 | if (chunk_size < 4 || (buf = malloc(chunk_size)) == 0) |
| 108 | return -1; |
| 109 | pcm_read(&reader->io, buf, chunk_size); |
| 110 | key = buf + 4; |
| 111 | end = buf + chunk_size; |
| 112 | do { |
| 113 | if ((val = key + strlen(key) + 1) < end) { |
| 114 | len = strlen(val); |
| 115 | if (reader->tag_callback) |
| 116 | reader->tag_callback(reader->tag_ctx, key, val, len); |
| 117 | key = val + len + 1; |
| 118 | } |
| 119 | } while (key < end && val < end); |
| 120 | |
| 121 | if (reader->tag_callback) |
| 122 | reader->tag_callback(reader->tag_ctx, 0, 0, 0); |
| 123 | free(buf); |
| 124 | return 0; |
| 125 | } |
| 126 | |
| 127 | static |
| 128 | int caf_read_frames(pcm_reader_t *preader, void *buffer, unsigned nframes) |
| 129 | { |
| 130 | int rc; |
| 131 | unsigned i, j, nbytes; |
| 132 | caf_reader_t *reader = (caf_reader_t *)preader; |
| 133 | unsigned bpf = reader->sample_format.bytes_per_frame; |
| 134 | unsigned nchannels = reader->sample_format.channels_per_frame; |
| 135 | unsigned bpc = bpf / nchannels; |
| 136 | uint8_t tmp[64]; /* enough room for maximum bpf: 8ch float64 */ |
| 137 | uint8_t *bp; |
| 138 | uint8_t *chanmap = reader->chanmap; |
| 139 | |
| 140 | if (nframes > reader->length - reader->position) |
| 141 | nframes = reader->length - reader->position; |
| 142 | nbytes = nframes * bpf; |
| 143 | if (nbytes) { |
| 144 | if ((rc = pcm_read(&reader->io, buffer, nbytes)) < 0) |
| 145 | return -1; |
| 146 | nframes = rc / bpf; |
| 147 | for (bp = buffer, i = 0; i < nframes; ++i, bp += bpf) { |
| 148 | memcpy(tmp, bp, bpf); |
| 149 | for (j = 0; j < nchannels; ++j) |
| 150 | memcpy(bp + bpc * j, tmp + bpc * chanmap[j], bpc); |
| 151 | } |
| 152 | reader->position += nframes; |
| 153 | } |
| 154 | if (nframes == 0) { |
| 155 | /* fetch info after data chunk */ |
| 156 | uint32_t fcc; |
| 157 | int64_t chunk_size; |
| 158 | while ((fcc = caf_next_chunk(reader, &chunk_size)) != 0) { |
| 159 | if (fcc == M4AF_FOURCC('i','n','f','o')) |
| 160 | TRY_IO(caf_info(reader, chunk_size)); |
| 161 | else |
| 162 | TRY_IO(pcm_skip(&reader->io, chunk_size)); |
| 163 | } |
| 164 | } |
| 165 | return nframes; |
| 166 | FAIL: |
| 167 | return 0; |
| 168 | } |
| 169 | |
| 170 | static |
| 171 | int caf_parse(caf_reader_t *reader, int64_t *data_length) |
| 172 | { |
| 173 | uint32_t fcc; |
| 174 | int64_t chunk_size; |
| 175 | |
| 176 | *data_length = 0; |
| 177 | |
| 178 | /* CAFFileHeader */ |
| 179 | TRY_IO(pcm_read32be(&reader->io, &fcc)); |
| 180 | ENSURE(fcc == M4AF_FOURCC('c','a','f','f')); |
| 181 | TRY_IO(pcm_skip(&reader->io, 4)); /* mFileVersion, mFileFlags */ |
| 182 | |
| 183 | while ((fcc = caf_next_chunk(reader, &chunk_size)) != 0) { |
| 184 | if (fcc == M4AF_FOURCC('d','e','s','c')) |
| 185 | TRY_IO(caf_desc(reader, chunk_size)); |
| 186 | else if (fcc == M4AF_FOURCC('i','n','f','o')) |
| 187 | TRY_IO(caf_info(reader, chunk_size)); |
| 188 | else if (fcc == M4AF_FOURCC('c','h','a','n')) { |
| 189 | ENSURE(reader->sample_format.channels_per_frame); |
| 190 | if (apple_chan_chunk(&reader->io, chunk_size, |
| 191 | &reader->sample_format, reader->chanmap) < 0) |
| 192 | goto FAIL; |
| 193 | } else if (fcc == M4AF_FOURCC('d','a','t','a')) { |
| 194 | TRY_IO(pcm_skip(&reader->io, 4)); /* mEditCount */ |
| 195 | *data_length = (chunk_size == ~0ULL) ? chunk_size : chunk_size - 4; |
| 196 | reader->data_offset = pcm_tell(&reader->io); |
| 197 | break; |
| 198 | } else |
| 199 | TRY_IO(pcm_skip(&reader->io, chunk_size)); |
| 200 | } |
| 201 | ENSURE(reader->sample_format.channels_per_frame); |
| 202 | ENSURE(fcc == M4AF_FOURCC('d','a','t','a')); |
| 203 | return 0; |
| 204 | FAIL: |
| 205 | return -1; |
| 206 | } |
| 207 | |
| 208 | static pcm_reader_vtbl_t caf_vtable = { |
| 209 | caf_get_format, |
| 210 | caf_get_length, |
| 211 | caf_get_position, |
| 212 | caf_read_frames, |
| 213 | caf_teardown |
| 214 | }; |
| 215 | |
| 216 | pcm_reader_t *caf_open(pcm_io_context_t *io, |
| 217 | aacenc_tag_callback_t tag_callback, void *tag_ctx) |
| 218 | { |
| 219 | caf_reader_t *reader = 0; |
| 220 | int64_t data_length; |
| 221 | unsigned bpf; |
| 222 | |
| 223 | if ((reader = calloc(1, sizeof(caf_reader_t))) == 0) |
| 224 | return 0; |
| 225 | memcpy(&reader->io, io, sizeof(pcm_io_context_t)); |
| 226 | reader->tag_callback = tag_callback; |
| 227 | reader->tag_ctx = tag_ctx; |
| 228 | memcpy(reader->chanmap, "\000\001\002\003\004\005\006\007", 8); |
| 229 | |
| 230 | if (caf_parse(reader, &data_length) < 0) { |
| 231 | free(reader); |
| 232 | return 0; |
| 233 | } |
| 234 | bpf = reader->sample_format.bytes_per_frame; |
| 235 | |
| 236 | /* CAF uses -1 to indicate "unknown size" */ |
| 237 | if (data_length < 0 || data_length % bpf) |
| 238 | reader->length = INT64_MAX; |
| 239 | else |
| 240 | reader->length = data_length / bpf; |
| 241 | |
| 242 | if (reader->length == INT64_MAX) { |
| 243 | if (pcm_seek(&reader->io, 0, SEEK_END) >= 0) { |
| 244 | int64_t size = pcm_tell(&reader->io); |
| 245 | if (size > 0) |
| 246 | reader->length = (size - reader->data_offset) / bpf; |
| 247 | pcm_seek(&reader->io, reader->data_offset, SEEK_SET); |
| 248 | } |
| 249 | } |
| 250 | reader->vtbl = &caf_vtable; |
| 251 | return (pcm_reader_t *)reader; |
| 252 | } |