1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Michael Sevakis 2013-07-04 05:27:29 -04:00
parent 08e466ff92
commit 95bc93194e
2 changed files with 2272 additions and 1776 deletions

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,10 @@
CODEC_ENC_HEADER CODEC_ENC_HEADER
#if NUM_CORES > 1
#define WAVPACK_ENC_COP
#endif
/** Types **/ /** Types **/
typedef struct typedef struct
{ {
@ -74,13 +78,24 @@ struct wvpk_chunk_data
/** Data **/ /** Data **/
static int32_t input_buffer[PCM_SAMP_PER_CHUNK*2] IBSS_ATTR; static int32_t input_buffer[PCM_SAMP_PER_CHUNK*2] IBSS_ATTR;
#ifdef WAVPACK_ENC_COP
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002
/* Not enough for IRAM */
static uint8_t output_buffer[PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*2*110/100]
SHAREDBSS_ATTR MEM_ALIGN_ATTR;
#else
static uint8_t output_buffer[PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*2*110/100]
IBSS_ATTR MEM_ALIGN_ATTR;
#endif
#endif /* WAVPACK_ENC_COP */
static WavpackConfig config IBSS_ATTR; static WavpackConfig config IBSS_ATTR;
static WavpackContext *wpc; static WavpackContext *wpc IBSS_ATTR;
static uint32_t sample_rate; static uint32_t sample_rate IBSS_ATTR;
static int num_channels; static int num_channels IBSS_ATTR;
static uint32_t total_samples; static uint32_t total_samples IBSS_ATTR;
static size_t out_reqsize; static size_t out_reqsize IBSS_ATTR;
static size_t frame_size; static size_t frame_size IBSS_ATTR;
static const WavpackMetadataHeader wvpk_mdh = static const WavpackMetadataHeader wvpk_mdh =
{ {
@ -230,6 +245,89 @@ static int on_stream_end(void)
return 0; return 0;
} }
static inline uint32_t encode_block_(uint8_t *outbuf)
{
if (WavpackStartBlock(wpc, outbuf, outbuf + out_reqsize) &&
WavpackPackSamples(wpc, input_buffer, PCM_SAMP_PER_CHUNK))
return WavpackFinishBlock(wpc);
return 0;
}
#ifdef WAVPACK_ENC_COP
/* This is to relieve CPU of encoder load since it has other significant tasks
to perform when recording. It is not written to provide parallelism within
the codec. */
static const char enc_thread_name[] = { "Wavpack enc" };
static bool quit IBSS_ATTR;
static uint32_t out_size IBSS_ATTR;
static struct semaphore enc_sema IBSS_ATTR;
static struct semaphore cod_sema IBSS_ATTR;
static unsigned int enc_thread_id;
static void ICODE_ATTR enc_thread(void)
{
while (1)
{
ci->semaphore_wait(&enc_sema, TIMEOUT_BLOCK);
if (quit)
break;
out_size = encode_block_(output_buffer);
ci->semaphore_release(&cod_sema);
}
}
static inline bool enc_thread_init(void *stack, size_t stack_size)
{
quit = false;
ci->semaphore_init(&enc_sema, 1, 0);
ci->semaphore_init(&cod_sema, 1, 0);
enc_thread_id = ci->create_thread(enc_thread, stack, stack_size,
0, enc_thread_name
IF_PRIO(, PRIORITY_PLAYBACK)
IF_COP(, COP));
return enc_thread_id != 0;
}
static inline void enc_thread_stop(void)
{
quit = true;
ci->semaphore_release(&enc_sema);
ci->thread_wait(enc_thread_id);
}
static inline uint32_t encode_block(uint8_t *outbuf)
{
ci->semaphore_release(&enc_sema);
ci->semaphore_wait(&cod_sema, TIMEOUT_BLOCK);
ci->memcpy(outbuf, output_buffer, out_size);
return out_size;
}
#else /* !WAVPACK_ENC_COP */
static inline uint32_t encode_block(uint8_t *outbuf)
{
return encode_block_(outbuf);
}
static inline bool enc_thread_init(void *stack, size_t stack_size)
{
return true;
(void)stack; (void)stack_size;
}
static inline void enc_thread_stop(void)
{
}
#endif /* WAVPACK_ENC_COP */
/* this is the codec entry point */ /* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason) enum codec_status codec_main(enum codec_entry_call_reason reason)
{ {
@ -242,6 +340,13 @@ enum codec_status codec_main(enum codec_entry_call_reason reason)
/* this is called for each file to process */ /* this is called for each file to process */
enum codec_status codec_run(void) enum codec_status codec_run(void)
{ {
/* Encoder thread stack goes on our stack - leave 4k for us
Will be optimized away when single-threaded */
uint32_t enc_stack[(DEFAULT_STACK_SIZE+0x1000) / sizeof(uint32_t)];
if (!enc_thread_init(enc_stack, sizeof (enc_stack)))
return CODEC_ERROR;
enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC;
struct enc_chunk_data *data = NULL; struct enc_chunk_data *data = NULL;
@ -269,11 +374,12 @@ enum codec_status codec_run(void)
input_buffer_to_int32(frame_size); input_buffer_to_int32(frame_size);
if (WavpackStartBlock(wpc, data->data, data->data + out_reqsize) && uint32_t size = encode_block(data->data);
WavpackPackSamples(wpc, input_buffer, PCM_SAMP_PER_CHUNK))
if (size)
{ {
/* finish the chunk and store chunk size info */ /* finish the chunk and store chunk size info */
data->hdr.size = WavpackFinishBlock(wpc); data->hdr.size = size;
data->pcm_count = PCM_SAMP_PER_CHUNK; data->pcm_count = PCM_SAMP_PER_CHUNK;
} }
else else
@ -285,6 +391,7 @@ enum codec_status codec_run(void)
ci->enc_encbuf_finish_buffer(); ci->enc_encbuf_finish_buffer();
} }
enc_thread_stop();
return CODEC_OK; return CODEC_OK;
} }