summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/mpegplayer/audio_thread.c93
-rw-r--r--apps/plugins/mpegplayer/mpeg_misc.h9
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.c174
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.h18
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.h17
-rw-r--r--apps/plugins/mpegplayer/pcm_output.c35
-rw-r--r--apps/plugins/mpegplayer/pcm_output.h2
-rw-r--r--apps/plugins/mpegplayer/video_thread.c12
8 files changed, 285 insertions, 75 deletions
diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c
index 78d28e4..2bb766a 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 2da9c2e..6c5a416 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 fa8fad8..fc99460 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 4d6da47..1557ff4 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 11bc1ea..b92af38 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 ac89308..e17f635 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 8a230b8..94ca6ee 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 feee643..6508d28 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)
{