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
32
33 #define AA_MAGIC 1469084982 /* this identifies an audible .aa file */
34 #define MAX_CODEC_SECOND_SIZE 3982
35 #define MAX_TOC_ENTRIES 16
36 #define MAX_DICTIONARY_ENTRIES 128
37 #define TEA_BLOCK_SIZE 8
38
50
52 {
53 int result = -1;
54
55 if (!strcmp(codec_name, "mp332")) {
56 result = 3982;
57 } else if (!strcmp(codec_name, "acelp16")) {
58 result = 2000;
59 } else if (!strcmp(codec_name, "acelp85")) {
60 result = 1045;
61 }
62
63 return result;
64 }
65
67 {
68 int i, j, idx, largest_idx = -1;
69 uint32_t nkey, nval, toc_size, npairs, header_seed = 0,
start;
70 char key[128],
val[128], codec_name[64] = {0};
72 int64_t largest_size = -1, current_size = -1;
73 struct toc_entry {
77 uint32_t header_key_part[4];
82
83 /* parse .aa header */
90 for (i = 0; i < toc_size; i++) { // read TOC
92 TOC[i].offset =
avio_rb32(pb);
// block offset
93 TOC[i].size =
avio_rb32(pb);
// block size
94 }
95 avio_skip(pb, 24);
// header termination block (ignored)
96 npairs =
avio_rb32(pb);
// read dictionary entries
99 for (i = 0; i < npairs; i++) {
100 memset(val, 0, sizeof(val));
101 memset(key, 0, sizeof(key));
102 avio_skip(pb, 1);
// unidentified integer
103 nkey =
avio_rb32(pb);
// key string length
104 nval =
avio_rb32(pb);
// value string length
107 if (!strcmp(key, "codec")) {
109 strncpy(codec_name, val, sizeof(codec_name) - 1);
110 } else if (!strcmp(key, "HeaderSeed")) {
112 header_seed = atoi(val);
113 } else if (!strcmp(key, "HeaderKey")) { // this looks like "1234567890 1234567890 1234567890 1234567890"
115 sscanf(val, "%"SCNu32"%"SCNu32"%"SCNu32"%"SCNu32,
116 &header_key_part[0], &header_key_part[1], &header_key_part[2], &header_key_part[3]);
117 for (idx = 0; idx < 4; idx++) {
118 AV_WB32(&header_key[idx * 4], header_key_part[idx]);
// convert each part to BE!
119 }
121 for (i = 0; i < 16; i++)
124 } else {
126 }
127 }
128
129 /* verify fixed key */
133 }
134
135 /* verify codec */
139 }
140
141 /* decryption key derivation */
146 output[0] = output[1] = 0; // purely for padding purposes
147 memcpy(output + 2, header_key, 16);
148 idx = 0;
149 for (i = 0; i < 3; i++) { // TEA CBC with weird mixed endianness
151 AV_WB32(src + 4, header_seed + 1);
152 header_seed += 2;
155 output[idx] = output[idx] ^ dst[j];
156 }
157 }
158 memcpy(c->
file_key, output + 2, 16);
// skip first 2 bytes of output
160 for (i = 0; i < 16; i++)
163
164 /* decoder setup */
166 if (!st) {
169 }
171 if (!strcmp(codec_name, "mp332")) {
176 } else if (!strcmp(codec_name, "acelp85")) {
182 } else if (!strcmp(codec_name, "acelp16")) {
188 }
189
190 /* determine, and jump to audio start offset */
191 for (i = 1; i < toc_size; i++) { // skip the first entry!
192 current_size = TOC[i].size;
193 if (current_size > largest_size) {
194 largest_idx = i;
195 largest_size = current_size;
196 }
197 }
198 start = TOC[largest_idx].offset;
201
202 return 0;
203 }
204
206 {
209 int i;
210 int trailing_bytes;
211 int blocks;
213 int written = 0;
214 int ret;
216
217 // are we at the start of a chapter?
222 }
227 }
228
229 // is this the last block in this chapter?
232 }
233
234 // decrypt c->current_codec_second_size bytes
236 for (i = 0; i < blocks; i++) {
242 }
244 if (trailing_bytes != 0) { // trailing bytes are left unencrypted!
246 memcpy(buf + written, src, trailing_bytes);
247 written = written + trailing_bytes;
248 }
249
250 // update state
254
256 if (ret < 0)
257 return ret;
258 memcpy(pkt->
data, buf, written);
259
260 return 0;
261 }
262
264 {
266
267 // first 4 bytes are file size, next 4 bytes are the magic
269 return 0;
270
272 }
273
275 {
277
279
280 return 0;
281 }
282
283 #define OFFSET(x) offsetof(AADemuxContext, x)
285 { "aa_fixed_key", // extracted from libAAX_SDK.so and AAXSDKWin.dll files!
286 "Fixed key used for handling Audible AA files",
OFFSET(aa_fixed_key),
290 };
291
297 };
298
304 .extensions = "aa",
310 };
const char const char void * val
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
#define LIBAVUTIL_VERSION_INT
static int aa_read_packet(AVFormatContext *s, AVPacket *pkt)
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
int current_codec_second_size
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
struct AVTEA * av_tea_alloc(void)
Allocate an AVTEA context To free the struct: av_free(ptr)
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
static int aa_probe(AVProbeData *p)
#define MAX_CODEC_SECOND_SIZE
unsigned int avio_rb32(AVIOContext *s)
static const AVOption aa_options[]
enum AVStreamParseType need_parsing
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
#define AVERROR_EOF
End of file.
static av_cold int read_close(AVFormatContext *ctx)
AVInputFormat ff_aa_demuxer
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
AVDictionary * metadata
Metadata that applies to the whole file.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
preferred ID for decoding MPEG audio layer 1, 2 or 3
enum AVMediaType codec_type
General type of the encoded data.
static int aa_read_header(AVFormatContext *s)
static const uint8_t offset[127][2]
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
int64_t current_chapter_size
int block_align
Audio only.
Public header for libavutil TEA algorithm.
void av_tea_crypt(AVTEA *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt)
Encrypt or decrypt a buffer using a previously initialized context.
#define MAX_DICTIONARY_ENTRIES
offset must point to a pointer immediately followed by an int for the length
static int read_header(FFV1Context *f)
static int aa_read_close(AVFormatContext *s)
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
AVIOContext * pb
I/O context.
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Describe the class of an AVClass context structure.
#define AV_OPT_FLAG_DECODING_PARAM
a generic parameter which can be set by the user for demuxing or decoding
static int get_second_size(char *codec_name)
static const AVClass aa_class
This structure contains the data a format has to probe a file.
int sample_rate
Audio only.
void av_tea_init(AVTEA *ctx, const uint8_t key[16], int rounds)
Initialize an AVTEA context.
int64_t start_time
Decoding: pts of the first frame of the stream in presentation order, in stream time base...
void * priv_data
Format private data.
AVCodecParameters * codecpar
int avio_get_str(AVIOContext *pb, int maxlen, char *buf, int buflen)
Read a string from pb into buf.
This structure stores compressed data.