1 // this file is a modified version for deadbeef player
2 /***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 *
10 * $Id$
11 *
12 * Copyright (C) 2007 Dave Chapman
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #include "../../config.h"
26 #endif
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <inttypes.h>
32 #include <unistd.h>
33 #include "../../deadbeef.h"
34
35 #include <libasf/asf.h>
36
37 #define MIN(x,y) ((x)<(y)?(x):(y))
38 #define MAX(x,y) ((x)>(y)?(x):(y))
39
40 //#define trace(...) { fprintf (stderr, __VA_ARGS__); }
41 #define trace(fmt,...)
42 #define DEBUGF trace
43
44 #define SKIP_BYTES(fd,x) {\
45 if (x > 0) {\
46 char buf[x];\
47 deadbeef->fread (buf, x, 1, fd);\
48 }\
49 }
50
51 extern DB_functions_t *deadbeef;
52
53 enum {
54 AFMT_WMAPRO = 1,
55 AFMT_WMAVOICE = 2,
56 };
57
swap16(uint16_t value)58 static inline uint16_t swap16(uint16_t value)
59 /*
60 result[15..8] = value[ 7..0];
61 result[ 7..0] = value[15..8];
62 */
63 {
64 return (value >> 8) | (value << 8);
65 }
66
67
swap32(uint32_t value)68 static inline uint32_t swap32(uint32_t value)
69 /*
70 result[31..24] = value[ 7.. 0];
71 result[23..16] = value[15.. 8];
72 result[15.. 8] = value[23..16];
73 result[ 7.. 0] = value[31..24];
74 */
75 {
76 uint32_t hi = swap16(value >> 16);
77 uint32_t lo = swap16(value & 0xffff);
78 return (lo << 16) | hi;
79 }
80
81 #if WORDS_BIGENDIAN
82 #define read_uint16be(fd,buf) deadbeef->fread((buf), 2, 1, (fd))
83 #define read_uint32be(fd,buf) deadbeef->fread((buf), 4, 1, (fd))
84 #define read_uint64be(fd,buf) deadbeef->fread((buf), 8, 1, (fd))
85 int read_uint16le(DB_FILE *fd, uint16_t* buf);
86 int read_uint32le(DB_FILE *fd, uint32_t* buf);
87 int read_uint64le(DB_FILE *fd, uint64_t* buf);
88 #define letoh16(x) swap16(x)
89 #define letoh32(x) swap32(x)
90 #define htole16(x) swap16(x)
91 #define htole32(x) swap32(x)
92 #define betoh16(x) (x)
93 #define betoh32(x) (x)
94 #define htobe16(x) (x)
95 #define htobe32(x) (x)
96 #define swap_odd_even_be32(x) swap_odd_even32(x)
97 #define swap_odd_even_le32(x) (x)
98 #else
99 #define letoh16(x) (x)
100 #define letoh32(x) (x)
101 #define htole16(x) (x)
102 #define htole32(x) (x)
103 #define betoh16(x) swap16(x)
104 #define betoh32(x) swap32(x)
105 //#define htobe16(x) swap16(x)
106 //#define htobe32(x) swap32(x)
107 #define swap_odd_even_be32(x) (x)
108 #define swap_odd_even_le32(x) swap_odd_even32(x)
109 int read_uint16be(DB_FILE *fd, uint16_t* buf);
110 int read_uint32be(DB_FILE *fd, uint32_t* buf);
111 int read_uint64be(DB_FILE *fd, uint64_t* buf);
112 #define read_uint16le(fd,buf) deadbeef->fread((buf), 2, 1, (fd))
113 #define read_uint32le(fd,buf) deadbeef->fread((buf), 4, 1, (fd))
114 #define read_uint64le(fd,buf) deadbeef->fread((buf), 8, 1, (fd))
115 #endif
116
117
118 #if !WORDS_BIGENDIAN
119 /* Read an unsigned 16-bit integer from a big-endian file. */
read_uint16be(DB_FILE * fd,uint16_t * buf)120 int read_uint16be(DB_FILE *fd, uint16_t* buf)
121 {
122 size_t n;
123
124 n = deadbeef->fread(buf, 1, 2, fd);
125 *buf = betoh16(*buf);
126 return n;
127 }
128 /* Read an unsigned 32-bit integer from a big-endian file. */
read_uint32be(DB_FILE * fd,uint32_t * buf)129 int read_uint32be(DB_FILE *fd, uint32_t* buf)
130 {
131 size_t n;
132
133 n = deadbeef->fread(buf, 1, 4, fd);
134 *buf = betoh32(*buf);
135 return n;
136 }
137 /* Read an unsigned 64-bit integer from a big-endian file. */
read_uint64be(DB_FILE * fd,uint64_t * buf)138 int read_uint64be(DB_FILE *fd, uint64_t* buf)
139 {
140 size_t n;
141 uint8_t data[8];
142 int i;
143
144 n = deadbeef->fread(data, 1, 8, fd);
145
146 for (i=0, *buf=0; i<=7; i++) {
147 *buf <<= 8;
148 *buf |= data[i];
149 }
150 return n;
151 }
152 #else
153 /* Read unsigned integers from a little-endian file. */
read_uint16le(DB_FILE * fd,uint16_t * buf)154 int read_uint16le(DB_FILE *fd, uint16_t* buf)
155 {
156 size_t n;
157
158 n = deadbeef->fread((char*) buf, 1, 2, fd);
159 *buf = letoh16(*buf);
160 return n;
161 }
read_uint32le(DB_FILE * fd,uint32_t * buf)162 int read_uint32le(DB_FILE *fd, uint32_t* buf)
163 {
164 size_t n;
165
166 n = deadbeef->fread(buf, 1, 4, fd);
167 *buf = letoh32(*buf);
168 return n;
169 }
read_uint64le(DB_FILE * fd,uint64_t * buf)170 int read_uint64le(DB_FILE *fd, uint64_t* buf)
171 {
172 size_t n;
173 uint8_t data[8];
174 int i;
175
176 n = deadbeef->fread(data, 1, 8, fd);
177
178 for (i=7, *buf=0; i>=0; i--) {
179 *buf <<= 8;
180 *buf |= data[i];
181 }
182
183 return n;
184 }
185 #endif
186
187 /* TODO: Just read the GUIDs into a 16-byte array, and use memcmp to compare */
188 struct guid_s {
189 uint32_t v1;
190 uint16_t v2;
191 uint16_t v3;
192 uint8_t v4[8];
193 };
194 typedef struct guid_s guid_t;
195
196 struct asf_object_s {
197 guid_t guid;
198 uint64_t size;
199 uint64_t datalen;
200 };
201 typedef struct asf_object_s asf_object_t;
202
203 static const guid_t asf_guid_null =
204 {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
205
206 /* top level object guids */
207
208 static const guid_t asf_guid_header =
209 {0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
210
211 static const guid_t asf_guid_data =
212 {0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
213
214 static const guid_t asf_guid_index =
215 {0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
216
217 /* header level object guids */
218
219 static const guid_t asf_guid_file_properties =
220 {0x8cabdca1, 0xa947, 0x11cf, {0x8E, 0xe4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
221
222 static const guid_t asf_guid_stream_properties =
223 {0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
224
225 static const guid_t asf_guid_content_description =
226 {0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
227
228 static const guid_t asf_guid_extended_content_description =
229 {0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
230
231 static const guid_t asf_guid_content_encryption =
232 {0x2211b3fb, 0xbd23, 0x11d2, {0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e}};
233
234 static const guid_t asf_guid_extended_content_encryption =
235 {0x298ae614, 0x2622, 0x4c17, {0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c}};
236
237 /* stream type guids */
238
239 static const guid_t asf_guid_stream_type_audio =
240 {0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
241
asf_guid_match(const guid_t * guid1,const guid_t * guid2)242 static int asf_guid_match(const guid_t *guid1, const guid_t *guid2)
243 {
244 if((guid1->v1 != guid2->v1) ||
245 (guid1->v2 != guid2->v2) ||
246 (guid1->v3 != guid2->v3) ||
247 (memcmp(guid1->v4, guid2->v4, 8))) {
248 return 0;
249 }
250
251 return 1;
252 }
253
254 /* Read the 16 byte GUID from a file */
asf_readGUID(DB_FILE * fd,guid_t * guid)255 static void asf_readGUID(DB_FILE *fd, guid_t* guid)
256 {
257 read_uint32le(fd, &guid->v1);
258 read_uint16le(fd, &guid->v2);
259 read_uint16le(fd, &guid->v3);
260 deadbeef->fread(guid->v4, 8, 1, fd);
261 }
262
asf_read_object_header(asf_object_t * obj,DB_FILE * fd)263 static void asf_read_object_header(asf_object_t *obj, DB_FILE *fd)
264 {
265 asf_readGUID(fd, &obj->guid);
266 read_uint64le(fd, &obj->size);
267 obj->datalen = 0;
268 }
269
270 /* Parse an integer from the extended content object - we always
271 convert to an int, regardless of native format.
272 */
asf_intdecode(DB_FILE * fd,int type,int length)273 static int asf_intdecode(DB_FILE *fd, int type, int length)
274 {
275 uint16_t tmp16;
276 uint32_t tmp32;
277 uint64_t tmp64;
278
279 if (type == 3) {
280 read_uint32le(fd, &tmp32);
281 SKIP_BYTES(fd,length - 4);
282 return (int)tmp32;
283 } else if (type == 4) {
284 read_uint64le(fd, &tmp64);
285 SKIP_BYTES(fd,length - 8);
286 return (int)tmp64;
287 } else if (type == 5) {
288 read_uint16le(fd, &tmp16);
289 SKIP_BYTES(fd,length - 2);
290 return (int)tmp16;
291 }
292
293 return 0;
294 }
295
296 /* Decode a LE utf16 string from a disk buffer into a fixed-sized
297 utf8 buffer.
298 */
299 #define MASK 0xC0 /* 11000000 */
300 #define COMP 0x80 /* 10x */
301
302 static const unsigned char utf8comp[6] =
303 {
304 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
305 };
306
307 /* Encode a UCS value as UTF-8 and return a pointer after this UTF-8 char. */
utf8encode(unsigned long ucs,unsigned char * utf8)308 unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8)
309 {
310 int tail = 0;
311
312 if (ucs > 0x7F)
313 while (ucs >> (5*tail + 6))
314 tail++;
315
316 *utf8++ = (ucs >> (6*tail)) | utf8comp[tail];
317 while (tail--)
318 *utf8++ = ((ucs >> (6*tail)) & (MASK ^ 0xFF)) | COMP;
319
320 return utf8;
321 }
322
323
asf_utf16LEdecode(DB_FILE * fd,uint16_t utf16bytes,unsigned char ** utf8,int * utf8bytes)324 static void asf_utf16LEdecode(DB_FILE *fd,
325 uint16_t utf16bytes,
326 unsigned char **utf8,
327 int* utf8bytes
328 )
329 {
330 unsigned long ucs;
331 int n;
332 unsigned char utf16buf[256];
333 unsigned char* utf16 = utf16buf;
334 unsigned char* newutf8;
335
336 n = deadbeef->fread(utf16buf, 1, MIN(sizeof(utf16buf), utf16bytes), fd);
337 utf16bytes -= n;
338
339 while (n > 0) {
340 /* Check for a surrogate pair */
341 if (utf16[1] >= 0xD8 && utf16[1] < 0xE0) {
342 if (n < 4) {
343 /* Run out of utf16 bytes, read some more */
344 utf16buf[0] = utf16[0];
345 utf16buf[1] = utf16[1];
346
347 n = deadbeef->fread(utf16buf + 2, 1, MIN(sizeof(utf16buf)-2, utf16bytes), fd);
348 utf16 = utf16buf;
349 utf16bytes -= n;
350 n += 2;
351 }
352
353 if (n < 4) {
354 /* Truncated utf16 string, abort */
355 break;
356 }
357 ucs = 0x10000 + ((utf16[0] << 10) | ((utf16[1] - 0xD8) << 18)
358 | utf16[2] | ((utf16[3] - 0xDC) << 8));
359 utf16 += 4;
360 n -= 4;
361 } else {
362 ucs = (utf16[0] | (utf16[1] << 8));
363 utf16 += 2;
364 n -= 2;
365 }
366
367 if (*utf8bytes > 6) {
368 newutf8 = utf8encode(ucs, *utf8);
369 *utf8bytes -= (newutf8 - *utf8);
370 *utf8 += (newutf8 - *utf8);
371 }
372
373 /* We have run out of utf16 bytes, read more if available */
374 if ((n == 0) && (utf16bytes > 0)) {
375 n = deadbeef->fread(utf16buf, 1, MIN(sizeof(utf16buf), utf16bytes), fd);
376 utf16 = utf16buf;
377 utf16bytes -= n;
378 }
379 }
380
381 *utf8[0] = 0;
382 --*utf8bytes;
383
384 if (utf16bytes > 0) {
385 /* Skip any remaining bytes */
386 SKIP_BYTES(fd, utf16bytes);
387 }
388 return;
389 }
390
391 static int
asf_add_disc_meta(DB_playItem_t * it,const char * disc)392 asf_add_disc_meta (DB_playItem_t *it, const char *disc) {
393 char *slash = strchr (disc, '/');
394 if (slash) {
395 // split into track/number
396 *slash = 0;
397 slash++;
398 deadbeef->pl_add_meta (it, "numdiscs", slash);
399 }
400 deadbeef->pl_add_meta (it, "disc", disc);
401 return 0;
402 }
403
asf_parse_header(DB_FILE * fd,asf_waveformatex_t * wfx,DB_playItem_t * it)404 static int asf_parse_header(DB_FILE *fd, asf_waveformatex_t* wfx, DB_playItem_t *it)
405 {
406 asf_object_t current;
407 asf_object_t header;
408 uint64_t datalen = 0;
409 int i = 0;
410 int fileprop = 0;
411 uint64_t play_duration = 0;
412 uint16_t flags = 0;
413 uint32_t subobjects = 0;
414 uint8_t utf8buf[512];
415 int codectype = 0;
416 unsigned char id3buffer[2048];
417 unsigned char *id3buf = id3buffer;
418 int id3buf_remaining = sizeof(id3buffer);
419
420 memset (¤t, 0, sizeof (current));
421 memset (&header, 0, sizeof (header));
422 memset (&utf8buf, 0, sizeof (utf8buf));
423 memset (&id3buffer, 0, sizeof (id3buffer));
424
425 asf_read_object_header((asf_object_t *) &header, fd);
426
427 DEBUGF("header.size=%d\n",(int)header.size);
428 if (header.size < 30) {
429 /* invalid size for header object */
430 return ASF_ERROR_OBJECT_SIZE;
431 }
432
433 read_uint32le(fd, &subobjects);
434
435 /* Two reserved bytes - do we need to read them? */
436 SKIP_BYTES(fd, 2);
437
438 DEBUGF("Read header - size=%d, subobjects=%d\n",(int)header.size, (int)subobjects);
439
440 if (subobjects > 0) {
441 header.datalen = header.size - 30;
442
443 /* TODO: Check that we have datalen bytes left in the file */
444 datalen = header.datalen;
445 DEBUGF("datalen: %d\n", datalen);
446
447 for (i=0; i<(int)subobjects; i++) {
448 DEBUGF("Parsing header object %d - datalen=%d\n",i,(int)datalen);
449 if (datalen < 24) {
450 DEBUGF("not enough data for reading object\n");
451 break;
452 }
453
454 asf_read_object_header(¤t, fd);
455
456 if (current.size > datalen || current.size < 24) {
457 DEBUGF("invalid object size - current.size=%lld, datalen=%lld\n",current.size,datalen);
458 break;
459 }
460
461 if (asf_guid_match(¤t.guid, &asf_guid_file_properties)) {
462 if (current.size < 104)
463 return ASF_ERROR_OBJECT_SIZE;
464
465 if (fileprop) {
466 /* multiple file properties objects not allowed */
467 return ASF_ERROR_INVALID_OBJECT;
468 }
469
470 fileprop = 1;
471
472 /* Get the number of logical packets - uint64_t at offset 32
473 * (Big endian byte order) */
474 SKIP_BYTES(fd, 32);
475 read_uint64le(fd, &wfx->numpackets);
476 read_uint64le(fd, &wfx->play_duration);
477 read_uint64le(fd, &wfx->send_duration);
478 read_uint64le(fd, &wfx->preroll);
479 read_uint32le(fd, &wfx->flags);
480
481 // DEBUGF("****** length = %lld\n", wfx->play_duration);
482
483 /* Read the packet size - uint32_t at offset 68 */
484 // SKIP_BYTES(fd, 20);
485 read_uint32le(fd, &wfx->packet_size);
486 read_uint32le(fd, &wfx->max_packet_size);
487
488 /* Skip bytes remaining in object */
489 SKIP_BYTES(fd, current.size - 24 - 72 - 4);
490 } else if (asf_guid_match(¤t.guid, &asf_guid_stream_properties)) {
491 guid_t guid;
492 uint32_t propdatalen;
493
494 if (current.size < 78)
495 return ASF_ERROR_OBJECT_SIZE;
496
497 #if 0
498 asf_byteio_getGUID(&guid, current->data);
499 datalen = asf_byteio_getDWLE(current->data + 40);
500 flags = asf_byteio_getWLE(current->data + 48);
501 #endif
502
503 asf_readGUID(fd, &guid);
504
505 SKIP_BYTES(fd, 24);
506 read_uint32le(fd, &propdatalen);
507 SKIP_BYTES(fd, 4);
508 read_uint16le(fd, &flags);
509
510 if (!asf_guid_match(&guid, &asf_guid_stream_type_audio)) {
511 DEBUGF("Found stream properties for non audio stream, skipping\n");
512 SKIP_BYTES(fd,current.size - 24 - 50);
513 } else if (wfx->audiostream == -1) {
514 SKIP_BYTES(fd, 4);
515 DEBUGF("Found stream properties for audio stream %d\n",flags&0x7f);
516
517 if (propdatalen < 18) {
518 return ASF_ERROR_INVALID_LENGTH;
519 }
520
521 #if 0
522 if (asf_byteio_getWLE(data + 16) > datalen - 16) {
523 return ASF_ERROR_INVALID_LENGTH;
524 }
525 #endif
526 read_uint16le(fd, &wfx->codec_id);
527 read_uint16le(fd, &wfx->channels);
528 read_uint32le(fd, &wfx->rate);
529 read_uint32le(fd, &wfx->bitrate);
530 wfx->bitrate *= 8;
531 read_uint16le(fd, &wfx->blockalign);
532 read_uint16le(fd, &wfx->bitspersample);
533 read_uint16le(fd, &wfx->datalen);
534
535 if (wfx->codec_id == ASF_CODEC_ID_WMAV1) {
536 deadbeef->fread(wfx->data, 4, 1, fd);
537 SKIP_BYTES(fd,current.size - 24 - 72 - 4);
538 wfx->audiostream = flags&0x7f;
539 } else if (wfx->codec_id == ASF_CODEC_ID_WMAV2) {
540 deadbeef->fread(wfx->data, 6, 1, fd);
541 SKIP_BYTES(fd,current.size - 24 - 72 - 6);
542 wfx->audiostream = flags&0x7f;
543 } else if (wfx->codec_id == ASF_CODEC_ID_WMAPRO) {
544 /* wma pro decoder needs the extra-data */
545 deadbeef->fread(wfx->data, wfx->datalen, 1, fd);
546 SKIP_BYTES(fd,current.size - 24 - 72 - wfx->datalen);
547 wfx->audiostream = flags&0x7f;
548 /* Correct codectype to redirect playback to the proper .codec */
549 codectype = AFMT_WMAPRO;
550 } else if (wfx->codec_id == ASF_CODEC_ID_WMAVOICE) {
551 deadbeef->fread(wfx->data, wfx->datalen, 1, fd);
552 SKIP_BYTES(fd,current.size - 24 - 72 - wfx->datalen);
553 wfx->audiostream = flags&0x7f;
554 codectype = AFMT_WMAVOICE;
555 } else {
556 trace("Unsupported WMA codec (Lossless, Voice, etc)\n");
557 SKIP_BYTES(fd,current.size - 24 - 72);
558 }
559 }
560 } else if (it && asf_guid_match(¤t.guid, &asf_guid_content_description)) {
561 /* Object contains five 16-bit string lengths, followed by the five strings:
562 title, artist, copyright, description, rating
563 */
564 uint16_t strlength[5];
565 int i;
566
567 DEBUGF("Found GUID_CONTENT_DESCRIPTION - size=%d\n",(int)(current.size - 24));
568
569 /* Read the 5 string lengths - number of bytes included trailing zero */
570 for (i=0; i<5; i++) {
571 read_uint16le(fd, &strlength[i]);
572 DEBUGF("strlength = %u\n",strlength[i]);
573 }
574
575 if (strlength[0] > 0) { /* 0 - Title */
576 unsigned char *s = id3buf;
577 asf_utf16LEdecode(fd, strlength[0], &id3buf, &id3buf_remaining);
578 deadbeef->pl_append_meta (it, "title", s);
579 }
580
581 if (strlength[1] > 0) { /* 1 - Artist */
582 unsigned char *s = id3buf;
583 asf_utf16LEdecode(fd, strlength[1], &id3buf, &id3buf_remaining);
584 deadbeef->pl_append_meta (it, "artist", s);
585 }
586
587 SKIP_BYTES(fd, strlength[2]); /* 2 - copyright */
588
589 if (strlength[3] > 0) { /* 3 - description */
590 unsigned char *s = id3buf;
591 asf_utf16LEdecode(fd, strlength[3], &id3buf, &id3buf_remaining);
592 deadbeef->pl_append_meta (it, "comment", s);
593 }
594
595 SKIP_BYTES(fd, strlength[4]); /* 4 - rating */
596 } else if (it && asf_guid_match(¤t.guid, &asf_guid_extended_content_description)) {
597 uint16_t count;
598 int i;
599 int bytesleft = current.size - 24;
600 DEBUGF("Found GUID_EXTENDED_CONTENT_DESCRIPTION\n");
601
602 read_uint16le(fd, &count);
603 bytesleft -= 2;
604 DEBUGF("extended metadata count = %u\n",count);
605
606 for (i=0; i < count; i++) {
607 uint16_t length, type;
608 unsigned char* utf8 = utf8buf;
609 int utf8length = 512;
610
611 read_uint16le(fd, &length);
612 asf_utf16LEdecode(fd, length, &utf8, &utf8length);
613 bytesleft -= 2 + length;
614
615 read_uint16le(fd, &type);
616 read_uint16le(fd, &length);
617 trace ("ext md id: %s\n", utf8buf);
618
619 if (!strcmp("WM/TrackNumber",utf8buf) || !strcmp("WM/Track",utf8buf)) {
620 if (type == 0) {
621 unsigned char *s = id3buf;
622 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
623 deadbeef->pl_append_meta (it, "track", s);
624 } else if ((type >=2) && (type <= 5)) {
625 int tracknum = asf_intdecode(fd, type, length);
626 char n[100];
627 snprintf (n, sizeof (n), "%d", tracknum);
628 deadbeef->pl_append_meta (it, "track", n);
629 } else {
630 SKIP_BYTES(fd, length);
631 }
632 } else if (!strcmp("TotalTracks",utf8buf)) {
633 if (type == 0) {
634 unsigned char *s = id3buf;
635 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
636 deadbeef->pl_append_meta (it, "numtracks", s);
637 } else if ((type >=2) && (type <= 5)) {
638 int tracknum = asf_intdecode(fd, type, length);
639 char n[100];
640 snprintf (n, sizeof (n), "%d", tracknum);
641 deadbeef->pl_append_meta (it, "numtracks", n);
642 } else {
643 SKIP_BYTES(fd, length);
644 }
645 } else if (!strcmp("WM/PartOfSet",utf8buf)) {
646 if (type == 0) {
647 unsigned char *s = id3buf;
648 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
649 asf_add_disc_meta (it, s);
650 } else if ((type >=2) && (type <= 5)) {
651 int num = asf_intdecode(fd, type, length);
652 char n[100];
653 snprintf (n, sizeof (n), "%d", num);
654 deadbeef->pl_replace_meta (it, "disc", n);
655 } else {
656 SKIP_BYTES(fd, length);
657 }
658 } else if ((!strcmp("WM/Genre", utf8buf)) && (type == 0)) {
659 unsigned char *s = id3buf;
660 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
661 deadbeef->pl_append_meta (it, "genre", s);
662 } else if ((!strcmp("WM/AlbumTitle", utf8buf)) && (type == 0)) {
663 unsigned char *s = id3buf;
664 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
665 deadbeef->pl_append_meta (it, "album", s);
666 } else if ((!strcmp("WM/AlbumArtist", utf8buf)) && (type == 0)) {
667 unsigned char *s = id3buf;
668 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
669 deadbeef->pl_append_meta (it, "albumartist", s);
670 } else if ((!strcmp("WM/Composer", utf8buf)) && (type == 0)) {
671 unsigned char *s = id3buf;
672 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
673 deadbeef->pl_append_meta (it, "composer", s);
674 } else if ((!strcasecmp("foobar2000/cuesheet", utf8buf)) && (type == 0)) {
675 unsigned char *s = id3buf;
676 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
677 deadbeef->pl_append_meta (it, "cuesheet", s);
678 } else if (!strcmp("WM/Year", utf8buf)) {
679 if (type == 0) {
680 unsigned char *s = id3buf;
681 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
682 deadbeef->pl_append_meta (it, "year", s);
683 } else if ((type >=2) && (type <= 5)) {
684 int year = asf_intdecode(fd, type, length);
685 char n[100];
686 snprintf (n, sizeof (n), "%d", year);
687 deadbeef->pl_append_meta (it, "year", n);
688 } else {
689 SKIP_BYTES(fd, length);
690 }
691 } else if (!strcmp("WM/OriginalReleaseYear", utf8buf)) {
692 if (type == 0) {
693 unsigned char *s = id3buf;
694 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
695 deadbeef->pl_append_meta (it, "original_release_year", s);
696 } else if ((type >=2) && (type <= 5)) {
697 int year = asf_intdecode(fd, type, length);
698 char n[100];
699 snprintf (n, sizeof (n), "%d", year);
700 deadbeef->pl_append_meta (it, "original_release_year", n);
701 } else {
702 SKIP_BYTES(fd, length);
703 }
704 } else if (!strcmp("WM/OriginalReleaseTime", utf8buf)) {
705 if (type == 0) {
706 unsigned char *s = id3buf;
707 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
708 deadbeef->pl_append_meta (it, "original_release_time", s);
709 } else if ((type >=2) && (type <= 5)) {
710 int date = asf_intdecode(fd, type, length);
711 char n[100];
712 snprintf (n, sizeof (n), "%d", date);
713 deadbeef->pl_append_meta (it, "original_release_time", n);
714 } else {
715 SKIP_BYTES(fd, length);
716 }
717 } else if (!strncmp("replaygain_", utf8buf, 11)) {
718 char *s = utf8buf;
719 char *value = id3buf;
720 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
721 // parse_replaygain(utf8buf, value, id3);
722 if (!strncasecmp (s, "replaygain_album_gain", 21)) {
723 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMGAIN, atof (value));
724 }
725 else if (!strncasecmp (s, "replaygain_album_peak", 21)) {
726 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_ALBUMPEAK, atof (value));
727 }
728 else if (!strncasecmp (s, "replaygain_track_gain", 21)) {
729 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKGAIN, atof (value));
730 }
731 else if (!strncasecmp (s, "replaygain_track_peak", 21)) {
732 deadbeef->pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, atof (value));
733 }
734 } else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
735 unsigned char *s = id3buf;
736 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
737 deadbeef->pl_append_meta (it, "MusicBrainzId", s);
738 #ifdef HAVE_ALBUMART
739 } else if (!strcmp("WM/Picture", utf8buf)) {
740 uint32_t datalength, strlength;
741 /* Expected is either "01 00 xx xx 03 yy yy yy yy" or
742 * "03 yy yy yy yy". xx is the size of the WM/Picture
743 * container in bytes. yy equals the raw data length of
744 * the embedded image. */
745 SKIP_BYTES(fd, -4);
746 deadbeef->fread(&type, 1, 1, fd);
747 if (type == 1) {
748 SKIP_BYTES(fd, 3);
749 deadbeef->fread(&type, 1, 1, fd);
750 /* In case the parsing will fail in the next step we
751 * might at least be able to skip the whole section. */
752 datalength = length - 1;
753 }
754 if (type == 3) {
755 /* Read the raw data length of the embedded image. */
756 read_uint32le(fd, &datalength);
757
758 /* Reset utf8 buffer */
759 utf8 = utf8buf;
760 utf8length = 512;
761
762 /* Gather the album art format, this string has a
763 * double zero-termination. */
764 asf_utf16LEdecode(fd, 32, &utf8, &utf8length);
765 strlength = (strlen(utf8buf) + 2) * 2;
766 SKIP_BYTES(fd, strlength-32);
767 if (!strcmp("image/jpeg", utf8buf)) {
768 id3->albumart.type = AA_TYPE_JPG;
769 } else if (!strcmp("image/jpg", utf8buf)) {
770 /* image/jpg is technically invalid,
771 * but it does occur in the wild */
772 id3->albumart.type = AA_TYPE_JPG;
773 } else if (!strcmp("image/png", utf8buf)) {
774 id3->albumart.type = AA_TYPE_PNG;
775 } else {
776 id3->albumart.type = AA_TYPE_UNKNOWN;
777 }
778
779 /* Set the album art size and position. */
780 if (id3->albumart.type != AA_TYPE_UNKNOWN) {
781 id3->albumart.pos = SKIP_BYTES(fd, 0);
782 id3->albumart.size = datalength;
783 id3->has_embedded_albumart = true;
784 }
785 }
786
787 SKIP_BYTES(fd, datalength);
788 #endif
789 } else {
790 if (type == 0) { // FIXME: custom fields -- after others work
791 unsigned char *s = id3buf;
792 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
793 if (!strcmp (utf8buf, "MusicBrainz/Track Id")) {
794 strcpy (utf8buf, "musicbrainz_trackid");
795 }
796 deadbeef->pl_append_meta (it, utf8buf, s);
797 }
798 else {
799 SKIP_BYTES(fd, length);
800 }
801 }
802 bytesleft -= 4 + length;
803 }
804
805 SKIP_BYTES(fd, bytesleft);
806 } else if (asf_guid_match(¤t.guid, &asf_guid_content_encryption)
807 || asf_guid_match(¤t.guid, &asf_guid_extended_content_encryption)) {
808 DEBUGF("File is encrypted\n");
809 return ASF_ERROR_ENCRYPTED;
810 } else {
811 DEBUGF("Skipping %d bytes of object\n",(int)(current.size - 24));
812 SKIP_BYTES(fd,current.size - 24);
813 }
814
815 DEBUGF("Parsed object - size = %d\n",(int)current.size);
816 datalen -= current.size;
817 }
818
819 if (i != (int)subobjects || datalen != 0) {
820 DEBUGF("header data doesn't match given subobject count\n");
821 return ASF_ERROR_INVALID_VALUE;
822 }
823
824 DEBUGF("%d subobjects read successfully\n", i);
825 }
826
827 #if 0
828 tmp = asf_parse_header_validate(file, &header);
829 if (tmp < 0) {
830 /* header read ok but doesn't validate correctly */
831 return tmp;
832 }
833 #endif
834
835 DEBUGF("header validated correctly\n");
836
837 return 0;
838 }
839
get_asf_metadata(DB_FILE * fd,DB_playItem_t * it,asf_waveformatex_t * wfx,int64_t * first_frame_offset)840 int get_asf_metadata(DB_FILE *fd, DB_playItem_t *it, asf_waveformatex_t *wfx, int64_t *first_frame_offset)
841 {
842 int res;
843 asf_object_t obj;
844
845 wfx->audiostream = -1;
846
847 res = asf_parse_header(fd, wfx, it);
848
849 if (res < 0) {
850 DEBUGF("ASF: parsing error - %d\n",res);
851 return 0;
852 }
853
854 if (wfx->audiostream == -1) {
855 DEBUGF("ASF: No WMA streams found\n");
856 return 0;
857 }
858
859 asf_read_object_header(&obj, fd);
860
861 if (!asf_guid_match(&obj.guid, &asf_guid_data)) {
862 DEBUGF("ASF: No data object found\n");
863 return 0;
864 }
865
866 /* Store the current file position - no need to parse the header
867 again in the codec. The +26 skips the rest of the data object
868 header.
869 */
870 *first_frame_offset = deadbeef->ftell(fd) + 26;
871
872 if (!fd->vfs->is_streaming ()) {
873 // check if we got a fragment
874 if (0 != deadbeef->fseek (fd, 26, SEEK_CUR)) {
875 DEBUGF("ASF: failed to seek to 1st frame\n");
876 return 0;
877 }
878 int duration = 0;
879 int time = asf_get_timestamp(&duration, fd);
880 if (time != 0) {
881 wfx->first_frame_timestamp = time;
882 // need to scan entire file to find out the duration
883 int pmn = (int)(time * 0.001f / 60);
884 int psc = time * 0.001f - pmn * 60;
885 trace ("wma: the file is a fragment, start time: %d:%02d\n", pmn, psc);
886 trace ("play_duration %lld, numpackets %lld, packet_size %d\n", wfx->play_duration, wfx->numpackets, wfx->packet_size);
887 }
888 if (wfx->play_duration == 0) {
889 wfx->preroll = 0;
890 wfx->numpackets = 1;
891 // calc duration from packets (scan the file)
892 wfx->play_duration += duration * 10000;
893 while (0 == deadbeef->fseek (fd, *first_frame_offset + wfx->packet_size * wfx->numpackets, SEEK_SET)) {
894 time = asf_get_timestamp(&duration, fd);
895 if (time < 0) {
896 break;
897 }
898 wfx->play_duration += duration * 10000;
899 wfx->numpackets++;
900 }
901 }
902 }
903
904 return 1;
905 }
906