summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nielsen Feltzing <linus@haxx.se>2003-03-10 18:05:01 +0000
committerLinus Nielsen Feltzing <linus@haxx.se>2003-03-10 18:05:01 +0000
commit6475aa0c85fcca7a37a7aa4316173270fcb6d038 (patch)
treee6dbe18217113212a9b8e713d3325c5803b3f4a6
parent673937d65402b058b5b5bfa5a1bf990c2d218dba (diff)
downloadrockbox-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.c46
-rw-r--r--firmware/export/id3.h2
-rw-r--r--firmware/export/mp3data.h4
-rw-r--r--firmware/mp3data.c118
-rw-r--r--firmware/mpeg.c33
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
656extern int d_1;
657extern int d_2;
658
659void 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
672void 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
656static int onplay_screen(char* dir, char* file) 690static 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));
62int create_xing_header(int fd, int startpos, int filesize, 62int 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[];
263static int fnf_read_index; 263static int fnf_read_index;
264static int fnf_buf_len; 264static int fnf_buf_len;
265 265
266static int fd; 266static int buf_getbyte(int fd, unsigned char *c)
267
268static 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
294static int buf_seek(int len) 292static 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
323unsigned long buf_find_next_frame(int *offset, int max_offset, 321unsigned 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
586int create_xing_header(int fd, int startpos, int filesize, 590int 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
355static bool paused; /* playback is paused */ 355static bool paused; /* playback is paused */
356
357static unsigned char xingbuf[417];
358
356#ifdef SIMULATOR 359#ifdef SIMULATOR
357static bool is_playing = false; 360static bool is_playing = false;
358static bool playing = false; 361static bool playing = false;
@@ -500,9 +503,16 @@ static bool mpeg_stop_done;
500 503
501static void recalculate_watermark(int bitrate) 504static 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;
2982int mpeg_create_xing_header(char *filename, void (*progressfunc)(int)) 3004int 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 {