mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
Some small mpegplayer improvements/bug-fixes, and improved A/V sync. Audio is used as the master clock and video is synced to the number of samples played. This doesn't take account of any PTS difference at the start of the stream. Also enable Limit FPS and Skip Frames by default - these options need to be enabled for A/V sync to work. Adds pcm_get_bytes_waiting() to the plugin API
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12884 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
81cad7db46
commit
8310848421
5 changed files with 109 additions and 108 deletions
|
@ -487,6 +487,8 @@ static const struct plugin_api rockbox_api = {
|
||||||
playlist_resume,
|
playlist_resume,
|
||||||
playlist_start,
|
playlist_start,
|
||||||
&global_status,
|
&global_status,
|
||||||
|
|
||||||
|
pcm_get_bytes_waiting,
|
||||||
};
|
};
|
||||||
|
|
||||||
int plugin_load(const char* plugin, void* parameter)
|
int plugin_load(const char* plugin, void* parameter)
|
||||||
|
|
|
@ -110,7 +110,7 @@
|
||||||
#define PLUGIN_MAGIC 0x526F634B /* RocK */
|
#define PLUGIN_MAGIC 0x526F634B /* RocK */
|
||||||
|
|
||||||
/* increase this every time the api struct changes */
|
/* increase this every time the api struct changes */
|
||||||
#define PLUGIN_API_VERSION 48
|
#define PLUGIN_API_VERSION 49
|
||||||
|
|
||||||
/* update this to latest version if a change to the api struct breaks
|
/* update this to latest version if a change to the api struct breaks
|
||||||
backwards compatibility (and please take the opportunity to sort in any
|
backwards compatibility (and please take the opportunity to sort in any
|
||||||
|
@ -602,6 +602,8 @@ struct plugin_api {
|
||||||
int (*playlist_resume)(void);
|
int (*playlist_resume)(void);
|
||||||
int (*playlist_start)(int start_index, int offset);
|
int (*playlist_start)(int start_index, int offset);
|
||||||
struct system_status *global_status;
|
struct system_status *global_status;
|
||||||
|
|
||||||
|
size_t (*pcm_get_bytes_waiting)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* plugin header */
|
/* plugin header */
|
||||||
|
|
|
@ -36,6 +36,7 @@ void mpeg2_alloc_init(unsigned char* buf, int mallocsize)
|
||||||
mem_ptr = 0;
|
mem_ptr = 0;
|
||||||
bufsize = mallocsize;
|
bufsize = mallocsize;
|
||||||
mallocbuf = buf;
|
mallocbuf = buf;
|
||||||
|
rb->memset(buf,0,bufsize);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,8 +82,8 @@ void init_settings(void)
|
||||||
{
|
{
|
||||||
/* Set the default settings */
|
/* Set the default settings */
|
||||||
settings.showfps = 0; /* Do not show FPS */
|
settings.showfps = 0; /* Do not show FPS */
|
||||||
settings.limitfps = 0; /* Do not limit FPS */
|
settings.limitfps = 1; /* Limit FPS */
|
||||||
settings.skipframes = 0; /* Do not skip frames */
|
settings.skipframes = 1; /* Skip frames */
|
||||||
|
|
||||||
configfile_init(rb);
|
configfile_init(rb);
|
||||||
|
|
||||||
|
|
|
@ -83,16 +83,16 @@ In libmpeg2, info->sequence->frame_period contains the frame_period.
|
||||||
Working with Rockbox's 100Hz tick, the common frame rates would need
|
Working with Rockbox's 100Hz tick, the common frame rates would need
|
||||||
to be as follows:
|
to be as follows:
|
||||||
|
|
||||||
FPS | 27Mhz | 100Hz
|
FPS | 27Mhz | 100Hz | 44.1KHz | 48KHz
|
||||||
--------|----------------
|
--------|-----------------------------------------------------------
|
||||||
10* | 2700000 | 10
|
10* | 2700000 | 10 | 4410 | 4800
|
||||||
12* | 2250000 | 8.3333
|
12* | 2250000 | 8.3333 | 3675 | 4000
|
||||||
15* | 1800000 | 6.6667
|
15* | 1800000 | 6.6667 | 2940 | 3200
|
||||||
23.9760 | 1126125 | 4.170833333
|
23.9760 | 1126125 | 4.170833333 | 1839.3375 | 2002
|
||||||
24 | 1125000 | 4.166667
|
24 | 1125000 | 4.166667 | 1837.5 | 2000
|
||||||
25 | 1080000 | 4
|
25 | 1080000 | 4 | 1764 | 1920
|
||||||
29.9700 | 900900 | 3.336667
|
29.9700 | 900900 | 3.336667 | 1471,47 | 1601.6
|
||||||
30 | 900000 | 3.333333
|
30 | 900000 | 3.333333 | 1470 | 1600
|
||||||
|
|
||||||
|
|
||||||
*Unofficial framerates
|
*Unofficial framerates
|
||||||
|
@ -177,8 +177,12 @@ typedef struct
|
||||||
int id;
|
int id;
|
||||||
} Stream;
|
} Stream;
|
||||||
|
|
||||||
static Stream audio_str, video_str;
|
static Stream audio_str IBSS_ATTR;
|
||||||
|
static Stream video_str IBSS_ATTR;
|
||||||
|
|
||||||
|
/* NOTE: Putting the following variables in IRAM cause audio corruption
|
||||||
|
on the ipod (reason unknown)
|
||||||
|
*/
|
||||||
static uint8_t *disk_buf, *disk_buf_end;
|
static uint8_t *disk_buf, *disk_buf_end;
|
||||||
|
|
||||||
/* Events */
|
/* Events */
|
||||||
|
@ -195,8 +199,10 @@ static struct thread_entry* videothread_id;
|
||||||
#define STREAM_PLAYING 0
|
#define STREAM_PLAYING 0
|
||||||
#define STREAM_DONE 1
|
#define STREAM_DONE 1
|
||||||
#define STREAM_PAUSING 2
|
#define STREAM_PAUSING 2
|
||||||
#define PLEASE_STOP 3
|
#define STREAM_BUFFERING 3
|
||||||
#define PLEASE_PAUSE 4
|
#define STREAM_ERROR 4
|
||||||
|
#define PLEASE_STOP 5
|
||||||
|
#define PLEASE_PAUSE 6
|
||||||
|
|
||||||
int audiostatus IBSS_ATTR;
|
int audiostatus IBSS_ATTR;
|
||||||
int videostatus IBSS_ATTR;
|
int videostatus IBSS_ATTR;
|
||||||
|
@ -207,34 +213,6 @@ int videostatus IBSS_ATTR;
|
||||||
#define AUDIOBUFFER_SIZE (32*1024)
|
#define AUDIOBUFFER_SIZE (32*1024)
|
||||||
#define LIBMPEG2BUFFER_SIZE (2*1024*1024)
|
#define LIBMPEG2BUFFER_SIZE (2*1024*1024)
|
||||||
|
|
||||||
static int tick_enabled IBSS_ATTR = 0;
|
|
||||||
|
|
||||||
#define MPEG_CURRENT_TICK ((unsigned int)((*rb->current_tick - tick_offset)))
|
|
||||||
|
|
||||||
/* The value to subtract from current_tick to get the current mpeg tick */
|
|
||||||
static int tick_offset IBSS_ATTR;
|
|
||||||
|
|
||||||
/* The last tick - i.e. the time to reset the tick_offset to when unpausing */
|
|
||||||
static int last_tick IBSS_ATTR;
|
|
||||||
|
|
||||||
static void start_timer(void)
|
|
||||||
{
|
|
||||||
last_tick = 0;
|
|
||||||
tick_offset = *rb->current_tick;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unpause_timer(void)
|
|
||||||
{
|
|
||||||
tick_offset = *rb->current_tick - last_tick;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pause_timer(void)
|
|
||||||
{
|
|
||||||
/* Save the current MPEG tick */
|
|
||||||
last_tick = *rb->current_tick - tick_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void button_loop(void)
|
static void button_loop(void)
|
||||||
{
|
{
|
||||||
bool result;
|
bool result;
|
||||||
|
@ -276,37 +254,35 @@ static void button_loop(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MPEG_MENU:
|
case MPEG_MENU:
|
||||||
videostatus=PLEASE_PAUSE;
|
|
||||||
rb->pcm_play_pause(false);
|
rb->pcm_play_pause(false);
|
||||||
pause_timer();
|
if (videostatus != STREAM_DONE) {
|
||||||
|
videostatus=PLEASE_PAUSE;
|
||||||
|
|
||||||
/* Wait for video thread to stop */
|
/* Wait for video thread to stop */
|
||||||
while (videostatus == PLEASE_PAUSE) { rb->sleep(HZ/25); }
|
while (videostatus == PLEASE_PAUSE) { rb->sleep(HZ/25); }
|
||||||
|
}
|
||||||
result = mpeg_menu();
|
result = mpeg_menu();
|
||||||
|
|
||||||
/* The menu can change the font, so restore */
|
/* The menu can change the font, so restore */
|
||||||
rb->lcd_setfont(FONT_SYSFIXED);
|
rb->lcd_setfont(FONT_SYSFIXED);
|
||||||
|
|
||||||
unpause_timer();
|
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
audiostatus = PLEASE_STOP;
|
audiostatus = PLEASE_STOP;
|
||||||
videostatus = PLEASE_STOP;
|
if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP;
|
||||||
} else {
|
} else {
|
||||||
videostatus = STREAM_PLAYING;
|
if (videostatus != STREAM_DONE) videostatus = STREAM_PLAYING;
|
||||||
rb->pcm_play_pause(true);
|
rb->pcm_play_pause(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MPEG_STOP:
|
case MPEG_STOP:
|
||||||
audiostatus = PLEASE_STOP;
|
audiostatus = PLEASE_STOP;
|
||||||
videostatus = PLEASE_STOP;
|
if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MPEG_PAUSE:
|
case MPEG_PAUSE:
|
||||||
videostatus=PLEASE_PAUSE;
|
if (videostatus != STREAM_DONE) videostatus=PLEASE_PAUSE;
|
||||||
rb->pcm_play_pause(false);
|
rb->pcm_play_pause(false);
|
||||||
pause_timer(); /* Freeze time */
|
|
||||||
|
|
||||||
button = BUTTON_NONE;
|
button = BUTTON_NONE;
|
||||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||||
|
@ -316,23 +292,22 @@ static void button_loop(void)
|
||||||
button = rb->button_get(true);
|
button = rb->button_get(true);
|
||||||
if (button == MPEG_STOP) {
|
if (button == MPEG_STOP) {
|
||||||
audiostatus = PLEASE_STOP;
|
audiostatus = PLEASE_STOP;
|
||||||
videostatus = PLEASE_STOP;
|
if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} while (button != MPEG_PAUSE);
|
} while (button != MPEG_PAUSE);
|
||||||
|
|
||||||
videostatus = STREAM_PLAYING;
|
if (videostatus != STREAM_DONE) videostatus = STREAM_PLAYING;
|
||||||
rb->pcm_play_pause(true);
|
rb->pcm_play_pause(true);
|
||||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||||
rb->cpu_boost(true);
|
rb->cpu_boost(true);
|
||||||
#endif
|
#endif
|
||||||
unpause_timer(); /* Resume time */
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if(rb->default_event_handler(button) == SYS_USB_CONNECTED) {
|
if(rb->default_event_handler(button) == SYS_USB_CONNECTED) {
|
||||||
audiostatus = PLEASE_STOP;
|
audiostatus = PLEASE_STOP;
|
||||||
videostatus = PLEASE_STOP;
|
if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,13 +354,15 @@ static void get_next_data( Stream* str )
|
||||||
0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
if( str->curr_packet_end == NULL )
|
if (str->curr_packet_end == NULL) {
|
||||||
{
|
/* What does this do? */
|
||||||
while( (p = disk_buf) == NULL )
|
while( (p = disk_buf) == NULL )
|
||||||
{
|
{
|
||||||
|
rb->lcd_putsxy(0,LCD_HEIGHT-10,"FREEZE!");
|
||||||
|
rb->lcd_update();
|
||||||
rb->sleep(100);
|
rb->sleep(100);
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
p = str->curr_packet_end;
|
p = str->curr_packet_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,14 +510,16 @@ static void get_next_data( Stream* str )
|
||||||
uint8_t* mpa_buffer;
|
uint8_t* mpa_buffer;
|
||||||
size_t mpa_buffer_size;
|
size_t mpa_buffer_size;
|
||||||
|
|
||||||
static volatile int madpcm_playing;
|
static volatile int madpcm_playing IBSS_ATTR;
|
||||||
static volatile int16_t* pcm_buffer;
|
static volatile int16_t* pcm_buffer IBSS_ATTR;
|
||||||
static volatile size_t pcm_buffer_size;
|
static volatile size_t pcm_buffer_size IBSS_ATTR;
|
||||||
|
|
||||||
static volatile size_t pcmbuf_len;
|
static volatile size_t pcmbuf_len IBSS_ATTR;
|
||||||
static volatile int16_t* pcmbuf_end;
|
static volatile int16_t* pcmbuf_end IBSS_ATTR;
|
||||||
static volatile int16_t* pcmbuf_head;
|
static volatile int16_t* pcmbuf_head IBSS_ATTR;
|
||||||
static volatile int16_t* pcmbuf_tail;
|
static volatile int16_t* pcmbuf_tail IBSS_ATTR;
|
||||||
|
|
||||||
|
static volatile uint32_t samplesplayed IBSS_ATTR;
|
||||||
|
|
||||||
static void init_pcmbuf(void)
|
static void init_pcmbuf(void)
|
||||||
{
|
{
|
||||||
|
@ -557,18 +536,22 @@ static void get_more(unsigned char** start, size_t* size)
|
||||||
*start = NULL;
|
*start = NULL;
|
||||||
*size = 0;
|
*size = 0;
|
||||||
madpcm_playing = 0;
|
madpcm_playing = 0;
|
||||||
|
pcmbuf_len = 0;
|
||||||
} else {
|
} else {
|
||||||
*start = (unsigned char*)(pcmbuf_tail);
|
*start = (unsigned char*)(pcmbuf_tail);
|
||||||
*size = 32*1024;
|
*size = 32*1024;
|
||||||
pcmbuf_tail += (32*1024)/sizeof(int16_t);
|
pcmbuf_tail += (32*1024)/sizeof(int16_t);
|
||||||
pcmbuf_len -= 32*1024;
|
pcmbuf_len -= 32*1024;
|
||||||
if (pcmbuf_tail >= pcmbuf_end) { pcmbuf_tail = pcm_buffer; }
|
if (pcmbuf_tail >= pcmbuf_end) { pcmbuf_tail = pcm_buffer; }
|
||||||
|
|
||||||
|
/* Update master clock */
|
||||||
|
samplesplayed += (32*1024)/4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int line;
|
int line;
|
||||||
|
|
||||||
static void mad_decode(void)
|
static void audio_thread(void)
|
||||||
{
|
{
|
||||||
int32_t* left;
|
int32_t* left;
|
||||||
int32_t* right;
|
int32_t* right;
|
||||||
|
@ -594,6 +577,8 @@ static void mad_decode(void)
|
||||||
if (n < 1000) { /* TODO: What is the maximum size of an MPEG audio frame? */
|
if (n < 1000) { /* TODO: What is the maximum size of an MPEG audio frame? */
|
||||||
get_next_data( &audio_str );
|
get_next_data( &audio_str );
|
||||||
if (audio_str.curr_packet == NULL) {
|
if (audio_str.curr_packet == NULL) {
|
||||||
|
/* Wait for audio to finish */
|
||||||
|
while (pcmbuf_len > 0) { rb->sleep(HZ/10); }
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
len = audio_str.curr_packet_end - audio_str.curr_packet;
|
len = audio_str.curr_packet_end - audio_str.curr_packet;
|
||||||
|
@ -701,6 +686,7 @@ static void mad_decode(void)
|
||||||
if ((!madpcm_playing) && (pcmbuf_len > 64*1024)) {
|
if ((!madpcm_playing) && (pcmbuf_len > 64*1024)) {
|
||||||
madpcm_playing = 1;
|
madpcm_playing = 1;
|
||||||
rb->pcm_play_data(get_more,NULL,0);
|
rb->pcm_play_data(get_more,NULL,0);
|
||||||
|
audiostatus = STREAM_PLAYING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rb->yield();
|
rb->yield();
|
||||||
|
@ -710,7 +696,10 @@ done:
|
||||||
rb->pcm_play_stop();
|
rb->pcm_play_stop();
|
||||||
audiostatus=STREAM_DONE;
|
audiostatus=STREAM_DONE;
|
||||||
|
|
||||||
for (;;) { rb->sleep(HZ); }
|
for (;;) {
|
||||||
|
button_loop();
|
||||||
|
rb->sleep(HZ/4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End of libmad stuff */
|
/* End of libmad stuff */
|
||||||
|
@ -728,25 +717,37 @@ uint32_t audio_stack[AUDIO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
|
||||||
#define VIDEO_STACKSIZE (4*1024)
|
#define VIDEO_STACKSIZE (4*1024)
|
||||||
static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
|
static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
|
||||||
|
|
||||||
static void decode_mpeg2 (void)
|
static void video_thread(void)
|
||||||
{
|
{
|
||||||
const mpeg2_info_t * info;
|
const mpeg2_info_t * info;
|
||||||
mpeg2_state_t state;
|
mpeg2_state_t state;
|
||||||
char str[80];
|
char str[80];
|
||||||
static int skipped = 0;
|
int skipped = 0;
|
||||||
int skipcount = 0;
|
int skipcount = 0;
|
||||||
static int frame = 0;
|
int frame = 0;
|
||||||
static int starttick = 0;
|
int lasttick;
|
||||||
static int lasttick;
|
|
||||||
unsigned int eta2;
|
unsigned int eta2;
|
||||||
unsigned int x;
|
unsigned int s;
|
||||||
int fps;
|
int fps;
|
||||||
|
|
||||||
if (starttick == 0) {
|
rb->sleep(HZ/5);
|
||||||
starttick=*rb->current_tick-1; /* Avoid divby0 */
|
mpeg2dec = mpeg2_init ();
|
||||||
lasttick=starttick;
|
|
||||||
|
if (mpeg2dec == NULL) {
|
||||||
|
videostatus = STREAM_ERROR;
|
||||||
|
rb->splash(0, "mpeg2_init failed");
|
||||||
|
/* Commit suicide */
|
||||||
|
rb->remove_thread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear the display - this is mainly just to indicate that the
|
||||||
|
video thread has started successfully. */
|
||||||
|
rb->lcd_clear_display();
|
||||||
|
rb->lcd_update();
|
||||||
|
|
||||||
|
/* Used to decide when to display FPS */
|
||||||
|
lasttick = *rb->current_tick - HZ;
|
||||||
|
|
||||||
/* Request the first packet data */
|
/* Request the first packet data */
|
||||||
get_next_data( &video_str );
|
get_next_data( &video_str );
|
||||||
mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
|
mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end);
|
||||||
|
@ -791,26 +792,26 @@ static void decode_mpeg2 (void)
|
||||||
case STATE_INVALID_END:
|
case STATE_INVALID_END:
|
||||||
/* draw current picture */
|
/* draw current picture */
|
||||||
if (info->display_fbuf) {
|
if (info->display_fbuf) {
|
||||||
/* We start the timer when we draw the first frame */
|
/* Wait if the audio thread is buffering - i.e. before
|
||||||
if (!tick_enabled) {
|
the first frames are decoded */
|
||||||
start_timer();
|
while (audiostatus == STREAM_BUFFERING) {
|
||||||
tick_enabled = 1 ;
|
rb->sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
eta += (info->sequence->frame_period);
|
eta += (info->sequence->frame_period);
|
||||||
eta2 = eta / (27000000 / HZ);
|
|
||||||
|
|
||||||
|
/* Convert eta (in 27MHz ticks) into audio samples */
|
||||||
|
eta2 =(eta * 44100) / 27000000;
|
||||||
|
s = samplesplayed - (rb->pcm_get_bytes_waiting() >> 2);
|
||||||
if (settings.limitfps) {
|
if (settings.limitfps) {
|
||||||
if (eta2 > MPEG_CURRENT_TICK) {
|
if (eta2 > s) {
|
||||||
rb->sleep(eta2-MPEG_CURRENT_TICK);
|
rb->sleep(4); //((eta2-s)*HZ)/44100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x = MPEG_CURRENT_TICK;
|
|
||||||
|
|
||||||
/* If we are more than 1/20 second behind schedule (and
|
/* If we are more than 1/20 second behind schedule (and
|
||||||
more than 1/20 second into the decoding), skip frame */
|
more than 1/20 second into the decoding), skip frame */
|
||||||
if (settings.skipframes && (x > HZ/20) &&
|
if (settings.skipframes && (s > (44100/20)) &&
|
||||||
(eta2 < (x - (HZ/20))) && (skipcount < 10)) {
|
(eta2 < (s - (44100/20))) && (skipcount < 10)) {
|
||||||
skipped++;
|
skipped++;
|
||||||
skipcount++;
|
skipcount++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -821,9 +822,9 @@ static void decode_mpeg2 (void)
|
||||||
/* Calculate fps */
|
/* Calculate fps */
|
||||||
frame++;
|
frame++;
|
||||||
if (settings.showfps && (*rb->current_tick-lasttick>=HZ)) {
|
if (settings.showfps && (*rb->current_tick-lasttick>=HZ)) {
|
||||||
fps=(frame*(HZ*10))/x;
|
fps=(frame*441000)/s;
|
||||||
rb->snprintf(str,sizeof(str),"%d.%d %d %d %d",
|
rb->snprintf(str,sizeof(str),"%d.%d %d %d %d",
|
||||||
(fps/10),fps%10,skipped,x,eta2);
|
(fps/10),fps%10,skipped,s,eta2);
|
||||||
rb->lcd_putsxy(0,0,str);
|
rb->lcd_putsxy(0,0,str);
|
||||||
rb->lcd_update_rect(0,0,LCD_WIDTH,8);
|
rb->lcd_update_rect(0,0,LCD_WIDTH,8);
|
||||||
|
|
||||||
|
@ -840,7 +841,8 @@ static void decode_mpeg2 (void)
|
||||||
|
|
||||||
done:
|
done:
|
||||||
videostatus = STREAM_DONE;
|
videostatus = STREAM_DONE;
|
||||||
for (;;) { rb->sleep(HZ); }
|
/* Commit suicide */
|
||||||
|
rb->remove_thread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
||||||
|
@ -919,13 +921,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
||||||
|
|
||||||
init_settings();
|
init_settings();
|
||||||
|
|
||||||
mpeg2dec = mpeg2_init ();
|
|
||||||
|
|
||||||
rb->queue_init( &msg_queue, false ); /* Msg queue init */
|
rb->queue_init( &msg_queue, false ); /* Msg queue init */
|
||||||
|
|
||||||
if (mpeg2dec == NULL)
|
|
||||||
return PLUGIN_ERROR;
|
|
||||||
|
|
||||||
/* make sure the backlight is always on when viewing video
|
/* make sure the backlight is always on when viewing video
|
||||||
(actually it should also set the timeout when plugged in,
|
(actually it should also set the timeout when plugged in,
|
||||||
but the function backlight_set_timeout_plugged is not
|
but the function backlight_set_timeout_plugged is not
|
||||||
|
@ -952,23 +949,23 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
||||||
|
|
||||||
rb->lcd_setfont(FONT_SYSFIXED);
|
rb->lcd_setfont(FONT_SYSFIXED);
|
||||||
|
|
||||||
audiostatus = STREAM_PLAYING;
|
audiostatus = STREAM_BUFFERING;
|
||||||
videostatus = STREAM_PLAYING;
|
videostatus = STREAM_PLAYING;
|
||||||
|
|
||||||
/* We put the video thread on the second processor for multi-core targets. */
|
/* We put the video thread on the second processor for multi-core targets. */
|
||||||
if ((videothread_id = rb->create_thread(decode_mpeg2,
|
if ((videothread_id = rb->create_thread(video_thread,
|
||||||
(uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK)
|
(uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK)
|
||||||
IF_COP(, COP, true))) == NULL)
|
IF_COP(, COP, true))) == NULL)
|
||||||
{
|
{
|
||||||
rb->splash(HZ, "Cannot create video thread!");
|
rb->splash(HZ, "Cannot create video thread!");
|
||||||
return PLUGIN_ERROR;
|
return PLUGIN_ERROR;
|
||||||
}
|
}
|
||||||
|
if ((audiothread_id = rb->create_thread(audio_thread,
|
||||||
if ((audiothread_id = rb->create_thread(mad_decode,
|
|
||||||
(uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK)
|
(uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK)
|
||||||
IF_COP(, CPU, false))) == NULL)
|
IF_COP(, CPU, false))) == NULL)
|
||||||
{
|
{
|
||||||
rb->splash(HZ, "Cannot create audio thread!");
|
rb->splash(HZ, "Cannot create audio thread!");
|
||||||
|
/* To do: Handle this error correctly on dual-core targets */
|
||||||
rb->remove_thread(videothread_id);
|
rb->remove_thread(videothread_id);
|
||||||
return PLUGIN_ERROR;
|
return PLUGIN_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -979,7 +976,6 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
rb->remove_thread(audiothread_id);
|
rb->remove_thread(audiothread_id);
|
||||||
rb->remove_thread(videothread_id);
|
|
||||||
rb->yield(); /* Is this needed? */
|
rb->yield(); /* Is this needed? */
|
||||||
|
|
||||||
rb->lcd_clear_display();
|
rb->lcd_clear_display();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue