From af410ec9958573909a6cfaaf0ab2b2723bbe039f Mon Sep 17 00:00:00 2001 From: jethead71 Date: Fri, 1 Feb 2008 02:25:15 +0000 Subject: [PATCH] mpegplayer: Use the core DSP to process audio. Removes the sample rate restriction on audio and any mpeg audio samplerate may be used. Use the global sound settings for audio output with the option to force any one of the processing stages off. All are forced off by default. I didn't personally care to fully duplicate the Sound Settings menu which would have been needed since using the core one would affect settings globally and exactly the same configuration probably isn't desired since the CPU load for video playback is much greater. Rebalance the threading to compensate with some expense to buffering speed. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16194 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugin.c | 5 + apps/plugin.h | 9 +- apps/plugins/mpegplayer/audio_thread.c | 93 +++++++++-------- apps/plugins/mpegplayer/mpeg_misc.h | 9 -- apps/plugins/mpegplayer/mpeg_settings.c | 174 ++++++++++++++++++++++++++++++++ apps/plugins/mpegplayer/mpeg_settings.h | 18 +++- apps/plugins/mpegplayer/mpegplayer.h | 17 ++-- apps/plugins/mpegplayer/pcm_output.c | 35 +++++-- apps/plugins/mpegplayer/pcm_output.h | 2 + apps/plugins/mpegplayer/video_thread.c | 12 ++- 10 files changed, 298 insertions(+), 76 deletions(-) diff --git a/apps/plugin.c b/apps/plugin.c index 1f773cfd2..6862ddb08 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -586,6 +586,11 @@ static const struct plugin_api rockbox_api = { #endif sound_unit, sound_val2phys, + dsp_set_crossfeed, + dsp_set_eq, + dsp_dither_enable, + dsp_configure, + dsp_process, #endif /* CONFIG_CODEC == SWCODEC */ }; diff --git a/apps/plugin.h b/apps/plugin.h index f91d80385..164a2c984 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -119,7 +119,7 @@ #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 98 +#define PLUGIN_API_VERSION 99 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any @@ -723,6 +723,13 @@ struct plugin_api { #endif const char * (*sound_unit)(int setting); int (*sound_val2phys)(int setting, int value); + void (*dsp_set_crossfeed)(bool enable); + void (*dsp_set_eq)(bool enable); + void (*dsp_dither_enable)(bool enable); + intptr_t (*dsp_configure)(struct dsp_config *dsp, int setting, + intptr_t value); + int (*dsp_process)(struct dsp_config *dsp, char *dest, + const char *src[], int count); #endif /* CONFIG_CODEC == SWCODEC */ }; diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c index 78d28e40c..2bb766ad8 100644 --- a/apps/plugins/mpegplayer/audio_thread.c +++ b/apps/plugins/mpegplayer/audio_thread.c @@ -27,10 +27,13 @@ struct pts_queue_slot; struct audio_thread_data { - struct queue_event ev; /* Our event queue to receive commands */ - int state; /* Thread state */ - int status; /* Media status (STREAM_PLAYING, etc.) */ - int mad_errors; /* A count of the errors in each frame */ + struct queue_event ev; /* Our event queue to receive commands */ + int state; /* Thread state */ + int status; /* Media status (STREAM_PLAYING, etc.) */ + int mad_errors; /* A count of the errors in each frame */ + unsigned samplerate; /* Current stream sample rate */ + int nchannels; /* Number of audio channels */ + struct dsp_config *dsp; /* The DSP we're using */ }; /* The audio stack is stolen from the core codec thread (but not in uisim) */ @@ -402,6 +405,8 @@ static void audio_thread_msg(struct audio_thread_data *td) td->status = STREAM_STOPPED; td->state = TSTATE_INIT; + td->samplerate = 0; + td->nchannels = 0; init_mad(); td->mad_errors = 0; @@ -460,12 +465,19 @@ static void audio_thread(void) { struct audio_thread_data td; + rb->memset(&td, 0, sizeof (td)); td.status = STREAM_STOPPED; td.state = TSTATE_EOS; /* We need this here to init the EMAC for Coldfire targets */ init_mad(); + td.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP, + CODEC_IDX_AUDIO); + rb->sound_set_pitch(1000); + rb->dsp_configure(td.dsp, DSP_RESET, 0); + rb->dsp_configure(td.dsp, DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); + goto message_wait; /* This is the decoding loop. */ @@ -594,64 +606,56 @@ static void audio_thread(void) mad_synth_frame(&synth, &frame); /** Output **/ + if (frame.header.samplerate != td.samplerate) + { + td.samplerate = frame.header.samplerate; + rb->dsp_configure(td.dsp, DSP_SWITCH_FREQUENCY, + td.samplerate); + } - /* TODO: Output through core dsp. We'll still use our own PCM buffer - since the core pcm buffer has no timestamping or clock facilities */ + if (MAD_NCHANNELS(&frame.header) != td.nchannels) + { + td.nchannels = MAD_NCHANNELS(&frame.header); + rb->dsp_configure(td.dsp, DSP_SET_STEREO_MODE, + td.nchannels == 1 ? + STEREO_MONO : STEREO_NONINTERLEAVED); + } + + td.state = TSTATE_RENDER_WAIT; /* Add a frame of audio to the pcm buffer. Maximum is 1152 samples. */ render_wait: if (synth.pcm.length > 0) { - struct pcm_frame_header *pcm_insert = pcm_output_get_buffer(); - int16_t *audio_data = (int16_t *)pcm_insert->data; - unsigned length = synth.pcm.length; - ssize_t size = sizeof(*pcm_insert) + length*4; - - td.state = TSTATE_RENDER_WAIT; + struct pcm_frame_header *dst_hdr = pcm_output_get_buffer(); + const char *src[2] = + { (char *)synth.pcm.samples[0], (char *)synth.pcm.samples[1] }; + int out_count = (synth.pcm.length * CLOCK_RATE + + (td.samplerate - 1)) / td.samplerate; + ssize_t size = sizeof(*dst_hdr) + out_count*4; /* Wait for required amount of free buffer space */ while (pcm_output_free() < size) { /* Wait one frame */ - int timeout = synth.pcm.length*HZ / synth.pcm.samplerate; + int timeout = out_count*HZ / td.samplerate; str_get_msg_w_tmo(&audio_str, &td.ev, MAX(timeout, 1)); if (td.ev.id != SYS_TIMEOUT) goto message_process; } - pcm_insert->time = audio_queue.curr->time; - pcm_insert->size = size; + out_count = rb->dsp_process(td.dsp, dst_hdr->data, src, + synth.pcm.length); - /* As long as we're on this timestamp, the time is just incremented - by the number of samples */ - audio_queue.curr->time += length; - - if (MAD_NCHANNELS(&frame.header) == 2) - { - int32_t *left = &synth.pcm.samples[0][0]; - int32_t *right = &synth.pcm.samples[1][0]; + if (out_count <= 0) + break; - do - { - /* libmad outputs s3.28 */ - *audio_data++ = clip_sample(*left++ >> 13); - *audio_data++ = clip_sample(*right++ >> 13); - } - while (--length > 0); - } - else /* mono */ - { - int32_t *mono = &synth.pcm.samples[0][0]; + dst_hdr->size = sizeof(*dst_hdr) + out_count*4; + dst_hdr->time = audio_queue.curr->time; - do - { - int32_t s = clip_sample(*mono++ >> 13); - *audio_data++ = s; - *audio_data++ = s; - } - while (--length > 0); - } - /**/ + /* As long as we're on this timestamp, the time is just + incremented by the number of samples */ + audio_queue.curr->time += out_count; /* Make this data available to DMA */ pcm_output_add_data(); @@ -712,9 +716,10 @@ bool audio_thread_init(void) rb->queue_init(audio_str.hdr.q, false); rb->queue_enable_queue_send(audio_str.hdr.q, &audio_str_queue_send); + /* One-up on the priority since the core DSP over-yields internally */ audio_str.thread = rb->create_thread( audio_thread, audio_stack, audio_stack_size, 0, - "mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK) IF_COP(, CPU)); + "mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK-1) IF_COP(, CPU)); if (audio_str.thread == NULL) return false; diff --git a/apps/plugins/mpegplayer/mpeg_misc.h b/apps/plugins/mpegplayer/mpeg_misc.h index 2da9c2e31..6c5a41655 100644 --- a/apps/plugins/mpegplayer/mpeg_misc.h +++ b/apps/plugins/mpegplayer/mpeg_misc.h @@ -168,15 +168,6 @@ void stream_scan_normalize(struct stream_scan *sk); * direction, otherwise opposite the scan direction */ void stream_scan_offset(struct stream_scan *sk, off_t by); -/** Audio helpers **/ -static inline int32_t clip_sample(int32_t sample) -{ - if ((int16_t)sample != sample) - sample = 0x7fff ^ (sample >> 31); - - return sample; -} - /** Time helpers **/ struct hms { diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c index fa8fad8b4..fc99460d7 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.c +++ b/apps/plugins/mpegplayer/mpeg_settings.c @@ -109,6 +109,11 @@ static struct configdata config[] = {TYPE_INT, 0, INT_MAX, &settings.displayoptions, "Display options", NULL, NULL}, #endif + {TYPE_INT, 0, 2, &settings.tone_controls, "Tone controls", NULL, NULL}, + {TYPE_INT, 0, 2, &settings.channel_modes, "Channel modes", NULL, NULL}, + {TYPE_INT, 0, 2, &settings.crossfeed, "Crossfeed", NULL, NULL}, + {TYPE_INT, 0, 2, &settings.equalizer, "Equalizer", NULL, NULL}, + {TYPE_INT, 0, 2, &settings.dithering, "Dithering", NULL, NULL}, }; static const struct opt_items noyes[2] = { @@ -121,6 +126,11 @@ static const struct opt_items enabledisable[2] = { { "Enable", -1 }, }; +static const struct opt_items globaloff[2] = { + { "Force off", -1 }, + { "Use sound setting", -1 }, +}; + static long mpeg_menu_sysevent_id; void mpeg_menu_sysevent_clear(void) @@ -184,6 +194,70 @@ static bool mpeg_set_option(const char* string, return usb; } +/* Sync a particular audio setting to global or mpegplayer forced off */ +static void sync_audio_setting(int setting, bool global) +{ + int val0, val1; + + switch (setting) + { + case MPEG_AUDIO_TONE_CONTROLS: + if (global || settings.tone_controls) + { + val0 = rb->global_settings->bass; + val1 = rb->global_settings->treble; + } + else + { + val0 = rb->sound_default(SOUND_BASS); + val1 = rb->sound_default(SOUND_TREBLE); + } + rb->sound_set(SOUND_BASS, val0); + rb->sound_set(SOUND_TREBLE, val1); + break; + + case MPEG_AUDIO_CHANNEL_MODES: + val0 = (global || settings.channel_modes) ? + rb->global_settings->channel_config : + SOUND_CHAN_STEREO; + rb->sound_set(SOUND_CHANNELS, val0); + break; + + case MPEG_AUDIO_CROSSFEED: + rb->dsp_set_crossfeed((global || settings.crossfeed) ? + rb->global_settings->crossfeed : false); + break; + + case MPEG_AUDIO_EQUALIZER: + rb->dsp_set_eq((global || settings.equalizer) ? + rb->global_settings->eq_enabled : false); + break; + + case MPEG_AUDIO_DITHERING: + rb->dsp_dither_enable((global || settings.dithering) ? + rb->global_settings->dithering_enabled : false); + break; + } +} + +/* Sync all audio settings to global or mpegplayer forced off */ +static void sync_audio_settings(bool global) +{ + static const int setting_index[] = + { + MPEG_AUDIO_TONE_CONTROLS, + MPEG_AUDIO_CHANNEL_MODES, + MPEG_AUDIO_CROSSFEED, + MPEG_AUDIO_EQUALIZER, + MPEG_AUDIO_DITHERING, + }; + unsigned i; + + for (i = 0; i < ARRAYLEN(setting_index); i++) + { + sync_audio_setting(setting_index[i], global); + } +} #ifndef HAVE_LCD_COLOR /* Cheapo splash implementation for the grey surface */ @@ -736,6 +810,79 @@ static void display_options(void) menu_exit(menu_id); } +static void audio_options(void) +{ + int result; + int menu_id; + bool menu_quit = false; + + static const struct menu_item items[] = { + [MPEG_AUDIO_TONE_CONTROLS] = + { "Tone Controls", NULL }, + [MPEG_AUDIO_CHANNEL_MODES] = + { "Channel Modes", NULL }, + [MPEG_AUDIO_CROSSFEED] = + { "Crossfeed", NULL }, + [MPEG_AUDIO_EQUALIZER] = + { "Equalizer", NULL }, + [MPEG_AUDIO_DITHERING] = + { "Dithering", NULL }, + }; + + menu_id = menu_init(rb, items, ARRAYLEN(items), + mpeg_menu_sysevent_callback, NULL, NULL, NULL); + + rb->button_clear_queue(); + + while (!menu_quit) + { + mpeg_menu_sysevent_clear(); + result = menu_show(menu_id); + + switch (result) + { + case MPEG_AUDIO_TONE_CONTROLS: + mpeg_set_option("Tone Controls", &settings.tone_controls, INT, + globaloff, 2, NULL); + sync_audio_setting(result, false); + break; + + case MPEG_AUDIO_CHANNEL_MODES: + mpeg_set_option("Channel Modes", &settings.channel_modes, + INT, globaloff, 2, NULL); + sync_audio_setting(result, false); + break; + + case MPEG_AUDIO_CROSSFEED: + mpeg_set_option("Crossfeed", &settings.crossfeed, INT, + globaloff, 2, NULL); + sync_audio_setting(result, false); + break; + + case MPEG_AUDIO_EQUALIZER: + mpeg_set_option("Equalizer", &settings.equalizer, INT, + globaloff, 2, NULL); + sync_audio_setting(result, false); + break; + + case MPEG_AUDIO_DITHERING: + mpeg_set_option("Dithering", &settings.dithering, INT, + globaloff, 2, NULL); + sync_audio_setting(result, false); + break; + + default: + menu_quit = true; + break; + } + + if (mpeg_menu_sysevent() != 0) + menu_quit = true; + } + + menu_exit(menu_id); +} + static void resume_options(void) { static const struct opt_items items[MPEG_RESUME_NUM_OPTIONS] = { @@ -775,6 +922,8 @@ int mpeg_menu(unsigned flags) struct menu_item items[] = { [MPEG_MENU_DISPLAY_SETTINGS] = { "Display Options", NULL }, + [MPEG_MENU_AUDIO_SETTINGS] = + { "Audio Options", NULL }, [MPEG_MENU_ENABLE_START_MENU] = { "Resume Options", NULL }, [MPEG_MENU_CLEAR_RESUMES] = @@ -809,6 +958,10 @@ int mpeg_menu(unsigned flags) display_options(); break; + case MPEG_MENU_AUDIO_SETTINGS: + audio_options(); + break; + case MPEG_MENU_ENABLE_START_MENU: resume_options(); break; @@ -849,6 +1002,11 @@ void init_settings(const char* filename) #if MPEG_OPTION_DITHERING_ENABLED settings.displayoptions = 0; /* No visual effects */ #endif + settings.tone_controls = false; + settings.channel_modes = false; + settings.crossfeed = false; + settings.equalizer = false; + settings.dithering = false; configfile_init(rb); @@ -886,6 +1044,9 @@ void init_settings(const char* filename) { settings.resume_time = 0; } + + /* Set our audio options */ + sync_audio_settings(false); } void save_settings(void) @@ -911,4 +1072,17 @@ void save_settings(void) configfile_update_entry(SETTINGS_FILENAME, "Display options", settings.displayoptions); #endif + configfile_update_entry(SETTINGS_FILENAME, "Tone controls", + settings.tone_controls); + configfile_update_entry(SETTINGS_FILENAME, "Channel modes", + settings.channel_modes); + configfile_update_entry(SETTINGS_FILENAME, "Crossfeed", + settings.crossfeed); + configfile_update_entry(SETTINGS_FILENAME, "Equalizer", + settings.equalizer); + configfile_update_entry(SETTINGS_FILENAME, "Dithering", + settings.dithering); + + /* Restore audio options */ + sync_audio_settings(true); } diff --git a/apps/plugins/mpegplayer/mpeg_settings.h b/apps/plugins/mpegplayer/mpeg_settings.h index 4d6da478e..1557ff433 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.h +++ b/apps/plugins/mpegplayer/mpeg_settings.h @@ -1,7 +1,7 @@ #include "plugin.h" -#define SETTINGS_VERSION 3 +#define SETTINGS_VERSION 4 #define SETTINGS_MIN_VERSION 1 #define SETTINGS_FILENAME "mpegplayer.cfg" @@ -24,6 +24,15 @@ enum mpeg_option_id MPEG_OPTION_SKIP_FRAMES, }; +enum mpeg_audio_option_id +{ + MPEG_AUDIO_TONE_CONTROLS, + MPEG_AUDIO_CHANNEL_MODES, + MPEG_AUDIO_CROSSFEED, + MPEG_AUDIO_EQUALIZER, + MPEG_AUDIO_DITHERING, +}; + enum mpeg_resume_id { MPEG_RESUME_MENU_ALWAYS = 0, @@ -46,6 +55,7 @@ enum mpeg_start_id enum mpeg_menu_id { MPEG_MENU_DISPLAY_SETTINGS, + MPEG_MENU_AUDIO_SETTINGS, MPEG_MENU_ENABLE_START_MENU, MPEG_MENU_CLEAR_RESUMES, MPEG_MENU_QUIT, @@ -62,6 +72,12 @@ struct mpeg_settings { #if MPEG_OPTION_DITHERING_ENABLED int displayoptions; #endif + /* Audio options - simple on/off specification */ + int tone_controls; + int channel_modes; + int crossfeed; + int equalizer; + int dithering; }; extern struct mpeg_settings settings; diff --git a/apps/plugins/mpegplayer/mpegplayer.h b/apps/plugins/mpegplayer/mpegplayer.h index 11bc1ea66..b92af38e6 100644 --- a/apps/plugins/mpegplayer/mpegplayer.h +++ b/apps/plugins/mpegplayer/mpegplayer.h @@ -53,18 +53,19 @@ enum mpeg_malloc_reason_t #define AUDIOBUF_ALLOC_SIZE (AUDIOBUF_SIZE+AUDIOBUF_GUARD_SIZE) /** PCM buffer **/ -#define CLOCK_RATE 44100 /* Our clock rate in ticks/second (samplerate) */ +#define CLOCK_RATE NATIVE_FREQUENCY /* Our clock rate in ticks/second (samplerate) */ /* Define this as "1" to have a test tone instead of silence clip */ #define SILENCE_TEST_TONE 0 -#define PCMOUT_BUFSIZE (CLOCK_RATE) /* 1s */ -#define PCMOUT_GUARD_SIZE (1152*4 + sizeof (struct pcm_frame_header)) -#define PCMOUT_ALLOC_SIZE (PCMOUT_BUFSIZE + PCMOUT_GUARD_SIZE) - /* Start pcm playback @ 25% full */ -#define PCMOUT_PLAY_WM (PCMOUT_BUFSIZE/4) - /* No valid audio frame is smaller */ -#define PCMOUT_LOW_WM (sizeof (struct pcm_frame_header)) +#define PCMOUT_BUFSIZE (CLOCK_RATE/2*4) /* 1/2s */ +#define PCMOUT_GUARD_SAMPLES ((CLOCK_RATE*576+7999)/8000) /* Worst upsampling case */ +#define PCMOUT_GUARD_SIZE (PCMOUT_GUARD_SAMPLES*4 + sizeof (struct pcm_frame_header)) +#define PCMOUT_ALLOC_SIZE (PCMOUT_BUFSIZE + PCMOUT_GUARD_SIZE) + /* Start pcm playback @ 25% full */ +#define PCMOUT_PLAY_WM (PCMOUT_BUFSIZE/4) + /* No valid audio frame is smaller */ +#define PCMOUT_LOW_WM (sizeof (struct pcm_frame_header)) /** disk buffer **/ #define DISK_BUF_LOW_WATERMARK (1024*1024) diff --git a/apps/plugins/mpegplayer/pcm_output.c b/apps/plugins/mpegplayer/pcm_output.c index ac89308af..e17f635f7 100644 --- a/apps/plugins/mpegplayer/pcm_output.c +++ b/apps/plugins/mpegplayer/pcm_output.c @@ -33,6 +33,7 @@ static struct pcm_frame_header * ALIGNED_ATTR(4) pcmbuf_head IBSS_ATTR; static struct pcm_frame_header * ALIGNED_ATTR(4) pcmbuf_tail IBSS_ATTR; /* Bytes */ +static ssize_t pcmbuf_curr_size IBSS_ATTR; /* Size of currently playing frame */ static uint64_t pcmbuf_read IBSS_ATTR; /* Number of bytes read by DMA */ static uint64_t pcmbuf_written IBSS_ATTR; /* Number of bytes written by source */ static ssize_t pcmbuf_threshold IBSS_ATTR; /* Non-silence threshold */ @@ -42,6 +43,9 @@ static uint32_t clock_base IBSS_ATTR; /* Our base clock */ static uint32_t clock_start IBSS_ATTR; /* Clock at playback start */ static int32_t clock_adjust IBSS_ATTR; /* Clock drift adjustment */ +int pcm_skipped = 0; +int pcm_underruns = 0; + /* Small silence clip. ~5.80ms @ 44.1kHz */ static int16_t silence[256*2] ALIGNED_ATTR(4) = { 0 }; @@ -51,7 +55,7 @@ static inline void pcm_advance_buffer(struct pcm_frame_header **p, { *p = SKIPBYTES(*p, size); if (*p >= pcmbuf_end) - *p = pcm_buffer; + *p = SKIPBYTES(*p, -PCMOUT_BUFSIZE); } /* Inline internally but not externally */ @@ -68,7 +72,13 @@ inline ssize_t pcm_output_free(void) /* Audio DMA handler */ static void get_more(unsigned char **start, size_t *size) { - ssize_t sz = pcm_output_used(); + ssize_t sz; + + /* Free-up the last frame played frame if any */ + pcmbuf_read += pcmbuf_curr_size; + pcmbuf_curr_size = 0; + + sz = pcm_output_used(); if (sz > pcmbuf_threshold) { @@ -95,16 +105,20 @@ static void get_more(unsigned char **start, size_t *size) /* Frame more than 100ms late - drop it */ pcm_advance_buffer(&pcmbuf_head, sz); pcmbuf_read += sz; + pcm_skipped++; if (pcmbuf_read < pcmbuf_written) continue; + + /* Ran out so revert to default watermark */ + pcmbuf_threshold = PCMOUT_PLAY_WM; } else if (offset < 100*CLOCK_RATE/1000) { /* Frame less than 100ms early - play it */ - *start = (unsigned char *)pcmbuf_head->data; + *start = pcmbuf_head->data; pcm_advance_buffer(&pcmbuf_head, sz); - pcmbuf_read += sz; + pcmbuf_curr_size = sz; sz -= sizeof (struct pcm_frame_header); @@ -124,6 +138,9 @@ static void get_more(unsigned char **start, size_t *size) else { /* Ran out so revert to default watermark */ + if (pcmbuf_threshold == PCMOUT_LOW_WM) + pcm_underruns++; + pcmbuf_threshold = PCMOUT_PLAY_WM; } @@ -164,8 +181,9 @@ void pcm_output_flush(void) rb->pcm_play_stop(); pcmbuf_threshold = PCMOUT_PLAY_WM; - pcmbuf_read = pcmbuf_written = 0; + pcmbuf_curr_size = pcmbuf_read = pcmbuf_written = 0; pcmbuf_head = pcmbuf_tail = pcm_buffer; + pcm_skipped = pcm_underruns = 0; /* Restart if playing state was current */ if (playing && !paused) @@ -251,10 +269,9 @@ bool pcm_output_init(void) pcmbuf_head = pcm_buffer; pcmbuf_tail = pcm_buffer; pcmbuf_end = SKIPBYTES(pcm_buffer, PCMOUT_BUFSIZE); - pcmbuf_read = 0; - pcmbuf_written = 0; + pcmbuf_curr_size = pcmbuf_read = pcmbuf_written = 0; - rb->pcm_set_frequency(SAMPR_44); + rb->pcm_set_frequency(NATIVE_FREQUENCY); #if INPUT_SRC_CAPS != 0 /* Select playback */ @@ -264,7 +281,7 @@ bool pcm_output_init(void) #if SILENCE_TEST_TONE /* Make the silence clip a square wave */ - const int16_t silence_amp = 32767 / 16; + const int16_t silence_amp = INT16_MAX / 16; unsigned i; for (i = 0; i < ARRAYLEN(silence); i += 2) diff --git a/apps/plugins/mpegplayer/pcm_output.h b/apps/plugins/mpegplayer/pcm_output.h index 8a230b87a..94ca6eed3 100644 --- a/apps/plugins/mpegplayer/pcm_output.h +++ b/apps/plugins/mpegplayer/pcm_output.h @@ -29,6 +29,8 @@ struct pcm_frame_header /* Header added to pcm data every time a decoded unsigned char data[]; /* open array of audio data */ } ALIGNED_ATTR(4); +extern int pcm_skipped, pcm_underruns; + bool pcm_output_init(void); void pcm_output_exit(void); void pcm_output_flush(void); diff --git a/apps/plugins/mpegplayer/video_thread.c b/apps/plugins/mpegplayer/video_thread.c index feee643d1..6508d28d1 100644 --- a/apps/plugins/mpegplayer/video_thread.c +++ b/apps/plugins/mpegplayer/video_thread.c @@ -63,15 +63,21 @@ static void draw_fps(struct video_thread_data *td) uint32_t start; uint32_t clock_ticks = stream_get_ticks(&start); int fps = 0; + int buf_pct; char str[80]; clock_ticks -= start; if (clock_ticks != 0) fps = muldiv_uint32(CLOCK_RATE*100, td->num_drawn, clock_ticks); - rb->snprintf(str, sizeof(str), "%d.%02d %d %d ", + buf_pct = muldiv_uint32(100, pcm_output_used(), PCMOUT_BUFSIZE); + + rb->snprintf(str, sizeof(str), "v:%d.%02d %d %d a:%02d%% %d %d ", + /* Video information */ fps / 100, fps % 100, td->num_skipped, - td->info->display_picture->temporal_reference); + td->info->display_picture->temporal_reference, + /* Audio information */ + buf_pct, pcm_underruns, pcm_skipped); lcd_(putsxy)(0, 0, str); vo_lock(); @@ -277,7 +283,6 @@ static int sync_decoder(struct video_thread_data *td, while (1) { mpeg2_state_t mp2state = mpeg2_parse(td->mpeg2dec); - rb->yield(); switch (mp2state) { @@ -697,7 +702,6 @@ static void video_thread(void) picture_decode: mp2state = mpeg2_parse (td.mpeg2dec); - rb->yield(); switch (mp2state) { -- 2.11.4.GIT