1af8624b |
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 "caf_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 += 12; |
197 | break; |
198 | } else |
199 | TRY_IO(pcm_skip(&reader->io, chunk_size)); |
200 | |
201 | reader->data_offset += (chunk_size + 8); |
202 | } |
203 | ENSURE(reader->sample_format.channels_per_frame); |
204 | ENSURE(fcc == M4AF_FOURCC('d','a','t','a')); |
205 | return 0; |
206 | FAIL: |
207 | return -1; |
208 | } |
209 | |
210 | static pcm_reader_vtbl_t caf_vtable = { |
211 | caf_get_format, |
212 | caf_get_length, |
213 | caf_get_position, |
214 | caf_read_frames, |
215 | caf_teardown |
216 | }; |
217 | |
218 | pcm_reader_t *caf_open(pcm_io_context_t *io, |
219 | aacenc_tag_callback_t tag_callback, void *tag_ctx) |
220 | { |
221 | caf_reader_t *reader = 0; |
222 | int64_t data_length; |
223 | unsigned bpf; |
224 | |
225 | if ((reader = calloc(1, sizeof(caf_reader_t))) == 0) |
226 | return 0; |
227 | memcpy(&reader->io, io, sizeof(pcm_io_context_t)); |
228 | reader->tag_callback = tag_callback; |
229 | reader->tag_ctx = tag_ctx; |
230 | |
231 | if (caf_parse(reader, &data_length) < 0) { |
232 | free(reader); |
233 | return 0; |
234 | } |
235 | bpf = reader->sample_format.bytes_per_frame; |
236 | |
237 | /* CAF uses -1 to indicate "unknown size" */ |
238 | if (data_length < 0 || data_length % bpf) |
239 | reader->length = INT64_MAX; |
240 | else |
241 | reader->length = data_length / bpf; |
242 | |
243 | if (reader->length == INT64_MAX) { |
244 | if (pcm_seek(&reader->io, 0, SEEK_END) >= 0) { |
245 | int64_t size = pcm_tell(&reader->io); |
246 | if (size > 0) |
247 | reader->length = (size - reader->data_offset) / bpf; |
248 | pcm_seek(&reader->io, reader->data_offset, SEEK_SET); |
249 | } |
250 | } |
251 | reader->vtbl = &caf_vtable; |
252 | return (pcm_reader_t *)reader; |
253 | } |