1
0
Fork 0
forked from len0rd/rockbox

Simplify synchronizaton for MPA codec and make it fully atomic, let synth thread exist for life of codec, do a bit of cleanup and use number of cores do determine if it is compiled as multithread instead of CPU type.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18573 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2008-09-23 08:09:04 +00:00
parent b95dbd21cf
commit 5c903724fb

View file

@ -25,7 +25,7 @@
CODEC_HEADER CODEC_HEADER
#if defined(CPU_PP) && !defined(MPEGPLAYER) #if NUM_CORES > 1 && !defined(MPEGPLAYER)
#define MPA_SYNTH_ON_COP #define MPA_SYNTH_ON_COP
#endif #endif
@ -34,8 +34,7 @@ struct mad_frame frame IBSS_ATTR;
struct mad_synth synth IBSS_ATTR; struct mad_synth synth IBSS_ATTR;
#ifdef MPA_SYNTH_ON_COP #ifdef MPA_SYNTH_ON_COP
volatile short synth_running IBSS_ATTR; /*synthesis is running*/ volatile short die IBSS_ATTR = 0; /*thread should die*/
volatile short die IBSS_ATTR; /*thread should die*/
#if (CONFIG_CPU == PP5024) || (CONFIG_CPU == PP5022) #if (CONFIG_CPU == PP5024) || (CONFIG_CPU == PP5022)
mad_fixed_t sbsample_prev[2][36][32] IBSS_ATTR; mad_fixed_t sbsample_prev[2][36][32] IBSS_ATTR;
@ -68,7 +67,6 @@ void init_mad(void)
#ifdef MPA_SYNTH_ON_COP #ifdef MPA_SYNTH_ON_COP
frame.sbsample_prev = &sbsample_prev; frame.sbsample_prev = &sbsample_prev;
ci->memset(&sbsample_prev, 0, sizeof(sbsample_prev)); ci->memset(&sbsample_prev, 0, sizeof(sbsample_prev));
synth_running=0;
#else #else
frame.sbsample_prev = &sbsample; frame.sbsample_prev = &sbsample;
#endif #endif
@ -208,73 +206,78 @@ static struct thread_entry *mad_synth_thread_p;
static void mad_synth_thread(void){ static void mad_synth_thread(void){
while(1){ while(1){
ci->semaphore_release(&synth_done_sem);
ci->semaphore_wait(&synth_pending_sem); ci->semaphore_wait(&synth_pending_sem);
if(die){ if(die)
die=0; break;
invalidate_icache();
return ;
}
synth_running = 1;
mad_synth_frame(&synth, &frame); mad_synth_frame(&synth, &frame);
synth_running = 0;
ci->semaphore_release(&synth_done_sem);
} }
} }
/* wait for the synth thread to go idle which indicates a PCM frame has been
static int mad_synth_thread_wait_pcm(void){ * synthesized */
static inline void mad_synth_thread_wait_pcm(void){
ci->semaphore_wait(&synth_done_sem); ci->semaphore_wait(&synth_done_sem);
return 0;
} }
/* increment the done semaphore - used after a wait for idle to preserve the
* semaphore count */
static inline void mad_synth_thread_unwait_pcm(void){
ci->semaphore_release(&synth_done_sem);
}
/* after synth thread has gone idle - switch decoded frames and commence
* synthesis on it */
static void mad_synth_thread_ready(void){ static void mad_synth_thread_ready(void){
mad_fixed_t (*temp)[2][36][32]; mad_fixed_t (*temp)[2][36][32];
while(1){
/*check if synth is currently running before changing its inputs! */ /*circular buffer that holds 2 frames' samples*/
if(!synth_running){ temp=frame.sbsample;
/*circular buffer that holds 2 frames' samples*/ frame.sbsample = frame.sbsample_prev;
temp=frame.sbsample; frame.sbsample_prev=temp;
frame.sbsample = frame.sbsample_prev;
frame.sbsample_prev=temp; ci->semaphore_release(&synth_pending_sem);
ci->semaphore_release(&synth_pending_sem);
return ;
}
ci->yield(); /*synth thread currently running, wait for it*/
}
} }
static int mad_synth_thread_create(void){ static bool mad_synth_thread_create(void){
synth_running=0; ci->semaphore_init(&synth_done_sem, 1, 0);
die=0; ci->semaphore_init(&synth_pending_sem, 1, 0);
ci->semaphore_init(&synth_done_sem, 1, 0);
ci->semaphore_init(&synth_pending_sem, 1, 0);
mad_synth_thread_p = ci->create_thread(mad_synth_thread, mad_synth_thread_p = ci->create_thread(mad_synth_thread,
mad_synth_thread_stack, mad_synth_thread_stack,
sizeof(mad_synth_thread_stack), 0, sizeof(mad_synth_thread_stack), 0,
mad_synth_thread_name mad_synth_thread_name
IF_PRIO(, PRIORITY_PLAYBACK), COP); IF_PRIO(, PRIORITY_PLAYBACK)
IF_COP(, COP));
if (mad_synth_thread_p == NULL)
return false;
return true;
if (mad_synth_thread_p == NULL)
return false;
return true;
}
static void mad_synth_thread_quit(void){
/*mop up COP thread*/
die=1;
ci->semaphore_release(&synth_pending_sem);
ci->thread_wait(mad_synth_thread_p);
invalidate_icache();
} }
#else #else
static void mad_synth_thread_ready(void){ static inline void mad_synth_thread_ready(void){
mad_synth_frame(&synth, &frame); mad_synth_frame(&synth, &frame);
} }
static int mad_synth_thread_create(void){ static inline bool mad_synth_thread_create(void){
return 0; return true;
} }
static int mad_synth_thread_wait_pcm(void){ static inline void mad_synth_thread_quit(void){
return 0; }
static inline void mad_synth_thread_wait_pcm(void){
}
static inline void mad_synth_thread_unwait_pcm(void){
} }
#endif #endif
/* this is the codec entry point */ /* this is the codec entry point */
@ -298,12 +301,13 @@ enum codec_status codec_main(void)
/* Create a decoder instance */ /* Create a decoder instance */
ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS);
/*does nothing on 1 processor systems except return true*/
if(!mad_synth_thread_create())
return CODEC_ERROR;
next_track: next_track:
/*does nothing on 1 processor systems*/
mad_synth_thread_create();
status = CODEC_OK; status = CODEC_OK;
/* Reinitializing seems to be necessary to avoid playback quircks when seeking. */ /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */
@ -365,11 +369,10 @@ next_track:
if (ci->seek_time) { if (ci->seek_time) {
int newpos; int newpos;
#ifdef MPA_SYNTH_ON_COP /*make sure the synth thread is idle before seeking - MT only*/
/*make sure the synth thread is idle before seeking*/ mad_synth_thread_wait_pcm();
if(synth_running) mad_synth_thread_unwait_pcm();
mad_synth_thread_wait_pcm();
#endif
samplesdone = ((int64_t)(ci->seek_time-1))*current_frequency/1000; samplesdone = ((int64_t)(ci->seek_time-1))*current_frequency/1000;
if (ci->seek_time-1 == 0) { if (ci->seek_time-1 == 0) {
@ -426,10 +429,10 @@ next_track:
/* Do the pcmbuf insert here. Note, this is the PREVIOUS frame's pcm /* Do the pcmbuf insert here. Note, this is the PREVIOUS frame's pcm
data (not the one just decoded above). When we exit the decoding data (not the one just decoded above). When we exit the decoding
loop we will need to process the final frame that was decoded. */ loop we will need to process the final frame that was decoded. */
mad_synth_thread_wait_pcm();
if (framelength > 0) { if (framelength > 0) {
mad_synth_thread_wait_pcm();
/* In case of a mono file, the second array will be ignored. */ /* In case of a mono file, the second array will be ignored. */
ci->pcmbuf_insert(&synth.pcm.samples[0][samples_to_skip], ci->pcmbuf_insert(&synth.pcm.samples[0][samples_to_skip],
&synth.pcm.samples[1][samples_to_skip], &synth.pcm.samples[1][samples_to_skip],
@ -438,9 +441,9 @@ next_track:
/* Only skip samples for the first frame added. */ /* Only skip samples for the first frame added. */
samples_to_skip = 0; samples_to_skip = 0;
} }
/* Initiate PCM synthesis on the COP (MT) or perform it here (ST) */
mad_synth_thread_ready(); mad_synth_thread_ready();
//mad_synth_frame(&synth, &frame);
/* Check if sample rate and stereo settings changed in this frame. */ /* Check if sample rate and stereo settings changed in this frame. */
if (frame.header.samplerate != current_frequency) { if (frame.header.samplerate != current_frequency) {
@ -474,25 +477,22 @@ next_track:
ci->set_elapsed(samplesdone / (current_frequency / 1000)); ci->set_elapsed(samplesdone / (current_frequency / 1000));
} }
/* wait for synth idle - MT only*/
mad_synth_thread_wait_pcm();
mad_synth_thread_unwait_pcm();
/* Finish the remaining decoded frame. /* Finish the remaining decoded frame.
Cut the required samples from the end. */ Cut the required samples from the end. */
if (framelength > stop_skip){ if (framelength > stop_skip){
mad_synth_thread_wait_pcm();
ci->pcmbuf_insert(synth.pcm.samples[0], synth.pcm.samples[1], ci->pcmbuf_insert(synth.pcm.samples[0], synth.pcm.samples[1],
framelength - stop_skip); framelength - stop_skip);
} }
#ifdef MPA_SYNTH_ON_COP
/*mop up COP thread*/
die=1;
ci->semaphore_release(&synth_pending_sem);
ci->thread_wait(mad_synth_thread_p);
invalidate_icache();
stream.error = 0;
#endif
if (ci->request_next_track()) if (ci->request_next_track())
goto next_track; goto next_track;
/*mop up COP thread - MT only*/
mad_synth_thread_quit();
return status; return status;
} }