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
34
35 #define AA_MAGIC 1469084982 /* this identifies an audible .aa file */
36 #define MAX_TOC_ENTRIES 16
37 #define MAX_DICTIONARY_ENTRIES 128
38 #define TEA_BLOCK_SIZE 8
39 #define CHAPTER_HEADER_SIZE 8
41 #define MP3_FRAME_SIZE 104
42
57
59 {
61
62 if (!strcmp(codec_name, "mp332")) {
64 } else if (!strcmp(codec_name, "acelp16")) {
66 } else if (!strcmp(codec_name, "acelp85")) {
68 }
69
71 }
72
74 {
75 int largest_idx = -1;
76 uint32_t toc_size, npairs, header_seed = 0, start;
77 char codec_name[64] = {0};
78 uint8_t buf[24];
79 int64_t largest_size = -1, current_size = -1, chapter_pos;
80 struct toc_entry {
84 uint8_t header_key[16] = {0};
86 char file_key[2 *
sizeof(
c->file_key) + 1];
91
92 /* parse .aa header */
99 for (uint32_t
i = 0;
i < toc_size;
i++) {
// read TOC
101 TOC[
i].offset =
avio_rb32(pb);
// block offset
103 }
104 avio_skip(pb, 24);
// header termination block (ignored)
105 npairs =
avio_rb32(pb);
// read dictionary entries
108 for (uint32_t
i = 0;
i < npairs;
i++) {
110 uint32_t nkey, nval;
111
112 avio_skip(pb, 1);
// unidentified integer
113 nkey =
avio_rb32(pb);
// key string length
114 nval =
avio_rb32(pb);
// value string length
117 if (!strcmp(
key,
"codec")) {
120 }
else if (!strcmp(
key,
"HeaderSeed")) {
122 header_seed = atoi(
val);
123 }
else if (!strcmp(
key,
"HeaderKey")) {
// this looks like "1234567890 1234567890 1234567890 1234567890"
124 uint32_t header_key_part[4];
126
127 ret = sscanf(
val,
"%"SCNu32
"%"SCNu32
"%"SCNu32
"%"SCNu32,
128 &header_key_part[0], &header_key_part[1], &header_key_part[2], &header_key_part[3]);
131
132 for (int idx = 0; idx < 4; idx++)
133 AV_WB32(&header_key[idx * 4], header_key_part[idx]);
// convert each part to BE!
136 } else {
138 }
139 }
140
141 /* verify fixed key */
142 if (
c->aa_fixed_key_len != 16) {
145 }
146
147 /* verify codec */
151 }
152
153 /* decryption key derivation */
158 for (
int i = 0;
i < 6;
i++)
166
167 /* decoder setup */
169 if (!st)
173 if (!strcmp(codec_name, "mp332")) {
178 // encoded audio frame is MP3_FRAME_SIZE bytes (+1 with padding, unlikely)
179 } else if (!strcmp(codec_name, "acelp85")) {
187 } else if (!strcmp(codec_name, "acelp16")) {
195 }
196
197 /* determine, and jump to audio start offset */
198 for (uint32_t
i = 1;
i < toc_size;
i++) {
// skip the first entry!
199 current_size = TOC[
i].size;
200 if (current_size > largest_size) {
202 largest_size = current_size;
203 }
204 }
205 start = TOC[largest_idx].offset;
207
208 // extract chapter positions. since all formats have constant bit rate, use it
209 // as time base in bytes/s, for easy stream position <-> timestamp conversion
211 c->content_start = start;
212 c->content_end = start + largest_size;
213
214 while ((chapter_pos =
avio_tell(pb)) >= 0 && chapter_pos < c->content_end) {
215 unsigned chapter_idx =
s->nb_chapters;
218 break;
225 }
226
228
231 c->current_chapter_size = 0;
233
234 return 0;
235 }
236
238 {
242
243 // are we at the end of the audio content?
244 if (
pos >=
c->content_end) {
246 }
247
248 // are we at the start of a chapter?
249 if (
c->current_chapter_size == 0) {
251 if (
c->current_chapter_size == 0) {
253 }
254 av_log(
s,
AV_LOG_DEBUG,
"Chapter %d (%" PRId64
" bytes)\n",
c->chapter_idx,
c->current_chapter_size);
255 c->chapter_idx =
c->chapter_idx + 1;
257 c->current_codec_second_size =
c->codec_second_size;
258 }
259
260 // is this the last block in this chapter?
261 if (
c->current_chapter_size /
c->current_codec_second_size == 0) {
262 c->current_codec_second_size =
c->current_chapter_size %
c->current_codec_second_size;
263 }
264
266 if (
ret !=
c->current_codec_second_size)
268
269 // decrypt c->current_codec_second_size bytes in blocks of TEA_BLOCK_SIZE
270 // trailing bytes are left unencrypted!
273
274 // update state
275 c->current_chapter_size =
c->current_chapter_size -
c->current_codec_second_size;
276 if (
c->current_chapter_size <= 0)
277 c->current_chapter_size = 0;
278
279 if (
c->seek_offset >
c->current_codec_second_size)
280 c->seek_offset = 0;
// ignore wrong estimate
284
285 return 0;
286 }
287
289 int stream_index, int64_t timestamp,
int flags)
290 {
293 int64_t chapter_pos, chapter_start, chapter_size;
294 int chapter_idx = 0;
295
296 // find chapter containing seek timestamp
297 if (timestamp < 0)
298 timestamp = 0;
299
300 while (chapter_idx < s->nb_chapters && timestamp >=
s->chapters[chapter_idx]->end) {
301 ++chapter_idx;
302 }
303
304 if (chapter_idx >=
s->nb_chapters) {
305 chapter_idx =
s->nb_chapters - 1;
306 if (chapter_idx < 0) return -1; // there is no chapter.
307 timestamp =
s->chapters[chapter_idx]->end;
308 }
309
310 ch =
s->chapters[chapter_idx];
311
312 // sync by clamping timestamp to nearest valid block position in its chapter
315 1,
c->codec_second_size,
317 *
c->codec_second_size;
318 if (chapter_pos >= chapter_size)
319 chapter_pos = chapter_size;
321
322 // reinit read state
323 avio_seek(
s->pb, chapter_start + chapter_pos, SEEK_SET);
324 c->current_codec_second_size =
c->codec_second_size;
325 c->current_chapter_size = chapter_size - chapter_pos;
326 c->chapter_idx = 1 + chapter_idx;
327
328 // for unaligned frames, estimate offset of first frame in block (assume no padding)
331 }
332
334
335 return 1;
336 }
337
339 {
340 uint8_t *buf = p->
buf;
341
342 // first 4 bytes are file size, next 4 bytes are the magic
344 return 0;
345
347 }
348
350 {
352
354
355 return 0;
356 }
357
358 #define OFFSET(x) offsetof(AADemuxContext, x)
360 { "aa_fixed_key", // extracted from libAAX_SDK.so and AAXSDKWin.dll files!
361 "Fixed key used for handling Audible AA files",
OFFSET(aa_fixed_key),
365 };
366
372 };
373
379 .extensions = "aa",
387 };