From 24a8b6ad09dc3ba357543c36ca17880d09461022 Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Sun, 2 Nov 2003 11:24:38 +0000 Subject: Frame-accurate file splits when recording. Now the PLAY button closes the current file and opens a new one. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3998 a1c6a512-1295-4272-9138-f99709370657 --- apps/recorder/recording.c | 10 ++- firmware/export/mp3data.h | 2 + firmware/export/mpeg.h | 1 + firmware/mp3data.c | 75 +++++++++--------- firmware/mpeg.c | 191 ++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 209 insertions(+), 70 deletions(-) diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index 868f45f07c..0f095bef48 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c @@ -221,6 +221,11 @@ bool recording_screen(void) update_countdown = 1; /* Update immediately */ last_seconds = 0; } + else + { + mpeg_new_file(create_filename()); + update_countdown = 1; /* Update immediately */ + } break; case BUTTON_UP: @@ -389,10 +394,7 @@ bool recording_screen(void) if (mpeg_status() && (seconds >= dseconds)) { - /* stop and restart recording */ - mpeg_stop(); - have_recorded = true; - mpeg_record(create_filename()); + mpeg_new_file(create_filename()); update_countdown = 1; last_seconds = 0; } 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 { unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header); +unsigned long mem_find_next_frame(int startpos, int *offset, int max_offset, + unsigned long last_header); int get_mp3file_info(int fd, struct mp3info *info); int count_mp3_frames(int fd, int startpos, int filesize, 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); void mpeg_init_recording(void); void mpeg_init_playback(void); void mpeg_record(char *filename); +void mpeg_new_file(char *filename); void mpeg_set_recording_options(int frequency, int quality, int source, int channel_mode, 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) return true; } -unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header) +static unsigned long __find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header, int(*getfunc)(int fd, unsigned char *c)) { unsigned long header=0; unsigned char tmp; @@ -227,7 +227,7 @@ unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long /* Fill up header with first 24 bits */ for(i = 0; i < 3; i++) { header <<= 8; - if(!read(fd, &tmp, 1)) + if(!getfunc(fd, &tmp)) return 0; header |= tmp; pos++; @@ -235,7 +235,7 @@ unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long do { header <<= 8; - if(!read(fd, &tmp, 1)) + if(!getfunc(fd, &tmp)) return 0; header |= tmp; pos++; @@ -254,6 +254,16 @@ unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long return header; } +static int fileread(int fd, unsigned char *c) +{ + return read(fd, c, 1); +} + +unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header) +{ + return __find_next_frame(fd, offset, max_offset, last_header, fileread); +} + static int fnf_read_index; static int fnf_buf_len; @@ -315,44 +325,37 @@ static void buf_init(void) unsigned long buf_find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header) { - unsigned long header=0; - unsigned char tmp; - int i; - - int pos = 0; + return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte); +} - /* We remember the last header we found, to use as a template to see if - the header we find has the same frequency, layer etc */ - last_header &= 0xffff0c00; +static int mp3buflen; +static int mem_pos; +static int mem_cnt; +static int mem_maxlen; - /* Fill up header with first 24 bits */ - for(i = 0; i < 3; i++) { - header <<= 8; - if(!buf_getbyte(fd, &tmp)) - return 0; - header |= tmp; - pos++; - } +static int mem_getbyte(int dummy, unsigned char *c) +{ + dummy = dummy; + + *c = mp3buf[mem_pos++]; + if(mem_pos >= mp3buflen) + mem_pos = 0; - do { - header <<= 8; - if(!buf_getbyte(fd, &tmp)) - return 0; - header |= tmp; - pos++; - if(max_offset > 0 && pos > max_offset) - return 0; - } while(!is_mp3frameheader(header) || - (last_header?((header & 0xffff0c00) != last_header):false)); + if(mem_cnt++ >= mem_maxlen) + return 0; + else + return 1; +} - *offset = pos - 4; +unsigned long mem_find_next_frame(int startpos, int *offset, int max_offset, + unsigned long last_header) +{ + mp3buflen = mp3end - mp3buf; + mem_pos = startpos; + mem_cnt = 0; + mem_maxlen = max_offset; -#ifdef DEBUG - if(*offset) - DEBUGF("Warning: skipping %d bytes of garbage\n", *offset); -#endif - - return header; + return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte); } 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); static int get_unplayed_space(void); static int get_playable_space(void); static int get_unswapped_space(void); +static int get_unsaved_space(void); #endif #define MPEG_PLAY 1 @@ -65,6 +66,7 @@ static int get_unswapped_space(void); #define MPEG_RECORD 9 #define MPEG_INIT_RECORDING 10 #define MPEG_INIT_PLAYBACK 11 +#define MPEG_NEW_FILE 12 #define MPEG_NEED_DATA 100 #define MPEG_TRACK_CHANGE 101 #define MPEG_SAVE_DATA 102 @@ -494,6 +496,7 @@ static bool saving; /* We are saving the buffer to disk */ static char recording_filename[MAX_PATH]; static int rec_frequency_index; /* For create_xing_header() calls */ static int rec_version_index; /* For create_xing_header() calls */ +static bool disable_xing_header; /* When splitting files */ #endif static int mpeg_file; @@ -687,6 +690,16 @@ static int get_unswapped_space(void) return space; } +#ifdef HAVE_MAS3587F +static int get_unsaved_space(void) +{ + int space = mp3buf_write - mp3buf_read; + if (space < 0) + space += mp3buflen; + return space; +} +#endif + static void init_dma(void) { SAR3 = (unsigned int) mp3buf + mp3buf_read; @@ -1270,6 +1283,9 @@ static void mpeg_thread(void) int writelen; int framelen; unsigned long saved_header; + int startpos; + int rc; + int offset; #endif is_playing = false; @@ -1893,29 +1909,34 @@ static void mpeg_thread(void) if(mpeg_file >= 0) close(mpeg_file); - /* Create the Xing header */ - mpeg_file = open(recording_filename, O_RDWR); - if(mpeg_file < 0) - panicf("rec upd: %d (%s)", mpeg_file, recording_filename); - - /* If the number of recorded frames have reached 0x7ffff, - we can no longer trust it */ - if(num_recorded_frames == 0x7ffff) - num_recorded_frames = 0; - - /* Read the first MP3 frame from the recorded stream */ - lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE, SEEK_SET); - read(mpeg_file, &saved_header, 4); - - framelen = create_xing_header(mpeg_file, 0, num_rec_bytes, - mp3buf, num_recorded_frames, - saved_header, NULL, false); - - lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen, - SEEK_SET); - write(mpeg_file, mp3buf, framelen); - close(mpeg_file); - + if(!disable_xing_header) + { + /* Create the Xing header */ + mpeg_file = open(recording_filename, O_RDWR); + if(mpeg_file < 0) + panicf("rec upd: %d (%s)", mpeg_file, + recording_filename); + + /* If the number of recorded frames have + reached 0x7ffff, we can no longer trust it */ + if(num_recorded_frames == 0x7ffff) + num_recorded_frames = 0; + + /* Read the first MP3 frame from the recorded stream */ + lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE, SEEK_SET); + read(mpeg_file, &saved_header, 4); + + framelen = create_xing_header(mpeg_file, 0, + num_rec_bytes, mp3buf, + num_recorded_frames, + saved_header, NULL, + false); + + lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen, + SEEK_SET); + write(mpeg_file, mp3buf, framelen); + close(mpeg_file); + } mpeg_file = -1; #ifdef DEBUG1 @@ -1933,9 +1954,105 @@ static void mpeg_thread(void) #endif mpeg_stop_done = true; break; + + case MPEG_NEW_FILE: + /* Make sure we have at least one complete frame + in the buffer */ + amount_to_save = get_unsaved_space(); + while(amount_to_save < 1800) + { + sleep(HZ/10); + amount_to_save = get_unsaved_space(); + } + + /* Now find a frame boundary to split at */ + startpos = mp3buf_write - 1800; + if(startpos < 0) + startpos += mp3buflen; + + { + unsigned long tmp[2]; + /* Find out how the mp3 header should look like */ + mas_readmem(MAS_BANK_D0, 0xfd1, tmp, 2); + saved_header = 0xffe00000 | + ((tmp[0] & 0x7c00) << 6) | + (tmp[1] & 0xffff); + DEBUGF("Header: %08x\n", saved_header); + } + + mem_find_next_frame(startpos, &offset, 1800, saved_header); + + /* offset will now contain the number of bytes to + add to startpos to find the frame boundary */ + startpos += offset; + if(startpos >= mp3buflen) + startpos -= mp3buflen; + + amount_to_save = startpos - mp3buf_read; + if(amount_to_save < 0) + amount_to_save += mp3buflen; + + /* First save up to the end of the buffer */ + writelen = MIN(amount_to_save, + mp3buflen - mp3buf_read); + + rc = write(mpeg_file, mp3buf + mp3buf_read, writelen); + if(rc < 0) + { + if(errno == ENOSPC) + { + mpeg_errno = MPEGERR_DISK_FULL; + demand_irq_enable(false); + stop_recording(); + queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); + break; + } + else + { + panicf("rec wrt: %d", rc); + } + } + + /* Then save the rest */ + writelen = amount_to_save - writelen; + if(writelen) + { + rc = write(mpeg_file, mp3buf, writelen); + if(rc < 0) + { + if(errno == ENOSPC) + { + mpeg_errno = MPEGERR_DISK_FULL; + demand_irq_enable(false); + stop_recording(); + queue_post(&mpeg_queue, MPEG_STOP_DONE, 0); + break; + } + else + { + panicf("spt wrt: %d", rc); + } + } + } + + /* Advance the buffer pointers */ + mp3buf_read += amount_to_save; + if(mp3buf_read >= mp3buflen) + mp3buf_read -= mp3buflen; + + /* Close the current file */ + rc = close(mpeg_file); + if(rc < 0) + panicf("spt cls: %d", rc); + + /* Open the new file */ + mpeg_file = open(recording_filename, O_WRONLY|O_CREAT); + if(mpeg_file < 0) + panicf("sptfile: %d", mpeg_file); + break; case MPEG_SAVE_DATA: - amount_to_save = mp3buf_write - mp3buf_read; + amount_to_save = get_unsaved_space(); /* If the result is negative, the write index has wrapped */ @@ -1954,8 +2071,6 @@ static void mpeg_thread(void) amount_to_save < MPEG_RECORDING_LOW_WATER || stop_pending) { - int rc; - /* Only save up to the end of the buffer */ writelen = MIN(amount_to_save, mp3buflen - mp3buf_read); @@ -1981,14 +2096,14 @@ static void mpeg_thread(void) } } - rc = fsync(mpeg_file); - if(rc < 0) - panicf("rec fls: %d", rc); - mp3buf_read += amount_to_save; if(mp3buf_read >= mp3buflen) mp3buf_read = 0; + rc = fsync(mpeg_file); + if(rc < 0) + panicf("rec fls: %d", rc); + queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0); } else @@ -2257,6 +2372,7 @@ void mpeg_record(char *filename) recording_filename[MAX_PATH - 1] = 0; num_rec_bytes = 0; + disable_xing_header = false; queue_post(&mpeg_queue, MPEG_RECORD, NULL); } @@ -2311,6 +2427,21 @@ static void stop_recording(void) drain_dma_buffer(); } +void mpeg_new_file(char *filename) +{ + mpeg_errno = 0; + + strncpy(recording_filename, filename, MAX_PATH - 1); + recording_filename[MAX_PATH - 1] = 0; + + disable_xing_header = true; + + /* Store the current time */ + record_start_time = current_tick; + + queue_post(&mpeg_queue, MPEG_NEW_FILE, NULL); +} + unsigned long mpeg_recorded_time(void) { if(is_recording) -- cgit v1.2.3