summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2005-09-15 05:29:26 +0000
committerJens Arnold <amiconn@rockbox.org>2005-09-15 05:29:26 +0000
commitba966c17614fc2de2b443a82071415b194753aa4 (patch)
tree85b1af551200ab551b4e52a57008ca92ca454e29
parent0c1a2c7651c0727f2a5565e1302f50f64202a9f6 (diff)
downloadrockbox-ba966c17614fc2de2b443a82071415b194753aa4.tar.gz
rockbox-ba966c17614fc2de2b443a82071415b194753aa4.tar.bz2
rockbox-ba966c17614fc2de2b443a82071415b194753aa4.zip
Archos recording/playback: (1) Xing header creation: * Now estimates the framecount from the recording time if the MAS frame counter saturates, so it always writes a valid Xing header. * Reverted my brainless short-xing-header change. This was only valid for layer 3. (2) Xing/VBRI header evaluation: Fixed possible overflow in bitrate calculation. (3) MPEG thread: Avoid double chunk size limiting for the rare case of 8 MB modded Ondios.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7522 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs.h10
-rw-r--r--apps/plugin.h10
-rw-r--r--apps/plugins/vbrfix.c2
-rw-r--r--firmware/export/mp3data.h11
-rw-r--r--firmware/export/mpeg.h2
-rw-r--r--firmware/mp3data.c96
-rw-r--r--firmware/mpeg.c35
7 files changed, 89 insertions, 77 deletions
diff --git a/apps/codecs.h b/apps/codecs.h
index 517d68ba03..d7242a8330 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -79,12 +79,12 @@
#endif
/* increase this every time the api struct changes */
-#define CODEC_API_VERSION 43
+#define CODEC_API_VERSION 44
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
-#define CODEC_MIN_API_VERSION 43
+#define CODEC_MIN_API_VERSION 44
/* codec return codes */
enum codec_status {
@@ -303,9 +303,9 @@ struct codec_api {
bool (*mp3info)(struct mp3entry *entry, const char *filename, bool v1first);
int (*count_mp3_frames)(int fd, int startpos, int filesize,
void (*progressfunc)(int));
- int (*create_xing_header)(int fd, int startpos, int filesize,
- unsigned char *buf, int num_frames,
- unsigned long header_template,
+ int (*create_xing_header)(int fd, long startpos, long filesize,
+ unsigned char *buf, unsigned long num_frames,
+ unsigned long rec_time, unsigned long header_template,
void (*progressfunc)(int), bool generate_toc);
unsigned long (*find_next_frame)(int fd, long *offset,
long max_offset, unsigned long last_header);
diff --git a/apps/plugin.h b/apps/plugin.h
index 01ace98690..5cc9c1b58a 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -89,12 +89,12 @@
#endif
/* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 50
+#define PLUGIN_API_VERSION 51
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 50
+#define PLUGIN_MIN_API_VERSION 51
/* plugin return codes */
enum plugin_status {
@@ -404,9 +404,9 @@ struct plugin_api {
bool (*mp3info)(struct mp3entry *entry, const char *filename, bool v1first);
int (*count_mp3_frames)(int fd, int startpos, int filesize,
void (*progressfunc)(int));
- int (*create_xing_header)(int fd, int startpos, int filesize,
- unsigned char *buf, int num_frames,
- unsigned long header_template,
+ int (*create_xing_header)(int fd, long startpos, long filesize,
+ unsigned char *buf, unsigned long num_frames,
+ unsigned long rec_time, unsigned long header_template,
void (*progressfunc)(int), bool generate_toc);
unsigned long (*find_next_frame)(int fd, long *offset,
long max_offset, unsigned long last_header);
diff --git a/apps/plugins/vbrfix.c b/apps/plugins/vbrfix.c
index b821b9c5fa..ca6b9ca096 100644
--- a/apps/plugins/vbrfix.c
+++ b/apps/plugins/vbrfix.c
@@ -168,7 +168,7 @@ static bool vbr_fix(char *selected_file)
/* Note: We don't need to pass a template header because it will be
taken from the mpeg stream */
framelen = rb->create_xing_header(fd, entry.first_frame_offset,
- flen, xingbuf, num_frames,
+ flen, xingbuf, num_frames, 0,
0, xingupdate, true);
/* Try to fit the Xing header first in the stream. Replace the existing
diff --git a/firmware/export/mp3data.h b/firmware/export/mp3data.h
index 3961664815..f36120a4e5 100644
--- a/firmware/export/mp3data.h
+++ b/firmware/export/mp3data.h
@@ -59,17 +59,18 @@ struct mp3info {
#define VBR_TOC_FLAG 0x04
#define VBR_QUALITY_FLAG 0x08
-#define MAX_XING_HEADER_SIZE 288
+#define MAX_XING_HEADER_SIZE 576
-unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header);
+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);
int get_mp3file_info(int fd, struct mp3info *info);
int count_mp3_frames(int fd, int startpos, int filesize,
void (*progressfunc)(int));
-int create_xing_header(int fd, int startpos, int filesize,
- unsigned char *buf, int num_frames,
- unsigned long header_template,
+int create_xing_header(int fd, long startpos, long filesize,
+ unsigned char *buf, unsigned long num_frames,
+ unsigned long rec_time, unsigned long header_template,
void (*progressfunc)(int), bool generate_toc);
#endif
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h
index a0ad3c405c..a7c9cac321 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 + 288)
+#define MPEG_RESERVED_HEADER_SPACE (4096 + 576)
#if (CONFIG_CODEC == MAS3587F) || defined(SIMULATOR)
void mpeg_init_recording(void);
diff --git a/firmware/mp3data.c b/firmware/mp3data.c
index c2d4cd2c37..519bc60b04 100644
--- a/firmware/mp3data.c
+++ b/firmware/mp3data.c
@@ -406,7 +406,7 @@ int get_mp3file_info(int fd, struct mp3info *info)
/* Is it a VBR file? */
info->is_vbr = info->is_xing_vbr = !memcmp(vbrheader, "Xing", 4);
- if(vbrheader[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
+ if (vbrheader[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
{
info->frame_count = BYTES2INT(vbrheader[i], vbrheader[i+1],
vbrheader[i+2], vbrheader[i+3]);
@@ -417,19 +417,24 @@ int get_mp3file_info(int fd, struct mp3info *info)
i += 4;
}
- if(vbrheader[7] & VBR_BYTES_FLAG) /* Is byte count there? */
+ if (vbrheader[7] & VBR_BYTES_FLAG) /* Is byte count there? */
{
info->byte_count = BYTES2INT(vbrheader[i], vbrheader[i+1],
vbrheader[i+2], vbrheader[i+3]);
i += 4;
}
- if(info->file_time && info->byte_count)
- info->bitrate = info->byte_count * 8 / info->file_time;
+ if (info->file_time && info->byte_count)
+ {
+ if (info->byte_count <= (ULONG_MAX/8))
+ info->bitrate = info->byte_count * 8 / info->file_time;
+ else
+ info->bitrate = info->byte_count / (info->file_time >> 3);
+ }
else
info->bitrate = 0;
-
- if(vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
+
+ if (vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
{
memcpy( info->toc, vbrheader+i, 100 );
i += 100;
@@ -492,7 +497,11 @@ int get_mp3file_info(int fd, struct mp3info *info)
info->file_time = info->frame_count * info->ft_num / info->ft_den;
else
info->file_time = info->frame_count / info->ft_den * info->ft_num;
- info->bitrate = info->byte_count * 8 / info->file_time;
+
+ if (info->byte_count <= (ULONG_MAX/8))
+ info->bitrate = info->byte_count * 8 / info->file_time;
+ else
+ info->bitrate = info->byte_count / (info->file_time >> 3);
/* We don't parse the TOC, since we don't yet know how to (FIXME) */
num_offsets = BYTES2INT(0, 0, vbrheader[18], vbrheader[19]);
@@ -587,37 +596,35 @@ 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, /* must be at least 288 bytes */
- int num_frames, unsigned long header_template,
+/* buf needs to be the audio buffer with TOC generation enabled,
+ and at least MAX_XING_HEADER_SIZE bytes otherwise */
+int create_xing_header(int fd, long startpos, long filesize,
+ unsigned char *buf, unsigned long num_frames,
+ unsigned long rec_time, unsigned long header_template,
void (*progressfunc)(int), bool generate_toc)
-{
- unsigned long header = 0;
+{
struct mp3info info;
- int pos, last_pos;
- int i, j;
- long bytes;
+ unsigned char toc[100];
+ unsigned long header = 0;
+ unsigned long xing_header_template = header_template;
unsigned long filepos;
- int x;
+ long pos, last_pos;
+ long j;
+ long bytes;
+ int i;
int index;
- unsigned char toc[100];
- unsigned long xing_header_template = 0;
DEBUGF("create_xing_header()\n");
- if(header_template)
- xing_header_template = header_template;
-
if(generate_toc)
{
lseek(fd, startpos, SEEK_SET);
buf_init();
-
+
/* Generate filepos table */
last_pos = 0;
filepos = 0;
header = 0;
- x = 0;
for(i = 0;i < 100;i++) {
/* Calculate the absolute frame number for this seek point */
pos = i * num_frames / 100;
@@ -654,7 +661,7 @@ int create_xing_header(int fd, int startpos, int filesize,
* the upper 8 bits of the file position are nonzero
* (i.e. files over 16mb in size).
*/
- if (filepos > 0xFFFFFF)
+ if (filepos > (ULONG_MAX/256))
{
/* instead of multiplying filepos by 256, we divide
* filesize by 256.
@@ -673,46 +680,49 @@ int create_xing_header(int fd, int startpos, int filesize,
}
}
- /* Check the template header for validity and get some preliminary info. */
- if (!mp3headerinfo(&info, xing_header_template))
+ /* Use the template header and create a new one.
+ We ignore the Protection bit even if the rest of the stream is
+ protected. */
+ header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
+ header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
+
+ if (!mp3headerinfo(&info, header))
return 0; /* invalid header */
+ if (num_frames == 0 && rec_time) {
+ /* estimate the number of frames based on the recording time */
+ if (rec_time <= ULONG_MAX / info.ft_den)
+ num_frames = rec_time * info.ft_den / info.ft_num;
+ else
+ num_frames = rec_time / info.ft_num * info.ft_den;
+ }
+
/* Clear the frame */
memset(buf, 0, MAX_XING_HEADER_SIZE);
- /* Use the template header and create a new one. */
- header = xing_header_template & ~(BITRATE_MASK | PROTECTION_MASK);
+ /* Write the header to the buffer */
+ long2bytes(buf, header);
- /* Calculate position of VBR header and required frame bitrate */
+ /* Calculate position of VBR header */
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);
- long2bytes(&buf[index+4], ((num_frames?VBR_FRAMES_FLAG:0) |
- (filesize?VBR_BYTES_FLAG:0) |
- (generate_toc?VBR_TOC_FLAG:0)));
- index = index+8;
+ long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
+ | (filesize ? VBR_BYTES_FLAG : 0)
+ | (generate_toc ? VBR_TOC_FLAG : 0));
+ index += 8;
if(num_frames)
{
long2bytes(&buf[index], num_frames);
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index 8d2d13b6ee..9d1aa3b9d6 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -190,6 +190,7 @@ unsigned long record_start_time; /* Value of current_tick when recording
was started */
unsigned long pause_start_time; /* Value of current_tick when pause was
started */
+static unsigned long last_rec_time;
static unsigned long num_rec_bytes;
static unsigned long last_rec_bytes;
static unsigned long frame_count_start;
@@ -1611,12 +1612,11 @@ static void mpeg_thread(void)
/* Don't read more than until the end of the buffer */
amount_to_read = MIN(audiobuflen - audiobuf_write,
amount_to_read);
-#if MEM == 8
- amount_to_read = MIN(0x100000, amount_to_read);
-#endif /* MEM == 8 */
#ifdef HAVE_MMC /* MMC is slow, so don't read too large chunks */
amount_to_read = MIN(0x40000, amount_to_read);
-#endif /* HAVE_MMC */
+#elif MEM == 8
+ amount_to_read = MIN(0x100000, amount_to_read);
+#endif
/* Read as much mpeg data as we can fit in the buffer */
if(mpeg_file >= 0)
@@ -1810,7 +1810,7 @@ static void mpeg_thread(void)
DEBUGF("MPEG_STOP\n");
stop_recording();
-
+
/* Save the remaining data in the buffer */
save_endpos = audiobuf_write;
saving_status = STOP_RECORDING;
@@ -1848,7 +1848,7 @@ static void mpeg_thread(void)
case MPEG_NEW_FILE:
/* Bail out when a more important save is happening */
- if (saving_status > NEW_FILE)
+ if (saving_status > NEW_FILE)
break;
/* Make sure we have at least one complete frame
@@ -1865,6 +1865,11 @@ static void mpeg_thread(void)
mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT,
&frame_count_end, 1);
+ last_rec_time = current_tick - record_start_time;
+ record_start_time = current_tick;
+ if (paused)
+ pause_start_time = record_start_time;
+
/* capture all values at one point */
level = set_irq_level(HIGHEST_IRQ_LEVEL);
save_endpos = audiobuf_write;
@@ -1916,11 +1921,10 @@ static void mpeg_thread(void)
amount_to_save = MIN(amount_to_save,
audiobuflen - audiobuf_read);
-#if MEM == 8
- amount_to_save = MIN(0x100000, amount_to_save);
-#endif
#ifdef HAVE_MMC /* MMC is slow, so don't save too large chunks at once */
amount_to_save = MIN(0x40000, amount_to_save);
+#elif MEM == 8
+ amount_to_save = MIN(0x100000, amount_to_save);
#endif
rc = write(mpeg_file, audiobuf + audiobuf_read,
amount_to_save);
@@ -2210,7 +2214,7 @@ void mpeg_record(const char *filename)
strncpy(recording_filename, filename, MAX_PATH - 1);
recording_filename[MAX_PATH - 1] = 0;
-
+
queue_post(&mpeg_queue, MPEG_RECORD, NULL);
}
@@ -2274,7 +2278,8 @@ static void update_header(void)
/* 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);
+ frames, last_rec_time * (1000/HZ),
+ saved_header, NULL, false);
lseek(fd, MPEG_RESERVED_HEADER_SPACE - framelen, SEEK_SET);
write(fd, xing_buffer, framelen);
@@ -2350,7 +2355,7 @@ static void start_recording(void)
record_start_time = current_tick;
pause_start_time = 0;
-
+
demand_irq_enable(true);
}
@@ -2398,6 +2403,7 @@ static void stop_recording(void)
last_rec_bytes = num_rec_bytes;
mas_readmem(MAS_BANK_D0, MAS_D0_MPEG_FRAME_COUNT, &frame_count_end, 1);
+ last_rec_time = current_tick - record_start_time;
/* Start monitoring */
shadow_io_control_main |= (1 << 10);
@@ -2524,11 +2530,6 @@ void mpeg_new_file(const char *filename)
strncpy(recording_filename, filename, MAX_PATH - 1);
recording_filename[MAX_PATH - 1] = 0;
- /* Store the current time */
- record_start_time = current_tick;
- if(paused)
- pause_start_time = record_start_time;
-
queue_post(&mpeg_queue, MPEG_NEW_FILE, NULL);
}