forked from len0rd/rockbox
Experimental Xing header generation added. Use with caution
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3418 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
673937d654
commit
6475aa0c85
5 changed files with 148 additions and 59 deletions
46
apps/tree.c
46
apps/tree.c
|
|
@ -653,6 +653,40 @@ void set_current_file(char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LCD_BITMAP
|
#ifdef HAVE_LCD_BITMAP
|
||||||
|
extern int d_1;
|
||||||
|
extern int d_2;
|
||||||
|
|
||||||
|
void xingupdate(int percent)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
snprintf(buf, 32, "%d%%", percent);
|
||||||
|
lcd_puts(0, 3, buf);
|
||||||
|
snprintf(buf, 32, "%x", d_1);
|
||||||
|
lcd_puts(0, 4, buf);
|
||||||
|
snprintf(buf, 32, "%x", d_2);
|
||||||
|
lcd_puts(0, 5, buf);
|
||||||
|
lcd_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_xing(char *filename)
|
||||||
|
{
|
||||||
|
char buf2[32];
|
||||||
|
unsigned long dbg_tick;
|
||||||
|
|
||||||
|
lcd_clear_display();
|
||||||
|
lcd_puts(0, 0, filename);
|
||||||
|
lcd_update();
|
||||||
|
dbg_tick = current_tick;
|
||||||
|
mpeg_create_xing_header(filename, xingupdate);
|
||||||
|
dbg_tick = current_tick - dbg_tick;
|
||||||
|
snprintf(buf2, 32, "%d ticks", dbg_tick);
|
||||||
|
lcd_puts(0, 1, buf2);
|
||||||
|
snprintf(buf2, 32, "%d seconds", dbg_tick/HZ);
|
||||||
|
lcd_puts(0, 2, buf2);
|
||||||
|
lcd_update();
|
||||||
|
}
|
||||||
|
|
||||||
static int onplay_screen(char* dir, char* file)
|
static int onplay_screen(char* dir, char* file)
|
||||||
{
|
{
|
||||||
bool exit = false;
|
bool exit = false;
|
||||||
|
|
@ -697,6 +731,12 @@ static int onplay_screen(char* dir, char* file)
|
||||||
lcd_putsxy(0, LCD_HEIGHT/2 - h/2, ptr);
|
lcd_putsxy(0, LCD_HEIGHT/2 - h/2, ptr);
|
||||||
lcd_bitmap(bitmap_icons_7x8[Icon_FastBackward],
|
lcd_bitmap(bitmap_icons_7x8[Icon_FastBackward],
|
||||||
LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8, true);
|
LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8, true);
|
||||||
|
|
||||||
|
ptr = "VBR Fix";
|
||||||
|
lcd_getstringsize(ptr,&w,&h);
|
||||||
|
lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr);
|
||||||
|
lcd_bitmap(bitmap_icons_7x8[Icon_DownArrow],
|
||||||
|
LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8, true);
|
||||||
}
|
}
|
||||||
lcd_update();
|
lcd_update();
|
||||||
|
|
||||||
|
|
@ -760,6 +800,12 @@ static int onplay_screen(char* dir, char* file)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BUTTON_DOWN:
|
||||||
|
case BUTTON_ON | BUTTON_DOWN:
|
||||||
|
do_xing(buf);
|
||||||
|
// exit = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case BUTTON_PLAY:
|
case BUTTON_PLAY:
|
||||||
case BUTTON_ON | BUTTON_PLAY: {
|
case BUTTON_ON | BUTTON_PLAY: {
|
||||||
if (playing)
|
if (playing)
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ struct mp3entry {
|
||||||
unsigned int first_frame_offset; /* Byte offset to first real MP3 frame.
|
unsigned int first_frame_offset; /* Byte offset to first real MP3 frame.
|
||||||
Used for skipping leading garbage to
|
Used for skipping leading garbage to
|
||||||
avoid gaps between tracks. */
|
avoid gaps between tracks. */
|
||||||
unsigned int xing_header_pos;
|
unsigned int vbr_header_pos;
|
||||||
unsigned int filesize; /* in bytes */
|
unsigned int filesize; /* in bytes */
|
||||||
unsigned int length; /* song length */
|
unsigned int length; /* song length */
|
||||||
unsigned int elapsed; /* ms played */
|
unsigned int elapsed; /* ms played */
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ struct mp3info {
|
||||||
int frame_count; /* Number of frames in the file (if VBR) */
|
int frame_count; /* Number of frames in the file (if VBR) */
|
||||||
int byte_count; /* File size in bytes */
|
int byte_count; /* File size in bytes */
|
||||||
int file_time; /* Length of the whole file in milliseconds */
|
int file_time; /* Length of the whole file in milliseconds */
|
||||||
int xing_header_pos;
|
int vbr_header_pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Xing header information */
|
/* Xing header information */
|
||||||
|
|
@ -61,6 +61,6 @@ int count_mp3_frames(int fd, int startpos, int filesize,
|
||||||
void (*progressfunc)(int));
|
void (*progressfunc)(int));
|
||||||
int create_xing_header(int fd, int startpos, int filesize,
|
int create_xing_header(int fd, int startpos, int filesize,
|
||||||
unsigned char *buf, int num_frames,
|
unsigned char *buf, int num_frames,
|
||||||
void (*progressfunc)(int));
|
void (*progressfunc)(int), bool generate_toc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -263,9 +263,7 @@ extern unsigned char mp3end[];
|
||||||
static int fnf_read_index;
|
static int fnf_read_index;
|
||||||
static int fnf_buf_len;
|
static int fnf_buf_len;
|
||||||
|
|
||||||
static int fd;
|
static int buf_getbyte(int fd, unsigned char *c)
|
||||||
|
|
||||||
static int buf_getbyte(unsigned char *c)
|
|
||||||
{
|
{
|
||||||
if(fnf_read_index < fnf_buf_len)
|
if(fnf_read_index < fnf_buf_len)
|
||||||
{
|
{
|
||||||
|
|
@ -291,7 +289,7 @@ static int buf_getbyte(unsigned char *c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int buf_seek(int len)
|
static int buf_seek(int fd, int len)
|
||||||
{
|
{
|
||||||
fnf_read_index += len;
|
fnf_read_index += len;
|
||||||
if(fnf_read_index > fnf_buf_len)
|
if(fnf_read_index > fnf_buf_len)
|
||||||
|
|
@ -320,7 +318,7 @@ static void buf_init(void)
|
||||||
fnf_read_index = 0;
|
fnf_read_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long buf_find_next_frame(int *offset, int max_offset,
|
unsigned long buf_find_next_frame(int fd, int *offset, int max_offset,
|
||||||
unsigned long last_header)
|
unsigned long last_header)
|
||||||
{
|
{
|
||||||
unsigned long header=0;
|
unsigned long header=0;
|
||||||
|
|
@ -336,7 +334,7 @@ unsigned long buf_find_next_frame(int *offset, int max_offset,
|
||||||
/* Fill up header with first 24 bits */
|
/* Fill up header with first 24 bits */
|
||||||
for(i = 0; i < 3; i++) {
|
for(i = 0; i < 3; i++) {
|
||||||
header <<= 8;
|
header <<= 8;
|
||||||
if(!buf_getbyte(&tmp))
|
if(!buf_getbyte(fd, &tmp))
|
||||||
return 0;
|
return 0;
|
||||||
header |= tmp;
|
header |= tmp;
|
||||||
pos++;
|
pos++;
|
||||||
|
|
@ -344,7 +342,7 @@ unsigned long buf_find_next_frame(int *offset, int max_offset,
|
||||||
|
|
||||||
do {
|
do {
|
||||||
header <<= 8;
|
header <<= 8;
|
||||||
if(!buf_getbyte(&tmp))
|
if(!buf_getbyte(fd, &tmp))
|
||||||
return 0;
|
return 0;
|
||||||
header |= tmp;
|
header |= tmp;
|
||||||
pos++;
|
pos++;
|
||||||
|
|
@ -413,7 +411,7 @@ int get_mp3file_info(int fd, struct mp3info *info)
|
||||||
DEBUGF("Xing header\n");
|
DEBUGF("Xing header\n");
|
||||||
|
|
||||||
/* Remember where in the file the Xing header is */
|
/* Remember where in the file the Xing header is */
|
||||||
info->xing_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size;
|
info->vbr_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size;
|
||||||
|
|
||||||
/* We want to skip the Xing frame when playing the stream */
|
/* We want to skip the Xing frame when playing the stream */
|
||||||
bytecount += info->frame_size;
|
bytecount += info->frame_size;
|
||||||
|
|
@ -423,7 +421,7 @@ int get_mp3file_info(int fd, struct mp3info *info)
|
||||||
header = find_next_frame(fd, &tmp, 0x20000, 0);
|
header = find_next_frame(fd, &tmp, 0x20000, 0);
|
||||||
if(header == 0)
|
if(header == 0)
|
||||||
return -4;
|
return -4;
|
||||||
|
|
||||||
if(!mp3headerinfo(info, header))
|
if(!mp3headerinfo(info, header))
|
||||||
return -5;
|
return -5;
|
||||||
|
|
||||||
|
|
@ -443,10 +441,14 @@ int get_mp3file_info(int fd, struct mp3info *info)
|
||||||
{
|
{
|
||||||
info->byte_count = BYTES2INT(vbrheader[i], vbrheader[i+1],
|
info->byte_count = BYTES2INT(vbrheader[i], vbrheader[i+1],
|
||||||
vbrheader[i+2], vbrheader[i+3]);
|
vbrheader[i+2], vbrheader[i+3]);
|
||||||
info->bitrate = info->byte_count * 8 / info->file_time;
|
|
||||||
i += 4;
|
i += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(info->file_time && info->byte_count)
|
||||||
|
info->bitrate = info->byte_count * 8 / info->file_time;
|
||||||
|
else
|
||||||
|
info->bitrate = 0;
|
||||||
|
|
||||||
if(vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
|
if(vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
|
||||||
{
|
{
|
||||||
memcpy( info->toc, vbrheader+i, 100 );
|
memcpy( info->toc, vbrheader+i, 100 );
|
||||||
|
|
@ -554,6 +556,8 @@ int count_mp3_frames(int fd, int startpos, int filesize,
|
||||||
int progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
|
int progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
|
||||||
int progress_cnt = 0;
|
int progress_cnt = 0;
|
||||||
|
|
||||||
|
/* Nasty stuff to avoid passing the file handle around */
|
||||||
|
|
||||||
if(lseek(fd, startpos, SEEK_SET) < 0)
|
if(lseek(fd, startpos, SEEK_SET) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
@ -563,9 +567,9 @@ int count_mp3_frames(int fd, int startpos, int filesize,
|
||||||
num_frames = 0;
|
num_frames = 0;
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
|
|
||||||
while((header = buf_find_next_frame(&bytes, -1, header))) {
|
while((header = buf_find_next_frame(fd, &bytes, -1, header))) {
|
||||||
mp3headerinfo(&info, header);
|
mp3headerinfo(&info, header);
|
||||||
buf_seek(info.frame_size-4);
|
buf_seek(fd, info.frame_size-4);
|
||||||
num_frames++;
|
num_frames++;
|
||||||
if(progressfunc)
|
if(progressfunc)
|
||||||
{
|
{
|
||||||
|
|
@ -585,7 +589,7 @@ int count_mp3_frames(int fd, int startpos, int filesize,
|
||||||
|
|
||||||
int create_xing_header(int fd, int startpos, int filesize,
|
int create_xing_header(int fd, int startpos, int filesize,
|
||||||
unsigned char *buf, int num_frames,
|
unsigned char *buf, int num_frames,
|
||||||
void (*progressfunc)(int))
|
void (*progressfunc)(int), bool generate_toc)
|
||||||
{
|
{
|
||||||
unsigned long header = 0;
|
unsigned long header = 0;
|
||||||
struct mp3info info;
|
struct mp3info info;
|
||||||
|
|
@ -595,6 +599,7 @@ int create_xing_header(int fd, int startpos, int filesize,
|
||||||
int filepos;
|
int filepos;
|
||||||
int tocentry;
|
int tocentry;
|
||||||
int x;
|
int x;
|
||||||
|
int index;
|
||||||
|
|
||||||
DEBUGF("create_xing_header()\n");
|
DEBUGF("create_xing_header()\n");
|
||||||
|
|
||||||
|
|
@ -609,46 +614,61 @@ int create_xing_header(int fd, int startpos, int filesize,
|
||||||
buf[36+1] = 'i';
|
buf[36+1] = 'i';
|
||||||
buf[36+2] = 'n';
|
buf[36+2] = 'n';
|
||||||
buf[36+3] = 'g';
|
buf[36+3] = 'g';
|
||||||
int2bytes(&buf[36+4], (VBR_FRAMES_FLAG | VBR_BYTES_FLAG | VBR_TOC_FLAG));
|
int2bytes(&buf[36+4], (num_frames?VBR_FRAMES_FLAG:0 |
|
||||||
int2bytes(&buf[36+8], num_frames);
|
filesize?VBR_BYTES_FLAG:0 |
|
||||||
int2bytes(&buf[36+12], filesize - startpos);
|
generate_toc?VBR_TOC_FLAG:0));
|
||||||
|
index = 36+8;
|
||||||
/* Generate filepos table */
|
if(num_frames)
|
||||||
last_pos = 0;
|
{
|
||||||
filepos = 0;
|
int2bytes(&buf[index], num_frames);
|
||||||
header = 0;
|
index += 4;
|
||||||
x = 0;
|
|
||||||
for(i = 0;i < 100;i++) {
|
|
||||||
/* Calculate the absolute frame number for this seek point */
|
|
||||||
pos = i * num_frames / 100;
|
|
||||||
|
|
||||||
/* Advance from the last seek point to this one */
|
|
||||||
for(j = 0;j < pos - last_pos;j++)
|
|
||||||
{
|
|
||||||
DEBUGF("fpos: %x frame no: %x ", filepos, x++);
|
|
||||||
header = buf_find_next_frame(&bytes, -1, header);
|
|
||||||
mp3headerinfo(&info, header);
|
|
||||||
buf_seek(info.frame_size-4);
|
|
||||||
filepos += info.frame_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(progressfunc)
|
|
||||||
{
|
|
||||||
progressfunc(50 + i/2);
|
|
||||||
}
|
|
||||||
|
|
||||||
tocentry = filepos * 256 / filesize;
|
|
||||||
|
|
||||||
DEBUGF("Pos %d: %d relpos: %d filepos: %x tocentry: %x\n",
|
|
||||||
i, pos, pos-last_pos, filepos, tocentry);
|
|
||||||
|
|
||||||
/* Fill in the TOC entry */
|
|
||||||
buf[36+16+i] = tocentry;
|
|
||||||
|
|
||||||
last_pos = pos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buf+152, cooltext, sizeof(cooltext));
|
if(filesize)
|
||||||
|
{
|
||||||
|
int2bytes(&buf[index], filesize - startpos);
|
||||||
|
index += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(generate_toc)
|
||||||
|
{
|
||||||
|
/* Generate filepos table */
|
||||||
|
last_pos = 0;
|
||||||
|
filepos = 0;
|
||||||
|
header = 0;
|
||||||
|
x = 0;
|
||||||
|
for(i = 0;i < 100;i++) {
|
||||||
|
/* Calculate the absolute frame number for this seek point */
|
||||||
|
pos = i * num_frames / 100;
|
||||||
|
|
||||||
|
/* Advance from the last seek point to this one */
|
||||||
|
for(j = 0;j < pos - last_pos;j++)
|
||||||
|
{
|
||||||
|
DEBUGF("fpos: %x frame no: %x ", filepos, x++);
|
||||||
|
header = buf_find_next_frame(fd, &bytes, -1, header);
|
||||||
|
mp3headerinfo(&info, header);
|
||||||
|
buf_seek(fd, info.frame_size-4);
|
||||||
|
filepos += info.frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(progressfunc)
|
||||||
|
{
|
||||||
|
progressfunc(50 + i/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
tocentry = filepos * 256 / filesize;
|
||||||
|
|
||||||
|
DEBUGF("Pos %d: %d relpos: %d filepos: %x tocentry: %x\n",
|
||||||
|
i, pos, pos-last_pos, filepos, tocentry);
|
||||||
|
|
||||||
|
/* Fill in the TOC entry */
|
||||||
|
buf[index + i] = tocentry;
|
||||||
|
|
||||||
|
last_pos = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf + index + 100, cooltext, sizeof(cooltext));
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for(i = 0;i < 417;i++)
|
for(i = 0;i < 417;i++)
|
||||||
|
|
|
||||||
|
|
@ -353,6 +353,9 @@ static void set_elapsed(struct mp3entry* id3)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool paused; /* playback is paused */
|
static bool paused; /* playback is paused */
|
||||||
|
|
||||||
|
static unsigned char xingbuf[417];
|
||||||
|
|
||||||
#ifdef SIMULATOR
|
#ifdef SIMULATOR
|
||||||
static bool is_playing = false;
|
static bool is_playing = false;
|
||||||
static bool playing = false;
|
static bool playing = false;
|
||||||
|
|
@ -500,9 +503,16 @@ static bool mpeg_stop_done;
|
||||||
|
|
||||||
static void recalculate_watermark(int bitrate)
|
static void recalculate_watermark(int bitrate)
|
||||||
{
|
{
|
||||||
int bytes_per_sec = bitrate * 1000 / 8;
|
int bytes_per_sec;
|
||||||
int time = ata_spinup_time;
|
int time = ata_spinup_time;
|
||||||
|
|
||||||
|
/* A bitrate of 0 probably means empty VBR header. We play safe
|
||||||
|
and set a high threshold */
|
||||||
|
if(bitrate == 0)
|
||||||
|
bitrate = 320000;
|
||||||
|
|
||||||
|
bytes_per_sec = bitrate * 1000 / 8;
|
||||||
|
|
||||||
if(time)
|
if(time)
|
||||||
{
|
{
|
||||||
/* No drive spins up faster than 3.5s */
|
/* No drive spins up faster than 3.5s */
|
||||||
|
|
@ -1857,6 +1867,18 @@ static void mpeg_thread(void)
|
||||||
|
|
||||||
if(mpeg_file >= 0)
|
if(mpeg_file >= 0)
|
||||||
close(mpeg_file);
|
close(mpeg_file);
|
||||||
|
|
||||||
|
mpeg_file = open(recording_filename, O_RDWR);
|
||||||
|
if(mpeg_file < 0)
|
||||||
|
panicf("rec upd: %d", mpeg_file);
|
||||||
|
|
||||||
|
create_xing_header(mpeg_file, 0, mpeg_num_recorded_bytes(),
|
||||||
|
xingbuf, 0, NULL, false);
|
||||||
|
|
||||||
|
lseek(mpeg_file, 4096, SEEK_SET);
|
||||||
|
write(mpeg_file, xingbuf, 417);
|
||||||
|
close(mpeg_file);
|
||||||
|
|
||||||
mpeg_file = -1;
|
mpeg_file = -1;
|
||||||
|
|
||||||
#ifdef DEBUG1
|
#ifdef DEBUG1
|
||||||
|
|
@ -2982,7 +3004,6 @@ int d_2;
|
||||||
int mpeg_create_xing_header(char *filename, void (*progressfunc)(int))
|
int mpeg_create_xing_header(char *filename, void (*progressfunc)(int))
|
||||||
{
|
{
|
||||||
struct mp3entry entry;
|
struct mp3entry entry;
|
||||||
char xingbuf[417];
|
|
||||||
int fd;
|
int fd;
|
||||||
int rc;
|
int rc;
|
||||||
int flen;
|
int flen;
|
||||||
|
|
@ -3013,15 +3034,17 @@ int mpeg_create_xing_header(char *filename, void (*progressfunc)(int))
|
||||||
progressfunc);
|
progressfunc);
|
||||||
|
|
||||||
create_xing_header(fd, entry.first_frame_offset,
|
create_xing_header(fd, entry.first_frame_offset,
|
||||||
flen, xingbuf, num_frames, progressfunc);
|
flen, xingbuf, num_frames, progressfunc, true);
|
||||||
|
|
||||||
/* Try to fit the Xing header first in the stream. Replace the existing
|
/* Try to fit the Xing header first in the stream. Replace the existing
|
||||||
Xing header if there is one, else see if there is room between the
|
Xing header if there is one, else see if there is room between the
|
||||||
ID3 tag and the first MP3 frame. */
|
ID3 tag and the first MP3 frame. */
|
||||||
if(entry.xing_header_pos)
|
if(entry.vbr_header_pos)
|
||||||
{
|
{
|
||||||
/* Reuse existing Xing header */
|
/* Reuse existing Xing header */
|
||||||
fpos = entry.xing_header_pos;
|
fpos = entry.vbr_header_pos;
|
||||||
|
|
||||||
|
DEBUGF("Reusing Xing header at %d\n", fpos);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue