summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2007-05-07 17:23:31 +0000
committerDave Chapman <dave@dchapman.com>2007-05-07 17:23:31 +0000
commit7cdd0fe6ea8561a94862f0b0dd53fa8b5a7628e9 (patch)
tree59448bc2cbc66bb7369d87a3864162d90618ba38
parent1feb8bd4a11cdfc552799958ad8539090eec2b74 (diff)
downloadrockbox-7cdd0fe6ea8561a94862f0b0dd53fa8b5a7628e9.tar.gz
rockbox-7cdd0fe6ea8561a94862f0b0dd53fa8b5a7628e9.zip
Initial version of a test_codec plugin (viewer). This loads the audio file into the audio buffer and decodes it as fast as it can via a locally implemented version of the codec API. Intended for use when optimising codecs - so isn't built by default. Remember to add it to both plugins/SOURCES and viewers.config to enable it. Currently the codec is run in the main thread which means mpa.codec doesn't work - it requires more stack than is available on the main thread. The solution will be to create a new thread in the plugin which steals the main codec thread's IRAM stack, but that's not done yet.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13345 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/playback.c3
-rw-r--r--apps/playback.h1
-rw-r--r--apps/plugin.c6
-rw-r--r--apps/plugin.h12
-rw-r--r--apps/plugins/test_codec.c345
5 files changed, 364 insertions, 3 deletions
diff --git a/apps/playback.c b/apps/playback.c
index b26754eb3a..889cf9406e 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -275,7 +275,6 @@ static size_t high_watermark = 0; /* High watermark for rebuffer (A/V/other) */
275 275
276/* Multiple threads */ 276/* Multiple threads */
277static void set_current_codec(int codec_idx); 277static void set_current_codec(int codec_idx);
278static const char *get_codec_filename(int enc_spec); /* (A-/C-/V-) */
279/* Set the watermark to trigger buffer fill (A/C) FIXME */ 278/* Set the watermark to trigger buffer fill (A/C) FIXME */
280static void set_filebuf_watermark(int seconds); 279static void set_filebuf_watermark(int seconds);
281 280
@@ -995,7 +994,7 @@ static void set_filebuf_watermark(int seconds)
995 conf_watermark = bytes; 994 conf_watermark = bytes;
996} 995}
997 996
998static const char * get_codec_filename(int cod_spec) 997const char * get_codec_filename(int cod_spec)
999{ 998{
1000 const char *fname; 999 const char *fname;
1001 1000
diff --git a/apps/playback.h b/apps/playback.h
index 9a8bd10390..eaab4386e0 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -57,6 +57,7 @@ struct track_info {
57}; 57};
58 58
59/* Functions */ 59/* Functions */
60const char * get_codec_filename(int cod_spec);
60void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)); 61void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3));
61void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3, 62void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3,
62 bool last_track)); 63 bool last_track));
diff --git a/apps/plugin.c b/apps/plugin.c
index ea228c454c..9e17c232ce 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -488,6 +488,12 @@ static const struct plugin_api rockbox_api = {
488 spinlock_lock, 488 spinlock_lock,
489 spinlock_unlock, 489 spinlock_unlock,
490#endif 490#endif
491
492#if (CONFIG_CODEC == SWCODEC)
493 codec_load_file,
494 get_metadata,
495 get_codec_filename,
496#endif
491}; 497};
492 498
493int plugin_load(const char* plugin, void* parameter) 499int plugin_load(const char* plugin, void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index 987c07067d..cb8324febe 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -59,6 +59,9 @@
59#include "misc.h" 59#include "misc.h"
60#if (CONFIG_CODEC == SWCODEC) 60#if (CONFIG_CODEC == SWCODEC)
61#include "dsp.h" 61#include "dsp.h"
62#include "codecs.h"
63#include "playback.h"
64#include "metadata.h"
62#ifdef HAVE_RECORDING 65#ifdef HAVE_RECORDING
63#include "recording.h" 66#include "recording.h"
64#endif 67#endif
@@ -110,7 +113,7 @@
110#define PLUGIN_MAGIC 0x526F634B /* RocK */ 113#define PLUGIN_MAGIC 0x526F634B /* RocK */
111 114
112/* increase this every time the api struct changes */ 115/* increase this every time the api struct changes */
113#define PLUGIN_API_VERSION 54 116#define PLUGIN_API_VERSION 55
114 117
115/* update this to latest version if a change to the api struct breaks 118/* update this to latest version if a change to the api struct breaks
116 backwards compatibility (and please take the opportunity to sort in any 119 backwards compatibility (and please take the opportunity to sort in any
@@ -602,6 +605,13 @@ struct plugin_api {
602 void (*spinlock_lock)(struct mutex *m); 605 void (*spinlock_lock)(struct mutex *m);
603 void (*spinlock_unlock)(struct mutex *m); 606 void (*spinlock_unlock)(struct mutex *m);
604#endif 607#endif
608
609#if (CONFIG_CODEC == SWCODEC)
610 int (*codec_load_file)(const char* codec, struct codec_api *api);
611 bool (*get_metadata)(struct track_info* track, int fd, const char* trackname,
612 bool v1first);
613 const char *(*get_codec_filename)(int cod_spec);
614#endif
605}; 615};
606 616
607/* plugin header */ 617/* plugin header */
diff --git a/apps/plugins/test_codec.c b/apps/plugins/test_codec.c
new file mode 100644
index 0000000000..56d59b3ab3
--- /dev/null
+++ b/apps/plugins/test_codec.c
@@ -0,0 +1,345 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2007 Dave Chapman
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
21PLUGIN_HEADER
22
23static struct plugin_api* rb;
24
25static void* audiobuf;
26static void* codec_mallocbuf;
27static size_t audiosize;
28static char str[40];
29
30/* Our local implementation of the codec API */
31static struct codec_api ci;
32
33
34static struct track_info track;
35
36static bool taginfo_ready = true;
37
38
39/* Returns buffer to malloc array. Only codeclib should need this. */
40static void* get_codec_memory(size_t *size)
41{
42 DEBUGF("get_codec_memory(%d)\n",(int)size);
43 *size = 512*1024;
44 return codec_mallocbuf;
45}
46
47
48/* Insert PCM data into audio buffer for playback. Playback will start
49 automatically. */
50static bool pcmbuf_insert(const void *ch1, const void *ch2, int count)
51{
52 /* Always successful - just discard data */
53 (void)ch1;
54 (void)ch2;
55 (void)count;
56
57 return true;
58}
59
60
61static unsigned int prev_value = 0;
62
63/* Set song position in WPS (value in ms). */
64static void set_elapsed(unsigned int value)
65{
66 if ((value - prev_value) > 2000)
67 {
68 rb->snprintf(str,sizeof(str),"%d of %d",value,(int)track.id3.length);
69 rb->lcd_puts(0,0,str);
70 rb->lcd_update();
71 prev_value = value;
72 }
73}
74
75
76/* Read next <size> amount bytes from file buffer to <ptr>.
77 Will return number of bytes read or 0 if end of file. */
78static size_t read_filebuf(void *ptr, size_t size)
79{
80 DEBUGF("read_filebuf(_,%d)\n",(int)size);
81 if (ci.curpos > (off_t)track.filesize)
82 {
83 return 0;
84 } else {
85 /* TODO: Don't read beyond end of buffer */
86 rb->memcpy(ptr, audiobuf + ci.curpos, size);
87 ci.curpos += size;
88 DEBUGF("New ci.curpos = %d\n",ci.curpos);
89 return size;
90 }
91}
92
93
94/* Request pointer to file buffer which can be used to read
95 <realsize> amount of data. <reqsize> tells the buffer system
96 how much data it should try to allocate. If <realsize> is 0,
97 end of file is reached. */
98static void* request_buffer(size_t *realsize, size_t reqsize)
99{
100 *realsize = MIN(track.filesize-ci.curpos,reqsize);
101
102 return (audiobuf + ci.curpos);
103}
104
105
106/* Advance file buffer position by <amount> amount of bytes. */
107static void advance_buffer(size_t amount)
108{
109 ci.curpos += amount;
110 DEBUGF("advance_buffer(%d) - new ci.curpos=%d\n",(int)amount,(int)ci.curpos);
111}
112
113
114/* Advance file buffer to a pointer location inside file buffer. */
115static void advance_buffer_loc(void *ptr)
116{
117 ci.curpos = ptr - audiobuf;
118}
119
120
121/* Seek file buffer to position <newpos> beginning of file. */
122static bool seek_buffer(size_t newpos)
123{
124 ci.curpos = newpos;
125 return true;
126}
127
128
129/* Codec should call this function when it has done the seeking. */
130static void seek_complete(void)
131{
132 /* Do nothing */
133}
134
135
136/* Calculate mp3 seek position from given time data in ms. */
137static off_t mp3_get_filepos(int newtime)
138{
139 /* We don't ask the codec to seek, so no need to implement this. */
140 (void)newtime;
141 return 0;
142}
143
144
145/* Request file change from file buffer. Returns true is next
146 track is available and changed. If return value is false,
147 codec should exit immediately with PLUGIN_OK status. */
148static bool request_next_track(void)
149{
150 /* We are only decoding a single track */
151 return false;
152}
153
154
155/* Free the buffer area of the current codec after its loaded */
156static void discard_codec(void)
157{
158 /* ??? */
159}
160
161
162static void set_offset(size_t value)
163{
164 DEBUGF("set_offset(%d)\n",(int)value);
165 /* ??? */
166 (void)value;
167}
168
169
170/* Configure different codec buffer parameters. */
171static void configure(int setting, intptr_t value)
172{
173 (void)setting;
174 (void)value;
175 DEBUGF("setting %d = %d\n",setting,(int)value);
176}
177
178static void init_ci(void)
179{
180 /* --- Our "fake" implementations of the codec API functions. --- */
181
182 ci.get_codec_memory = get_codec_memory;
183 ci.pcmbuf_insert = pcmbuf_insert;
184 ci.set_elapsed = set_elapsed;
185 ci.read_filebuf = read_filebuf;
186 ci.request_buffer = request_buffer;
187 ci.advance_buffer = advance_buffer;
188 ci.advance_buffer_loc = advance_buffer_loc;
189 ci.seek_buffer = seek_buffer;
190 ci.seek_complete = seek_complete;
191 ci.mp3_get_filepos = mp3_get_filepos;
192 ci.request_next_track = request_next_track;
193 ci.discard_codec = discard_codec;
194 ci.set_offset = set_offset;
195 ci.configure = configure;
196
197 /* --- "Core" functions --- */
198
199 /* kernel/ system */
200 ci.PREFIX(sleep) = rb->PREFIX(sleep);
201 ci.yield = rb->yield;
202
203 /* strings and memory */
204 ci.strcpy = rb->strcpy;
205 ci.strncpy = rb->strncpy;
206 ci.strlen = rb->strlen;
207 ci.strcmp = rb->strcmp;
208 ci.strcat = rb->strcat;
209 ci.memset = rb->memset;
210 ci.memcpy = rb->memcpy;
211 ci.memmove = rb->memmove;
212 ci.memcmp = rb->memcmp;
213 ci.memchr = rb->memchr;
214
215#if defined(DEBUG) || defined(SIMULATOR)
216 ci.debugf = rb->debugf;
217#endif
218#ifdef ROCKBOX_HAS_LOGF
219 ci.logf = rb->logf;
220#endif
221
222 ci.qsort = rb->qsort;
223 ci.global_settings = rb->global_settings;
224
225#ifdef RB_PROFILE
226 ci.profile_thread = rb->profile_thread;
227 ci.profstop = rb->profstop;
228 ci.profile_func_enter = rb->profile_func_enter;
229 ci.profile_func_exit = rb->profile_func_exit;
230#endif
231}
232
233/* plugin entry point */
234enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
235{
236 size_t n;
237 int fd;
238 const char* codecname;
239 int res;
240 unsigned long starttick;
241 unsigned long ticks;
242 unsigned long speed;
243 unsigned long duration;
244
245 rb = api;
246
247 if (parameter == NULL)
248 {
249 rb->splash(HZ*2, "No File");
250 return PLUGIN_ERROR;
251 }
252
253 codec_mallocbuf = rb->plugin_get_audio_buffer(&audiosize);
254 audiobuf = codec_mallocbuf + 512*1024;
255 audiosize -= 512*1024;
256
257 fd = rb->open(parameter,O_RDONLY);
258 if (fd < 0)
259 {
260 rb->splash(HZ*2, "Cannot open file");
261 return PLUGIN_ERROR;
262 }
263
264 track.filesize = rb->filesize(fd);
265
266 if (!rb->get_metadata(&track, fd, parameter,
267 rb->global_settings->id3_v1_first))
268 {
269 rb->splash(HZ*2, "Cannot read metadata");
270 return PLUGIN_ERROR;
271 }
272
273 if (track.filesize > audiosize)
274 {
275 rb->splash(HZ*2, "File too large");
276 return PLUGIN_ERROR;
277 }
278
279 rb->splash(0, "Loading...");
280
281 n = rb->read(fd, audiobuf, track.filesize);
282
283 if (n != track.filesize)
284 {
285 rb->splash(HZ*2, "Read failed.");
286 return PLUGIN_ERROR;
287 }
288
289 /* Initialise the function pointers in the codec API */
290 init_ci();
291
292 /* Prepare the codec struct for playing the whole file */
293 ci.filesize = track.filesize;
294 ci.id3 = &track.id3;
295 ci.taginfo_ready = &taginfo_ready;
296 ci.curpos = 0;
297 ci.stop_codec = false;
298 ci.new_track = 0;
299 ci.seek_time = 0;
300
301 codecname = rb->get_codec_filename(track.id3.codectype);
302
303#ifdef HAVE_ADJUSTABLE_CPU_FREQ
304 rb->cpu_boost(true);
305#endif
306 rb->lcd_set_backdrop(NULL);
307 rb->lcd_set_foreground(LCD_WHITE);
308 rb->lcd_set_background(LCD_BLACK);
309 rb->lcd_clear_display();
310 rb->lcd_update();
311
312 starttick = *rb->current_tick;
313
314 /* Load the codec and start decoding. */
315 res = rb->codec_load_file(codecname,&ci);
316
317
318 /* Display benchmark information */
319
320 ticks = *rb->current_tick - starttick;
321 rb->snprintf(str,sizeof(str),"Decode time - %d.%02ds",(int)ticks/100,(int)ticks%100);
322 rb->lcd_puts(0,1,str);
323
324 duration = track.id3.length / 10;
325 rb->snprintf(str,sizeof(str),"File duration - %d.%02ds",(int)duration/100,(int)duration%100);
326 rb->lcd_puts(0,2,str);
327
328 if (ticks > 0)
329 speed = duration * 10000 / ticks;
330 else
331 speed = 0;
332
333 rb->snprintf(str,sizeof(str),"%d.%02d%% realtime",(int)speed/100,(int)speed%100);
334 rb->lcd_puts(0,3,str);
335
336 rb->lcd_update();
337
338 while (rb->button_get(true) != BUTTON_SELECT);
339
340#ifdef HAVE_ADJUSTABLE_CPU_FREQ
341 rb->cpu_boost(false);
342#endif
343
344 return PLUGIN_OK;
345}