From 6475aa0c85fcca7a37a7aa4316173270fcb6d038 Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Mon, 10 Mar 2003 18:05:01 +0000 Subject: Experimental Xing header generation added. Use with caution git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3418 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/id3.h | 2 +- firmware/export/mp3data.h | 4 +- firmware/mp3data.c | 118 +++++++++++++++++++++++++++------------------- firmware/mpeg.c | 33 +++++++++++-- 4 files changed, 100 insertions(+), 57 deletions(-) (limited to 'firmware') diff --git a/firmware/export/id3.h b/firmware/export/id3.h index 30be4bf883..a9ab9ef36f 100644 --- a/firmware/export/id3.h +++ b/firmware/export/id3.h @@ -39,7 +39,7 @@ struct mp3entry { unsigned int first_frame_offset; /* Byte offset to first real MP3 frame. Used for skipping leading garbage to avoid gaps between tracks. */ - unsigned int xing_header_pos; + unsigned int vbr_header_pos; unsigned int filesize; /* in bytes */ unsigned int length; /* song length */ unsigned int elapsed; /* ms played */ diff --git a/firmware/export/mp3data.h b/firmware/export/mp3data.h index a1018ebaa2..54a6899a78 100644 --- a/firmware/export/mp3data.h +++ b/firmware/export/mp3data.h @@ -46,7 +46,7 @@ struct mp3info { int frame_count; /* Number of frames in the file (if VBR) */ int byte_count; /* File size in bytes */ int file_time; /* Length of the whole file in milliseconds */ - int xing_header_pos; + int vbr_header_pos; }; /* Xing header information */ @@ -61,6 +61,6 @@ int count_mp3_frames(int fd, int startpos, int filesize, void (*progressfunc)(int)); int create_xing_header(int fd, int startpos, int filesize, unsigned char *buf, int num_frames, - void (*progressfunc)(int)); + void (*progressfunc)(int), bool generate_toc); #endif diff --git a/firmware/mp3data.c b/firmware/mp3data.c index 8d925041ce..21f01ea19e 100644 --- a/firmware/mp3data.c +++ b/firmware/mp3data.c @@ -263,9 +263,7 @@ extern unsigned char mp3end[]; static int fnf_read_index; static int fnf_buf_len; -static int fd; - -static int buf_getbyte(unsigned char *c) +static int buf_getbyte(int fd, unsigned char *c) { if(fnf_read_index < fnf_buf_len) { @@ -291,7 +289,7 @@ static int buf_getbyte(unsigned char *c) return 0; } -static int buf_seek(int len) +static int buf_seek(int fd, int len) { fnf_read_index += len; if(fnf_read_index > fnf_buf_len) @@ -320,7 +318,7 @@ static void buf_init(void) 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 header=0; @@ -336,7 +334,7 @@ unsigned long buf_find_next_frame(int *offset, int max_offset, /* Fill up header with first 24 bits */ for(i = 0; i < 3; i++) { header <<= 8; - if(!buf_getbyte(&tmp)) + if(!buf_getbyte(fd, &tmp)) return 0; header |= tmp; pos++; @@ -344,7 +342,7 @@ unsigned long buf_find_next_frame(int *offset, int max_offset, do { header <<= 8; - if(!buf_getbyte(&tmp)) + if(!buf_getbyte(fd, &tmp)) return 0; header |= tmp; pos++; @@ -413,7 +411,7 @@ int get_mp3file_info(int fd, struct mp3info *info) DEBUGF("Xing header\n"); /* 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 */ 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); if(header == 0) return -4; - + if(!mp3headerinfo(info, header)) return -5; @@ -443,10 +441,14 @@ int get_mp3file_info(int fd, struct mp3info *info) { info->byte_count = BYTES2INT(vbrheader[i], vbrheader[i+1], vbrheader[i+2], vbrheader[i+3]); - info->bitrate = info->byte_count * 8 / info->file_time; 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? */ { 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_cnt = 0; + /* Nasty stuff to avoid passing the file handle around */ + if(lseek(fd, startpos, SEEK_SET) < 0) return -1; @@ -563,9 +567,9 @@ int count_mp3_frames(int fd, int startpos, int filesize, num_frames = 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); - buf_seek(info.frame_size-4); + buf_seek(fd, info.frame_size-4); num_frames++; 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, unsigned char *buf, int num_frames, - void (*progressfunc)(int)) + void (*progressfunc)(int), bool generate_toc) { unsigned long header = 0; struct mp3info info; @@ -595,6 +599,7 @@ int create_xing_header(int fd, int startpos, int filesize, int filepos; int tocentry; int x; + int index; 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+2] = 'n'; buf[36+3] = 'g'; - int2bytes(&buf[36+4], (VBR_FRAMES_FLAG | VBR_BYTES_FLAG | VBR_TOC_FLAG)); - int2bytes(&buf[36+8], num_frames); - int2bytes(&buf[36+12], filesize - startpos); - - /* 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(&bytes, -1, header); - mp3headerinfo(&info, header); - buf_seek(info.frame_size-4); - filepos += info.frame_size; - } + int2bytes(&buf[36+4], (num_frames?VBR_FRAMES_FLAG:0 | + filesize?VBR_BYTES_FLAG:0 | + generate_toc?VBR_TOC_FLAG:0)); + index = 36+8; + if(num_frames) + { + int2bytes(&buf[index], num_frames); + index += 4; + } - 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); + if(filesize) + { + int2bytes(&buf[index], filesize - startpos); + index += 4; + } - /* Fill in the TOC entry */ - buf[36+16+i] = tocentry; - - last_pos = pos; + 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+152, cooltext, sizeof(cooltext)); + memcpy(buf + index + 100, cooltext, sizeof(cooltext)); #ifdef DEBUG for(i = 0;i < 417;i++) diff --git a/firmware/mpeg.c b/firmware/mpeg.c index c3288dfdac..13c4b01b8a 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c @@ -353,6 +353,9 @@ static void set_elapsed(struct mp3entry* id3) } static bool paused; /* playback is paused */ + +static unsigned char xingbuf[417]; + #ifdef SIMULATOR static bool is_playing = false; static bool playing = false; @@ -500,9 +503,16 @@ static bool mpeg_stop_done; static void recalculate_watermark(int bitrate) { - int bytes_per_sec = bitrate * 1000 / 8; + int bytes_per_sec; 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) { /* No drive spins up faster than 3.5s */ @@ -1857,6 +1867,18 @@ static void mpeg_thread(void) if(mpeg_file >= 0) 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; #ifdef DEBUG1 @@ -2982,7 +3004,6 @@ int d_2; int mpeg_create_xing_header(char *filename, void (*progressfunc)(int)) { struct mp3entry entry; - char xingbuf[417]; int fd; int rc; int flen; @@ -3013,15 +3034,17 @@ int mpeg_create_xing_header(char *filename, void (*progressfunc)(int)) progressfunc); 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 Xing header if there is one, else see if there is room between the ID3 tag and the first MP3 frame. */ - if(entry.xing_header_pos) + if(entry.vbr_header_pos) { /* Reuse existing Xing header */ - fpos = entry.xing_header_pos; + fpos = entry.vbr_header_pos; + + DEBUGF("Reusing Xing header at %d\n", fpos); } else { -- cgit v1.2.3