blob: 187459b7fba3d9322a250e921bda62a2bc1caa14 [file] [log] [blame]
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Magnus Holmgrenc5683b32007-08-24 12:40:31 +000010 * Copyright (C) 2005 Magnus Holmgren
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +000011 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "errno.h"
29#include "id3.h"
30#include "metadata_common.h"
Bertrik Sikken1273f952008-05-03 07:03:59 +000031#include "metadata_parsers.h"
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +000032#include "logf.h"
33#include "debug.h"
34#include "replaygain.h"
35
36#define MP4_ID(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
37
38#define MP4_3gp6 MP4_ID('3', 'g', 'p', '6')
Dan Everton708ac7f2007-06-25 11:15:44 +000039#define MP4_aART MP4_ID('a', 'A', 'R', 'T')
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +000040#define MP4_alac MP4_ID('a', 'l', 'a', 'c')
41#define MP4_calb MP4_ID(0xa9, 'a', 'l', 'b')
42#define MP4_cART MP4_ID(0xa9, 'A', 'R', 'T')
Dan Evertoneecfe9f2007-08-08 10:19:56 +000043#define MP4_cgrp MP4_ID(0xa9, 'g', 'r', 'p')
Magnus Holmgrencfe00132007-07-22 21:16:52 +000044#define MP4_cgen MP4_ID(0xa9, 'g', 'e', 'n')
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +000045#define MP4_cnam MP4_ID(0xa9, 'n', 'a', 'm')
46#define MP4_cwrt MP4_ID(0xa9, 'w', 'r', 't')
Magnus Holmgrenb1d07b42007-07-26 11:59:48 +000047#define MP4_ccmt MP4_ID(0xa9, 'c', 'm', 't')
48#define MP4_cday MP4_ID(0xa9, 'd', 'a', 'y')
Dan Evertonf4a61f02007-08-03 10:00:42 +000049#define MP4_disk MP4_ID('d', 'i', 's', 'k')
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +000050#define MP4_esds MP4_ID('e', 's', 'd', 's')
51#define MP4_ftyp MP4_ID('f', 't', 'y', 'p')
52#define MP4_gnre MP4_ID('g', 'n', 'r', 'e')
53#define MP4_hdlr MP4_ID('h', 'd', 'l', 'r')
54#define MP4_ilst MP4_ID('i', 'l', 's', 't')
55#define MP4_M4A MP4_ID('M', '4', 'A', ' ')
56#define MP4_M4B MP4_ID('M', '4', 'B', ' ')
57#define MP4_mdat MP4_ID('m', 'd', 'a', 't')
58#define MP4_mdia MP4_ID('m', 'd', 'i', 'a')
59#define MP4_mdir MP4_ID('m', 'd', 'i', 'r')
60#define MP4_meta MP4_ID('m', 'e', 't', 'a')
61#define MP4_minf MP4_ID('m', 'i', 'n', 'f')
62#define MP4_moov MP4_ID('m', 'o', 'o', 'v')
63#define MP4_mp4a MP4_ID('m', 'p', '4', 'a')
64#define MP4_mp42 MP4_ID('m', 'p', '4', '2')
65#define MP4_qt MP4_ID('q', 't', ' ', ' ')
66#define MP4_soun MP4_ID('s', 'o', 'u', 'n')
67#define MP4_stbl MP4_ID('s', 't', 'b', 'l')
68#define MP4_stsd MP4_ID('s', 't', 's', 'd')
69#define MP4_stts MP4_ID('s', 't', 't', 's')
70#define MP4_trak MP4_ID('t', 'r', 'a', 'k')
71#define MP4_trkn MP4_ID('t', 'r', 'k', 'n')
72#define MP4_udta MP4_ID('u', 'd', 't', 'a')
73#define MP4_extra MP4_ID('-', '-', '-', '-')
74
75/* Read the tag data from an MP4 file, storing up to buffer_size bytes in
76 * buffer.
77 */
78static unsigned long read_mp4_tag(int fd, unsigned int size_left, char* buffer,
79 unsigned int buffer_left)
80{
81 unsigned int bytes_read = 0;
82
83 if (buffer_left == 0)
84 {
85 lseek(fd, size_left, SEEK_CUR); /* Skip everything */
86 }
87 else
88 {
89 /* Skip the data tag header - maybe we should parse it properly? */
90 lseek(fd, 16, SEEK_CUR);
91 size_left -= 16;
92
93 if (size_left > buffer_left)
94 {
95 read(fd, buffer, buffer_left);
96 lseek(fd, size_left - buffer_left, SEEK_CUR);
97 bytes_read = buffer_left;
98 }
99 else
100 {
101 read(fd, buffer, size_left);
102 bytes_read = size_left;
103 }
104 }
105
106 return bytes_read;
107}
108
109/* Read a string tag from an MP4 file */
110static unsigned int read_mp4_tag_string(int fd, int size_left, char** buffer,
111 unsigned int* buffer_left, char** dest)
112{
113 unsigned int bytes_read = read_mp4_tag(fd, size_left, *buffer,
Magnus Holmgren9146f202007-10-14 13:27:01 +0000114 *buffer_left > 0 ? *buffer_left - 1 : 0);
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000115 unsigned int length = 0;
116
117 if (bytes_read)
118 {
119 (*buffer)[bytes_read] = 0;
120 *dest = *buffer;
121 length = strlen(*buffer) + 1;
122 *buffer_left -= length;
123 *buffer += length;
124 }
125 else
126 {
127 *dest = NULL;
128 }
129
130 return length;
131}
132
133static unsigned int read_mp4_atom(int fd, unsigned int* size,
134 unsigned int* type, unsigned int size_left)
135{
136 read_uint32be(fd, size);
137 read_uint32be(fd, type);
138
139 if (*size == 1)
140 {
141 /* FAT32 doesn't support files this big, so something seems to
142 * be wrong. (64-bit sizes should only be used when required.)
143 */
144 errno = EFBIG;
145 *type = 0;
146 return 0;
147 }
148
149 if (*size > 0)
150 {
151 if (*size > size_left)
152 {
153 size_left = 0;
154 }
155 else
156 {
157 size_left -= *size;
158 }
159
160 *size -= 8;
161 }
162 else
163 {
164 *size = size_left;
165 size_left = 0;
166 }
167
168 return size_left;
169}
170
171static unsigned int read_mp4_length(int fd, unsigned int* size)
172{
173 unsigned int length = 0;
174 int bytes = 0;
175 unsigned char c;
176
177 do
178 {
179 read(fd, &c, 1);
180 bytes++;
181 (*size)--;
182 length = (length << 7) | (c & 0x7F);
183 }
184 while ((c & 0x80) && (bytes < 4) && (*size > 0));
185
186 return length;
187}
188
189static bool read_mp4_esds(int fd, struct mp3entry* id3,
190 unsigned int* size)
191{
192 unsigned char buf[8];
193 bool sbr = false;
194
195 lseek(fd, 4, SEEK_CUR); /* Version and flags. */
196 read(fd, buf, 1); /* Verify ES_DescrTag. */
197 *size -= 5;
198
199 if (*buf == 3)
200 {
201 /* read length */
202 if (read_mp4_length(fd, size) < 20)
203 {
204 return sbr;
205 }
206
207 lseek(fd, 3, SEEK_CUR);
208 *size -= 3;
209 }
210 else
211 {
212 lseek(fd, 2, SEEK_CUR);
213 *size -= 2;
214 }
215
216 read(fd, buf, 1); /* Verify DecoderConfigDescrTab. */
217 *size -= 1;
218
219 if (*buf != 4)
220 {
221 return sbr;
222 }
223
224 if (read_mp4_length(fd, size) < 13)
225 {
226 return sbr;
227 }
228
229 lseek(fd, 13, SEEK_CUR); /* Skip audio type, bit rates, etc. */
230 read(fd, buf, 1);
231 *size -= 14;
232
233 if (*buf != 5) /* Verify DecSpecificInfoTag. */
234 {
235 return sbr;
236 }
237
238 {
239 static const int sample_rates[] =
240 {
241 96000, 88200, 64000, 48000, 44100, 32000,
242 24000, 22050, 16000, 12000, 11025, 8000
243 };
244 unsigned long bits;
245 unsigned int length;
246 unsigned int index;
247 unsigned int type;
248
249 /* Read the (leading part of the) decoder config. */
250 length = read_mp4_length(fd, size);
251 length = MIN(length, *size);
252 length = MIN(length, sizeof(buf));
253 memset(buf, 0, sizeof(buf));
254 read(fd, buf, length);
255 *size -= length;
256
257 /* Maybe time to write a simple read_bits function... */
258
259 /* Decoder config format:
260 * Object type - 5 bits
261 * Frequency index - 4 bits
262 * Channel configuration - 4 bits
263 */
264 bits = get_long_be(buf);
265 type = bits >> 27; /* Object type - 5 bits */
266 index = (bits >> 23) & 0xf; /* Frequency index - 4 bits */
267
268 if (index < (sizeof(sample_rates) / sizeof(*sample_rates)))
269 {
270 id3->frequency = sample_rates[index];
271 }
272
273 if (type == 5)
274 {
275 DEBUGF("MP4: SBR\n");
276 unsigned int old_index = index;
277
278 sbr = true;
279 index = (bits >> 15) & 0xf; /* Frequency index - 4 bits */
280
281 if (index == 15)
282 {
283 /* 17 bits read so far... */
284 bits = get_long_be(&buf[2]);
285 id3->frequency = (bits >> 7) & 0x00ffffff;
286 }
287 else if (index < (sizeof(sample_rates) / sizeof(*sample_rates)))
288 {
289 id3->frequency = sample_rates[index];
290 }
291
292 if (old_index == index)
293 {
294 /* Downsampled SBR */
295 id3->frequency *= 2;
296 }
297 }
298 /* Skip 13 bits from above, plus 3 bits, then read 11 bits */
299 else if ((length >= 4) && (((bits >> 5) & 0x7ff) == 0x2b7))
300 {
301 /* extensionAudioObjectType */
302 DEBUGF("MP4: extensionAudioType\n");
303 type = bits & 0x1f; /* Object type - 5 bits*/
304 bits = get_long_be(&buf[4]);
305
306 if (type == 5)
307 {
308 sbr = bits >> 31;
309
310 if (sbr)
311 {
312 unsigned int old_index = index;
313
314 /* 1 bit read so far */
315 index = (bits >> 27) & 0xf; /* Frequency index - 4 bits */
316
317 if (index == 15)
318 {
319 /* 5 bits read so far */
320 id3->frequency = (bits >> 3) & 0x00ffffff;
321 }
322 else if (index < (sizeof(sample_rates) / sizeof(*sample_rates)))
323 {
324 id3->frequency = sample_rates[index];
325 }
326
327 if (old_index == index)
328 {
329 /* Downsampled SBR */
330 id3->frequency *= 2;
331 }
332 }
333 }
334 }
335
336 if (!sbr && (id3->frequency <= 24000) && (length <= 2))
337 {
338 /* Double the frequency for low-frequency files without a "long"
339 * DecSpecificConfig header. The file may or may not contain SBR,
340 * but here we guess it does if the header is short. This can
341 * fail on some files, but it's the best we can do, short of
342 * decoding (parts of) the file.
343 */
344 id3->frequency *= 2;
345 }
346 }
347
348 return sbr;
349}
350
351static bool read_mp4_tags(int fd, struct mp3entry* id3,
352 unsigned int size_left)
353{
354 unsigned int size;
355 unsigned int type;
356 unsigned int buffer_left = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
357 char* buffer = id3->id3v2buf;
358 bool cwrt = false;
359
360 do
361 {
362 size_left = read_mp4_atom(fd, &size, &type, size_left);
363
364 /* DEBUGF("Tag atom: '%c%c%c%c' (%d bytes left)\n", type >> 24 & 0xff,
365 type >> 16 & 0xff, type >> 8 & 0xff, type & 0xff, size); */
366
367 switch (type)
368 {
369 case MP4_cnam:
370 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
371 &id3->title);
372 break;
373
374 case MP4_cART:
375 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
376 &id3->artist);
377 break;
378
Dan Everton708ac7f2007-06-25 11:15:44 +0000379 case MP4_aART:
380 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
381 &id3->albumartist);
382 break;
383
Dan Evertoneecfe9f2007-08-08 10:19:56 +0000384 case MP4_cgrp:
385 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
386 &id3->grouping);
387 break;
388
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000389 case MP4_calb:
390 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
391 &id3->album);
392 break;
393
394 case MP4_cwrt:
395 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
396 &id3->composer);
397 cwrt = false;
398 break;
399
Magnus Holmgrenb1d07b42007-07-26 11:59:48 +0000400 case MP4_ccmt:
401 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
402 &id3->comment);
403 break;
404
405 case MP4_cday:
406 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
Daniel Stenbergc61e4622007-10-11 22:53:08 +0000407 &id3->year_string);
Magnus Holmgrenb1d07b42007-07-26 11:59:48 +0000408
409 /* Try to parse it as a year, for the benefit of the database.
410 */
Daniel Stenbergc61e4622007-10-11 22:53:08 +0000411 if(id3->year_string)
Magnus Holmgrenb1d07b42007-07-26 11:59:48 +0000412 {
Daniel Stenbergc61e4622007-10-11 22:53:08 +0000413 id3->year = atoi(id3->year_string);
414 if (id3->year < 1900)
415 {
416 id3->year = 0;
417 }
Magnus Holmgrenb1d07b42007-07-26 11:59:48 +0000418 }
Daniel Stenbergc61e4622007-10-11 22:53:08 +0000419 else
420 id3->year = 0;
421
Magnus Holmgrenb1d07b42007-07-26 11:59:48 +0000422 break;
423
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000424 case MP4_gnre:
425 {
426 unsigned short genre;
427
428 read_mp4_tag(fd, size, (char*) &genre, sizeof(genre));
429 id3->genre_string = id3_get_num_genre(betoh16(genre) - 1);
430 }
431 break;
Magnus Holmgrencfe00132007-07-22 21:16:52 +0000432
433 case MP4_cgen:
434 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
435 &id3->genre_string);
436 break;
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000437
Dan Evertonf4a61f02007-08-03 10:00:42 +0000438 case MP4_disk:
439 {
440 unsigned short n[2];
441
442 read_mp4_tag(fd, size, (char*) &n, sizeof(n));
Dan Everton60aeda02007-08-03 10:06:52 +0000443 id3->discnum = betoh16(n[1]);
Dan Evertonf4a61f02007-08-03 10:00:42 +0000444 }
445 break;
446
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000447 case MP4_trkn:
448 {
449 unsigned short n[2];
450
451 read_mp4_tag(fd, size, (char*) &n, sizeof(n));
452 id3->tracknum = betoh16(n[1]);
453 }
454 break;
455
456 case MP4_extra:
457 {
458 char tag_name[TAG_NAME_LENGTH];
459 unsigned int sub_size;
460
461 /* "mean" atom */
462 read_uint32be(fd, &sub_size);
463 size -= sub_size;
464 lseek(fd, sub_size - 4, SEEK_CUR);
465 /* "name" atom */
466 read_uint32be(fd, &sub_size);
467 size -= sub_size;
468 lseek(fd, 8, SEEK_CUR);
469 sub_size -= 12;
470
471 if (sub_size > sizeof(tag_name) - 1)
472 {
473 read(fd, tag_name, sizeof(tag_name) - 1);
Magnus Holmgren277ee082007-07-24 20:40:10 +0000474 lseek(fd, sub_size - (sizeof(tag_name) - 1), SEEK_CUR);
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000475 tag_name[sizeof(tag_name) - 1] = 0;
476 }
477 else
478 {
479 read(fd, tag_name, sub_size);
480 tag_name[sub_size] = 0;
481 }
482
483 if ((strcasecmp(tag_name, "composer") == 0) && !cwrt)
484 {
485 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
486 &id3->composer);
487 }
488 else if (strcasecmp(tag_name, "iTunSMPB") == 0)
489 {
490 char value[TAG_VALUE_LENGTH];
491 char* value_p = value;
492 char* any;
493 unsigned int length = sizeof(value);
494
495 read_mp4_tag_string(fd, size, &value_p, &length, &any);
496 id3->lead_trim = get_itunes_int32(value, 1);
497 id3->tail_trim = get_itunes_int32(value, 2);
498 DEBUGF("AAC: lead_trim %d, tail_trim %d\n",
499 id3->lead_trim, id3->tail_trim);
500 }
501 else
502 {
503 char* any;
504 unsigned int length = read_mp4_tag_string(fd, size,
505 &buffer, &buffer_left, &any);
506
507 if (length > 0)
508 {
509 /* Re-use the read buffer as the dest buffer... */
510 buffer -= length;
511 buffer_left += length;
512
513 if (parse_replaygain(tag_name, buffer, id3,
514 buffer, buffer_left) > 0)
515 {
516 /* Data used, keep it. */
517 buffer += length;
518 buffer_left -= length;
519 }
520 }
521 }
522 }
523 break;
524
525 default:
526 lseek(fd, size, SEEK_CUR);
527 break;
528 }
529 }
530 while ((size_left > 0) && (errno == 0));
531
532 return true;
533}
534
535static bool read_mp4_container(int fd, struct mp3entry* id3,
536 unsigned int size_left)
537{
538 unsigned int size;
539 unsigned int type;
540 unsigned int handler = 0;
541 bool rc = true;
542
543 do
544 {
545 size_left = read_mp4_atom(fd, &size, &type, size_left);
546
547 /* DEBUGF("Atom: '%c%c%c%c' (0x%08x, %d bytes left)\n",
548 (type >> 24) & 0xff, (type >> 16) & 0xff, (type >> 8) & 0xff,
549 type & 0xff, type, size); */
550
551 switch (type)
552 {
553 case MP4_ftyp:
554 {
555 unsigned int id;
556
557 read_uint32be(fd, &id);
558 size -= 4;
559
560 if ((id != MP4_M4A) && (id != MP4_M4B) && (id != MP4_mp42)
561 && (id != MP4_qt) && (id != MP4_3gp6))
562 {
563 DEBUGF("Unknown MP4 file type: '%c%c%c%c'\n",
564 id >> 24 & 0xff, id >> 16 & 0xff, id >> 8 & 0xff,
565 id & 0xff);
566 return false;
567 }
568 }
569 break;
570
571 case MP4_meta:
572 lseek(fd, 4, SEEK_CUR); /* Skip version */
573 size -= 4;
574 /* Fall through */
575
576 case MP4_moov:
577 case MP4_udta:
578 case MP4_mdia:
579 case MP4_stbl:
580 case MP4_trak:
581 rc = read_mp4_container(fd, id3, size);
582 size = 0;
583 break;
584
585 case MP4_ilst:
586 if (handler == MP4_mdir)
587 {
588 rc = read_mp4_tags(fd, id3, size);
589 size = 0;
590 }
591 break;
592
593 case MP4_minf:
594 if (handler == MP4_soun)
595 {
596 rc = read_mp4_container(fd, id3, size);
597 size = 0;
598 }
599 break;
600
601 case MP4_stsd:
602 lseek(fd, 8, SEEK_CUR);
603 size -= 8;
604 rc = read_mp4_container(fd, id3, size);
605 size = 0;
606 break;
607
608 case MP4_hdlr:
609 lseek(fd, 8, SEEK_CUR);
610 read_uint32be(fd, &handler);
611 size -= 12;
612 /* DEBUGF(" Handler '%c%c%c%c'\n", handler >> 24 & 0xff,
613 handler >> 16 & 0xff, handler >> 8 & 0xff,handler & 0xff); */
614 break;
615
616 case MP4_stts:
617 {
618 unsigned int entries;
619 unsigned int i;
620
621 lseek(fd, 4, SEEK_CUR);
622 read_uint32be(fd, &entries);
623 id3->samples = 0;
624
625 for (i = 0; i < entries; i++)
626 {
627 unsigned int n;
628 unsigned int l;
629
630 read_uint32be(fd, &n);
631 read_uint32be(fd, &l);
632 id3->samples += n * l;
633 }
634
635 size = 0;
636 }
637 break;
638
639 case MP4_mp4a:
640 case MP4_alac:
641 {
642 unsigned int frequency;
643
644 id3->codectype = (type == MP4_mp4a) ? AFMT_AAC : AFMT_ALAC;
645 lseek(fd, 22, SEEK_CUR);
646 read_uint32be(fd, &frequency);
647 size -= 26;
648 id3->frequency = frequency;
649
650 if (type == MP4_mp4a)
651 {
652 unsigned int subsize;
653 unsigned int subtype;
654
655 /* Get frequency from the decoder info tag, if possible. */
656 lseek(fd, 2, SEEK_CUR);
657 /* The esds atom is a part of the mp4a atom, so ignore
658 * the returned size (it's already accounted for).
659 */
660 read_mp4_atom(fd, &subsize, &subtype, size);
661 size -= 10;
662
663 if (subtype == MP4_esds)
664 {
665 read_mp4_esds(fd, id3, &size);
666 }
667 }
668 }
669 break;
670
671 case MP4_mdat:
672 id3->filesize = size;
673 break;
674
675 default:
676 break;
677 }
678
679 lseek(fd, size, SEEK_CUR);
680 }
681 while (rc && (size_left > 0) && (errno == 0) && (id3->filesize == 0));
682 /* Break on non-zero filesize, since Rockbox currently doesn't support
683 * metadata after the mdat atom (which sets the filesize field).
684 */
685
686 return rc;
687}
688
689bool get_mp4_metadata(int fd, struct mp3entry* id3)
690{
691 id3->codectype = AFMT_UNKNOWN;
692 id3->filesize = 0;
693 errno = 0;
694
695 if (read_mp4_container(fd, id3, filesize(fd)) && (errno == 0)
696 && (id3->samples > 0) && (id3->frequency > 0)
697 && (id3->filesize > 0))
698 {
699 if (id3->codectype == AFMT_UNKNOWN)
700 {
701 logf("Not an ALAC or AAC file");
702 return false;
703 }
704
705 id3->length = ((int64_t) id3->samples * 1000) / id3->frequency;
706
707 if (id3->length <= 0)
708 {
709 logf("mp4 length invalid!");
710 return false;
711 }
712
713 id3->bitrate = ((int64_t) id3->filesize * 8) / id3->length;
714 DEBUGF("MP4 bitrate %d, frequency %ld Hz, length %ld ms\n",
715 id3->bitrate, id3->frequency, id3->length);
716 }
717 else
718 {
719 logf("MP4 metadata error");
Magnus Holmgren277ee082007-07-24 20:40:10 +0000720 DEBUGF("MP4 metadata error. errno %d, frequency %ld, filesize %ld\n",
721 errno, id3->frequency, id3->filesize);
Marcoen Hirschberg2175d1e2007-06-16 18:19:51 +0000722 return false;
723 }
724
725 return true;
726}