diff options
-rw-r--r-- | apps/onplay.c | 130 | ||||
-rw-r--r-- | firmware/export/mp3data.h | 1 | ||||
-rw-r--r-- | firmware/mp3data.c | 41 | ||||
-rw-r--r-- | firmware/mpeg.c | 43 |
4 files changed, 118 insertions, 97 deletions
diff --git a/apps/onplay.c b/apps/onplay.c index ceaae2c238..3ba4c1b49c 100644 --- a/apps/onplay.c +++ b/apps/onplay.c | |||
@@ -210,14 +210,15 @@ static const unsigned char empty_id3_header[] = | |||
210 | 210 | ||
211 | static bool vbr_fix(void) | 211 | static bool vbr_fix(void) |
212 | { | 212 | { |
213 | unsigned char xingbuf[417]; | 213 | unsigned char xingbuf[1500]; |
214 | struct mp3entry entry; | 214 | struct mp3entry entry; |
215 | int fd; | 215 | int fd; |
216 | int rc; | 216 | int rc; |
217 | int flen; | 217 | int flen; |
218 | int num_frames; | 218 | int num_frames; |
219 | int fpos; | ||
220 | int numbytes; | 219 | int numbytes; |
220 | int framelen; | ||
221 | int unused_space; | ||
221 | 222 | ||
222 | if(mpeg_status()) { | 223 | if(mpeg_status()) { |
223 | splash(HZ*2, 0, true, str(LANG_VBRFIX_STOP_PLAY)); | 224 | splash(HZ*2, 0, true, str(LANG_VBRFIX_STOP_PLAY)); |
@@ -250,26 +251,45 @@ static bool vbr_fix(void) | |||
250 | flen, xingupdate); | 251 | flen, xingupdate); |
251 | 252 | ||
252 | if(num_frames) { | 253 | if(num_frames) { |
253 | create_xing_header(fd, entry.first_frame_offset, | 254 | /* Note: We don't need to pass any values for mpeg_version and |
254 | flen, xingbuf, num_frames, xingupdate, true); | 255 | sample_rate because they will be extracted from the mpeg stream */ |
256 | framelen = create_xing_header(fd, entry.first_frame_offset, | ||
257 | flen, xingbuf, num_frames, | ||
258 | 0, 0, xingupdate, true); | ||
255 | 259 | ||
256 | /* Try to fit the Xing header first in the stream. Replace the existing | 260 | /* Try to fit the Xing header first in the stream. Replace the existing |
257 | Xing header if there is one, else see if there is room between the | 261 | VBR header if there is one, else see if there is room between the |
258 | ID3 tag and the first MP3 frame. */ | 262 | ID3 tag and the first MP3 frame. */ |
259 | if(entry.vbr_header_pos) { | 263 | if(entry.first_frame_offset - entry.id3v2len >= |
260 | /* Reuse existing Xing header */ | 264 | (unsigned int)framelen) { |
261 | fpos = entry.vbr_header_pos; | 265 | DEBUGF("Using existing space between ID3 and first frame\n"); |
262 | 266 | ||
263 | DEBUGF("Reusing Xing header at %d\n", fpos); | 267 | /* Seek to the beginning of the unused space */ |
264 | 268 | rc = lseek(fd, entry.id3v2len, SEEK_SET); | |
265 | rc = lseek(fd, entry.vbr_header_pos, SEEK_SET); | ||
266 | if(rc < 0) { | 269 | if(rc < 0) { |
267 | close(fd); | 270 | close(fd); |
268 | fileerror(rc); | 271 | fileerror(rc); |
269 | return true; | 272 | return true; |
270 | } | 273 | } |
274 | |||
275 | unused_space = | ||
276 | entry.first_frame_offset - entry.id3v2len - framelen; | ||
271 | 277 | ||
272 | rc = write(fd, xingbuf, 417); | 278 | /* Fill the unused space with 0's (using the MP3 buffer) |
279 | and write it to the file */ | ||
280 | if(unused_space) | ||
281 | { | ||
282 | memset(mp3buf, 0, unused_space); | ||
283 | rc = write(fd, mp3buf, unused_space); | ||
284 | if(rc < 0) { | ||
285 | close(fd); | ||
286 | fileerror(rc); | ||
287 | return true; | ||
288 | } | ||
289 | } | ||
290 | |||
291 | /* Then write the Xing header */ | ||
292 | rc = write(fd, xingbuf, framelen); | ||
273 | if(rc < 0) { | 293 | if(rc < 0) { |
274 | close(fd); | 294 | close(fd); |
275 | fileerror(rc); | 295 | fileerror(rc); |
@@ -278,61 +298,41 @@ static bool vbr_fix(void) | |||
278 | 298 | ||
279 | close(fd); | 299 | close(fd); |
280 | } else { | 300 | } else { |
281 | /* Any room between ID3 tag and first MP3 frame? */ | 301 | /* If not, insert some space. If there is an ID3 tag in the |
282 | if(entry.first_frame_offset - entry.id3v2len > 417) { | 302 | file we only insert just enough to squeeze the Xing header |
283 | DEBUGF("Using existing space between ID3 and first frame\n"); | 303 | in. If not, we insert an additional empty ID3 tag of 4K. */ |
284 | rc = lseek(fd, entry.first_frame_offset - 417, SEEK_SET); | 304 | |
285 | if(rc < 0) { | 305 | close(fd); |
286 | close(fd); | 306 | |
287 | fileerror(rc); | 307 | /* Nasty trick alert! The insert_data_in_file() function |
288 | return true; | 308 | uses the MP3 buffer when copying the data. We assume |
289 | } | 309 | that the ID3 tag isn't longer than 1MB so the xing |
290 | 310 | buffer won't be overwritten. */ | |
291 | rc = write(fd, xingbuf, 417); | 311 | |
292 | if(rc < 0) { | 312 | if(entry.first_frame_offset) { |
293 | close(fd); | 313 | DEBUGF("Inserting %d bytes\n", framelen); |
294 | fileerror(rc); | 314 | numbytes = framelen; |
295 | return true; | ||
296 | } | ||
297 | |||
298 | close(fd); | ||
299 | } else { | 315 | } else { |
300 | /* If not, insert some space. If there is an ID3 tag in the | 316 | DEBUGF("Inserting 4096+%d bytes\n", framelen); |
301 | file we only insert just enough to squeeze the Xing header | 317 | numbytes = 4096 + framelen; |
302 | in. If not, we insert an additional empty ID3 tag of 4K. */ | ||
303 | |||
304 | close(fd); | ||
305 | |||
306 | /* Nasty trick alert! The insert_data_in_file() function | ||
307 | uses the MP3 buffer when copying the data. We assume | ||
308 | that the ID3 tag isn't longer than 1MB so the xing | ||
309 | buffer won't be overwritten. */ | ||
310 | |||
311 | if(entry.first_frame_offset) { | ||
312 | DEBUGF("Inserting 417 bytes\n"); | ||
313 | numbytes = 417; | ||
314 | } else { | ||
315 | DEBUGF("Inserting 4096+417 bytes\n"); | ||
316 | numbytes = 4096 + 417; | ||
317 | |||
318 | memset(mp3buf + 0x100000, 0, numbytes); | ||
319 | |||
320 | /* Insert the ID3 header */ | ||
321 | memcpy(mp3buf + 0x100000, empty_id3_header, | ||
322 | sizeof(empty_id3_header)); | ||
323 | } | ||
324 | |||
325 | /* Copy the Xing header */ | ||
326 | memcpy(mp3buf + 0x100000 + numbytes - 417, xingbuf, 417); | ||
327 | 318 | ||
328 | rc = insert_data_in_file(selected_file, | 319 | memset(mp3buf + 0x100000, 0, numbytes); |
329 | entry.first_frame_offset, | ||
330 | mp3buf + 0x100000, numbytes); | ||
331 | 320 | ||
332 | if(rc < 0) { | 321 | /* Insert the ID3 header */ |
333 | fileerror(rc); | 322 | memcpy(mp3buf + 0x100000, empty_id3_header, |
334 | return true; | 323 | sizeof(empty_id3_header)); |
335 | } | 324 | } |
325 | |||
326 | /* Copy the Xing header */ | ||
327 | memcpy(mp3buf + 0x100000 + numbytes - framelen, xingbuf, framelen); | ||
328 | |||
329 | rc = insert_data_in_file(selected_file, | ||
330 | entry.first_frame_offset, | ||
331 | mp3buf + 0x100000, numbytes); | ||
332 | |||
333 | if(rc < 0) { | ||
334 | fileerror(rc); | ||
335 | return true; | ||
336 | } | 336 | } |
337 | } | 337 | } |
338 | 338 | ||
diff --git a/firmware/export/mp3data.h b/firmware/export/mp3data.h index 54a6899a78..d180935aa4 100644 --- a/firmware/export/mp3data.h +++ b/firmware/export/mp3data.h | |||
@@ -61,6 +61,7 @@ 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 | int mpeg_version, int sample_rate, | ||
64 | void (*progressfunc)(int), bool generate_toc); | 65 | void (*progressfunc)(int), bool generate_toc); |
65 | 66 | ||
66 | #endif | 67 | #endif |
diff --git a/firmware/mp3data.c b/firmware/mp3data.c index 28f2cb27f3..98dff50442 100644 --- a/firmware/mp3data.c +++ b/firmware/mp3data.c | |||
@@ -35,7 +35,7 @@ | |||
35 | #include "mp3data.h" | 35 | #include "mp3data.h" |
36 | #include "file.h" | 36 | #include "file.h" |
37 | 37 | ||
38 | #undef DEBUG_VERBOSE | 38 | #define DEBUG_VERBOSE |
39 | 39 | ||
40 | #define BYTES2INT(b1,b2,b3,b4) (((b1 & 0xFF) << (3*8)) | \ | 40 | #define BYTES2INT(b1,b2,b3,b4) (((b1 & 0xFF) << (3*8)) | \ |
41 | ((b2 & 0xFF) << (2*8)) | \ | 41 | ((b2 & 0xFF) << (2*8)) | \ |
@@ -530,9 +530,10 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
530 | return bytecount; | 530 | return bytecount; |
531 | } | 531 | } |
532 | 532 | ||
533 | /* This is an MP3 header, 128kbit/s, 44.1kHz, with silence */ | 533 | /* This is an MP3 header, 128kbit/s, with silence |
534 | MPEG version and sample frequency are not set */ | ||
534 | static const unsigned char xing_frame_header[] = { | 535 | static const unsigned char xing_frame_header[] = { |
535 | 0xff, 0xfa, 0x90, 0x64, 0x86, 0x1f | 536 | 0xff, 0xe2, 0x90, 0x64, 0x86, 0x1f |
536 | }; | 537 | }; |
537 | 538 | ||
538 | static const char cooltext[] = "Rockbox rocks"; | 539 | static const char cooltext[] = "Rockbox rocks"; |
@@ -601,11 +602,15 @@ int count_mp3_frames(int fd, int startpos, int filesize, | |||
601 | } | 602 | } |
602 | } | 603 | } |
603 | 604 | ||
605 | /* Note: mpeg_version and sample_rate are 2-bit values, as specified by the | ||
606 | MPEG frame standard. See the tables above. */ | ||
604 | int create_xing_header(int fd, int startpos, int filesize, | 607 | int create_xing_header(int fd, int startpos, int filesize, |
605 | unsigned char *buf, int num_frames, | 608 | unsigned char *buf, int num_frames, |
609 | int mpeg_version, int sample_rate, | ||
606 | void (*progressfunc)(int), bool generate_toc) | 610 | void (*progressfunc)(int), bool generate_toc) |
607 | { | 611 | { |
608 | unsigned long header = 0; | 612 | unsigned long header = 0; |
613 | unsigned long saved_header; | ||
609 | struct mp3info info; | 614 | struct mp3info info; |
610 | int pos, last_pos; | 615 | int pos, last_pos; |
611 | int i, j; | 616 | int i, j; |
@@ -618,9 +623,9 @@ int create_xing_header(int fd, int startpos, int filesize, | |||
618 | DEBUGF("create_xing_header()\n"); | 623 | DEBUGF("create_xing_header()\n"); |
619 | 624 | ||
620 | /* Create the frame header */ | 625 | /* Create the frame header */ |
621 | memset(buf, 0, 417); | 626 | memset(buf, 0, 1500); |
622 | memcpy(buf, xing_frame_header, 6); | 627 | memcpy(buf, xing_frame_header, 6); |
623 | 628 | ||
624 | lseek(fd, startpos, SEEK_SET); | 629 | lseek(fd, startpos, SEEK_SET); |
625 | buf_init(); | 630 | buf_init(); |
626 | 631 | ||
@@ -664,6 +669,10 @@ int create_xing_header(int fd, int startpos, int filesize, | |||
664 | buf_seek(fd, info.frame_size-4); | 669 | buf_seek(fd, info.frame_size-4); |
665 | filepos += info.frame_size; | 670 | filepos += info.frame_size; |
666 | } | 671 | } |
672 | |||
673 | /* Save one header for later use */ | ||
674 | if(i == 1) | ||
675 | saved_header = header; | ||
667 | 676 | ||
668 | if(progressfunc) | 677 | if(progressfunc) |
669 | { | 678 | { |
@@ -684,6 +693,26 @@ int create_xing_header(int fd, int startpos, int filesize, | |||
684 | 693 | ||
685 | memcpy(buf + index + 100, cooltext, sizeof(cooltext)); | 694 | memcpy(buf + index + 100, cooltext, sizeof(cooltext)); |
686 | 695 | ||
696 | /* We must fill in the correct sample rate and mpeg version. If the TOC | ||
697 | should be generated, we take that data from the actual stream. If not, | ||
698 | we use the supplied parameters. */ | ||
699 | if(generate_toc) | ||
700 | { | ||
701 | saved_header &= (VERSION_MASK | SAMPLERATE_MASK); | ||
702 | |||
703 | buf[1] |= (saved_header >> 16) & 0xff; | ||
704 | buf[2] |= (saved_header >> 8) & 0xff; | ||
705 | } | ||
706 | else | ||
707 | { | ||
708 | buf[1] |= mpeg_version << 3; | ||
709 | buf[2] |= sample_rate << 2; | ||
710 | } | ||
711 | |||
712 | /* Now get the length of the newly created frame */ | ||
713 | header = BYTES2INT(buf[0], buf[1], buf[2], buf[3]); | ||
714 | mp3headerinfo(&info, header); | ||
715 | |||
687 | #ifdef DEBUG | 716 | #ifdef DEBUG |
688 | for(i = 0;i < 417;i++) | 717 | for(i = 0;i < 417;i++) |
689 | { | 718 | { |
@@ -694,5 +723,5 @@ int create_xing_header(int fd, int startpos, int filesize, | |||
694 | } | 723 | } |
695 | #endif | 724 | #endif |
696 | 725 | ||
697 | return 0; | 726 | return info.frame_size; |
698 | } | 727 | } |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 85f9c72a25..7e48040da2 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -489,7 +489,8 @@ unsigned long record_start_time; /* Value of current_tick when recording | |||
489 | was started */ | 489 | was started */ |
490 | static bool saving; /* We are saving the buffer to disk */ | 490 | static bool saving; /* We are saving the buffer to disk */ |
491 | static char recording_filename[MAX_PATH]; | 491 | static char recording_filename[MAX_PATH]; |
492 | 492 | static int rec_frequency_index; /* For create_xing_header() calls */ | |
493 | static int rec_version_index; /* For create_xing_header() calls */ | ||
493 | #endif | 494 | #endif |
494 | 495 | ||
495 | static int mpeg_file; | 496 | static int mpeg_file; |
@@ -1010,13 +1011,6 @@ void IRQ3(void) | |||
1010 | dma_tick(); | 1011 | dma_tick(); |
1011 | else | 1012 | else |
1012 | postpone_dma_tick(); | 1013 | postpone_dma_tick(); |
1013 | |||
1014 | #if 0 | ||
1015 | if(mpeg_mode == MPEG_ENCODER) | ||
1016 | /* Shut off if recording is stopped */ | ||
1017 | if(!is_recording) | ||
1018 | demand_irq_enable(false); | ||
1019 | #endif | ||
1020 | } | 1014 | } |
1021 | #endif | 1015 | #endif |
1022 | 1016 | ||
@@ -1271,6 +1265,7 @@ static void mpeg_thread(void) | |||
1271 | #ifdef HAVE_MAS3587F | 1265 | #ifdef HAVE_MAS3587F |
1272 | int amount_to_save; | 1266 | int amount_to_save; |
1273 | int writelen; | 1267 | int writelen; |
1268 | int framelen; | ||
1274 | #endif | 1269 | #endif |
1275 | 1270 | ||
1276 | is_playing = false; | 1271 | is_playing = false; |
@@ -1734,15 +1729,6 @@ static void mpeg_thread(void) | |||
1734 | DEBUGF("R\n"); | 1729 | DEBUGF("R\n"); |
1735 | t1 = current_tick; | 1730 | t1 = current_tick; |
1736 | len = read(mpeg_file, mp3buf+mp3buf_write, amount_to_read); | 1731 | len = read(mpeg_file, mp3buf+mp3buf_write, amount_to_read); |
1737 | #if 0 | ||
1738 | if(id3tags[tag_read_idx]->id3.vbr) | ||
1739 | /* Average bitrate * 1.5 */ | ||
1740 | recalculate_watermark( | ||
1741 | (id3tags[tag_read_idx]->id3.bitrate * 3) / 2); | ||
1742 | else | ||
1743 | recalculate_watermark( | ||
1744 | id3tags[tag_read_idx]->id3.bitrate); | ||
1745 | #endif | ||
1746 | if(len > 0) | 1732 | if(len > 0) |
1747 | { | 1733 | { |
1748 | t2 = current_tick; | 1734 | t2 = current_tick; |
@@ -1854,10 +1840,10 @@ static void mpeg_thread(void) | |||
1854 | DEBUGF("Recording...\n"); | 1840 | DEBUGF("Recording...\n"); |
1855 | reset_mp3_buffer(); | 1841 | reset_mp3_buffer(); |
1856 | 1842 | ||
1857 | /* Advance the write pointer 4096+417 bytes to make | 1843 | /* Advance the write pointer 4096+1500 bytes to make |
1858 | room for an ID3 tag plus a VBR header */ | 1844 | room for an ID3 tag plus a VBR header */ |
1859 | mp3buf_write = 4096+417; | 1845 | mp3buf_write = 4096+1500; |
1860 | memset(mp3buf, 0, 4096+417); | 1846 | memset(mp3buf, 0, 4096+1500); |
1861 | 1847 | ||
1862 | /* Insert the ID3 header */ | 1848 | /* Insert the ID3 header */ |
1863 | memcpy(mp3buf, empty_id3_header, sizeof(empty_id3_header)); | 1849 | memcpy(mp3buf, empty_id3_header, sizeof(empty_id3_header)); |
@@ -1898,12 +1884,14 @@ static void mpeg_thread(void) | |||
1898 | if(num_recorded_frames == 0x7ffff) | 1884 | if(num_recorded_frames == 0x7ffff) |
1899 | num_recorded_frames = 0; | 1885 | num_recorded_frames = 0; |
1900 | 1886 | ||
1901 | create_xing_header(mpeg_file, 0, num_rec_bytes, | 1887 | framelen = create_xing_header(mpeg_file, 0, num_rec_bytes, |
1902 | mp3buf, num_recorded_frames, NULL, | 1888 | mp3buf, num_recorded_frames, |
1903 | false); | 1889 | rec_version_index, |
1890 | rec_frequency_index, | ||
1891 | NULL, false); | ||
1904 | 1892 | ||
1905 | lseek(mpeg_file, 4096, SEEK_SET); | 1893 | lseek(mpeg_file, 4096+1500-framelen, SEEK_SET); |
1906 | write(mpeg_file, mp3buf, 417); | 1894 | write(mpeg_file, mp3buf, framelen); |
1907 | close(mpeg_file); | 1895 | close(mpeg_file); |
1908 | 1896 | ||
1909 | mpeg_file = -1; | 1897 | mpeg_file = -1; |
@@ -2841,9 +2829,12 @@ void mpeg_set_recording_options(int frequency, int quality, | |||
2841 | unsigned long val; | 2829 | unsigned long val; |
2842 | 2830 | ||
2843 | is_mpeg1 = (frequency < 3)?true:false; | 2831 | is_mpeg1 = (frequency < 3)?true:false; |
2832 | |||
2833 | rec_version_index = is_mpeg1?3:2; | ||
2834 | rec_frequency_index = frequency % 3; | ||
2844 | 2835 | ||
2845 | val = (quality << 17) | | 2836 | val = (quality << 17) | |
2846 | ((frequency % 3) << 10) | | 2837 | (rec_frequency_index << 10) | |
2847 | ((is_mpeg1?1:0) << 9) | | 2838 | ((is_mpeg1?1:0) << 9) | |
2848 | (1 << 8) | /* CRC on */ | 2839 | (1 << 8) | /* CRC on */ |
2849 | (((channel_mode * 2 + 1) & 3) << 6) | | 2840 | (((channel_mode * 2 + 1) & 3) << 6) | |