diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2013-07-04 05:27:29 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2013-07-09 06:28:33 -0400 |
commit | 95bc93194e18d1f5c7bf49683bcbe1b6ecc2a073 (patch) | |
tree | 58e0c3b1063191ebf7246b8361ad484ef9aaaaf5 /lib/rbcodec/codecs/wavpack_enc.c | |
parent | 08e466ff92a367bc54b0cf13585ca0b5d94ddd6c (diff) | |
download | rockbox-95bc93194e18d1f5c7bf49683bcbe1b6ecc2a073.tar.gz rockbox-95bc93194e18d1f5c7bf49683bcbe1b6ecc2a073.zip |
Multithread compressing encoders on multicore targets.
For mp3_enc, split encoding duties between COP and CPU.
For wavpack_enc, simply run the encoding on COP (splitting that one
needs more consideration) which keeps the it and the UI from running
on the same core.
As a result, at least they are now useable on PP at "normal" sample
rates.
mp3_enc in all this gets an extensive renovation and some optimizations
for speed, to reduce IRAM requirements and remove unneeded stuff.
Change-Id: I215578dbe36f14e516b05a5ca70880eb01ca0ec2
Diffstat (limited to 'lib/rbcodec/codecs/wavpack_enc.c')
-rw-r--r-- | lib/rbcodec/codecs/wavpack_enc.c | 125 |
1 files changed, 116 insertions, 9 deletions
diff --git a/lib/rbcodec/codecs/wavpack_enc.c b/lib/rbcodec/codecs/wavpack_enc.c index 864012b4cd..ffb090f6ec 100644 --- a/lib/rbcodec/codecs/wavpack_enc.c +++ b/lib/rbcodec/codecs/wavpack_enc.c | |||
@@ -25,6 +25,10 @@ | |||
25 | 25 | ||
26 | CODEC_ENC_HEADER | 26 | CODEC_ENC_HEADER |
27 | 27 | ||
28 | #if NUM_CORES > 1 | ||
29 | #define WAVPACK_ENC_COP | ||
30 | #endif | ||
31 | |||
28 | /** Types **/ | 32 | /** Types **/ |
29 | typedef struct | 33 | typedef struct |
30 | { | 34 | { |
@@ -74,13 +78,24 @@ struct wvpk_chunk_data | |||
74 | /** Data **/ | 78 | /** Data **/ |
75 | static int32_t input_buffer[PCM_SAMP_PER_CHUNK*2] IBSS_ATTR; | 79 | static int32_t input_buffer[PCM_SAMP_PER_CHUNK*2] IBSS_ATTR; |
76 | 80 | ||
81 | #ifdef WAVPACK_ENC_COP | ||
82 | #if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 | ||
83 | /* Not enough for IRAM */ | ||
84 | static uint8_t output_buffer[PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*2*110/100] | ||
85 | SHAREDBSS_ATTR MEM_ALIGN_ATTR; | ||
86 | #else | ||
87 | static uint8_t output_buffer[PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*2*110/100] | ||
88 | IBSS_ATTR MEM_ALIGN_ATTR; | ||
89 | #endif | ||
90 | #endif /* WAVPACK_ENC_COP */ | ||
91 | |||
77 | static WavpackConfig config IBSS_ATTR; | 92 | static WavpackConfig config IBSS_ATTR; |
78 | static WavpackContext *wpc; | 93 | static WavpackContext *wpc IBSS_ATTR; |
79 | static uint32_t sample_rate; | 94 | static uint32_t sample_rate IBSS_ATTR; |
80 | static int num_channels; | 95 | static int num_channels IBSS_ATTR; |
81 | static uint32_t total_samples; | 96 | static uint32_t total_samples IBSS_ATTR; |
82 | static size_t out_reqsize; | 97 | static size_t out_reqsize IBSS_ATTR; |
83 | static size_t frame_size; | 98 | static size_t frame_size IBSS_ATTR; |
84 | 99 | ||
85 | static const WavpackMetadataHeader wvpk_mdh = | 100 | static const WavpackMetadataHeader wvpk_mdh = |
86 | { | 101 | { |
@@ -230,6 +245,89 @@ static int on_stream_end(void) | |||
230 | return 0; | 245 | return 0; |
231 | } | 246 | } |
232 | 247 | ||
248 | static inline uint32_t encode_block_(uint8_t *outbuf) | ||
249 | { | ||
250 | if (WavpackStartBlock(wpc, outbuf, outbuf + out_reqsize) && | ||
251 | WavpackPackSamples(wpc, input_buffer, PCM_SAMP_PER_CHUNK)) | ||
252 | return WavpackFinishBlock(wpc); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | #ifdef WAVPACK_ENC_COP | ||
258 | /* This is to relieve CPU of encoder load since it has other significant tasks | ||
259 | to perform when recording. It is not written to provide parallelism within | ||
260 | the codec. */ | ||
261 | static const char enc_thread_name[] = { "Wavpack enc" }; | ||
262 | static bool quit IBSS_ATTR; | ||
263 | static uint32_t out_size IBSS_ATTR; | ||
264 | static struct semaphore enc_sema IBSS_ATTR; | ||
265 | static struct semaphore cod_sema IBSS_ATTR; | ||
266 | static unsigned int enc_thread_id; | ||
267 | |||
268 | static void ICODE_ATTR enc_thread(void) | ||
269 | { | ||
270 | while (1) | ||
271 | { | ||
272 | ci->semaphore_wait(&enc_sema, TIMEOUT_BLOCK); | ||
273 | |||
274 | if (quit) | ||
275 | break; | ||
276 | |||
277 | out_size = encode_block_(output_buffer); | ||
278 | |||
279 | ci->semaphore_release(&cod_sema); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | static inline bool enc_thread_init(void *stack, size_t stack_size) | ||
284 | { | ||
285 | quit = false; | ||
286 | ci->semaphore_init(&enc_sema, 1, 0); | ||
287 | ci->semaphore_init(&cod_sema, 1, 0); | ||
288 | |||
289 | enc_thread_id = ci->create_thread(enc_thread, stack, stack_size, | ||
290 | 0, enc_thread_name | ||
291 | IF_PRIO(, PRIORITY_PLAYBACK) | ||
292 | IF_COP(, COP)); | ||
293 | |||
294 | return enc_thread_id != 0; | ||
295 | } | ||
296 | |||
297 | static inline void enc_thread_stop(void) | ||
298 | { | ||
299 | quit = true; | ||
300 | ci->semaphore_release(&enc_sema); | ||
301 | ci->thread_wait(enc_thread_id); | ||
302 | } | ||
303 | |||
304 | static inline uint32_t encode_block(uint8_t *outbuf) | ||
305 | { | ||
306 | ci->semaphore_release(&enc_sema); | ||
307 | ci->semaphore_wait(&cod_sema, TIMEOUT_BLOCK); | ||
308 | ci->memcpy(outbuf, output_buffer, out_size); | ||
309 | return out_size; | ||
310 | } | ||
311 | |||
312 | #else /* !WAVPACK_ENC_COP */ | ||
313 | |||
314 | static inline uint32_t encode_block(uint8_t *outbuf) | ||
315 | { | ||
316 | return encode_block_(outbuf); | ||
317 | } | ||
318 | |||
319 | static inline bool enc_thread_init(void *stack, size_t stack_size) | ||
320 | { | ||
321 | return true; | ||
322 | (void)stack; (void)stack_size; | ||
323 | } | ||
324 | |||
325 | static inline void enc_thread_stop(void) | ||
326 | { | ||
327 | } | ||
328 | |||
329 | #endif /* WAVPACK_ENC_COP */ | ||
330 | |||
233 | /* this is the codec entry point */ | 331 | /* this is the codec entry point */ |
234 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 332 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
235 | { | 333 | { |
@@ -242,6 +340,13 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) | |||
242 | /* this is called for each file to process */ | 340 | /* this is called for each file to process */ |
243 | enum codec_status codec_run(void) | 341 | enum codec_status codec_run(void) |
244 | { | 342 | { |
343 | /* Encoder thread stack goes on our stack - leave 4k for us | ||
344 | Will be optimized away when single-threaded */ | ||
345 | uint32_t enc_stack[(DEFAULT_STACK_SIZE+0x1000) / sizeof(uint32_t)]; | ||
346 | |||
347 | if (!enc_thread_init(enc_stack, sizeof (enc_stack))) | ||
348 | return CODEC_ERROR; | ||
349 | |||
245 | enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; | 350 | enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; |
246 | struct enc_chunk_data *data = NULL; | 351 | struct enc_chunk_data *data = NULL; |
247 | 352 | ||
@@ -269,11 +374,12 @@ enum codec_status codec_run(void) | |||
269 | 374 | ||
270 | input_buffer_to_int32(frame_size); | 375 | input_buffer_to_int32(frame_size); |
271 | 376 | ||
272 | if (WavpackStartBlock(wpc, data->data, data->data + out_reqsize) && | 377 | uint32_t size = encode_block(data->data); |
273 | WavpackPackSamples(wpc, input_buffer, PCM_SAMP_PER_CHUNK)) | 378 | |
379 | if (size) | ||
274 | { | 380 | { |
275 | /* finish the chunk and store chunk size info */ | 381 | /* finish the chunk and store chunk size info */ |
276 | data->hdr.size = WavpackFinishBlock(wpc); | 382 | data->hdr.size = size; |
277 | data->pcm_count = PCM_SAMP_PER_CHUNK; | 383 | data->pcm_count = PCM_SAMP_PER_CHUNK; |
278 | } | 384 | } |
279 | else | 385 | else |
@@ -285,6 +391,7 @@ enum codec_status codec_run(void) | |||
285 | ci->enc_encbuf_finish_buffer(); | 391 | ci->enc_encbuf_finish_buffer(); |
286 | } | 392 | } |
287 | 393 | ||
394 | enc_thread_stop(); | ||
288 | return CODEC_OK; | 395 | return CODEC_OK; |
289 | } | 396 | } |
290 | 397 | ||