forked from len0rd/rockbox
Finally, the archos directory sandbox works in the same way for both X11 and win32 simulators. Unfortunately, this breaks the VC++ compatibility. Also, the plugin API now supports DEBUGF. Last, but not least, we have a new plugin, vbrfix.rock.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4726 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
5fc1b64ae0
commit
a6142ab7ab
21 changed files with 415 additions and 397 deletions
280
apps/plugins/vbrfix.c
Normal file
280
apps/plugins/vbrfix.c
Normal file
|
@ -0,0 +1,280 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2004 Linus Nielsen Feltzing
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "plugin.h"
|
||||
|
||||
static struct plugin_api* rb;
|
||||
|
||||
static char *mp3buf;
|
||||
static int mp3buflen;
|
||||
|
||||
static void xingupdate(int percent)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
rb->snprintf(buf, 32, "%d%%", percent);
|
||||
rb->lcd_puts(0, 1, buf);
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
rb->lcd_update();
|
||||
#endif
|
||||
}
|
||||
|
||||
static int insert_data_in_file(char *fname, int fpos, char *buf, int num_bytes)
|
||||
{
|
||||
int readlen;
|
||||
int rc;
|
||||
int orig_fd, fd;
|
||||
char tmpname[MAX_PATH];
|
||||
|
||||
rb->snprintf(tmpname, MAX_PATH, "%s.tmp", fname);
|
||||
|
||||
orig_fd = rb->open(fname, O_RDONLY);
|
||||
if(orig_fd < 0) {
|
||||
return 10*orig_fd - 1;
|
||||
}
|
||||
|
||||
fd = rb->creat(tmpname, O_WRONLY);
|
||||
if(fd < 0) {
|
||||
rb->close(orig_fd);
|
||||
return 10*fd - 2;
|
||||
}
|
||||
|
||||
/* First, copy the initial portion (the ID3 tag) */
|
||||
if(fpos) {
|
||||
readlen = rb->read(orig_fd, mp3buf, fpos);
|
||||
if(readlen < 0) {
|
||||
rb->close(fd);
|
||||
rb->close(orig_fd);
|
||||
return 10*readlen - 3;
|
||||
}
|
||||
|
||||
rc = rb->write(fd, mp3buf, readlen);
|
||||
if(rc < 0) {
|
||||
rb->close(fd);
|
||||
rb->close(orig_fd);
|
||||
return 10*rc - 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now insert the data into the file */
|
||||
rc = rb->write(fd, buf, num_bytes);
|
||||
if(rc < 0) {
|
||||
rb->close(orig_fd);
|
||||
rb->close(fd);
|
||||
return 10*rc - 5;
|
||||
}
|
||||
|
||||
/* Copy the file */
|
||||
do {
|
||||
readlen = rb->read(orig_fd, mp3buf, mp3buflen);
|
||||
if(readlen < 0) {
|
||||
rb->close(fd);
|
||||
rb->close(orig_fd);
|
||||
return 10*readlen - 7;
|
||||
}
|
||||
|
||||
rc = rb->write(fd, mp3buf, readlen);
|
||||
if(rc < 0) {
|
||||
rb->close(fd);
|
||||
rb->close(orig_fd);
|
||||
return 10*rc - 8;
|
||||
}
|
||||
} while(readlen > 0);
|
||||
|
||||
rb->close(fd);
|
||||
rb->close(orig_fd);
|
||||
|
||||
/* Remove the old file */
|
||||
rc = rb->remove(fname);
|
||||
if(rc < 0) {
|
||||
return 10*rc - 9;
|
||||
}
|
||||
|
||||
/* Replace the old file with the new */
|
||||
rc = rb->rename(tmpname, fname);
|
||||
if(rc < 0) {
|
||||
return 10*rc - 9;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fileerror(int rc)
|
||||
{
|
||||
rb->splash(HZ*2, true, "File error: %d", rc);
|
||||
}
|
||||
|
||||
static const unsigned char empty_id3_header[] =
|
||||
{
|
||||
'I', 'D', '3', 0x04, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */
|
||||
};
|
||||
|
||||
static bool vbr_fix(char *selected_file)
|
||||
{
|
||||
unsigned char xingbuf[1500];
|
||||
struct mp3entry entry;
|
||||
int fd;
|
||||
int rc;
|
||||
int flen;
|
||||
int num_frames;
|
||||
int numbytes;
|
||||
int framelen;
|
||||
int unused_space;
|
||||
|
||||
rb->lcd_clear_display();
|
||||
rb->lcd_puts_scroll(0, 0, selected_file);
|
||||
#ifdef HAVE_LCD_BITMAP
|
||||
rb->lcd_update();
|
||||
#endif
|
||||
|
||||
xingupdate(0);
|
||||
|
||||
rc = rb->mp3info(&entry, selected_file);
|
||||
if(rc < 0) {
|
||||
fileerror(rc);
|
||||
return true;
|
||||
}
|
||||
|
||||
fd = rb->open(selected_file, O_RDWR);
|
||||
if(fd < 0) {
|
||||
fileerror(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
flen = rb->lseek(fd, 0, SEEK_END);
|
||||
|
||||
xingupdate(0);
|
||||
|
||||
num_frames = rb->count_mp3_frames(fd, entry.first_frame_offset,
|
||||
flen, xingupdate);
|
||||
|
||||
if(num_frames) {
|
||||
/* 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,
|
||||
0, xingupdate, true);
|
||||
|
||||
/* Try to fit the Xing header first in the stream. Replace the existing
|
||||
VBR header if there is one, else see if there is room between the
|
||||
ID3 tag and the first MP3 frame. */
|
||||
if(entry.first_frame_offset - entry.id3v2len >=
|
||||
(unsigned int)framelen) {
|
||||
DEBUGF("Using existing space between ID3 and first frame\n");
|
||||
|
||||
/* Seek to the beginning of the unused space */
|
||||
rc = rb->lseek(fd, entry.id3v2len, SEEK_SET);
|
||||
if(rc < 0) {
|
||||
rb->close(fd);
|
||||
fileerror(rc);
|
||||
return true;
|
||||
}
|
||||
|
||||
unused_space =
|
||||
entry.first_frame_offset - entry.id3v2len - framelen;
|
||||
|
||||
/* Fill the unused space with 0's (using the MP3 buffer)
|
||||
and write it to the file */
|
||||
if(unused_space)
|
||||
{
|
||||
rb->memset(mp3buf, 0, unused_space);
|
||||
rc = rb->write(fd, mp3buf, unused_space);
|
||||
if(rc < 0) {
|
||||
rb->close(fd);
|
||||
fileerror(rc);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Then write the Xing header */
|
||||
rc = rb->write(fd, xingbuf, framelen);
|
||||
if(rc < 0) {
|
||||
rb->close(fd);
|
||||
fileerror(rc);
|
||||
return true;
|
||||
}
|
||||
|
||||
rb->close(fd);
|
||||
} else {
|
||||
/* If not, insert some space. If there is an ID3 tag in the
|
||||
file we only insert just enough to squeeze the Xing header
|
||||
in. If not, we insert an additional empty ID3 tag of 4K. */
|
||||
|
||||
rb->close(fd);
|
||||
|
||||
/* Nasty trick alert! The insert_data_in_file() function
|
||||
uses the MP3 buffer when copying the data. We assume
|
||||
that the ID3 tag isn't longer than 1MB so the xing
|
||||
buffer won't be overwritten. */
|
||||
|
||||
if(entry.first_frame_offset) {
|
||||
DEBUGF("Inserting %d bytes\n", framelen);
|
||||
numbytes = framelen;
|
||||
} else {
|
||||
DEBUGF("Inserting 4096+%d bytes\n", framelen);
|
||||
numbytes = 4096 + framelen;
|
||||
|
||||
rb->memset(mp3buf + 0x100000, 0, numbytes);
|
||||
|
||||
/* Insert the ID3 header */
|
||||
rb->memcpy(mp3buf + 0x100000, empty_id3_header,
|
||||
sizeof(empty_id3_header));
|
||||
}
|
||||
|
||||
/* Copy the Xing header */
|
||||
rb->memcpy(mp3buf + 0x100000 + numbytes - framelen,
|
||||
xingbuf, framelen);
|
||||
|
||||
rc = insert_data_in_file(selected_file,
|
||||
entry.first_frame_offset,
|
||||
mp3buf + 0x100000, numbytes);
|
||||
|
||||
if(rc < 0) {
|
||||
fileerror(rc);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
xingupdate(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not a VBR file */
|
||||
DEBUGF("Not a VBR file\n");
|
||||
rb->splash(HZ*2, true, "Not a VBR file");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
enum plugin_status plugin_start(struct plugin_api* api, void *parameter)
|
||||
{
|
||||
TEST_PLUGIN_API(api);
|
||||
|
||||
rb = api;
|
||||
|
||||
if (!parameter)
|
||||
return PLUGIN_ERROR;
|
||||
|
||||
mp3buf = rb->plugin_get_mp3_buffer(&mp3buflen);
|
||||
|
||||
vbr_fix(parameter);
|
||||
|
||||
return PLUGIN_OK;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue