refactor pcm reader framework
[fdkaac.git] / src / caf_reader.c
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 }
This page took 0.028573 seconds and 4 git commands to generate.