summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2005-09-04 21:55:15 +0000
committerJens Arnold <amiconn@rockbox.org>2005-09-04 21:55:15 +0000
commit9352ac86680a2507b657c141029d831447f1bed8 (patch)
treeaab63cecd6cf9a6198c8d3fea202f41b63569668 /firmware
parentb7caf5ba6321b7a42bab113b571c5968ac3af064 (diff)
downloadrockbox-9352ac86680a2507b657c141029d831447f1bed8.tar.gz
rockbox-9352ac86680a2507b657c141029d831447f1bed8.tar.bz2
rockbox-9352ac86680a2507b657c141029d831447f1bed8.zip
Archos recording: Always prepend ID3V2 and Xing header to a recording file, even with prerecording and file splitting. Adjusted Xing header creation to create smaller headers. Fixed missing break; in the mpeg thread.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7472 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/mp3data.h2
-rw-r--r--firmware/export/mpeg.h2
-rw-r--r--firmware/mp3data.c39
-rw-r--r--firmware/mpeg.c312
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 {
#define VBR_TOC_FLAG 0x04
#define VBR_QUALITY_FLAG 0x08
+#define MAX_XING_HEADER_SIZE 288
+
unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header);
unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset,
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 @@
#define MPEG_MAX_PRERECORD_SECONDS 30
/* For ID3 info and VBR header */
-#define MPEG_RESERVED_HEADER_SPACE (4096 + 1500)
+#define MPEG_RESERVED_HEADER_SPACE (4096 + 288)
#if (CONFIG_CODEC == MAS3587F) || defined(SIMULATOR)
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,
static const char cooltext[] = "Rockbox - rocks your box";
int create_xing_header(int fd, int startpos, int filesize,
- unsigned char *buf, int num_frames,
- unsigned long header_template,
+ unsigned char *buf, /* must be at least 288 bytes */
+ int num_frames, unsigned long header_template,
void (*progressfunc)(int), bool generate_toc)
{
unsigned long header = 0;
@@ -691,35 +691,40 @@ int create_xing_header(int fd, int startpos, int filesize,
last_pos = pos;
}
}
-
- /* Use the template header and create a new one.
- We ignore the Protection bit even if the rest of the stream is
- protected. (fixme?) */
- header = xing_header_template & ~(BITRATE_MASK | PROTECTION_MASK);
- header |= 8 << 12; /* This gives us plenty of space, at least 192 bytes */
-
- if (!mp3headerinfo(&info, header))
- return 0; /* invalid header */
+
+ /* Check the template header for validity and get some preliminary info. */
+ if (!mp3headerinfo(&info, xing_header_template))
+ return 0; /* invalid header */
/* Clear the frame */
- memset(buf, 0, 1500);
+ memset(buf, 0, MAX_XING_HEADER_SIZE);
- /* Write the header to the buffer */
- long2bytes(buf, header);
-
- /* calculate position of VBR header */
- if ( info.version == MPEG_VERSION1 ) {
+ /* Use the template header and create a new one. */
+ header = xing_header_template & ~(BITRATE_MASK | PROTECTION_MASK);
+
+ /* Calculate position of VBR header and required frame bitrate */
+ if (info.version == MPEG_VERSION1) {
+ header |= 5 << 12;
if (info.channel_mode == 3) /* mono */
index = 21;
else
index = 36;
}
else {
+ if (info.version == MPEG_VERSION2)
+ header |= 8 << 12;
+ else /* MPEG_VERSION2_5 */
+ header |= 4 << 12;
if (info.channel_mode == 3) /* mono */
index = 13;
else
index = 21;
}
+ mp3headerinfo(&info, header); /* Get final header info */
+ /* Size is now always one of 192, 208 or 288 bytes */
+
+ /* Write the header to the buffer */
+ long2bytes(buf, header);
/* Create the Xing data */
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);
extern int playlist_amount(void);
extern int playlist_update_resume_info(const struct mp3entry* id3);
-#define MPEG_PLAY 1
-#define MPEG_STOP 2
-#define MPEG_PAUSE 3
-#define MPEG_RESUME 4
-#define MPEG_NEXT 5
-#define MPEG_PREV 6
-#define MPEG_FF_REWIND 7
-#define MPEG_FLUSH_RELOAD 8
-#define MPEG_RECORD 9
-#define MPEG_INIT_RECORDING 10
-#define MPEG_INIT_PLAYBACK 11
-#define MPEG_NEW_FILE 12
-#define MPEG_PAUSE_RECORDING 13
-#define MPEG_RESUME_RECORDING 14
-#define MPEG_NEED_DATA 100
-#define MPEG_TRACK_CHANGE 101
-#define MPEG_SAVE_DATA 102
-#define MPEG_STOP_DONE 103
+#define MPEG_PLAY 1
+#define MPEG_STOP 2
+#define MPEG_PAUSE 3
+#define MPEG_RESUME 4
+#define MPEG_NEXT 5
+#define MPEG_PREV 6
+#define MPEG_FF_REWIND 7
+#define MPEG_FLUSH_RELOAD 8
+#define MPEG_RECORD 9
+#define MPEG_INIT_RECORDING 10
+#define MPEG_INIT_PLAYBACK 11
+#define MPEG_NEW_FILE 12
+#define MPEG_PAUSE_RECORDING 13
+#define MPEG_RESUME_RECORDING 14
+#define MPEG_NEED_DATA 100
+#define MPEG_TRACK_CHANGE 101
+#define MPEG_SAVE_DATA 102
+#define MPEG_STOP_DONE 103
+#define MPEG_PRERECORDING_TICK 104
/* indicator for MPEG_NEED_DATA */
#define GENERATE_UNBUFFER_EVENTS ((void*)1)
@@ -155,12 +156,13 @@ static long lowest_watermark_level; /* Debug value to observe the buffer
static char recording_filename[MAX_PATH]; /* argument to thread */
static char delayed_filename[MAX_PATH]; /* internal copy of above */
+static char xing_buffer[MAX_XING_HEADER_SIZE];
+
static bool init_recording_done;
static bool init_playback_done;
static bool prerecording; /* True if prerecording is enabled */
static bool is_prerecording; /* True if we are prerecording */
static bool is_recording; /* We are recording */
-static bool disable_xing_header; /* When splitting files */
static enum {
NOT_SAVING = 0, /* reasons to save data, sorted by importance */
@@ -172,8 +174,12 @@ static enum {
static int rec_frequency_index; /* For create_xing_header() calls */
static int rec_version_index; /* For create_xing_header() calls */
-static int prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS];
- /* Array of buffer indexes for each prerecorded second */
+struct prerecord_info {
+ int mempos;
+ unsigned long framecount;
+};
+
+static struct prerecord_info prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS];
static int prerecord_index; /* Current index in the prerecord buffer */
static int prerecording_max_seconds; /* Max number of seconds to store */
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
unsigned long pause_start_time; /* Value of current_tick when pause was
started */
static unsigned long num_rec_bytes;
-static unsigned long num_recorded_frames;
+static unsigned long last_rec_bytes;
+static unsigned long frame_count_start;
+static unsigned long frame_count_end;
+static unsigned long saved_header = 0;
/* Shadow MAS registers */
unsigned long shadow_encoder_control = 0;
@@ -213,6 +222,8 @@ static int get_unswapped_space(void);
#if CONFIG_CODEC == MAS3587F
static void init_recording(void);
+static void prepend_header(void);
+static void update_header(void);
static void start_prerecording(void);
static void start_recording(void);
static void stop_recording(void);
@@ -745,17 +756,8 @@ void rec_tick(void)
if(TIME_AFTER(current_tick, prerecord_timeout))
{
prerecord_timeout = current_tick + HZ;
-
- /* Store the write pointer every second */
- prerecord_buffer[prerecord_index++] = audiobuf_write;
-
- /* Wrap if necessary */
- if(prerecord_index == prerecording_max_seconds)
- prerecord_index = 0;
-
- /* Update the number of seconds recorded */
- if(prerecord_count < prerecording_max_seconds)
- prerecord_count++;
+ queue_post(&mpeg_queue, MPEG_PRERECORDING_TICK, 0);
+ wake_up_thread();
}
}
else
@@ -1164,10 +1166,9 @@ static void mpeg_thread(void)
int start_offset;
#if CONFIG_CODEC == MAS3587F
int amount_to_save;
- int framelen;
- unsigned long saved_header = 0;
int save_endpos = 0;
int rc;
+ int level;
long offset;
#endif /* CONFIG_CODEC == MAS3587F */
@@ -1749,26 +1750,25 @@ static void mpeg_thread(void)
switch(ev.id)
{
case MPEG_RECORD:
- if(is_prerecording)
+ if (is_prerecording)
{
- int startpos, i;
- int level;
-
+ int startpos;
+
/* Go back prerecord_count seconds in the buffer */
startpos = prerecord_index - prerecord_count;
if(startpos < 0)
startpos += prerecording_max_seconds;
- /* Read the mp3 buffer pointer from the prerecord
- buffer */
- startpos = prerecord_buffer[startpos];
+ /* Read the position data from the prerecord buffer */
+ frame_count_start = prerecord_buffer[startpos].framecount;
+ startpos = prerecord_buffer[startpos].mempos;
DEBUGF("Start looking at address %x (%x)\n",
audiobuf+startpos, startpos);
saved_header = mpeg_get_last_header();
- mem_find_next_frame(startpos, &offset, 5000,
+ mem_find_next_frame(startpos, &offset, 1800,
saved_header);
audiobuf_read = startpos + offset;
@@ -1781,58 +1781,17 @@ static void mpeg_thread(void)
level = set_irq_level(HIGHEST_IRQ_LEVEL);
num_rec_bytes = get_unsaved_space();
set_irq_level(level);
-
- /* Make room for headers */
- audiobuf_read -= MPEG_RESERVED_HEADER_SPACE;
- if(audiobuf_read < 0)
- {
- /* Clear the bottom half */
- memset(audiobuf, 0,
- audiobuf_read + MPEG_RESERVED_HEADER_SPACE);
-
- /* And the top half */
- audiobuf_read += audiobuflen;
- memset(audiobuf + audiobuf_read, 0,
- audiobuflen - audiobuf_read);
- }
- else
- {
- memset(audiobuf + audiobuf_read, 0,
- MPEG_RESERVED_HEADER_SPACE);
- }
-
- /* Copy the empty ID3 header */
- startpos = audiobuf_read;
- for(i = 0;i < (int)sizeof(empty_id3_header);i++)
- {
- audiobuf[startpos++] = empty_id3_header[i];
- if(startpos == audiobuflen)
- startpos = 0;
- }
-
- DEBUGF("New audiobuf_read address (reservation): %x\n",
- audiobuf+audiobuf_read);
-
- DEBUGF("Prerecording...\n");
}
else
{
- reset_mp3_buffer();
-
+ frame_count_start = 0;
num_rec_bytes = 0;
-
- /* Advance the write pointer to make
- room for an ID3 tag plus a VBR header */
+ audiobuf_read = MPEG_RESERVED_HEADER_SPACE;
audiobuf_write = MPEG_RESERVED_HEADER_SPACE;
- memset(audiobuf, 0, MPEG_RESERVED_HEADER_SPACE);
-
- /* Insert the ID3 header */
- memcpy(audiobuf, empty_id3_header,
- sizeof(empty_id3_header));
-
- DEBUGF("Recording...\n");
}
+ prepend_header();
+ DEBUGF("Recording...\n");
start_recording();
/* Wait until at least one frame is encoded and get the
@@ -1840,7 +1799,7 @@ static void mpeg_thread(void)
generation */
sleep(HZ/5);
saved_header = mpeg_get_last_header();
-
+
/* delayed until buffer is saved, don't open yet */
strcpy(delayed_filename, recording_filename);
mpeg_file = -1;
@@ -1863,40 +1822,9 @@ static void mpeg_thread(void)
if (mpeg_file >= 0)
close(mpeg_file);
-
- if (!disable_xing_header && num_rec_bytes > 0)
- {
- /* 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;
-
- /* Also, if we have been prerecording, the frame count
- will be wrong */
- if (prerecording)
- num_recorded_frames = 0;
-
- /* saved_header is saved right before stopping
- the MAS */
- framelen = create_xing_header(mpeg_file, 0,
- num_rec_bytes, audiobuf,
- num_recorded_frames,
- saved_header, NULL,
- false);
-
- lseek(mpeg_file, MPEG_RESERVED_HEADER_SPACE-framelen,
- SEEK_SET);
- write(mpeg_file, audiobuf, framelen);
- close(mpeg_file);
- }
mpeg_file = -1;
+ update_header();
#ifdef DEBUG1
{
int i;
@@ -1934,37 +1862,41 @@ static void mpeg_thread(void)
amount_to_save = get_unsaved_space();
}
+ mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT,
+ &frame_count_end, 1);
+
+ /* capture all values at one point */
+ level = set_irq_level(HIGHEST_IRQ_LEVEL);
+ save_endpos = audiobuf_write;
+ last_rec_bytes = num_rec_bytes;
+ num_rec_bytes = 0;
+ set_irq_level(level);
+
if (amount_to_save >= 1800)
{
/* Now find a frame boundary to split at */
- save_endpos = audiobuf_write - 1800;
+ save_endpos -= 1800;
if (save_endpos < 0)
save_endpos += audiobuflen;
rc = mem_find_next_frame(save_endpos, &offset, 1800,
saved_header);
- if (rc) /* Header found? */
- {
- /* offset will now contain the number of bytes to
- add to startpos to find the frame boundary */
- save_endpos += offset;
- if (save_endpos >= audiobuflen)
- save_endpos -= audiobuflen;
- }
- else
- {
- /* No header found. Let's save the whole buffer. */
- save_endpos = audiobuf_write;
- }
- }
- else
- {
- /* Too few bytes recorded, timeout */
- save_endpos = audiobuf_write;
+ if (!rc) /* No header found, save whole buffer */
+ offset = 1800;
+
+ save_endpos += offset;
+ if (save_endpos >= audiobuflen)
+ save_endpos -= audiobuflen;
+
+ last_rec_bytes += offset - 1800;
+ level = set_irq_level(HIGHEST_IRQ_LEVEL);
+ num_rec_bytes += 1800 - offset;
+ set_irq_level(level);
}
saving_status = NEW_FILE;
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
+ break;
case MPEG_SAVE_DATA:
if (saving_status == BUFFER_FULL)
@@ -2025,18 +1957,22 @@ static void mpeg_thread(void)
/* Close the current file */
rc = close(mpeg_file);
if (rc < 0)
- panicf("spt cls: %d", rc);
- ata_sleep();
+ panicf("rec cls: %d", rc);
mpeg_file = -1;
+ update_header();
+ ata_sleep();
+
/* copy new filename */
strcpy(delayed_filename, recording_filename);
+ prepend_header();
+ frame_count_start = frame_count_end;
break;
case STOP_RECORDING:
queue_post(&mpeg_queue, MPEG_STOP_DONE, NULL);
/* will close the file */
break;
-
+
default:
break;
}
@@ -2046,6 +1982,24 @@ static void mpeg_thread(void)
queue_post(&mpeg_queue, MPEG_SAVE_DATA, 0);
break;
+
+ case MPEG_PRERECORDING_TICK:
+ if(!is_prerecording)
+ break;
+
+ /* Store the write pointer every second */
+ prerecord_buffer[prerecord_index].mempos = audiobuf_write;
+ mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT,
+ &prerecord_buffer[prerecord_index].framecount, 1);
+
+ /* Wrap if necessary */
+ if(++prerecord_index == prerecording_max_seconds)
+ prerecord_index = 0;
+
+ /* Update the number of seconds recorded */
+ if(prerecord_count < prerecording_max_seconds)
+ prerecord_count++;
+ break;
case MPEG_INIT_PLAYBACK:
/* Stop the prerecording */
@@ -2257,7 +2211,6 @@ void mpeg_record(const char *filename)
strncpy(recording_filename, filename, MAX_PATH - 1);
recording_filename[MAX_PATH - 1] = 0;
- disable_xing_header = false;
queue_post(&mpeg_queue, MPEG_RECORD, NULL);
}
@@ -2271,6 +2224,64 @@ void mpeg_resume_recording(void)
queue_post(&mpeg_queue, MPEG_RESUME_RECORDING, NULL);
}
+static void prepend_header(void)
+{
+ int startpos;
+ unsigned i;
+
+ /* Make room for header */
+ audiobuf_read -= MPEG_RESERVED_HEADER_SPACE;
+ if(audiobuf_read < 0)
+ {
+ /* Clear the bottom half */
+ memset(audiobuf, 0, audiobuf_read + MPEG_RESERVED_HEADER_SPACE);
+
+ /* And the top half */
+ audiobuf_read += audiobuflen;
+ memset(audiobuf + audiobuf_read, 0, audiobuflen - audiobuf_read);
+ }
+ else
+ {
+ memset(audiobuf + audiobuf_read, 0, MPEG_RESERVED_HEADER_SPACE);
+ }
+ /* Copy the empty ID3 header */
+ startpos = audiobuf_read;
+ for(i = 0; i < sizeof(empty_id3_header); i++)
+ {
+ audiobuf[startpos++] = empty_id3_header[i];
+ if(startpos == audiobuflen)
+ startpos = 0;
+ }
+}
+
+static void update_header(void)
+{
+ int fd, framelen;
+ unsigned long frames;
+
+ if (last_rec_bytes > 0)
+ {
+ /* Create the Xing header */
+ fd = open(delayed_filename, O_RDWR);
+ if (fd < 0)
+ panicf("rec upd: %d (%s)", fd, recording_filename);
+
+ frames = frame_count_end - frame_count_start;
+ /* If the number of recorded frames has reached 0x7ffff,
+ we can no longer trust it */
+ if (frame_count_end == 0x7ffff)
+ frames = 0;
+
+ /* saved_header is saved right before stopping the MAS */
+ framelen = create_xing_header(fd, 0, last_rec_bytes, xing_buffer,
+ frames, saved_header, NULL, false);
+
+ lseek(fd, MPEG_RESERVED_HEADER_SPACE - framelen, SEEK_SET);
+ write(fd, xing_buffer, framelen);
+ close(fd);
+ }
+}
+
static void start_prerecording(void)
{
unsigned long val;
@@ -2306,8 +2317,6 @@ static void start_recording(void)
{
unsigned long val;
- num_recorded_frames = 0;
-
if(is_prerecording)
{
/* This will make the IRQ handler start recording
@@ -2386,9 +2395,9 @@ static void stop_recording(void)
is_recording = false;
is_prerecording = false;
-
- /* Read the number of frames recorded */
- mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &num_recorded_frames, 1);
+
+ last_rec_bytes = num_rec_bytes;
+ mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count_end, 1);
/* Start monitoring */
shadow_io_control_main |= (1 << 10);
@@ -2514,9 +2523,6 @@ void mpeg_new_file(const char *filename)
strncpy(recording_filename, filename, MAX_PATH - 1);
recording_filename[MAX_PATH - 1] = 0;
- num_rec_bytes = 0;
- disable_xing_header = true;
-
/* Store the current time */
record_start_time = current_tick;
if(paused)
@@ -2554,7 +2560,7 @@ unsigned long mpeg_num_recorded_bytes(void)
if(index < 0)
index += prerecording_max_seconds;
- num_bytes = audiobuf_write - prerecord_buffer[index];
+ num_bytes = audiobuf_write - prerecord_buffer[index].mempos;
if(num_bytes < 0)
num_bytes += audiobuflen;