diff options
author | Linus Nielsen Feltzing <linus@haxx.se> | 2003-03-10 18:05:01 +0000 |
---|---|---|
committer | Linus Nielsen Feltzing <linus@haxx.se> | 2003-03-10 18:05:01 +0000 |
commit | 6475aa0c85fcca7a37a7aa4316173270fcb6d038 (patch) | |
tree | e6dbe18217113212a9b8e713d3325c5803b3f4a6 | |
parent | 673937d65402b058b5b5bfa5a1bf990c2d218dba (diff) | |
download | rockbox-6475aa0c85fcca7a37a7aa4316173270fcb6d038.tar.gz rockbox-6475aa0c85fcca7a37a7aa4316173270fcb6d038.zip |
Experimental Xing header generation added. Use with caution
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3418 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/tree.c | 46 | ||||
-rw-r--r-- | firmware/export/id3.h | 2 | ||||
-rw-r--r-- | firmware/export/mp3data.h | 4 | ||||
-rw-r--r-- | firmware/mp3data.c | 118 | ||||
-rw-r--r-- | firmware/mpeg.c | 33 |
5 files changed, 146 insertions, 57 deletions
diff --git a/apps/tree.c b/apps/tree.c index 677f9302c4..013bfce010 100644 --- a/apps/tree.c +++ b/apps/tree.c | |||
@@ -653,6 +653,40 @@ void set_current_file(char *path) | |||
653 | } | 653 | } |
654 | 654 | ||
655 | #ifdef HAVE_LCD_BITMAP | 655 | #ifdef HAVE_LCD_BITMAP |
656 | extern int d_1; | ||
657 | extern int d_2; | ||
658 | |||
659 | void xingupdate(int percent) | ||
660 | { | ||
661 | char buf[32]; | ||
662 | |||
663 | snprintf(buf, 32, "%d%%", percent); | ||
664 | lcd_puts(0, 3, buf); | ||
665 | snprintf(buf, 32, "%x", d_1); | ||
666 | lcd_puts(0, 4, buf); | ||
667 | snprintf(buf, 32, "%x", d_2); | ||
668 | lcd_puts(0, 5, buf); | ||
669 | lcd_update(); | ||
670 | } | ||
671 | |||
672 | void do_xing(char *filename) | ||
673 | { | ||
674 | char buf2[32]; | ||
675 | unsigned long dbg_tick; | ||
676 | |||
677 | lcd_clear_display(); | ||
678 | lcd_puts(0, 0, filename); | ||
679 | lcd_update(); | ||
680 | dbg_tick = current_tick; | ||
681 | mpeg_create_xing_header(filename, xingupdate); | ||
682 | dbg_tick = current_tick - dbg_tick; | ||
683 | snprintf(buf2, 32, "%d ticks", dbg_tick); | ||
684 | lcd_puts(0, 1, buf2); | ||
685 | snprintf(buf2, 32, "%d seconds", dbg_tick/HZ); | ||
686 | lcd_puts(0, 2, buf2); | ||
687 | lcd_update(); | ||
688 | } | ||
689 | |||
656 | static int onplay_screen(char* dir, char* file) | 690 | static int onplay_screen(char* dir, char* file) |
657 | { | 691 | { |
658 | bool exit = false; | 692 | bool exit = false; |
@@ -697,6 +731,12 @@ static int onplay_screen(char* dir, char* file) | |||
697 | lcd_putsxy(0, LCD_HEIGHT/2 - h/2, ptr); | 731 | lcd_putsxy(0, LCD_HEIGHT/2 - h/2, ptr); |
698 | lcd_bitmap(bitmap_icons_7x8[Icon_FastBackward], | 732 | lcd_bitmap(bitmap_icons_7x8[Icon_FastBackward], |
699 | LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8, true); | 733 | LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8, true); |
734 | |||
735 | ptr = "VBR Fix"; | ||
736 | lcd_getstringsize(ptr,&w,&h); | ||
737 | lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h, ptr); | ||
738 | lcd_bitmap(bitmap_icons_7x8[Icon_DownArrow], | ||
739 | LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8, true); | ||
700 | } | 740 | } |
701 | lcd_update(); | 741 | lcd_update(); |
702 | 742 | ||
@@ -760,6 +800,12 @@ static int onplay_screen(char* dir, char* file) | |||
760 | } | 800 | } |
761 | break; | 801 | break; |
762 | 802 | ||
803 | case BUTTON_DOWN: | ||
804 | case BUTTON_ON | BUTTON_DOWN: | ||
805 | do_xing(buf); | ||
806 | // exit = true; | ||
807 | break; | ||
808 | |||
763 | case BUTTON_PLAY: | 809 | case BUTTON_PLAY: |
764 | case BUTTON_ON | BUTTON_PLAY: { | 810 | case BUTTON_ON | BUTTON_PLAY: { |
765 | if (playing) | 811 | if (playing) |
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 { | |||
39 | unsigned int first_frame_offset; /* Byte offset to first real MP3 frame. | 39 | unsigned int first_frame_offset; /* Byte offset to first real MP3 frame. |
40 | Used for skipping leading garbage to | 40 | Used for skipping leading garbage to |
41 | avoid gaps between tracks. */ | 41 | avoid gaps between tracks. */ |
42 | unsigned int xing_header_pos; | 42 | unsigned int vbr_header_pos; |
43 | unsigned int filesize; /* in bytes */ | 43 | unsigned int filesize; /* in bytes */ |
44 | unsigned int length; /* song length */ | 44 | unsigned int length; /* song length */ |
45 | unsigned int elapsed; /* ms played */ | 45 | 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 { | |||
46 | int frame_count; /* Number of frames in the file (if VBR) */ | 46 | int frame_count; /* Number of frames in the file (if VBR) */ |
47 | int byte_count; /* File size in bytes */ | 47 | int byte_count; /* File size in bytes */ |
48 | int file_time; /* Length of the whole file in milliseconds */ | 48 | int file_time; /* Length of the whole file in milliseconds */ |
49 | int xing_header_pos; | 49 | int vbr_header_pos; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | /* Xing header information */ | 52 | /* Xing header information */ |
@@ -61,6 +61,6 @@ int count_mp3_frames(int fd, int startpos, int filesize, | |||
61 | void (*progressfunc)(int)); | 61 | void (*progressfunc)(int)); |
62 | int create_xing_header(int fd, int startpos, int filesize, | 62 | int create_xing_header(int fd, int startpos, int filesize, |
63 | unsigned char *buf, int num_frames, | 63 | unsigned char *buf, int num_frames, |
64 | void (*progressfunc)(int)); | 64 | void (*progressfunc)(int), bool generate_toc); |
65 | 65 | ||
66 | #endif | 66 | #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[]; | |||
263 | static int fnf_read_index; | 263 | static int fnf_read_index; |
264 | static int fnf_buf_len; | 264 | static int fnf_buf_len; |
265 | 265 | ||
266 | static int fd; | 266 | static int buf_getbyte(int fd, unsigned char *c) |
267 | |||
268 | static int buf_getbyte(unsigned char *c) | ||
269 | { | 267 | { |
270 | if(fnf_read_index < fnf_buf_len) | 268 | if(fnf_read_index < fnf_buf_len) |
271 | { | 269 | { |
@@ -291,7 +289,7 @@ static int buf_getbyte(unsigned char *c) | |||
291 | return 0; | 289 | return 0; |
292 | } | 290 | } |
293 | 291 | ||
294 | static int buf_seek(int len) | 292 | static int buf_seek(int fd, int len) |
295 | { | 293 | { |
296 | fnf_read_index += len; | 294 | fnf_read_index += len; |
297 | if(fnf_read_index > fnf_buf_len) | 295 | if(fnf_read_index > fnf_buf_len) |
@@ -320,7 +318,7 @@ static void buf_init(void) | |||
320 | fnf_read_index = 0; | 318 | fnf_read_index = 0; |
321 | } | 319 | } |
322 | 320 | ||
323 | unsigned long buf_find_next_frame(int *offset, int max_offset, | 321 | unsigned long buf_find_next_frame(int fd, int *offset, int max_offset, |
324 | unsigned long last_header) | 322 | unsigned long last_header) |
325 | { | 323 | { |
326 | unsigned long header=0; | 324 | unsigned long header=0; |
@@ -336,7 +334,7 @@ unsigned long buf_find_next_frame(int *offset, int max_offset, | |||
336 | /* Fill up header with first 24 bits */ | 334 | /* Fill up header with first 24 bits */ |
337 | for(i = 0; i < 3; i++) { | 335 | for(i = 0; i < 3; i++) { |
338 | header <<= 8; | 336 | header <<= 8; |
339 | if(!buf_getbyte(&tmp)) | 337 | if(!buf_getbyte(fd, &tmp)) |
340 | return 0; | 338 | return 0; |
341 | header |= tmp; | 339 | header |= tmp; |
342 | pos++; | 340 | pos++; |
@@ -344,7 +342,7 @@ unsigned long buf_find_next_frame(int *offset, int max_offset, | |||
344 | 342 | ||
345 | do { | 343 | do { |
346 | header <<= 8; | 344 | header <<= 8; |
347 | if(!buf_getbyte(&tmp)) | 345 | if(!buf_getbyte(fd, &tmp)) |
348 | return 0; | 346 | return 0; |
349 | header |= tmp; | 347 | header |= tmp; |
350 | pos++; | 348 | pos++; |
@@ -413,7 +411,7 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
413 | DEBUGF("Xing header\n"); | 411 | DEBUGF("Xing header\n"); |
414 | 412 | ||
415 | /* Remember where in the file the Xing header is */ | 413 | /* Remember where in the file the Xing header is */ |
416 | info->xing_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size; | 414 | info->vbr_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size; |
417 | 415 | ||
418 | /* We want to skip the Xing frame when playing the stream */ | 416 | /* We want to skip the Xing frame when playing the stream */ |
419 | bytecount += info->frame_size; | 417 | bytecount += info->frame_size; |
@@ -423,7 +421,7 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
423 | header = find_next_frame(fd, &tmp, 0x20000, 0); | 421 | header = find_next_frame(fd, &tmp, 0x20000, 0); |
424 | if(header == 0) | 422 | if(header == 0) |
425 | return -4; | 423 | return -4; |
426 | 424 | ||
427 | if(!mp3headerinfo(info, header)) | 425 | if(!mp3headerinfo(info, header)) |
428 | return -5; | 426 | return -5; |
429 | 427 | ||
@@ -443,10 +441,14 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
443 | { | 441 | { |
444 | info->byte_count = BYTES2INT(vbrheader[i], vbrheader[i+1], | 442 | info->byte_count = BYTES2INT(vbrheader[i], vbrheader[i+1], |
445 | vbrheader[i+2], vbrheader[i+3]); | 443 | vbrheader[i+2], vbrheader[i+3]); |
446 | info->bitrate = info->byte_count * 8 / info->file_time; | ||
447 | i += 4; | 444 | i += 4; |
448 | } | 445 | } |
449 | 446 | ||
447 | if(info->file_time && info->byte_count) | ||
448 | info->bitrate = info->byte_count * 8 / info->file_time; | ||
449 | else | ||
450 | info->bitrate = 0; | ||
451 | |||
450 | if(vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */ | 452 | if(vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */ |
451 | { | 453 | { |
452 | memcpy( info->toc, vbrheader+i, 100 ); | 454 | memcpy( info->toc, vbrheader+i, 100 ); |
@@ -554,6 +556,8 @@ int count_mp3_frames(int fd, int startpos, int filesize, | |||
554 | int progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */ | 556 | int progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */ |
555 | int progress_cnt = 0; | 557 | int progress_cnt = 0; |
556 | 558 | ||
559 | /* Nasty stuff to avoid passing the file handle around */ | ||
560 | |||
557 | if(lseek(fd, startpos, SEEK_SET) < 0) | 561 | if(lseek(fd, startpos, SEEK_SET) < 0) |
558 | return -1; | 562 | return -1; |
559 | 563 | ||
@@ -563,9 +567,9 @@ int count_mp3_frames(int fd, int startpos, int filesize, | |||
563 | num_frames = 0; | 567 | num_frames = 0; |
564 | cnt = 0; | 568 | cnt = 0; |
565 | 569 | ||
566 | while((header = buf_find_next_frame(&bytes, -1, header))) { | 570 | while((header = buf_find_next_frame(fd, &bytes, -1, header))) { |
567 | mp3headerinfo(&info, header); | 571 | mp3headerinfo(&info, header); |
568 | buf_seek(info.frame_size-4); | 572 | buf_seek(fd, info.frame_size-4); |
569 | num_frames++; | 573 | num_frames++; |
570 | if(progressfunc) | 574 | if(progressfunc) |
571 | { | 575 | { |
@@ -585,7 +589,7 @@ int count_mp3_frames(int fd, int startpos, int filesize, | |||
585 | 589 | ||
586 | int create_xing_header(int fd, int startpos, int filesize, | 590 | int create_xing_header(int fd, int startpos, int filesize, |
587 | unsigned char *buf, int num_frames, | 591 | unsigned char *buf, int num_frames, |
588 | void (*progressfunc)(int)) | 592 | void (*progressfunc)(int), bool generate_toc) |
589 | { | 593 | { |
590 | unsigned long header = 0; | 594 | unsigned long header = 0; |
591 | struct mp3info info; | 595 | struct mp3info info; |
@@ -595,6 +599,7 @@ int create_xing_header(int fd, int startpos, int filesize, | |||
595 | int filepos; | 599 | int filepos; |
596 | int tocentry; | 600 | int tocentry; |
597 | int x; | 601 | int x; |
602 | int index; | ||
598 | 603 | ||
599 | DEBUGF("create_xing_header()\n"); | 604 | DEBUGF("create_xing_header()\n"); |
600 | 605 | ||
@@ -609,46 +614,61 @@ int create_xing_header(int fd, int startpos, int filesize, | |||
609 | buf[36+1] = 'i'; | 614 | buf[36+1] = 'i'; |
610 | buf[36+2] = 'n'; | 615 | buf[36+2] = 'n'; |
611 | buf[36+3] = 'g'; | 616 | buf[36+3] = 'g'; |
612 | int2bytes(&buf[36+4], (VBR_FRAMES_FLAG | VBR_BYTES_FLAG | VBR_TOC_FLAG)); | 617 | int2bytes(&buf[36+4], (num_frames?VBR_FRAMES_FLAG:0 | |
613 | int2bytes(&buf[36+8], num_frames); | 618 | filesize?VBR_BYTES_FLAG:0 | |
614 | int2bytes(&buf[36+12], filesize - startpos); | 619 | generate_toc?VBR_TOC_FLAG:0)); |
615 | 620 | index = 36+8; | |
616 | /* Generate filepos table */ | 621 | if(num_frames) |
617 | last_pos = 0; | 622 | { |
618 | filepos = 0; | 623 | int2bytes(&buf[index], num_frames); |
619 | header = 0; | 624 | index += 4; |
620 | x = 0; | 625 | } |
621 | for(i = 0;i < 100;i++) { | ||
622 | /* Calculate the absolute frame number for this seek point */ | ||
623 | pos = i * num_frames / 100; | ||
624 | |||
625 | /* Advance from the last seek point to this one */ | ||
626 | for(j = 0;j < pos - last_pos;j++) | ||
627 | { | ||
628 | DEBUGF("fpos: %x frame no: %x ", filepos, x++); | ||
629 | header = buf_find_next_frame(&bytes, -1, header); | ||
630 | mp3headerinfo(&info, header); | ||
631 | buf_seek(info.frame_size-4); | ||
632 | filepos += info.frame_size; | ||
633 | } | ||
634 | 626 | ||
635 | if(progressfunc) | 627 | if(filesize) |
636 | { | 628 | { |
637 | progressfunc(50 + i/2); | 629 | int2bytes(&buf[index], filesize - startpos); |
638 | } | 630 | index += 4; |
639 | 631 | } | |
640 | tocentry = filepos * 256 / filesize; | ||
641 | |||
642 | DEBUGF("Pos %d: %d relpos: %d filepos: %x tocentry: %x\n", | ||
643 | i, pos, pos-last_pos, filepos, tocentry); | ||
644 | 632 | ||
645 | /* Fill in the TOC entry */ | 633 | if(generate_toc) |
646 | buf[36+16+i] = tocentry; | 634 | { |
647 | 635 | /* Generate filepos table */ | |
648 | last_pos = pos; | 636 | last_pos = 0; |
637 | filepos = 0; | ||
638 | header = 0; | ||
639 | x = 0; | ||
640 | for(i = 0;i < 100;i++) { | ||
641 | /* Calculate the absolute frame number for this seek point */ | ||
642 | pos = i * num_frames / 100; | ||
643 | |||
644 | /* Advance from the last seek point to this one */ | ||
645 | for(j = 0;j < pos - last_pos;j++) | ||
646 | { | ||
647 | DEBUGF("fpos: %x frame no: %x ", filepos, x++); | ||
648 | header = buf_find_next_frame(fd, &bytes, -1, header); | ||
649 | mp3headerinfo(&info, header); | ||
650 | buf_seek(fd, info.frame_size-4); | ||
651 | filepos += info.frame_size; | ||
652 | } | ||
653 | |||
654 | if(progressfunc) | ||
655 | { | ||
656 | progressfunc(50 + i/2); | ||
657 | } | ||
658 | |||
659 | tocentry = filepos * 256 / filesize; | ||
660 | |||
661 | DEBUGF("Pos %d: %d relpos: %d filepos: %x tocentry: %x\n", | ||
662 | i, pos, pos-last_pos, filepos, tocentry); | ||
663 | |||
664 | /* Fill in the TOC entry */ | ||
665 | buf[index + i] = tocentry; | ||
666 | |||
667 | last_pos = pos; | ||
668 | } | ||
649 | } | 669 | } |
650 | 670 | ||
651 | memcpy(buf+152, cooltext, sizeof(cooltext)); | 671 | memcpy(buf + index + 100, cooltext, sizeof(cooltext)); |
652 | 672 | ||
653 | #ifdef DEBUG | 673 | #ifdef DEBUG |
654 | for(i = 0;i < 417;i++) | 674 | 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) | |||
353 | } | 353 | } |
354 | 354 | ||
355 | static bool paused; /* playback is paused */ | 355 | static bool paused; /* playback is paused */ |
356 | |||
357 | static unsigned char xingbuf[417]; | ||
358 | |||
356 | #ifdef SIMULATOR | 359 | #ifdef SIMULATOR |
357 | static bool is_playing = false; | 360 | static bool is_playing = false; |
358 | static bool playing = false; | 361 | static bool playing = false; |
@@ -500,9 +503,16 @@ static bool mpeg_stop_done; | |||
500 | 503 | ||
501 | static void recalculate_watermark(int bitrate) | 504 | static void recalculate_watermark(int bitrate) |
502 | { | 505 | { |
503 | int bytes_per_sec = bitrate * 1000 / 8; | 506 | int bytes_per_sec; |
504 | int time = ata_spinup_time; | 507 | int time = ata_spinup_time; |
505 | 508 | ||
509 | /* A bitrate of 0 probably means empty VBR header. We play safe | ||
510 | and set a high threshold */ | ||
511 | if(bitrate == 0) | ||
512 | bitrate = 320000; | ||
513 | |||
514 | bytes_per_sec = bitrate * 1000 / 8; | ||
515 | |||
506 | if(time) | 516 | if(time) |
507 | { | 517 | { |
508 | /* No drive spins up faster than 3.5s */ | 518 | /* No drive spins up faster than 3.5s */ |
@@ -1857,6 +1867,18 @@ static void mpeg_thread(void) | |||
1857 | 1867 | ||
1858 | if(mpeg_file >= 0) | 1868 | if(mpeg_file >= 0) |
1859 | close(mpeg_file); | 1869 | close(mpeg_file); |
1870 | |||
1871 | mpeg_file = open(recording_filename, O_RDWR); | ||
1872 | if(mpeg_file < 0) | ||
1873 | panicf("rec upd: %d", mpeg_file); | ||
1874 | |||
1875 | create_xing_header(mpeg_file, 0, mpeg_num_recorded_bytes(), | ||
1876 | xingbuf, 0, NULL, false); | ||
1877 | |||
1878 | lseek(mpeg_file, 4096, SEEK_SET); | ||
1879 | write(mpeg_file, xingbuf, 417); | ||
1880 | close(mpeg_file); | ||
1881 | |||
1860 | mpeg_file = -1; | 1882 | mpeg_file = -1; |
1861 | 1883 | ||
1862 | #ifdef DEBUG1 | 1884 | #ifdef DEBUG1 |
@@ -2982,7 +3004,6 @@ int d_2; | |||
2982 | int mpeg_create_xing_header(char *filename, void (*progressfunc)(int)) | 3004 | int mpeg_create_xing_header(char *filename, void (*progressfunc)(int)) |
2983 | { | 3005 | { |
2984 | struct mp3entry entry; | 3006 | struct mp3entry entry; |
2985 | char xingbuf[417]; | ||
2986 | int fd; | 3007 | int fd; |
2987 | int rc; | 3008 | int rc; |
2988 | int flen; | 3009 | int flen; |
@@ -3013,15 +3034,17 @@ int mpeg_create_xing_header(char *filename, void (*progressfunc)(int)) | |||
3013 | progressfunc); | 3034 | progressfunc); |
3014 | 3035 | ||
3015 | create_xing_header(fd, entry.first_frame_offset, | 3036 | create_xing_header(fd, entry.first_frame_offset, |
3016 | flen, xingbuf, num_frames, progressfunc); | 3037 | flen, xingbuf, num_frames, progressfunc, true); |
3017 | 3038 | ||
3018 | /* Try to fit the Xing header first in the stream. Replace the existing | 3039 | /* Try to fit the Xing header first in the stream. Replace the existing |
3019 | Xing header if there is one, else see if there is room between the | 3040 | Xing header if there is one, else see if there is room between the |
3020 | ID3 tag and the first MP3 frame. */ | 3041 | ID3 tag and the first MP3 frame. */ |
3021 | if(entry.xing_header_pos) | 3042 | if(entry.vbr_header_pos) |
3022 | { | 3043 | { |
3023 | /* Reuse existing Xing header */ | 3044 | /* Reuse existing Xing header */ |
3024 | fpos = entry.xing_header_pos; | 3045 | fpos = entry.vbr_header_pos; |
3046 | |||
3047 | DEBUGF("Reusing Xing header at %d\n", fpos); | ||
3025 | } | 3048 | } |
3026 | else | 3049 | else |
3027 | { | 3050 | { |