diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/mp3data.h | 2 | ||||
-rw-r--r-- | firmware/export/mpeg.h | 1 | ||||
-rw-r--r-- | firmware/mp3data.c | 75 | ||||
-rw-r--r-- | firmware/mpeg.c | 191 |
4 files changed, 203 insertions, 66 deletions
diff --git a/firmware/export/mp3data.h b/firmware/export/mp3data.h index 6b3ff83b1a..833a4c9dfa 100644 --- a/firmware/export/mp3data.h +++ b/firmware/export/mp3data.h | |||
@@ -56,6 +56,8 @@ struct mp3info { | |||
56 | 56 | ||
57 | 57 | ||
58 | unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header); | 58 | unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header); |
59 | unsigned long mem_find_next_frame(int startpos, int *offset, int max_offset, | ||
60 | unsigned long last_header); | ||
59 | int get_mp3file_info(int fd, struct mp3info *info); | 61 | int get_mp3file_info(int fd, struct mp3info *info); |
60 | int count_mp3_frames(int fd, int startpos, int filesize, | 62 | int count_mp3_frames(int fd, int startpos, int filesize, |
61 | void (*progressfunc)(int)); | 63 | void (*progressfunc)(int)); |
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h index bdf65dd7a8..63eecf51db 100644 --- a/firmware/export/mpeg.h +++ b/firmware/export/mpeg.h | |||
@@ -86,6 +86,7 @@ void mpeg_set_pitch(int percent); | |||
86 | void mpeg_init_recording(void); | 86 | void mpeg_init_recording(void); |
87 | void mpeg_init_playback(void); | 87 | void mpeg_init_playback(void); |
88 | void mpeg_record(char *filename); | 88 | void mpeg_record(char *filename); |
89 | void mpeg_new_file(char *filename); | ||
89 | void mpeg_set_recording_options(int frequency, int quality, | 90 | void mpeg_set_recording_options(int frequency, int quality, |
90 | int source, int channel_mode, | 91 | int source, int channel_mode, |
91 | bool editable); | 92 | bool editable); |
diff --git a/firmware/mp3data.c b/firmware/mp3data.c index 670934d38d..83d916ff9f 100644 --- a/firmware/mp3data.c +++ b/firmware/mp3data.c | |||
@@ -212,7 +212,7 @@ static bool mp3headerinfo(struct mp3info *info, unsigned long header) | |||
212 | return true; | 212 | return true; |
213 | } | 213 | } |
214 | 214 | ||
215 | unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header) | 215 | static unsigned long __find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header, int(*getfunc)(int fd, unsigned char *c)) |
216 | { | 216 | { |
217 | unsigned long header=0; | 217 | unsigned long header=0; |
218 | unsigned char tmp; | 218 | unsigned char tmp; |
@@ -227,7 +227,7 @@ unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long | |||
227 | /* Fill up header with first 24 bits */ | 227 | /* Fill up header with first 24 bits */ |
228 | for(i = 0; i < 3; i++) { | 228 | for(i = 0; i < 3; i++) { |
229 | header <<= 8; | 229 | header <<= 8; |
230 | if(!read(fd, &tmp, 1)) | 230 | if(!getfunc(fd, &tmp)) |
231 | return 0; | 231 | return 0; |
232 | header |= tmp; | 232 | header |= tmp; |
233 | pos++; | 233 | pos++; |
@@ -235,7 +235,7 @@ unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long | |||
235 | 235 | ||
236 | do { | 236 | do { |
237 | header <<= 8; | 237 | header <<= 8; |
238 | if(!read(fd, &tmp, 1)) | 238 | if(!getfunc(fd, &tmp)) |
239 | return 0; | 239 | return 0; |
240 | header |= tmp; | 240 | header |= tmp; |
241 | pos++; | 241 | pos++; |
@@ -254,6 +254,16 @@ unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long | |||
254 | return header; | 254 | return header; |
255 | } | 255 | } |
256 | 256 | ||
257 | static int fileread(int fd, unsigned char *c) | ||
258 | { | ||
259 | return read(fd, c, 1); | ||
260 | } | ||
261 | |||
262 | unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header) | ||
263 | { | ||
264 | return __find_next_frame(fd, offset, max_offset, last_header, fileread); | ||
265 | } | ||
266 | |||
257 | static int fnf_read_index; | 267 | static int fnf_read_index; |
258 | static int fnf_buf_len; | 268 | static int fnf_buf_len; |
259 | 269 | ||
@@ -315,44 +325,37 @@ static void buf_init(void) | |||
315 | unsigned long buf_find_next_frame(int fd, int *offset, int max_offset, | 325 | unsigned long buf_find_next_frame(int fd, int *offset, int max_offset, |
316 | unsigned long last_header) | 326 | unsigned long last_header) |
317 | { | 327 | { |
318 | unsigned long header=0; | 328 | return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte); |
319 | unsigned char tmp; | 329 | } |
320 | int i; | ||
321 | |||
322 | int pos = 0; | ||
323 | 330 | ||
324 | /* We remember the last header we found, to use as a template to see if | 331 | static int mp3buflen; |
325 | the header we find has the same frequency, layer etc */ | 332 | static int mem_pos; |
326 | last_header &= 0xffff0c00; | 333 | static int mem_cnt; |
334 | static int mem_maxlen; | ||
327 | 335 | ||
328 | /* Fill up header with first 24 bits */ | 336 | static int mem_getbyte(int dummy, unsigned char *c) |
329 | for(i = 0; i < 3; i++) { | 337 | { |
330 | header <<= 8; | 338 | dummy = dummy; |
331 | if(!buf_getbyte(fd, &tmp)) | 339 | |
332 | return 0; | 340 | *c = mp3buf[mem_pos++]; |
333 | header |= tmp; | 341 | if(mem_pos >= mp3buflen) |
334 | pos++; | 342 | mem_pos = 0; |
335 | } | ||
336 | 343 | ||
337 | do { | 344 | if(mem_cnt++ >= mem_maxlen) |
338 | header <<= 8; | 345 | return 0; |
339 | if(!buf_getbyte(fd, &tmp)) | 346 | else |
340 | return 0; | 347 | return 1; |
341 | header |= tmp; | 348 | } |
342 | pos++; | ||
343 | if(max_offset > 0 && pos > max_offset) | ||
344 | return 0; | ||
345 | } while(!is_mp3frameheader(header) || | ||
346 | (last_header?((header & 0xffff0c00) != last_header):false)); | ||
347 | 349 | ||
348 | *offset = pos - 4; | 350 | unsigned long mem_find_next_frame(int startpos, int *offset, int max_offset, |
351 | unsigned long last_header) | ||
352 | { | ||
353 | mp3buflen = mp3end - mp3buf; | ||
354 | mem_pos = startpos; | ||
355 | mem_cnt = 0; | ||
356 | mem_maxlen = max_offset; | ||
349 | 357 | ||
350 | #ifdef DEBUG | 358 | return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte); |
351 | if(*offset) | ||
352 | DEBUGF("Warning: skipping %d bytes of garbage\n", *offset); | ||
353 | #endif | ||
354 | |||
355 | return header; | ||
356 | } | 359 | } |
357 | 360 | ||
358 | int get_mp3file_info(int fd, struct mp3info *info) | 361 | int get_mp3file_info(int fd, struct mp3info *info) |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 9d6718dc42..5a6fae4316 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -52,6 +52,7 @@ static void stop_recording(void); | |||
52 | static int get_unplayed_space(void); | 52 | static int get_unplayed_space(void); |
53 | static int get_playable_space(void); | 53 | static int get_playable_space(void); |
54 | static int get_unswapped_space(void); | 54 | static int get_unswapped_space(void); |
55 | static int get_unsaved_space(void); | ||
55 | #endif | 56 | #endif |
56 | 57 | ||
57 | #define MPEG_PLAY 1 | 58 | #define MPEG_PLAY 1 |
@@ -65,6 +66,7 @@ static int get_unswapped_space(void); | |||
65 | #define MPEG_RECORD 9 | 66 | #define MPEG_RECORD 9 |
66 | #define MPEG_INIT_RECORDING 10 | 67 | #define MPEG_INIT_RECORDING 10 |
67 | #define MPEG_INIT_PLAYBACK 11 | 68 | #define MPEG_INIT_PLAYBACK 11 |
69 | #define MPEG_NEW_FILE 12 | ||
68 | #define MPEG_NEED_DATA 100 | 70 | #define MPEG_NEED_DATA 100 |
69 | #define MPEG_TRACK_CHANGE 101 | 71 | #define MPEG_TRACK_CHANGE 101 |
70 | #define MPEG_SAVE_DATA 102 | 72 | #define MPEG_SAVE_DATA 102 |
@@ -494,6 +496,7 @@ static bool saving; /* We are saving the buffer to disk */ | |||
494 | static char recording_filename[MAX_PATH]; | 496 | static char recording_filename[MAX_PATH]; |
495 | static int rec_frequency_index; /* For create_xing_header() calls */ | 497 | static int rec_frequency_index; /* For create_xing_header() calls */ |
496 | static int rec_version_index; /* For create_xing_header() calls */ | 498 | static int rec_version_index; /* For create_xing_header() calls */ |
499 | static bool disable_xing_header; /* When splitting files */ | ||
497 | #endif | 500 | #endif |
498 | 501 | ||
499 | static int mpeg_file; | 502 | static int mpeg_file; |
@@ -687,6 +690,16 @@ static int get_unswapped_space(void) | |||
687 | return space; | 690 | return space; |
688 | } | 691 | } |
689 | 692 | ||
693 | #ifdef HAVE_MAS3587F | ||
694 | static int get_unsaved_space(void) | ||
695 | { | ||
696 | int space = mp3buf_write - mp3buf_read; | ||
697 | if (space < 0) | ||
698 | space += mp3buflen; | ||
699 | return space; | ||
700 | } | ||
701 | #endif | ||
702 | |||
690 | static void init_dma(void) | 703 | static void init_dma(void) |
691 | { | 704 | { |
692 | SAR3 = (unsigned int) mp3buf + mp3buf_read; | 705 | SAR3 = (unsigned int) mp3buf + mp3buf_read; |
@@ -1270,6 +1283,9 @@ static void mpeg_thread(void) | |||
1270 | int writelen; | 1283 | int writelen; |
1271 | int framelen; | 1284 | int framelen; |
1272 | unsigned long saved_header; | 1285 | unsigned long saved_header; |
1286 | int startpos; | ||
1287 | int rc; | ||
1288 | int offset; | ||
1273 | #endif | 1289 | #endif |
1274 | 1290 | ||
1275 | is_playing = false; | 1291 | is_playing = false; |
@@ -1893,29 +1909,34 @@ static void mpeg_thread(void) | |||
1893 | if(mpeg_file >= 0) | 1909 | if(mpeg_file >= 0) |
1894 | close(mpeg_file); | 1910 | close(mpeg_file); |
1895 | 1911 | ||
1896 | /* Create the Xing header */ | 1912 | if(!disable_xing_header) |
1897 | mpeg_file = open(recording_filename, O_RDWR); | 1913 | { |
1898 | if(mpeg_file < 0) | 1914 | /* Create the Xing header */ |
1899 | panicf("rec upd: %d (%s)", mpeg_file, recording_filename); | 1915 | mpeg_file = open(recording_filename, O_RDWR); |
1900 | 1916 | if(mpeg_file < 0) | |
1901 | /* If the number of recorded frames have reached 0x7ffff, | 1917 | panicf("rec upd: %d (%s)", mpeg_file, |
1902 | we can no longer trust it */ | 1918 | recording_filename); |
1903 | if(num_recorded_frames == 0x7ffff) | 1919 | |
1904 | num_recorded_frames = 0; | 1920 | /* If the number of recorded frames have |
1905 | 1921 | reached 0x7ffff, we can no longer trust it */ | |
1906 | /* Read the first MP3 frame from the recorded stream */ | 1922 | if(num_recorded_frames == 0x7ffff) |
1907 | lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE, SEEK_SET); | 1923 | num_recorded_frames = 0; |
1908 | read(mpeg_file, &saved_header, 4); | 1924 | |
1909 | 1925 | /* Read the first MP3 frame from the recorded stream */ | |
1910 | framelen = create_xing_header(mpeg_file, 0, num_rec_bytes, | 1926 | lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE, SEEK_SET); |
1911 | mp3buf, num_recorded_frames, | 1927 | read(mpeg_file, &saved_header, 4); |
1912 | saved_header, NULL, false); | 1928 | |
1913 | 1929 | framelen = create_xing_header(mpeg_file, 0, | |
1914 | lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen, | 1930 | num_rec_bytes, mp3buf, |
1915 | SEEK_SET); | 1931 | num_recorded_frames, |
1916 | write(mpeg_file, mp3buf, framelen); | 1932 | saved_header, NULL, |
1917 | close(mpeg_file); | 1933 | false); |
1918 | 1934 | ||
1935 | lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen, | ||
1936 | SEEK_SET); | ||
1937 | write(mpeg_file, mp3buf, framelen); | ||
1938 | close(mpeg_file); | ||
1939 | } | ||
1919 | mpeg_file = -1; | 1940 | mpeg_file = -1; |
1920 | 1941 | ||
1921 | #ifdef DEBUG1 | 1942 | #ifdef DEBUG1 |
@@ -1933,9 +1954,105 @@ static void mpeg_thread(void) | |||
1933 | #endif | 1954 | #endif |
1934 | mpeg_stop_done = true; | 1955 | mpeg_stop_done = true; |
1935 | break; | 1956 | break; |
1957 | |||
1958 | case MPEG_NEW_FILE: | ||
1959 | /* Make sure we have at least one complete frame | ||
1960 | in the buffer */ | ||
1961 | amount_to_save = get_unsaved_space(); | ||
1962 | while(amount_to_save < 1800) | ||
1963 | { | ||
1964 | sleep(HZ/10); | ||
1965 | amount_to_save = get_unsaved_space(); | ||
1966 | } | ||
1967 | |||
1968 | /* Now find a frame boundary to split at */ | ||
1969 | startpos = mp3buf_write - 1800; | ||
1970 | if(startpos < 0) | ||
1971 | startpos += mp3buflen; | ||
1972 | |||
1973 | { | ||
1974 | unsigned long tmp[2]; | ||
1975 | /* Find out how the mp3 header should look like */ | ||
1976 | mas_readmem(MAS_BANK_D0, 0xfd1, tmp, 2); | ||
1977 | saved_header = 0xffe00000 | | ||
1978 | ((tmp[0] & 0x7c00) << 6) | | ||
1979 | (tmp[1] & 0xffff); | ||
1980 | DEBUGF("Header: %08x\n", saved_header); | ||
1981 | } | ||
1982 | |||
1983 | mem_find_next_frame(startpos, &offset, 1800, saved_header); | ||
1984 | |||
1985 | /* offset will now contain the number of bytes to | ||
1986 | add to startpos to find the frame boundary */ | ||
1987 | startpos += offset; | ||
1988 | if(startpos >= mp3buflen) | ||
1989 | startpos -= mp3buflen; | ||
1990 | |||
1991 | amount_to_save = startpos - mp3buf_read; | ||
1992 | if(amount_to_save < 0) | ||
1993 | amount_to_save += mp3buflen; | ||
1994 | |||
1995 | /* First save up to the end of the buffer */ | ||
1996 | writelen = MIN(amount_to_save, | ||
1997 | mp3buflen - mp3buf_read); | ||
1998 | |||
1999 | rc = write(mpeg_file, mp3buf + mp3buf_read, writelen); | ||
2000 | if(rc < 0) | ||
2001 | { | ||
2002 | if(errno == ENOSPC) | ||
2003 | { | ||
2004 | mpeg_errno = MPEGERR_DISK_FULL; | ||
2005 | demand_irq_enable(false); | ||
2006 | stop_recording(); | ||
2007 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); | ||
2008 | break; | ||
2009 | } | ||
2010 | else | ||
2011 | { | ||
2012 | panicf("rec wrt: %d", rc); | ||
2013 | } | ||
2014 | } | ||
2015 | |||
2016 | /* Then save the rest */ | ||
2017 | writelen = amount_to_save - writelen; | ||
2018 | if(writelen) | ||
2019 | { | ||
2020 | rc = write(mpeg_file, mp3buf, writelen); | ||
2021 | if(rc < 0) | ||
2022 | { | ||
2023 | if(errno == ENOSPC) | ||
2024 | { | ||
2025 | mpeg_errno = MPEGERR_DISK_FULL; | ||
2026 | demand_irq_enable(false); | ||
2027 | stop_recording(); | ||
2028 | queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); | ||
2029 | break; | ||
2030 | } | ||
2031 | else | ||
2032 | { | ||
2033 | panicf("spt wrt: %d", rc); | ||
2034 | } | ||
2035 | } | ||
2036 | } | ||
2037 | |||
2038 | /* Advance the buffer pointers */ | ||
2039 | mp3buf_read += amount_to_save; | ||
2040 | if(mp3buf_read >= mp3buflen) | ||
2041 | mp3buf_read -= mp3buflen; | ||
2042 | |||
2043 | /* Close the current file */ | ||
2044 | rc = close(mpeg_file); | ||
2045 | if(rc < 0) | ||
2046 | panicf("spt cls: %d", rc); | ||
2047 | |||
2048 | /* Open the new file */ | ||
2049 | mpeg_file = open(recording_filename, O_WRONLY|O_CREAT); | ||
2050 | if(mpeg_file < 0) | ||
2051 | panicf("sptfile: %d", mpeg_file); | ||
2052 | break; | ||
1936 | 2053 | ||
1937 | case MPEG_SAVE_DATA: | 2054 | case MPEG_SAVE_DATA: |
1938 | amount_to_save = mp3buf_write - mp3buf_read; | 2055 | amount_to_save = get_unsaved_space(); |
1939 | 2056 | ||
1940 | /* If the result is negative, the write index has | 2057 | /* If the result is negative, the write index has |
1941 | wrapped */ | 2058 | wrapped */ |
@@ -1954,8 +2071,6 @@ static void mpeg_thread(void) | |||
1954 | amount_to_save < MPEG_RECORDING_LOW_WATER || | 2071 | amount_to_save < MPEG_RECORDING_LOW_WATER || |
1955 | stop_pending) | 2072 | stop_pending) |
1956 | { | 2073 | { |
1957 | int rc; | ||
1958 | |||
1959 | /* Only save up to the end of the buffer */ | 2074 | /* Only save up to the end of the buffer */ |
1960 | writelen = MIN(amount_to_save, | 2075 | writelen = MIN(amount_to_save, |
1961 | mp3buflen - mp3buf_read); | 2076 | mp3buflen - mp3buf_read); |
@@ -1981,14 +2096,14 @@ static void mpeg_thread(void) | |||
1981 | } | 2096 | } |
1982 | } | 2097 | } |
1983 | 2098 | ||
1984 | rc = fsync(mpeg_file); | ||
1985 | if(rc < 0) | ||
1986 | panicf("rec fls: %d", rc); | ||
1987 | |||
1988 | mp3buf_read += amount_to_save; | 2099 | mp3buf_read += amount_to_save; |
1989 | if(mp3buf_read >= mp3buflen) | 2100 | if(mp3buf_read >= mp3buflen) |
1990 | mp3buf_read = 0; | 2101 | mp3buf_read = 0; |
1991 | 2102 | ||
2103 | rc = fsync(mpeg_file); | ||
2104 | if(rc < 0) | ||
2105 | panicf("rec fls: %d", rc); | ||
2106 | |||
1992 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); | 2107 | queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); |
1993 | } | 2108 | } |
1994 | else | 2109 | else |
@@ -2257,6 +2372,7 @@ void mpeg_record(char *filename) | |||
2257 | recording_filename[MAX_PATH - 1] = 0; | 2372 | recording_filename[MAX_PATH - 1] = 0; |
2258 | 2373 | ||
2259 | num_rec_bytes = 0; | 2374 | num_rec_bytes = 0; |
2375 | disable_xing_header = false; | ||
2260 | queue_post(&mpeg_queue, MPEG_RECORD, NULL); | 2376 | queue_post(&mpeg_queue, MPEG_RECORD, NULL); |
2261 | } | 2377 | } |
2262 | 2378 | ||
@@ -2311,6 +2427,21 @@ static void stop_recording(void) | |||
2311 | drain_dma_buffer(); | 2427 | drain_dma_buffer(); |
2312 | } | 2428 | } |
2313 | 2429 | ||
2430 | void mpeg_new_file(char *filename) | ||
2431 | { | ||
2432 | mpeg_errno = 0; | ||
2433 | |||
2434 | strncpy(recording_filename, filename, MAX_PATH - 1); | ||
2435 | recording_filename[MAX_PATH - 1] = 0; | ||
2436 | |||
2437 | disable_xing_header = true; | ||
2438 | |||
2439 | /* Store the current time */ | ||
2440 | record_start_time = current_tick; | ||
2441 | |||
2442 | queue_post(&mpeg_queue, MPEG_NEW_FILE, NULL); | ||
2443 | } | ||
2444 | |||
2314 | unsigned long mpeg_recorded_time(void) | 2445 | unsigned long mpeg_recorded_time(void) |
2315 | { | 2446 | { |
2316 | if(is_recording) | 2447 | if(is_recording) |