summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndree Buschmann <AndreeBuschmann@t-online.de>2011-03-13 19:25:20 +0000
committerAndree Buschmann <AndreeBuschmann@t-online.de>2011-03-13 19:25:20 +0000
commitff1b2b7fab5bbfa9f81173cdb77a34f08231d0d9 (patch)
tree7c719e99a78ff3ef39eba3c16fb6cab0f2537d1c
parent92183d2dd0275ed91a635733cc5f3d85902a9373 (diff)
downloadrockbox-ff1b2b7fab5bbfa9f81173cdb77a34f08231d0d9.tar.gz
rockbox-ff1b2b7fab5bbfa9f81173cdb77a34f08231d0d9.zip
Refactor reading of Xing/Info/Vbri tags to prepare for further changes.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29582 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/mp3data.c299
1 files changed, 141 insertions, 158 deletions
diff --git a/apps/mp3data.c b/apps/mp3data.c
index f5ef122801..35b4608396 100644
--- a/apps/mp3data.c
+++ b/apps/mp3data.c
@@ -349,32 +349,135 @@ unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset,
349} 349}
350#endif 350#endif
351 351
352int get_mp3file_info(int fd, struct mp3info *info) 352/* Extract information from a 'Xing' or 'Info' header. */
353static void get_xing_info(struct mp3info *info, unsigned char *buf)
353{ 354{
354 unsigned char frame[1800]; 355 int i = 8;
355 unsigned char *vbrheader; 356
356 unsigned long header; 357 /* Is it a VBR file? */
357 long bytecount; 358 info->is_vbr = !memcmp(buf, "Xing", 4);
358 int num_offsets;
359 int i;
360 long offset;
361 int j;
362 long tmp;
363 359
364 header = find_next_frame(fd, &bytecount, 0x20000, 0); 360 if (buf[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
365 /* Quit if we haven't found a valid header within 128K */ 361 {
362 info->frame_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
363 if (info->frame_count <= ULONG_MAX / info->ft_num)
364 info->file_time = info->frame_count * info->ft_num / info->ft_den;
365 else
366 info->file_time = info->frame_count / info->ft_den * info->ft_num;
367 i += 4;
368 }
369
370 if (buf[7] & VBR_BYTES_FLAG) /* Is byte count there? */
371 {
372 info->byte_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
373 i += 4;
374 }
375
376 if (info->file_time && info->byte_count)
377 {
378 if (info->byte_count <= (ULONG_MAX/8))
379 info->bitrate = info->byte_count * 8 / info->file_time;
380 else
381 info->bitrate = info->byte_count / (info->file_time >> 3);
382 }
383
384 if (buf[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
385 {
386 info->has_toc = true;
387 memcpy( info->toc, buf+i, 100 );
388 i += 100;
389 }
390 if (buf[7] & VBR_QUALITY_FLAG)
391 {
392 /* We don't care about this, but need to skip it */
393 i += 4;
394 }
395#if CONFIG_CODEC==SWCODEC
396 i += 21;
397 info->enc_delay = ((int)buf[i ] << 4) | (buf[i+1] >> 4);
398 info->enc_padding = ((int)buf[i+1] << 8) | buf[i+2];
399 /* TODO: This sanity checking is rather silly, seeing as how the LAME
400 header contains a CRC field that can be used to verify integrity. */
401 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
402 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
403 {
404 /* Invalid data */
405 info->enc_delay = -1;
406 info->enc_padding = -1;
407 }
408#endif
409}
410
411/* Extract information from a 'VBRI' header. */
412static void get_vbri_info(struct mp3info *info, unsigned char *buf)
413{
414 int i, num_offsets, offset = 0;
415
416 info->is_vbr = true; /* Yes, it is a FhG VBR file */
417 info->has_toc = false; /* We don't parse the TOC (yet) */
418
419 info->byte_count = bytes2int(buf[10], buf[11], buf[12], buf[13]);
420 info->frame_count = bytes2int(buf[14], buf[15], buf[16], buf[17]);
421 if (info->frame_count <= ULONG_MAX / info->ft_num)
422 info->file_time = info->frame_count * info->ft_num / info->ft_den;
423 else
424 info->file_time = info->frame_count / info->ft_den * info->ft_num;
425
426 if (info->byte_count <= (ULONG_MAX/8))
427 info->bitrate = info->byte_count * 8 / info->file_time;
428 else
429 info->bitrate = info->byte_count / (info->file_time >> 3);
430
431 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
432 num_offsets = bytes2int(0, 0, buf[18], buf[19]);
433 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
434 info->bitrate, info->frame_size, info->frame_size);
435 VDEBUGF("Frame count: %lx\n", info->frame_count);
436 VDEBUGF("Byte count: %lx\n", info->byte_count);
437 VDEBUGF("Offsets: %d\n", num_offsets);
438 VDEBUGF("Frames/entry: %ld\n",
439 bytes2int(0, 0, buf[24], buf[25]));
440
441 for(i = 0; i < num_offsets; i++)
442 {
443 offset += bytes2int(0, 0, buf[26+i*2], buf[27+i*2]);;
444 VDEBUGF("%03d: %lx\n", i, offset - bytecount,);
445 }
446}
447
448/* Seek to next mpeg header and extract relevant information. */
449static int get_next_header_info(int fd, long *bytecount, struct mp3info *info)
450{
451 unsigned long header = find_next_frame(fd, bytecount, 0x20000, 0);
366 if(header == 0) 452 if(header == 0)
367 return -1; 453 return -1;
368 454
455 if(!mp3headerinfo(info, header))
456 return -2;
457
458 return 0;
459}
460
461int get_mp3file_info(int fd, struct mp3info *info)
462{
463 unsigned char frame[1800], *vbrheader;
464 long bytecount;
465 int result;
466
467 /* Initialize info and frame */
369 memset(info, 0, sizeof(struct mp3info)); 468 memset(info, 0, sizeof(struct mp3info));
370 memset(frame, 0, sizeof(frame)); 469 memset(frame, 0, sizeof(frame));
470
371#if CONFIG_CODEC==SWCODEC 471#if CONFIG_CODEC==SWCODEC
372 /* These two are needed for proper LAME gapless MP3 playback */ 472 /* These two are needed for proper LAME gapless MP3 playback */
373 info->enc_delay = -1; 473 info->enc_delay = -1;
374 info->enc_padding = -1; 474 info->enc_padding = -1;
375#endif 475#endif
376 if(!mp3headerinfo(info, header)) 476
377 return -2; 477 /* Get the very first MPEG frame. */
478 result = get_next_header_info(fd, &bytecount, info);
479 if(result)
480 return result;
378 481
379 /* OK, we have found a frame. Let's see if it has a Xing header */ 482 /* OK, we have found a frame. Let's see if it has a Xing header */
380 if (info->frame_size-4 >= (int)sizeof(frame)) 483 if (info->frame_size-4 >= (int)sizeof(frame))
@@ -386,170 +489,50 @@ int get_mp3file_info(int fd, struct mp3info *info)
386 if(read(fd, frame, info->frame_size-4) < 0) 489 if(read(fd, frame, info->frame_size-4) < 0)
387 return -3; 490 return -3;
388 491
389 /* calculate position of VBR header */ 492 /* Calculate position of a possible VBR header */
390 if ( info->version == MPEG_VERSION1 ) { 493 if (info->version == MPEG_VERSION1) {
391 if (info->channel_mode == 3) /* mono */ 494 if (info->channel_mode == 3) /* mono */
392 vbrheader = frame + 17; 495 vbrheader = frame + 17;
393 else 496 else
394 vbrheader = frame + 32; 497 vbrheader = frame + 32;
395 } 498 } else {
396 else {
397 if (info->channel_mode == 3) /* mono */ 499 if (info->channel_mode == 3) /* mono */
398 vbrheader = frame + 9; 500 vbrheader = frame + 9;
399 else 501 else
400 vbrheader = frame + 17; 502 vbrheader = frame + 17;
401 } 503 }
402 504
403 if (!memcmp(vbrheader, "Xing", 4) 505 if (!memcmp(vbrheader, "Xing", 4) || !memcmp(vbrheader, "Info", 4))
404 || !memcmp(vbrheader, "Info", 4))
405 { 506 {
406 int i = 8; /* Where to start parsing info */ 507 VDEBUGF("-- XING header --\n");
407
408 /* DEBUGF("Xing/Info header\n"); */
409 508
410 /* Remember where in the file the Xing header is */
411/* Rockbox: not used
412 info->vbr_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size;
413*/
414 /* We want to skip the Xing frame when playing the stream */ 509 /* We want to skip the Xing frame when playing the stream */
415 bytecount += info->frame_size; 510 bytecount += info->frame_size;
416 511
417 /* Now get the next frame to find out the real info about 512 /* Now get the next frame to read the real info about the mp3 stream */
418 the mp3 stream */ 513 result = get_next_header_info(fd, &bytecount, info);
419 header = find_next_frame(fd, &tmp, 0x20000, 0); 514 if(result)
420 if(header == 0) 515 return result;
421 return -4; 516
422 517 get_xing_info(info, vbrheader);
423 if(!mp3headerinfo(info, header))
424 return -5;
425
426 /* Is it a VBR file? */
427 info->is_vbr = !memcmp(vbrheader, "Xing", 4);
428/* Rockbox: not used
429 info->is_xing_vbr = info->is_vbr;
430*/
431
432 if (vbrheader[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
433 {
434 info->frame_count = bytes2int(vbrheader[i], vbrheader[i+1],
435 vbrheader[i+2], vbrheader[i+3]);
436 if (info->frame_count <= ULONG_MAX / info->ft_num)
437 info->file_time = info->frame_count * info->ft_num / info->ft_den;
438 else
439 info->file_time = info->frame_count / info->ft_den * info->ft_num;
440 i += 4;
441 }
442
443 if (vbrheader[7] & VBR_BYTES_FLAG) /* Is byte count there? */
444 {
445 info->byte_count = bytes2int(vbrheader[i], vbrheader[i+1],
446 vbrheader[i+2], vbrheader[i+3]);
447 i += 4;
448 }
449
450 if (info->file_time && info->byte_count)
451 {
452 if (info->byte_count <= (ULONG_MAX/8))
453 info->bitrate = info->byte_count * 8 / info->file_time;
454 else
455 info->bitrate = info->byte_count / (info->file_time >> 3);
456 }
457
458 if (vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
459 {
460 info->has_toc = true;
461 memcpy( info->toc, vbrheader+i, 100 );
462 i += 100;
463 }
464 if (vbrheader[7] & VBR_QUALITY_FLAG)
465 {
466 /* We don't care about this, but need to skip it */
467 i += 4;
468 }
469#if CONFIG_CODEC==SWCODEC
470 i += 21;
471 info->enc_delay = ((int)vbrheader[i ] << 4) | (vbrheader[i+1] >> 4);
472 info->enc_padding = ((int)vbrheader[i+1] << 8) | vbrheader[i+2];
473 /* TODO: This sanity checking is rather silly, seeing as how the LAME
474 header contains a CRC field that can be used to verify integrity. */
475 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
476 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
477 {
478 /* Invalid data */
479 info->enc_delay = -1;
480 info->enc_padding = -1;
481 }
482#endif
483 } 518 }
484 519 else if (!memcmp(vbrheader, "VBRI", 4))
485 if (!memcmp(vbrheader, "VBRI", 4))
486 { 520 {
487 VDEBUGF("VBRI header\n"); 521 VDEBUGF("-- VBRI header --\n");
488 522
489 /* We want to skip the VBRI frame when playing the stream */ 523 /* We want to skip the VBRI frame when playing the stream */
490 bytecount += info->frame_size; 524 bytecount += info->frame_size;
491 525
492 /* Now get the next frame to find out the real info about 526 /* Now get the next frame to read the real info about the mp3 stream */
493 the mp3 stream */ 527 result = get_next_header_info(fd, &bytecount, info);
494 header = find_next_frame(fd, &tmp, 0x20000, 0); 528 if(result)
495 if(header == 0) 529 return result;
496 return -6; 530
497 531 get_vbri_info(info, vbrheader);
498 bytecount += tmp; 532 }
499 533 else
500 if(!mp3headerinfo(info, header)) 534 {
501 return -7; 535 VDEBUGF("-- No VBR header --\n");
502
503 VDEBUGF("%04x: %04x %04x ", 0, (short)(header >> 16),
504 (short)(header & 0xffff));
505 for(i = 4;i < (int)sizeof(frame)-4;i+=2) {
506 if(i % 16 == 0) {
507 VDEBUGF("\n%04x: ", i-4);
508 }
509 VDEBUGF("%04x ", (frame[i-4] << 8) | frame[i-4+1]);
510 }
511
512 VDEBUGF("\n");
513
514 /* Yes, it is a FhG VBR file */
515 info->is_vbr = true;
516/* Rockbox: not used
517 info->is_vbri_vbr = true;
518*/
519 info->has_toc = false; /* We don't parse the TOC (yet) */
520
521 info->byte_count = bytes2int(vbrheader[10], vbrheader[11],
522 vbrheader[12], vbrheader[13]);
523 info->frame_count = bytes2int(vbrheader[14], vbrheader[15],
524 vbrheader[16], vbrheader[17]);
525 if (info->frame_count <= ULONG_MAX / info->ft_num)
526 info->file_time = info->frame_count * info->ft_num / info->ft_den;
527 else
528 info->file_time = info->frame_count / info->ft_den * info->ft_num;
529
530 if (info->byte_count <= (ULONG_MAX/8))
531 info->bitrate = info->byte_count * 8 / info->file_time;
532 else
533 info->bitrate = info->byte_count / (info->file_time >> 3);
534
535 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
536 num_offsets = bytes2int(0, 0, vbrheader[18], vbrheader[19]);
537 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
538 info->bitrate, info->frame_size, info->frame_size);
539 VDEBUGF("Frame count: %lx\n", info->frame_count);
540 VDEBUGF("Byte count: %lx\n", info->byte_count);
541 VDEBUGF("Offsets: %d\n", num_offsets);
542 VDEBUGF("Frames/entry: %ld\n",
543 bytes2int(0, 0, vbrheader[24], vbrheader[25]));
544
545 offset = 0;
546
547 for(i = 0;i < num_offsets;i++)
548 {
549 j = bytes2int(0, 0, vbrheader[26+i*2], vbrheader[27+i*2]);
550 offset += j;
551 VDEBUGF("%03d: %lx (%x)\n", i, offset - bytecount, j);
552 }
553 } 536 }
554 537
555 return bytecount; 538 return bytecount;