diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/mp3data.h | 2 | ||||
-rw-r--r-- | firmware/export/mpeg.h | 2 | ||||
-rw-r--r-- | firmware/mp3data.c | 39 | ||||
-rw-r--r-- | firmware/mpeg.c | 312 |
4 files changed, 184 insertions, 171 deletions
diff --git a/firmware/export/mp3data.h b/firmware/export/mp3data.h index a7f2e3d7f0..db1a93b8d6 100644 --- a/firmware/export/mp3data.h +++ b/firmware/export/mp3data.h | |||
@@ -57,6 +57,8 @@ struct mp3info { | |||
57 | #define VBR_TOC_FLAG 0x04 | 57 | #define VBR_TOC_FLAG 0x04 |
58 | #define VBR_QUALITY_FLAG 0x08 | 58 | #define VBR_QUALITY_FLAG 0x08 |
59 | 59 | ||
60 | #define MAX_XING_HEADER_SIZE 288 | ||
61 | |||
60 | unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header); | 62 | unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header); |
61 | unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset, | 63 | unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset, |
62 | unsigned long last_header); | 64 | unsigned long last_header); |
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h index 6ce3b47275..a0ad3c405c 100644 --- a/firmware/export/mpeg.h +++ b/firmware/export/mpeg.h | |||
@@ -41,7 +41,7 @@ | |||
41 | #define MPEG_MAX_PRERECORD_SECONDS 30 | 41 | #define MPEG_MAX_PRERECORD_SECONDS 30 |
42 | 42 | ||
43 | /* For ID3 info and VBR header */ | 43 | /* For ID3 info and VBR header */ |
44 | #define MPEG_RESERVED_HEADER_SPACE (4096 + 1500) | 44 | #define MPEG_RESERVED_HEADER_SPACE (4096 + 288) |
45 | 45 | ||
46 | #if (CONFIG_CODEC == MAS3587F) || defined(SIMULATOR) | 46 | #if (CONFIG_CODEC == MAS3587F) || defined(SIMULATOR) |
47 | void mpeg_init_recording(void); | 47 | void mpeg_init_recording(void); |
diff --git a/firmware/mp3data.c b/firmware/mp3data.c index 44c298a463..6f4c560578 100644 --- a/firmware/mp3data.c +++ b/firmware/mp3data.c | |||
@@ -607,8 +607,8 @@ int count_mp3_frames(int fd, int startpos, int filesize, | |||
607 | static const char cooltext[] = "Rockbox - rocks your box"; | 607 | static const char cooltext[] = "Rockbox - rocks your box"; |
608 | 608 | ||
609 | int create_xing_header(int fd, int startpos, int filesize, | 609 | int create_xing_header(int fd, int startpos, int filesize, |
610 | unsigned char *buf, int num_frames, | 610 | unsigned char *buf, /* must be at least 288 bytes */ |
611 | unsigned long header_template, | 611 | int num_frames, unsigned long header_template, |
612 | void (*progressfunc)(int), bool generate_toc) | 612 | void (*progressfunc)(int), bool generate_toc) |
613 | { | 613 | { |
614 | unsigned long header = 0; | 614 | unsigned long header = 0; |
@@ -691,35 +691,40 @@ int create_xing_header(int fd, int startpos, int filesize, | |||
691 | last_pos = pos; | 691 | last_pos = pos; |
692 | } | 692 | } |
693 | } | 693 | } |
694 | 694 | ||
695 | /* Use the template header and create a new one. | 695 | /* Check the template header for validity and get some preliminary info. */ |
696 | We ignore the Protection bit even if the rest of the stream is | 696 | if (!mp3headerinfo(&info, xing_header_template)) |
697 | protected. (fixme?) */ | 697 | return 0; /* invalid header */ |
698 | header = xing_header_template & ~(BITRATE_MASK | PROTECTION_MASK); | ||
699 | header |= 8 << 12; /* This gives us plenty of space, at least 192 bytes */ | ||
700 | |||
701 | if (!mp3headerinfo(&info, header)) | ||
702 | return 0; /* invalid header */ | ||
703 | 698 | ||
704 | /* Clear the frame */ | 699 | /* Clear the frame */ |
705 | memset(buf, 0, 1500); | 700 | memset(buf, 0, MAX_XING_HEADER_SIZE); |
706 | 701 | ||
707 | /* Write the header to the buffer */ | 702 | /* Use the template header and create a new one. */ |
708 | long2bytes(buf, header); | 703 | header = xing_header_template & ~(BITRATE_MASK | PROTECTION_MASK); |
709 | 704 | ||
710 | /* calculate position of VBR header */ | 705 | /* Calculate position of VBR header and required frame bitrate */ |
711 | if ( info.version == MPEG_VERSION1 ) { | 706 | if (info.version == MPEG_VERSION1) { |
707 | header |= 5 << 12; | ||
712 | if (info.channel_mode == 3) /* mono */ | 708 | if (info.channel_mode == 3) /* mono */ |
713 | index = 21; | 709 | index = 21; |
714 | else | 710 | else |
715 | index = 36; | 711 | index = 36; |
716 | } | 712 | } |
717 | else { | 713 | else { |
714 | if (info.version == MPEG_VERSION2) | ||
715 | header |= 8 << 12; | ||
716 | else /* MPEG_VERSION2_5 */ | ||
717 | header |= 4 << 12; | ||
718 | if (info.channel_mode == 3) /* mono */ | 718 | if (info.channel_mode == 3) /* mono */ |
719 | index = 13; | 719 | index = 13; |
720 | else | 720 | else |
721 | index = 21; | 721 | index = 21; |
722 | } | 722 | } |
723 | mp3headerinfo(&info, header); /* Get final header info */ | ||
724 | /* Size is now always one of 192, 208 or 288 bytes */ | ||
725 | |||
726 | /* Write the header to the buffer */ | ||
727 | long2bytes(buf, header); | ||
723 | 728 | ||
724 | /* Create the Xing data */ | 729 | /* Create the Xing data */ |
725 | memcpy(&buf[index], "Xing", 4); | 730 | memcpy(&buf[index], "Xing", 4); |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index cd413d60fd..831463a671 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -65,24 +65,25 @@ extern int playlist_next(int steps); | |||
65 | extern int playlist_amount(void); | 65 | extern int playlist_amount(void); |
66 | extern int playlist_update_resume_info(const struct mp3entry* id3); | 66 | extern int playlist_update_resume_info(const struct mp3entry* id3); |
67 | 67 | ||
68 | #define MPEG_PLAY 1 | 68 | #define MPEG_PLAY 1 |
69 | #define MPEG_STOP 2 | 69 | #define MPEG_STOP 2 |
70 | #define MPEG_PAUSE 3 | 70 | #define MPEG_PAUSE 3 |
71 | #define MPEG_RESUME 4 | 71 | #define MPEG_RESUME 4 |
72 | #define MPEG_NEXT 5 | 72 | #define MPEG_NEXT 5 |
73 | #define MPEG_PREV 6 | 73 | #define MPEG_PREV 6 |
74 | #define MPEG_FF_REWIND 7 | 74 | #define MPEG_FF_REWIND 7 |
75 | #define MPEG_FLUSH_RELOAD 8 | 75 | #define MPEG_FLUSH_RELOAD 8 |
76 | #define MPEG_RECORD 9 | 76 | #define MPEG_RECORD 9 |
77 | #define MPEG_INIT_RECORDING 10 | 77 | #define MPEG_INIT_RECORDING 10 |
78 | #define MPEG_INIT_PLAYBACK 11 | 78 | #define MPEG_INIT_PLAYBACK 11 |
79 | #define MPEG_NEW_FILE 12 | 79 | #define MPEG_NEW_FILE 12 |
80 | #define MPEG_PAUSE_RECORDING 13 | 80 | #define MPEG_PAUSE_RECORDING 13 |
81 | #define MPEG_RESUME_RECORDING 14 | 81 | #define MPEG_RESUME_RECORDING 14 |
82 | #define MPEG_NEED_DATA 100 | 82 | #define MPEG_NEED_DATA 100 |
83 | #define MPEG_TRACK_CHANGE 101 | 83 | #define MPEG_TRACK_CHANGE 101 |
84 | #define MPEG_SAVE_DATA 102 | 84 | #define MPEG_SAVE_DATA 102 |
85 | #define MPEG_STOP_DONE 103 | 85 | #define MPEG_STOP_DONE 103 |
86 | #define MPEG_PRERECORDING_TICK 104 | ||
86 | 87 | ||
87 | /* indicator for MPEG_NEED_DATA */ | 88 | /* indicator for MPEG_NEED_DATA */ |
88 | #define GENERATE_UNBUFFER_EVENTS ((void*)1) | 89 | #define GENERATE_UNBUFFER_EVENTS ((void*)1) |
@@ -155,12 +156,13 @@ static long lowest_watermark_level; /* Debug value to observe the buffer | |||
155 | static char recording_filename[MAX_PATH]; /* argument to thread */ | 156 | static char recording_filename[MAX_PATH]; /* argument to thread */ |
156 | static char delayed_filename[MAX_PATH]; /* internal copy of above */ | 157 | static char delayed_filename[MAX_PATH]; /* internal copy of above */ |
157 | 158 | ||
159 | static char xing_buffer[MAX_XING_HEADER_SIZE]; | ||
160 | |||
158 | static bool init_recording_done; | 161 | static bool init_recording_done; |
159 | static bool init_playback_done; | 162 | static bool init_playback_done; |
160 | static bool prerecording; /* True if prerecording is enabled */ | 163 | static bool prerecording; /* True if prerecording is enabled */ |
161 | static bool is_prerecording; /* True if we are prerecording */ | 164 | static bool is_prerecording; /* True if we are prerecording */ |
162 | static bool is_recording; /* We are recording */ | 165 | static bool is_recording; /* We are recording */ |
163 | static bool disable_xing_header; /* When splitting files */ | ||
164 | 166 | ||
165 | static enum { | 167 | static enum { |
166 | NOT_SAVING = 0, /* reasons to save data, sorted by importance */ | 168 | NOT_SAVING = 0, /* reasons to save data, sorted by importance */ |
@@ -172,8 +174,12 @@ static enum { | |||
172 | static int rec_frequency_index; /* For create_xing_header() calls */ | 174 | static int rec_frequency_index; /* For create_xing_header() calls */ |
173 | static int rec_version_index; /* For create_xing_header() calls */ | 175 | static int rec_version_index; /* For create_xing_header() calls */ |
174 | 176 | ||
175 | static int prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS]; | 177 | struct prerecord_info { |
176 | /* Array of buffer indexes for each prerecorded second */ | 178 | int mempos; |
179 | unsigned long framecount; | ||
180 | }; | ||
181 | |||
182 | static struct prerecord_info prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS]; | ||
177 | static int prerecord_index; /* Current index in the prerecord buffer */ | 183 | static int prerecord_index; /* Current index in the prerecord buffer */ |
178 | static int prerecording_max_seconds; /* Max number of seconds to store */ | 184 | static int prerecording_max_seconds; /* Max number of seconds to store */ |
179 | static int prerecord_count; /* Number of seconds in the prerecord buffer */ | 185 | static int prerecord_count; /* Number of seconds in the prerecord buffer */ |
@@ -185,7 +191,10 @@ unsigned long record_start_time; /* Value of current_tick when recording | |||
185 | unsigned long pause_start_time; /* Value of current_tick when pause was | 191 | unsigned long pause_start_time; /* Value of current_tick when pause was |
186 | started */ | 192 | started */ |
187 | static unsigned long num_rec_bytes; | 193 | static unsigned long num_rec_bytes; |
188 | static unsigned long num_recorded_frames; | 194 | static unsigned long last_rec_bytes; |
195 | static unsigned long frame_count_start; | ||
196 | static unsigned long frame_count_end; | ||
197 | static unsigned long saved_header = 0; | ||
189 | 198 | ||
190 | /* Shadow MAS registers */ | 199 | /* Shadow MAS registers */ |
191 | unsigned long shadow_encoder_control = 0; | 200 | unsigned long shadow_encoder_control = 0; |
@@ -213,6 +222,8 @@ static int get_unswapped_space(void); | |||
213 | 222 | ||
214 | #if CONFIG_CODEC == MAS3587F | 223 | #if CONFIG_CODEC == MAS3587F |
215 | static void init_recording(void); | 224 | static void init_recording(void); |
225 | static void prepend_header(void); | ||
226 | static void update_header(void); | ||
216 | static void start_prerecording(void); | 227 | static void start_prerecording(void); |
217 | static void start_recording(void); | 228 | static void start_recording(void); |
218 | static void stop_recording(void); | 229 | static void stop_recording(void); |
@@ -745,17 +756,8 @@ void rec_tick(void) | |||
745 | if(TIME_AFTER(current_tick, prerecord_timeout)) | 756 | if(TIME_AFTER(current_tick, prerecord_timeout)) |
746 | { | 757 | { |
747 | prerecord_timeout = current_tick + HZ; | 758 | prerecord_timeout = current_tick + HZ; |
748 | 759 | queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0); | |
749 | /* Store the write pointer every second */ | 760 | wake_up_thread(); |
750 | prerecord_buffer[prerecord_index++] = audiobuf_write; | ||
751 | |||
752 | /* Wrap if necessary */ | ||
753 | if(prerecord_index == prerecording_max_seconds) | ||
754 | prerecord_index = 0; | ||
755 | |||
756 | /* Update the number of seconds recorded */ | ||
757 | if(prerecord_count < prerecording_max_seconds) | ||
758 | prerecord_count++; | ||
759 | } | 761 | } |
760 | } | 762 | } |
761 | else | 763 | else |
@@ -1164,10 +1166,9 @@ static void mpeg_thread(void) | |||
1164 | int start_offset; | 1166 | int start_offset; |
1165 | #if CONFIG_CODEC == MAS3587F | 1167 | #if CONFIG_CODEC == MAS3587F |
1166 | int amount_to_save; | 1168 | int amount_to_save; |
1167 | int framelen; | ||
1168 | unsigned long saved_header = 0; | ||
1169 | int save_endpos = 0; | 1169 | int save_endpos = 0; |
1170 | int rc; | 1170 | int rc; |
1171 | int level; | ||
1171 | long offset; | 1172 | long offset; |
1172 | #endif /* CONFIG_CODEC == MAS3587F */ | 1173 | #endif /* CONFIG_CODEC == MAS3587F */ |
1173 | 1174 | ||
@@ -1749,26 +1750,25 @@ static void mpeg_thread(void) | |||
1749 | switch(ev.id) | 1750 | switch(ev.id) |
1750 | { | 1751 | { |
1751 | case MPEG_RECORD: | 1752 | case MPEG_RECORD: |
1752 | if(is_prerecording) | 1753 | if (is_prerecording) |
1753 | { | 1754 | { |
1754 | int startpos, i; | 1755 | int startpos; |
1755 | int level; | 1756 | |
1756 | |||
1757 | /* Go back prerecord_count seconds in the buffer */ | 1757 | /* Go back prerecord_count seconds in the buffer */ |
1758 | startpos = prerecord_index - prerecord_count; | 1758 | startpos = prerecord_index - prerecord_count; |
1759 | if(startpos < 0) | 1759 | if(startpos < 0) |
1760 | startpos += prerecording_max_seconds; | 1760 | startpos += prerecording_max_seconds; |
1761 | 1761 | ||
1762 | /* Read the mp3 buffer pointer from the prerecord | 1762 | /* Read the position data from the prerecord buffer */ |
1763 | buffer */ | 1763 | frame_count_start = prerecord_buffer[startpos].framecount; |
1764 | startpos = prerecord_buffer[startpos]; | 1764 | startpos = prerecord_buffer[startpos].mempos; |
1765 | 1765 | ||
1766 | DEBUGF("Start looking at address %x (%x)\n", | 1766 | DEBUGF("Start looking at address %x (%x)\n", |
1767 | audiobuf+startpos, startpos); | 1767 | audiobuf+startpos, startpos); |
1768 | 1768 | ||
1769 | saved_header = mpeg_get_last_header(); | 1769 | saved_header = mpeg_get_last_header(); |
1770 | 1770 | ||
1771 | mem_find_next_frame(startpos, &offset, 5000, | 1771 | mem_find_next_frame(startpos, &offset, 1800, |
1772 | saved_header); | 1772 | saved_header); |
1773 | 1773 | ||
1774 | audiobuf_read = startpos + offset; | 1774 | audiobuf_read = startpos + offset; |
@@ -1781,58 +1781,17 @@ static void mpeg_thread(void) | |||
1781 | level = set_irq_level(HIGHEST_IRQ_LEVEL); | 1781 | level = set_irq_level(HIGHEST_IRQ_LEVEL); |
1782 | num_rec_bytes = get_unsaved_space(); | 1782 | num_rec_bytes = get_unsaved_space(); |
1783 | set_irq_level(level); | 1783 | set_irq_level(level); |
1784 | |||
1785 | /* Make room for headers */ | ||
1786 | audiobuf_read -= MPEG_RESERVED_HEADER_SPACE; | ||
1787 | if(audiobuf_read < 0) | ||
1788 | { | ||
1789 | /* Clear the bottom half */ | ||
1790 | memset(audiobuf, 0, | ||
1791 | audiobuf_read + MPEG_RESERVED_HEADER_SPACE); | ||
1792 | |||
1793 | /* And the top half */ | ||
1794 | audiobuf_read += audiobuflen; | ||
1795 | memset(audiobuf + audiobuf_read, 0, | ||
1796 | audiobuflen - audiobuf_read); | ||
1797 | } | ||
1798 | else | ||
1799 | { | ||
1800 | memset(audiobuf + audiobuf_read, 0, | ||
1801 | MPEG_RESERVED_HEADER_SPACE); | ||
1802 | } | ||
1803 | |||
1804 | /* Copy the empty ID3 header */ | ||
1805 | startpos = audiobuf_read; | ||
1806 | for(i = 0;i < (int)sizeof(empty_id3_header);i++) | ||
1807 | { | ||
1808 | audiobuf[startpos++] = empty_id3_header[i]; | ||
1809 | if(startpos == audiobuflen) | ||
1810 | startpos = 0; | ||
1811 | } | ||
1812 | |||
1813 | DEBUGF("New audiobuf_read address (reservation): %x\n", | ||
1814 | audiobuf+audiobuf_read); | ||
1815 | |||
1816 | DEBUGF("Prerecording...\n"); | ||
1817 | } | 1784 | } |
1818 | else | 1785 | else |
1819 | { | 1786 | { |
1820 | reset_mp3_buffer(); | 1787 | frame_count_start = 0; |
1821 | |||
1822 | num_rec_bytes = 0; | 1788 | num_rec_bytes = 0; |
1823 | 1789 | audiobuf_read = MPEG_RESERVED_HEADER_SPACE; | |
1824 | /* Advance the write pointer to make | ||
1825 | room for an ID3 tag plus a VBR header */ | ||
1826 | audiobuf_write = MPEG_RESERVED_HEADER_SPACE; | 1790 | audiobuf_write = MPEG_RESERVED_HEADER_SPACE; |
1827 | memset(audiobuf, 0, MPEG_RESERVED_HEADER_SPACE); | ||
1828 | |||
1829 | /* Insert the ID3 header */ | ||
1830 | memcpy(audiobuf, empty_id3_header, | ||
1831 | sizeof(empty_id3_header)); | ||
1832 | |||
1833 | DEBUGF("Recording...\n"); | ||
1834 | } | 1791 | } |
1835 | 1792 | ||
1793 | prepend_header(); | ||
1794 | DEBUGF("Recording...\n"); | ||
1836 | start_recording(); | 1795 | start_recording(); |
1837 | 1796 | ||
1838 | /* Wait until at least one frame is encoded and get the | 1797 | /* Wait until at least one frame is encoded and get the |
@@ -1840,7 +1799,7 @@ static void mpeg_thread(void) | |||
1840 | generation */ | 1799 | generation */ |
1841 | sleep(HZ/5); | 1800 | sleep(HZ/5); |
1842 | saved_header = mpeg_get_last_header(); | 1801 | saved_header = mpeg_get_last_header(); |
1843 | 1802 | ||
1844 | /* delayed until buffer is saved, don't open yet */ | 1803 | /* delayed until buffer is saved, don't open yet */ |
1845 | strcpy(delayed_filename, recording_filename); | 1804 | strcpy(delayed_filename, recording_filename); |
1846 | mpeg_file = -1; | 1805 | mpeg_file = -1; |
@@ -1863,40 +1822,9 @@ static void mpeg_thread(void) | |||
1863 | 1822 | ||
1864 | if (mpeg_file >= 0) | 1823 | if (mpeg_file >= 0) |
1865 | close(mpeg_file); | 1824 | close(mpeg_file); |
1866 | |||
1867 | if (!disable_xing_header && num_rec_bytes > 0) | ||
1868 | { | ||
1869 | /* Create the Xing header */ | ||
1870 | mpeg_file = open(recording_filename, O_RDWR); | ||
1871 | if (mpeg_file < 0) | ||
1872 | panicf("rec upd: %d (%s)", mpeg_file, | ||
1873 | recording_filename); | ||
1874 | |||
1875 | /* If the number of recorded frames have | ||
1876 | reached 0x7ffff, we can no longer trust it */ | ||
1877 | if (num_recorded_frames == 0x7ffff) | ||
1878 | num_recorded_frames = 0; | ||
1879 | |||
1880 | /* Also, if we have been prerecording, the frame count | ||
1881 | will be wrong */ | ||
1882 | if (prerecording) | ||
1883 | num_recorded_frames = 0; | ||
1884 | |||
1885 | /* saved_header is saved right before stopping | ||
1886 | the MAS */ | ||
1887 | framelen = create_xing_header(mpeg_file, 0, | ||
1888 | num_rec_bytes, audiobuf, | ||
1889 | num_recorded_frames, | ||
1890 | saved_header, NULL, | ||
1891 | false); | ||
1892 | |||
1893 | lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen, | ||
1894 | SEEK_SET); | ||
1895 | write(mpeg_file, audiobuf, framelen); | ||
1896 | close(mpeg_file); | ||
1897 | } | ||
1898 | mpeg_file = -1; | 1825 | mpeg_file = -1; |
1899 | 1826 | ||
1827 | update_header(); | ||
1900 | #ifdef DEBUG1 | 1828 | #ifdef DEBUG1 |
1901 | { | 1829 | { |
1902 | int i; | 1830 | int i; |
@@ -1934,37 +1862,41 @@ static void mpeg_thread(void) | |||
1934 | amount_to_save = get_unsaved_space(); | 1862 | amount_to_save = get_unsaved_space(); |
1935 | } | 1863 | } |
1936 | 1864 | ||
1865 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, | ||
1866 | &frame_count_end, 1); | ||
1867 | |||
1868 | /* capture all values at one point */ | ||
1869 | level = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
1870 | save_endpos = audiobuf_write; | ||
1871 | last_rec_bytes = num_rec_bytes; | ||
1872 | num_rec_bytes = 0; | ||
1873 | set_irq_level(level); | ||
1874 | |||
1937 | if (amount_to_save >= 1800) | 1875 | if (amount_to_save >= 1800) |
1938 | { | 1876 | { |
1939 | /* Now find a frame boundary to split at */ | 1877 | /* Now find a frame boundary to split at */ |
1940 | save_endpos = audiobuf_write - 1800; | 1878 | save_endpos -= 1800; |
1941 | if (save_endpos < 0) | 1879 | if (save_endpos < 0) |
1942 | save_endpos += audiobuflen; | 1880 | save_endpos += audiobuflen; |
1943 | 1881 | ||
1944 | rc = mem_find_next_frame(save_endpos, &offset, 1800, | 1882 | rc = mem_find_next_frame(save_endpos, &offset, 1800, |
1945 | saved_header); | 1883 | saved_header); |
1946 | if (rc) /* Header found? */ | 1884 | if (!rc) /* No header found, save whole buffer */ |
1947 | { | 1885 | offset = 1800; |
1948 | /* offset will now contain the number of bytes to | 1886 | |
1949 | add to startpos to find the frame boundary */ | 1887 | save_endpos += offset; |
1950 | save_endpos += offset; | 1888 | if (save_endpos >= audiobuflen) |
1951 | if (save_endpos >= audiobuflen) | 1889 | save_endpos -= audiobuflen; |
1952 | save_endpos -= audiobuflen; | 1890 | |
1953 | } | 1891 | last_rec_bytes += offset - 1800; |
1954 | else | 1892 | level = set_irq_level(HIGHEST_IRQ_LEVEL); |
1955 | { | 1893 | num_rec_bytes += 1800 - offset; |
1956 | /* No header found. Let's save the whole buffer. */ | 1894 | set_irq_level(level); |
1957 | save_endpos = audiobuf_write; | ||
1958 | } | ||
1959 | } | ||
1960 | else | ||
1961 | { | ||
1962 | /* Too few bytes recorded, timeout */ | ||
1963 | save_endpos = audiobuf_write; | ||
1964 | } | 1895 | } |
1965 | 1896 | ||
1966 | saving_status = NEW_FILE; | 1897 | saving_status = NEW_FILE; |
1967 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | 1898 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); |
1899 | break; | ||
1968 | 1900 | ||
1969 | case MPEG_SAVE_DATA: | 1901 | case MPEG_SAVE_DATA: |
1970 | if (saving_status == BUFFER_FULL) | 1902 | if (saving_status == BUFFER_FULL) |
@@ -2025,18 +1957,22 @@ static void mpeg_thread(void) | |||
2025 | /* Close the current file */ | 1957 | /* Close the current file */ |
2026 | rc = close(mpeg_file); | 1958 | rc = close(mpeg_file); |
2027 | if (rc < 0) | 1959 | if (rc < 0) |
2028 | panicf("spt cls: %d", rc); | 1960 | panicf("rec cls: %d", rc); |
2029 | ata_sleep(); | ||
2030 | mpeg_file = -1; | 1961 | mpeg_file = -1; |
1962 | update_header(); | ||
1963 | ata_sleep(); | ||
1964 | |||
2031 | /* copy new filename */ | 1965 | /* copy new filename */ |
2032 | strcpy(delayed_filename, recording_filename); | 1966 | strcpy(delayed_filename, recording_filename); |
1967 | prepend_header(); | ||
1968 | frame_count_start = frame_count_end; | ||
2033 | break; | 1969 | break; |
2034 | 1970 | ||
2035 | case STOP_RECORDING: | 1971 | case STOP_RECORDING: |
2036 | queue_post(&mpeg_queue, MPEG_STOP_DONE, NULL); | 1972 | queue_post(&mpeg_queue, MPEG_STOP_DONE, NULL); |
2037 | /* will close the file */ | 1973 | /* will close the file */ |
2038 | break; | 1974 | break; |
2039 | 1975 | ||
2040 | default: | 1976 | default: |
2041 | break; | 1977 | break; |
2042 | } | 1978 | } |
@@ -2046,6 +1982,24 @@ static void mpeg_thread(void) | |||
2046 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | 1982 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); |
2047 | 1983 | ||
2048 | break; | 1984 | break; |
1985 | |||
1986 | case MPEG_PRERECORDING_TICK: | ||
1987 | if(!is_prerecording) | ||
1988 | break; | ||
1989 | |||
1990 | /* Store the write pointer every second */ | ||
1991 | prerecord_buffer[prerecord_index].mempos = audiobuf_write; | ||
1992 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, | ||
1993 | &prerecord_buffer[prerecord_index].framecount, 1); | ||
1994 | |||
1995 | /* Wrap if necessary */ | ||
1996 | if(++prerecord_index == prerecording_max_seconds) | ||
1997 | prerecord_index = 0; | ||
1998 | |||
1999 | /* Update the number of seconds recorded */ | ||
2000 | if(prerecord_count < prerecording_max_seconds) | ||
2001 | prerecord_count++; | ||
2002 | break; | ||
2049 | 2003 | ||
2050 | case MPEG_INIT_PLAYBACK: | 2004 | case MPEG_INIT_PLAYBACK: |
2051 | /* Stop the prerecording */ | 2005 | /* Stop the prerecording */ |
@@ -2257,7 +2211,6 @@ void mpeg_record(const char *filename) | |||
2257 | strncpy(recording_filename, filename, MAX_PATH - 1); | 2211 | strncpy(recording_filename, filename, MAX_PATH - 1); |
2258 | recording_filename[MAX_PATH - 1] = 0; | 2212 | recording_filename[MAX_PATH - 1] = 0; |
2259 | 2213 | ||
2260 | disable_xing_header = false; | ||
2261 | queue_post(&mpeg_queue, MPEG_RECORD, NULL); | 2214 | queue_post(&mpeg_queue, MPEG_RECORD, NULL); |
2262 | } | 2215 | } |
2263 | 2216 | ||
@@ -2271,6 +2224,64 @@ void mpeg_resume_recording(void) | |||
2271 | queue_post(&mpeg_queue, MPEG_RESUME_RECORDING, NULL); | 2224 | queue_post(&mpeg_queue, MPEG_RESUME_RECORDING, NULL); |
2272 | } | 2225 | } |
2273 | 2226 | ||
2227 | static void prepend_header(void) | ||
2228 | { | ||
2229 | int startpos; | ||
2230 | unsigned i; | ||
2231 | |||
2232 | /* Make room for header */ | ||
2233 | audiobuf_read -= MPEG_RESERVED_HEADER_SPACE; | ||
2234 | if(audiobuf_read < 0) | ||
2235 | { | ||
2236 | /* Clear the bottom half */ | ||
2237 | memset(audiobuf, 0, audiobuf_read + MPEG_RESERVED_HEADER_SPACE); | ||
2238 | |||
2239 | /* And the top half */ | ||
2240 | audiobuf_read += audiobuflen; | ||
2241 | memset(audiobuf + audiobuf_read, 0, audiobuflen - audiobuf_read); | ||
2242 | } | ||
2243 | else | ||
2244 | { | ||
2245 | memset(audiobuf + audiobuf_read, 0, MPEG_RESERVED_HEADER_SPACE); | ||
2246 | } | ||
2247 | /* Copy the empty ID3 header */ | ||
2248 | startpos = audiobuf_read; | ||
2249 | for(i = 0; i < sizeof(empty_id3_header); i++) | ||
2250 | { | ||
2251 | audiobuf[startpos++] = empty_id3_header[i]; | ||
2252 | if(startpos == audiobuflen) | ||
2253 | startpos = 0; | ||
2254 | } | ||
2255 | } | ||
2256 | |||
2257 | static void update_header(void) | ||
2258 | { | ||
2259 | int fd, framelen; | ||
2260 | unsigned long frames; | ||
2261 | |||
2262 | if (last_rec_bytes > 0) | ||
2263 | { | ||
2264 | /* Create the Xing header */ | ||
2265 | fd = open(delayed_filename, O_RDWR); | ||
2266 | if (fd < 0) | ||
2267 | panicf("rec upd: %d (%s)", fd, recording_filename); | ||
2268 | |||
2269 | frames = frame_count_end - frame_count_start; | ||
2270 | /* If the number of recorded frames has reached 0x7ffff, | ||
2271 | we can no longer trust it */ | ||
2272 | if (frame_count_end == 0x7ffff) | ||
2273 | frames = 0; | ||
2274 | |||
2275 | /* saved_header is saved right before stopping the MAS */ | ||
2276 | framelen = create_xing_header(fd, 0, last_rec_bytes, xing_buffer, | ||
2277 | frames, saved_header, NULL, false); | ||
2278 | |||
2279 | lseek(fd, MPEG_RESERVED_HEADER_SPACE - framelen, SEEK_SET); | ||
2280 | write(fd, xing_buffer, framelen); | ||
2281 | close(fd); | ||
2282 | } | ||
2283 | } | ||
2284 | |||
2274 | static void start_prerecording(void) | 2285 | static void start_prerecording(void) |
2275 | { | 2286 | { |
2276 | unsigned long val; | 2287 | unsigned long val; |
@@ -2306,8 +2317,6 @@ static void start_recording(void) | |||
2306 | { | 2317 | { |
2307 | unsigned long val; | 2318 | unsigned long val; |
2308 | 2319 | ||
2309 | num_recorded_frames = 0; | ||
2310 | |||
2311 | if(is_prerecording) | 2320 | if(is_prerecording) |
2312 | { | 2321 | { |
2313 | /* This will make the IRQ handler start recording | 2322 | /* This will make the IRQ handler start recording |
@@ -2386,9 +2395,9 @@ static void stop_recording(void) | |||
2386 | 2395 | ||
2387 | is_recording = false; | 2396 | is_recording = false; |
2388 | is_prerecording = false; | 2397 | is_prerecording = false; |
2389 | 2398 | ||
2390 | /* Read the number of frames recorded */ | 2399 | last_rec_bytes = num_rec_bytes; |
2391 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &num_recorded_frames, 1); | 2400 | mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count_end, 1); |
2392 | 2401 | ||
2393 | /* Start monitoring */ | 2402 | /* Start monitoring */ |
2394 | shadow_io_control_main |= (1 << 10); | 2403 | shadow_io_control_main |= (1 << 10); |
@@ -2514,9 +2523,6 @@ void mpeg_new_file(const char *filename) | |||
2514 | strncpy(recording_filename, filename, MAX_PATH - 1); | 2523 | strncpy(recording_filename, filename, MAX_PATH - 1); |
2515 | recording_filename[MAX_PATH - 1] = 0; | 2524 | recording_filename[MAX_PATH - 1] = 0; |
2516 | 2525 | ||
2517 | num_rec_bytes = 0; | ||
2518 | disable_xing_header = true; | ||
2519 | |||
2520 | /* Store the current time */ | 2526 | /* Store the current time */ |
2521 | record_start_time = current_tick; | 2527 | record_start_time = current_tick; |
2522 | if(paused) | 2528 | if(paused) |
@@ -2554,7 +2560,7 @@ unsigned long mpeg_num_recorded_bytes(void) | |||
2554 | if(index < 0) | 2560 | if(index < 0) |
2555 | index += prerecording_max_seconds; | 2561 | index += prerecording_max_seconds; |
2556 | 2562 | ||
2557 | num_bytes = audiobuf_write - prerecord_buffer[index]; | 2563 | num_bytes = audiobuf_write - prerecord_buffer[index].mempos; |
2558 | if(num_bytes < 0) | 2564 | if(num_bytes < 0) |
2559 | num_bytes += audiobuflen; | 2565 | num_bytes += audiobuflen; |
2560 | 2566 | ||