Added support for reading LAME header delay and padding fields for proper gapless MP3 support.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6689 a1c6a512-1295-4272-9138-f99709370657
diff --git a/firmware/export/mp3data.h b/firmware/export/mp3data.h
index c031cc2..a7f2e3d 100644
--- a/firmware/export/mp3data.h
+++ b/firmware/export/mp3data.h
@@ -47,13 +47,15 @@
long byte_count; /* File size in bytes */
long file_time; /* Length of the whole file in milliseconds */
int vbr_header_pos;
+ int enc_delay; /* Encoder delay, fetched from LAME header */
+ int enc_padding; /* Padded samples added to last frame. LAME header */
};
/* Xing header information */
-#define VBR_FRAMES_FLAG 0x01
-#define VBR_BYTES_FLAG 0x02
-#define VBR_TOC_FLAG 0x04
-
+#define VBR_FRAMES_FLAG 0x01
+#define VBR_BYTES_FLAG 0x02
+#define VBR_TOC_FLAG 0x04
+#define VBR_QUALITY_FLAG 0x08
unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header);
unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset,
diff --git a/firmware/mp3data.c b/firmware/mp3data.c
index 32b3be4..2b58710 100644
--- a/firmware/mp3data.c
+++ b/firmware/mp3data.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <stdbool.h>
#include "debug.h"
+#include "logf.h"
#include "mp3data.h"
#include "file.h"
#include "buffer.h"
@@ -379,6 +380,12 @@
return -1;
memset(info, 0, sizeof(struct mp3info));
+ /* These two are needed for proper LAME gapless MP3 playback */
+ /* TODO: These can be found in a LAME Info header as well, but currently
+ they are only looked for in a Xing header. Xing and Info headers have
+ the exact same format, but Info headers are used for CBR files. */
+ info->enc_delay = -1;
+ info->enc_padding = -1;
if(!mp3headerinfo(info, header))
return -2;
@@ -448,6 +455,22 @@
if(vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
{
memcpy( info->toc, vbrheader+i, 100 );
+ i += 100;
+ }
+ if (vbrheader[7] & VBR_QUALITY_FLAG)
+ {
+ /* We don't care about this, but need to skip it */
+ i += 4;
+ }
+ i += 21;
+ info->enc_delay = (vbrheader[i] << 4) | (vbrheader[i + 1] >> 4);
+ info->enc_padding = ((vbrheader[i + 1] & 0x0f) << 8) | vbrheader[i + 2];
+ if (!(info->enc_delay >= 0 && info->enc_delay <= 1152 &&
+ info->enc_padding >= 0 && info->enc_padding <= 2*1152))
+ {
+ /* Invalid data */
+ info->enc_delay = -1;
+ info->enc_padding = -1;
}
}
@@ -488,7 +511,6 @@
vbrheader[12], vbrheader[13]);
info->frame_count = BYTES2INT(vbrheader[14], vbrheader[15],
vbrheader[16], vbrheader[17]);
-
info->file_time = info->frame_count * info->frame_time;
info->bitrate = info->byte_count * 8 / info->file_time;