forked from len0rd/rockbox
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
This commit is contained in:
parent
1694847103
commit
24a8b6ad09
5 changed files with 210 additions and 71 deletions
|
|
@ -221,6 +221,11 @@ bool recording_screen(void)
|
||||||
update_countdown = 1; /* Update immediately */
|
update_countdown = 1; /* Update immediately */
|
||||||
last_seconds = 0;
|
last_seconds = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mpeg_new_file(create_filename());
|
||||||
|
update_countdown = 1; /* Update immediately */
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_UP:
|
case BUTTON_UP:
|
||||||
|
|
@ -389,10 +394,7 @@ bool recording_screen(void)
|
||||||
|
|
||||||
if (mpeg_status() && (seconds >= dseconds))
|
if (mpeg_status() && (seconds >= dseconds))
|
||||||
{
|
{
|
||||||
/* stop and restart recording */
|
mpeg_new_file(create_filename());
|
||||||
mpeg_stop();
|
|
||||||
have_recorded = true;
|
|
||||||
mpeg_record(create_filename());
|
|
||||||
update_countdown = 1;
|
update_countdown = 1;
|
||||||
last_seconds = 0;
|
last_seconds = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ struct mp3info {
|
||||||
|
|
||||||
|
|
||||||
unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header);
|
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 get_mp3file_info(int fd, struct mp3info *info);
|
||||||
int count_mp3_frames(int fd, int startpos, int filesize,
|
int count_mp3_frames(int fd, int startpos, int filesize,
|
||||||
void (*progressfunc)(int));
|
void (*progressfunc)(int));
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ void mpeg_set_pitch(int percent);
|
||||||
void mpeg_init_recording(void);
|
void mpeg_init_recording(void);
|
||||||
void mpeg_init_playback(void);
|
void mpeg_init_playback(void);
|
||||||
void mpeg_record(char *filename);
|
void mpeg_record(char *filename);
|
||||||
|
void mpeg_new_file(char *filename);
|
||||||
void mpeg_set_recording_options(int frequency, int quality,
|
void mpeg_set_recording_options(int frequency, int quality,
|
||||||
int source, int channel_mode,
|
int source, int channel_mode,
|
||||||
bool editable);
|
bool editable);
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ static bool mp3headerinfo(struct mp3info *info, unsigned long header)
|
||||||
return true;
|
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 long header=0;
|
||||||
unsigned char tmp;
|
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 */
|
/* Fill up header with first 24 bits */
|
||||||
for(i = 0; i < 3; i++) {
|
for(i = 0; i < 3; i++) {
|
||||||
header <<= 8;
|
header <<= 8;
|
||||||
if(!read(fd, &tmp, 1))
|
if(!getfunc(fd, &tmp))
|
||||||
return 0;
|
return 0;
|
||||||
header |= tmp;
|
header |= tmp;
|
||||||
pos++;
|
pos++;
|
||||||
|
|
@ -235,7 +235,7 @@ unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long
|
||||||
|
|
||||||
do {
|
do {
|
||||||
header <<= 8;
|
header <<= 8;
|
||||||
if(!read(fd, &tmp, 1))
|
if(!getfunc(fd, &tmp))
|
||||||
return 0;
|
return 0;
|
||||||
header |= tmp;
|
header |= tmp;
|
||||||
pos++;
|
pos++;
|
||||||
|
|
@ -254,6 +254,16 @@ unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long
|
||||||
return header;
|
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_read_index;
|
||||||
static int fnf_buf_len;
|
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 buf_find_next_frame(int fd, int *offset, int max_offset,
|
||||||
unsigned long last_header)
|
unsigned long last_header)
|
||||||
{
|
{
|
||||||
unsigned long header=0;
|
return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte);
|
||||||
unsigned char tmp;
|
}
|
||||||
int i;
|
|
||||||
|
|
||||||
int pos = 0;
|
static int mp3buflen;
|
||||||
|
static int mem_pos;
|
||||||
|
static int mem_cnt;
|
||||||
|
static int mem_maxlen;
|
||||||
|
|
||||||
/* We remember the last header we found, to use as a template to see if
|
static int mem_getbyte(int dummy, unsigned char *c)
|
||||||
the header we find has the same frequency, layer etc */
|
{
|
||||||
last_header &= 0xffff0c00;
|
dummy = dummy;
|
||||||
|
|
||||||
/* 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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
*offset = pos - 4;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if(*offset)
|
|
||||||
DEBUGF("Warning: skipping %d bytes of garbage\n", *offset);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return header;
|
*c = mp3buf[mem_pos++];
|
||||||
|
if(mem_pos >= mp3buflen)
|
||||||
|
mem_pos = 0;
|
||||||
|
|
||||||
|
if(mem_cnt++ >= mem_maxlen)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte);
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_mp3file_info(int fd, struct mp3info *info)
|
int get_mp3file_info(int fd, struct mp3info *info)
|
||||||
|
|
|
||||||
189
firmware/mpeg.c
189
firmware/mpeg.c
|
|
@ -52,6 +52,7 @@ static void stop_recording(void);
|
||||||
static int get_unplayed_space(void);
|
static int get_unplayed_space(void);
|
||||||
static int get_playable_space(void);
|
static int get_playable_space(void);
|
||||||
static int get_unswapped_space(void);
|
static int get_unswapped_space(void);
|
||||||
|
static int get_unsaved_space(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MPEG_PLAY 1
|
#define MPEG_PLAY 1
|
||||||
|
|
@ -65,6 +66,7 @@ static int get_unswapped_space(void);
|
||||||
#define MPEG_RECORD 9
|
#define MPEG_RECORD 9
|
||||||
#define MPEG_INIT_RECORDING 10
|
#define MPEG_INIT_RECORDING 10
|
||||||
#define MPEG_INIT_PLAYBACK 11
|
#define MPEG_INIT_PLAYBACK 11
|
||||||
|
#define MPEG_NEW_FILE 12
|
||||||
#define MPEG_NEED_DATA 100
|
#define MPEG_NEED_DATA 100
|
||||||
#define MPEG_TRACK_CHANGE 101
|
#define MPEG_TRACK_CHANGE 101
|
||||||
#define MPEG_SAVE_DATA 102
|
#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 char recording_filename[MAX_PATH];
|
||||||
static int rec_frequency_index; /* For create_xing_header() calls */
|
static int rec_frequency_index; /* For create_xing_header() calls */
|
||||||
static int rec_version_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
|
#endif
|
||||||
|
|
||||||
static int mpeg_file;
|
static int mpeg_file;
|
||||||
|
|
@ -687,6 +690,16 @@ static int get_unswapped_space(void)
|
||||||
return space;
|
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)
|
static void init_dma(void)
|
||||||
{
|
{
|
||||||
SAR3 = (unsigned int) mp3buf + mp3buf_read;
|
SAR3 = (unsigned int) mp3buf + mp3buf_read;
|
||||||
|
|
@ -1270,6 +1283,9 @@ static void mpeg_thread(void)
|
||||||
int writelen;
|
int writelen;
|
||||||
int framelen;
|
int framelen;
|
||||||
unsigned long saved_header;
|
unsigned long saved_header;
|
||||||
|
int startpos;
|
||||||
|
int rc;
|
||||||
|
int offset;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
is_playing = false;
|
is_playing = false;
|
||||||
|
|
@ -1893,29 +1909,34 @@ static void mpeg_thread(void)
|
||||||
if(mpeg_file >= 0)
|
if(mpeg_file >= 0)
|
||||||
close(mpeg_file);
|
close(mpeg_file);
|
||||||
|
|
||||||
/* Create the Xing header */
|
if(!disable_xing_header)
|
||||||
mpeg_file = open(recording_filename, O_RDWR);
|
{
|
||||||
if(mpeg_file < 0)
|
/* Create the Xing header */
|
||||||
panicf("rec upd: %d (%s)", mpeg_file, recording_filename);
|
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,
|
/* If the number of recorded frames have
|
||||||
we can no longer trust it */
|
reached 0x7ffff, we can no longer trust it */
|
||||||
if(num_recorded_frames == 0x7ffff)
|
if(num_recorded_frames == 0x7ffff)
|
||||||
num_recorded_frames = 0;
|
num_recorded_frames = 0;
|
||||||
|
|
||||||
/* Read the first MP3 frame from the recorded stream */
|
/* Read the first MP3 frame from the recorded stream */
|
||||||
lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE, SEEK_SET);
|
lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE, SEEK_SET);
|
||||||
read(mpeg_file, &saved_header, 4);
|
read(mpeg_file, &saved_header, 4);
|
||||||
|
|
||||||
framelen = create_xing_header(mpeg_file, 0, num_rec_bytes,
|
framelen = create_xing_header(mpeg_file, 0,
|
||||||
mp3buf, num_recorded_frames,
|
num_rec_bytes, mp3buf,
|
||||||
saved_header, NULL, false);
|
num_recorded_frames,
|
||||||
|
saved_header, NULL,
|
||||||
lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen,
|
false);
|
||||||
SEEK_SET);
|
|
||||||
write(mpeg_file, mp3buf, framelen);
|
lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen,
|
||||||
close(mpeg_file);
|
SEEK_SET);
|
||||||
|
write(mpeg_file, mp3buf, framelen);
|
||||||
|
close(mpeg_file);
|
||||||
|
}
|
||||||
mpeg_file = -1;
|
mpeg_file = -1;
|
||||||
|
|
||||||
#ifdef DEBUG1
|
#ifdef DEBUG1
|
||||||
|
|
@ -1933,9 +1954,105 @@ static void mpeg_thread(void)
|
||||||
#endif
|
#endif
|
||||||
mpeg_stop_done = true;
|
mpeg_stop_done = true;
|
||||||
break;
|
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:
|
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
|
/* If the result is negative, the write index has
|
||||||
wrapped */
|
wrapped */
|
||||||
|
|
@ -1954,8 +2071,6 @@ static void mpeg_thread(void)
|
||||||
amount_to_save < MPEG_RECORDING_LOW_WATER ||
|
amount_to_save < MPEG_RECORDING_LOW_WATER ||
|
||||||
stop_pending)
|
stop_pending)
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Only save up to the end of the buffer */
|
/* Only save up to the end of the buffer */
|
||||||
writelen = MIN(amount_to_save,
|
writelen = MIN(amount_to_save,
|
||||||
mp3buflen - mp3buf_read);
|
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;
|
mp3buf_read += amount_to_save;
|
||||||
if(mp3buf_read >= mp3buflen)
|
if(mp3buf_read >= mp3buflen)
|
||||||
mp3buf_read = 0;
|
mp3buf_read = 0;
|
||||||
|
|
||||||
|
rc = fsync(mpeg_file);
|
||||||
|
if(rc < 0)
|
||||||
|
panicf("rec fls: %d", rc);
|
||||||
|
|
||||||
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
|
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -2257,6 +2372,7 @@ void mpeg_record(char *filename)
|
||||||
recording_filename[MAX_PATH - 1] = 0;
|
recording_filename[MAX_PATH - 1] = 0;
|
||||||
|
|
||||||
num_rec_bytes = 0;
|
num_rec_bytes = 0;
|
||||||
|
disable_xing_header = false;
|
||||||
queue_post(&mpeg_queue, MPEG_RECORD, NULL);
|
queue_post(&mpeg_queue, MPEG_RECORD, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2311,6 +2427,21 @@ static void stop_recording(void)
|
||||||
drain_dma_buffer();
|
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)
|
unsigned long mpeg_recorded_time(void)
|
||||||
{
|
{
|
||||||
if(is_recording)
|
if(is_recording)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue