1 /*
2 * Audible AA demuxer
3 * Copyright (c) 2015 Vesselin Bontchev
4 *
5 * Header parsing is borrowed from https://github.com/jteeuwen/audible project.
6 * Copyright (c) 2001-2014, Jim Teeuwen
7 *
8 * Redistribution and use in source and binary forms, with or without modification,
9 * are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
35
36 #define AA_MAGIC 1469084982 /* this identifies an audible .aa file */
37 #define MAX_TOC_ENTRIES 16
38 #define MAX_DICTIONARY_ENTRIES 128
39 #define TEA_BLOCK_SIZE 8
40 #define CHAPTER_HEADER_SIZE 8
42 #define MP3_FRAME_SIZE 104
43
58
60 {
62
63 if (!strcmp(codec_name, "mp332")) {
65 } else if (!strcmp(codec_name, "acelp16")) {
67 } else if (!strcmp(codec_name, "acelp85")) {
69 }
70
72 }
73
75 {
76 int largest_idx = -1;
77 uint32_t toc_size, npairs, header_seed = 0, start;
78 char codec_name[64] = {0};
79 uint8_t buf[24];
80 int64_t largest_size = -1, current_size = -1, chapter_pos;
81 struct toc_entry {
85 uint8_t header_key[16] = {0};
87 char file_key[2 *
sizeof(
c->file_key) + 1];
92
93 /* parse .aa header */
100 for (uint32_t
i = 0;
i < toc_size;
i++) {
// read TOC
102 TOC[
i].offset =
avio_rb32(pb);
// block offset
104 }
105 avio_skip(pb, 24);
// header termination block (ignored)
106 npairs =
avio_rb32(pb);
// read dictionary entries
109 for (uint32_t
i = 0;
i < npairs;
i++) {
111 uint32_t nkey, nval;
112
113 avio_skip(pb, 1);
// unidentified integer
114 nkey =
avio_rb32(pb);
// key string length
115 nval =
avio_rb32(pb);
// value string length
118 if (!strcmp(
key,
"codec")) {
121 }
else if (!strcmp(
key,
"HeaderSeed")) {
123 header_seed = atoi(
val);
124 }
else if (!strcmp(
key,
"HeaderKey")) {
// this looks like "1234567890 1234567890 1234567890 1234567890"
125 uint32_t header_key_part[4];
127
128 ret = sscanf(
val,
"%"SCNu32
"%"SCNu32
"%"SCNu32
"%"SCNu32,
129 &header_key_part[0], &header_key_part[1], &header_key_part[2], &header_key_part[3]);
132
133 for (int idx = 0; idx < 4; idx++)
134 AV_WB32(&header_key[idx * 4], header_key_part[idx]);
// convert each part to BE!
137 } else {
139 }
140 }
141
142 /* verify fixed key */
143 if (
c->aa_fixed_key_len != 16) {
146 }
147
148 /* verify codec */
152 }
153
154 /* decryption key derivation */
159 for (
int i = 0;
i < 6;
i++)
167
168 /* decoder setup */
170 if (!st)
174 if (!strcmp(codec_name, "mp332")) {
179 // encoded audio frame is MP3_FRAME_SIZE bytes (+1 with padding, unlikely)
180 } else if (!strcmp(codec_name, "acelp85")) {
188 } else if (!strcmp(codec_name, "acelp16")) {
196 }
197
198 /* determine, and jump to audio start offset */
199 for (uint32_t
i = 1;
i < toc_size;
i++) {
// skip the first entry!
200 current_size = TOC[
i].size;
201 if (current_size > largest_size) {
203 largest_size = current_size;
204 }
205 }
206 start = TOC[largest_idx].offset;
208
209 // extract chapter positions. since all formats have constant bit rate, use it
210 // as time base in bytes/s, for easy stream position <-> timestamp conversion
212 c->content_start = start;
213 c->content_end = start + largest_size;
214
215 while ((chapter_pos =
avio_tell(pb)) >= 0 && chapter_pos < c->content_end) {
216 unsigned chapter_idx =
s->nb_chapters;
219 break;
226 }
227
229
232 c->current_chapter_size = 0;
234
235 return 0;
236 }
237
239 {
243
244 // are we at the end of the audio content?
245 if (
pos >=
c->content_end) {
247 }
248
249 // are we at the start of a chapter?
250 if (
c->current_chapter_size == 0) {
252 if (
c->current_chapter_size == 0) {
254 }
255 av_log(
s,
AV_LOG_DEBUG,
"Chapter %d (%" PRId64
" bytes)\n",
c->chapter_idx,
c->current_chapter_size);
256 c->chapter_idx =
c->chapter_idx + 1;
258 c->current_codec_second_size =
c->codec_second_size;
259 }
260
261 // is this the last block in this chapter?
262 if (
c->current_chapter_size /
c->current_codec_second_size == 0) {
263 c->current_codec_second_size =
c->current_chapter_size %
c->current_codec_second_size;
264 }
265
267 if (
ret !=
c->current_codec_second_size)
269
270 // decrypt c->current_codec_second_size bytes in blocks of TEA_BLOCK_SIZE
271 // trailing bytes are left unencrypted!
274
275 // update state
276 c->current_chapter_size =
c->current_chapter_size -
c->current_codec_second_size;
277 if (
c->current_chapter_size <= 0)
278 c->current_chapter_size = 0;
279
280 if (
c->seek_offset >
c->current_codec_second_size)
281 c->seek_offset = 0;
// ignore wrong estimate
285
286 return 0;
287 }
288
291 {
294 int64_t chapter_pos, chapter_start, chapter_size;
295 int chapter_idx = 0;
296
297 // find chapter containing seek timestamp
298 if (timestamp < 0)
299 timestamp = 0;
300
301 while (chapter_idx < s->nb_chapters && timestamp >=
s->chapters[chapter_idx]->end) {
302 ++chapter_idx;
303 }
304
305 if (chapter_idx >=
s->nb_chapters) {
306 chapter_idx =
s->nb_chapters - 1;
307 if (chapter_idx < 0) return -1; // there is no chapter.
308 timestamp =
s->chapters[chapter_idx]->end;
309 }
310
311 ch =
s->chapters[chapter_idx];
312
313 // sync by clamping timestamp to nearest valid block position in its chapter
316 1,
c->codec_second_size,
318 *
c->codec_second_size;
319 if (chapter_pos >= chapter_size)
320 chapter_pos = chapter_size;
322
323 // reinit read state
324 avio_seek(
s->pb, chapter_start + chapter_pos, SEEK_SET);
325 c->current_codec_second_size =
c->codec_second_size;
326 c->current_chapter_size = chapter_size - chapter_pos;
327 c->chapter_idx = 1 + chapter_idx;
328
329 // for unaligned frames, estimate offset of first frame in block (assume no padding)
332 }
333
335
336 return 1;
337 }
338
340 {
341 uint8_t *buf =
p->buf;
342
343 // first 4 bytes are file size, next 4 bytes are the magic
345 return 0;
346
348 }
349
351 {
353
355
356 return 0;
357 }
358
359 #define OFFSET(x) offsetof(AADemuxContext, x)
361 { "aa_fixed_key", // extracted from libAAX_SDK.so and AAXSDKWin.dll files!
362 "Fixed key used for handling Audible AA files",
OFFSET(aa_fixed_key),
366 };
367
373 };
374
379 .p.extensions = "aa",
388 };