summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/plugin.c16
-rw-r--r--apps/plugin.h20
-rw-r--r--apps/plugins/Makefile2
-rw-r--r--apps/plugins/vbrfix.c280
-rw-r--r--apps/plugins/viewers.config1
5 files changed, 312 insertions, 7 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index c7758afbcf..8d8d25fc99 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -21,6 +21,7 @@
21#include <stdio.h> 21#include <stdio.h>
22#include <atoi.h> 22#include <atoi.h>
23#include <timefuncs.h> 23#include <timefuncs.h>
24#include "debug.h"
24#include "button.h" 25#include "button.h"
25#include "lcd.h" 26#include "lcd.h"
26#include "dir.h" 27#include "dir.h"
@@ -39,6 +40,7 @@
39#include "backlight.h" 40#include "backlight.h"
40#include "ata.h" 41#include "ata.h"
41#include "talk.h" 42#include "talk.h"
43#include "mp3data.h"
42 44
43#ifdef HAVE_LCD_BITMAP 45#ifdef HAVE_LCD_BITMAP
44#include "widgets.h" 46#include "widgets.h"
@@ -48,11 +50,10 @@
48 #include <debug.h> 50 #include <debug.h>
49 #ifdef WIN32 51 #ifdef WIN32
50 #include "plugin-win32.h" 52 #include "plugin-win32.h"
51 #define PREFIX(_x_) _x_
52 #else 53 #else
53 #include <dlfcn.h> 54 #include <dlfcn.h>
54 #define PREFIX(_x_) x11_ ## _x_
55 #endif 55 #endif
56 #define PREFIX(_x_) sim_ ## _x_
56#else 57#else
57#define PREFIX(_x_) _x_ 58#define PREFIX(_x_) _x_
58#endif 59#endif
@@ -213,6 +214,12 @@ static struct plugin_api rockbox_api = {
213#ifdef HAVE_LCD_BITMAP 214#ifdef HAVE_LCD_BITMAP
214 font_get, 215 font_get,
215#endif 216#endif
217#if defined(DEBUG) || defined(SIMULATOR)
218 debugf,
219#endif
220 mp3info,
221 count_mp3_frames,
222 create_xing_header,
216}; 223};
217 224
218int plugin_load(char* plugin, void* parameter) 225int plugin_load(char* plugin, void* parameter)
@@ -246,11 +253,8 @@ int plugin_load(char* plugin, void* parameter)
246 lcd_clear_display(); 253 lcd_clear_display();
247#endif 254#endif
248#ifdef SIMULATOR 255#ifdef SIMULATOR
249#ifdef WIN32
250 snprintf(path, sizeof path, "%s", plugin);
251#else
252 snprintf(path, sizeof path, "archos%s", plugin); 256 snprintf(path, sizeof path, "archos%s", plugin);
253#endif 257
254 pd = dlopen(path, RTLD_NOW); 258 pd = dlopen(path, RTLD_NOW);
255 if (!pd) { 259 if (!pd) {
256 snprintf(buf, sizeof buf, "Can't open %s", plugin); 260 snprintf(buf, sizeof buf, "Can't open %s", plugin);
diff --git a/apps/plugin.h b/apps/plugin.h
index f539c3ef3a..c67f49ebda 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -45,6 +45,16 @@
45#include "settings.h" 45#include "settings.h"
46#include "thread.h" 46#include "thread.h"
47 47
48#ifdef PLUGIN
49#if defined(DEBUG) || defined(SIMULATOR)
50#define DEBUGF rb->debugf
51#define LDEBUGF rb->debugf
52#else
53#define DEBUGF(...)
54#define LDEBUGF(...)
55#endif
56#endif
57
48/* increase this every time the api struct changes */ 58/* increase this every time the api struct changes */
49#define PLUGIN_API_VERSION 14 59#define PLUGIN_API_VERSION 14
50 60
@@ -235,6 +245,16 @@ struct plugin_api {
235#ifdef HAVE_LCD_BITMAP 245#ifdef HAVE_LCD_BITMAP
236 struct font* (*font_get)(int font); 246 struct font* (*font_get)(int font);
237#endif 247#endif
248#if defined(DEBUG) || defined(SIMULATOR)
249 void (*debugf)(char *fmt, ...);
250#endif
251 bool (*mp3info)(struct mp3entry *entry, char *filename) ;
252 int (*count_mp3_frames)(int fd, int startpos, int filesize,
253 void (*progressfunc)(int));
254 int (*create_xing_header)(int fd, int startpos, int filesize,
255 unsigned char *buf, int num_frames,
256 unsigned long header_template,
257 void (*progressfunc)(int), bool generate_toc);
238}; 258};
239 259
240/* defined by the plugin loader (plugin.c) */ 260/* defined by the plugin loader (plugin.c) */
diff --git a/apps/plugins/Makefile b/apps/plugins/Makefile
index 367103be67..1c703f2573 100644
--- a/apps/plugins/Makefile
+++ b/apps/plugins/Makefile
@@ -15,7 +15,7 @@ FIRMWARE = ../../firmware
15INCLUDES = -I$(FIRMWARE)/include -I$(FIRMWARE)/export -I$(FIRMWARE)/common \ 15INCLUDES = -I$(FIRMWARE)/include -I$(FIRMWARE)/export -I$(FIRMWARE)/common \
16-I$(FIRMWARE)/drivers -I.. -Ilib 16-I$(FIRMWARE)/drivers -I.. -Ilib
17CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes \ 17CFLAGS = -O -W -Wall -m1 -nostdlib -ffreestanding -Wstrict-prototypes \
18$(INCLUDES) $(TARGET) $(EXTRA_DEFINES) -DMEM=${MEM} 18$(INCLUDES) $(TARGET) $(EXTRA_DEFINES) -DMEM=${MEM} -DPLUGIN
19 19
20LDS := plugin.lds 20LDS := plugin.lds
21LINKFILE := $(OBJDIR)/pluginlink.lds 21LINKFILE := $(OBJDIR)/pluginlink.lds
diff --git a/apps/plugins/vbrfix.c b/apps/plugins/vbrfix.c
new file mode 100644
index 0000000000..1beca2669d
--- /dev/null
+++ b/apps/plugins/vbrfix.c
@@ -0,0 +1,280 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "plugin.h"
20
21static struct plugin_api* rb;
22
23static char *mp3buf;
24static int mp3buflen;
25
26static void xingupdate(int percent)
27{
28 char buf[32];
29
30 rb->snprintf(buf, 32, "%d%%", percent);
31 rb->lcd_puts(0, 1, buf);
32#ifdef HAVE_LCD_BITMAP
33 rb->lcd_update();
34#endif
35}
36
37static int insert_data_in_file(char *fname, int fpos, char *buf, int num_bytes)
38{
39 int readlen;
40 int rc;
41 int orig_fd, fd;
42 char tmpname[MAX_PATH];
43
44 rb->snprintf(tmpname, MAX_PATH, "%s.tmp", fname);
45
46 orig_fd = rb->open(fname, O_RDONLY);
47 if(orig_fd < 0) {
48 return 10*orig_fd - 1;
49 }
50
51 fd = rb->creat(tmpname, O_WRONLY);
52 if(fd < 0) {
53 rb->close(orig_fd);
54 return 10*fd - 2;
55 }
56
57 /* First, copy the initial portion (the ID3 tag) */
58 if(fpos) {
59 readlen = rb->read(orig_fd, mp3buf, fpos);
60 if(readlen < 0) {
61 rb->close(fd);
62 rb->close(orig_fd);
63 return 10*readlen - 3;
64 }
65
66 rc = rb->write(fd, mp3buf, readlen);
67 if(rc < 0) {
68 rb->close(fd);
69 rb->close(orig_fd);
70 return 10*rc - 4;
71 }
72 }
73
74 /* Now insert the data into the file */
75 rc = rb->write(fd, buf, num_bytes);
76 if(rc < 0) {
77 rb->close(orig_fd);
78 rb->close(fd);
79 return 10*rc - 5;
80 }
81
82 /* Copy the file */
83 do {
84 readlen = rb->read(orig_fd, mp3buf, mp3buflen);
85 if(readlen < 0) {
86 rb->close(fd);
87 rb->close(orig_fd);
88 return 10*readlen - 7;
89 }
90
91 rc = rb->write(fd, mp3buf, readlen);
92 if(rc < 0) {
93 rb->close(fd);
94 rb->close(orig_fd);
95 return 10*rc - 8;
96 }
97 } while(readlen > 0);
98
99 rb->close(fd);
100 rb->close(orig_fd);
101
102 /* Remove the old file */
103 rc = rb->remove(fname);
104 if(rc < 0) {
105 return 10*rc - 9;
106 }
107
108 /* Replace the old file with the new */
109 rc = rb->rename(tmpname, fname);
110 if(rc < 0) {
111 return 10*rc - 9;
112 }
113
114 return 0;
115}
116
117static void fileerror(int rc)
118{
119 rb->splash(HZ*2, true, "File error: %d", rc);
120}
121
122static const unsigned char empty_id3_header[] =
123{
124 'I', 'D', '3', 0x04, 0x00, 0x00,
125 0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */
126};
127
128static bool vbr_fix(char *selected_file)
129{
130 unsigned char xingbuf[1500];
131 struct mp3entry entry;
132 int fd;
133 int rc;
134 int flen;
135 int num_frames;
136 int numbytes;
137 int framelen;
138 int unused_space;
139
140 rb->lcd_clear_display();
141 rb->lcd_puts_scroll(0, 0, selected_file);
142#ifdef HAVE_LCD_BITMAP
143 rb->lcd_update();
144#endif
145
146 xingupdate(0);
147
148 rc = rb->mp3info(&entry, selected_file);
149 if(rc < 0) {
150 fileerror(rc);
151 return true;
152 }
153
154 fd = rb->open(selected_file, O_RDWR);
155 if(fd < 0) {
156 fileerror(fd);
157 return true;
158 }
159
160 flen = rb->lseek(fd, 0, SEEK_END);
161
162 xingupdate(0);
163
164 num_frames = rb->count_mp3_frames(fd, entry.first_frame_offset,
165 flen, xingupdate);
166
167 if(num_frames) {
168 /* Note: We don't need to pass a template header because it will be
169 taken from the mpeg stream */
170 framelen = rb->create_xing_header(fd, entry.first_frame_offset,
171 flen, xingbuf, num_frames,
172 0, xingupdate, true);
173
174 /* Try to fit the Xing header first in the stream. Replace the existing
175 VBR header if there is one, else see if there is room between the
176 ID3 tag and the first MP3 frame. */
177 if(entry.first_frame_offset - entry.id3v2len >=
178 (unsigned int)framelen) {
179 DEBUGF("Using existing space between ID3 and first frame\n");
180
181 /* Seek to the beginning of the unused space */
182 rc = rb->lseek(fd, entry.id3v2len, SEEK_SET);
183 if(rc < 0) {
184 rb->close(fd);
185 fileerror(rc);
186 return true;
187 }
188
189 unused_space =
190 entry.first_frame_offset - entry.id3v2len - framelen;
191
192 /* Fill the unused space with 0's (using the MP3 buffer)
193 and write it to the file */
194 if(unused_space)
195 {
196 rb->memset(mp3buf, 0, unused_space);
197 rc = rb->write(fd, mp3buf, unused_space);
198 if(rc < 0) {
199 rb->close(fd);
200 fileerror(rc);
201 return true;
202 }
203 }
204
205 /* Then write the Xing header */
206 rc = rb->write(fd, xingbuf, framelen);
207 if(rc < 0) {
208 rb->close(fd);
209 fileerror(rc);
210 return true;
211 }
212
213 rb->close(fd);
214 } else {
215 /* If not, insert some space. If there is an ID3 tag in the
216 file we only insert just enough to squeeze the Xing header
217 in. If not, we insert an additional empty ID3 tag of 4K. */
218
219 rb->close(fd);
220
221 /* Nasty trick alert! The insert_data_in_file() function
222 uses the MP3 buffer when copying the data. We assume
223 that the ID3 tag isn't longer than 1MB so the xing
224 buffer won't be overwritten. */
225
226 if(entry.first_frame_offset) {
227 DEBUGF("Inserting %d bytes\n", framelen);
228 numbytes = framelen;
229 } else {
230 DEBUGF("Inserting 4096+%d bytes\n", framelen);
231 numbytes = 4096 + framelen;
232
233 rb->memset(mp3buf + 0x100000, 0, numbytes);
234
235 /* Insert the ID3 header */
236 rb->memcpy(mp3buf + 0x100000, empty_id3_header,
237 sizeof(empty_id3_header));
238 }
239
240 /* Copy the Xing header */
241 rb->memcpy(mp3buf + 0x100000 + numbytes - framelen,
242 xingbuf, framelen);
243
244 rc = insert_data_in_file(selected_file,
245 entry.first_frame_offset,
246 mp3buf + 0x100000, numbytes);
247
248 if(rc < 0) {
249 fileerror(rc);
250 return true;
251 }
252 }
253
254 xingupdate(100);
255 }
256 else
257 {
258 /* Not a VBR file */
259 DEBUGF("Not a VBR file\n");
260 rb->splash(HZ*2, true, "Not a VBR file");
261 }
262
263 return false;
264}
265
266enum plugin_status plugin_start(struct plugin_api* api, void *parameter)
267{
268 TEST_PLUGIN_API(api);
269
270 rb = api;
271
272 if (!parameter)
273 return PLUGIN_ERROR;
274
275 mp3buf = rb->plugin_get_mp3_buffer(&mp3buflen);
276
277 vbr_fix(parameter);
278
279 return PLUGIN_OK;
280}
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config
index ad1e696957..2acbe17af3 100644
--- a/apps/plugins/viewers.config
+++ b/apps/plugins/viewers.config
@@ -3,3 +3,4 @@ txt,viewer.rock,55 55 55 55 55 55
3jpg,jpeg.rock,18 24 3C 3C 24 18 3jpg,jpeg.rock,18 24 3C 3C 24 18
4ucl,rockbox_flash.rock,2A 7F 41 41 7F 2A 4ucl,rockbox_flash.rock,2A 7F 41 41 7F 2A
5rvf,video.rock,5D 7F 5D 7F 5D 7F 5rvf,video.rock,5D 7F 5D 7F 5D 7F
6mp3,vbrfix.rock,10 08 58 38 04 02