summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/plugin.c5
-rw-r--r--apps/plugin.h4
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c438
3 files changed, 297 insertions, 150 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index 793114539e..aff24e0059 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -488,13 +488,12 @@ static const struct plugin_api rockbox_api = {
488#endif 488#endif
489 /* new stuff at the end, sort into place next time 489 /* new stuff at the end, sort into place next time
490 the API gets incompatible */ 490 the API gets incompatible */
491#if NUM_CORES > 1 491
492#if (CONFIG_CODEC == SWCODEC)
492 spinlock_init, 493 spinlock_init,
493 spinlock_lock, 494 spinlock_lock,
494 spinlock_unlock, 495 spinlock_unlock,
495#endif
496 496
497#if (CONFIG_CODEC == SWCODEC)
498 codec_load_file, 497 codec_load_file,
499 get_codec_filename, 498 get_codec_filename,
500 get_metadata, 499 get_metadata,
diff --git a/apps/plugin.h b/apps/plugin.h
index 0edbc87e37..920d804ab5 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -610,13 +610,11 @@ struct plugin_api {
610 /* new stuff at the end, sort into place next time 610 /* new stuff at the end, sort into place next time
611 the API gets incompatible */ 611 the API gets incompatible */
612 612
613#if NUM_CORES > 1 613#if (CONFIG_CODEC == SWCODEC)
614 void (*spinlock_init)(struct mutex *m); 614 void (*spinlock_init)(struct mutex *m);
615 void (*spinlock_lock)(struct mutex *m); 615 void (*spinlock_lock)(struct mutex *m);
616 void (*spinlock_unlock)(struct mutex *m); 616 void (*spinlock_unlock)(struct mutex *m);
617#endif
618 617
619#if (CONFIG_CODEC == SWCODEC)
620 int (*codec_load_file)(const char* codec, struct codec_api *api); 618 int (*codec_load_file)(const char* codec, struct codec_api *api);
621 const char *(*get_codec_filename)(int cod_spec); 619 const char *(*get_codec_filename)(int cod_spec);
622 bool (*get_metadata)(struct track_info* track, int fd, const char* trackname, 620 bool (*get_metadata)(struct track_info* track, int fd, const char* trackname,
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
index 7e18ab4963..cbd4999655 100644
--- a/apps/plugins/mpegplayer/mpegplayer.c
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -169,38 +169,16 @@ static int total_offset = 0;
169static int num_drawn = 0; 169static int num_drawn = 0;
170static int count_start = 0; 170static int count_start = 0;
171 171
172/* Utility */
173
174/* Atomically add one long value to another - not core safe atm if ever needed */
175static inline void locked_add_long(volatile long *value, long amount)
176{
177#if defined (CPU_ARM)
178 /* Disable the fiq - this cuts an instruction out over using the
179 system functions */
180 long cpsr, x;
181 asm volatile (
182 "mrs %[sr], cpsr \r\n"
183 "orr %[sr], %[sr], #0x40 \r\n"
184 "msr cpsr_c, %[sr] \r\n"
185 "ldr %[x], [%[value]] \r\n"
186 "add %[x], %[x], %[amount] \r\n"
187 "str %[x], [%[value]] \r\n"
188 "bic %[sr], %[sr], #0x40 \r\n"
189 "msr cpsr_c, %[sr] \r\n"
190 : [sr]"=&r"(cpsr), [x]"=&r"(x)
191 : [value]"r"(value), [amount]"r"(amount)
192 );
193#elif defined (CPU_COLDFIRE)
194 add_l(amount, value);
195#else
196 /* Don't know what this is so can't lock it */
197 *value += amount;
198#endif
199}
200
201/* Streams */ 172/* Streams */
202typedef struct 173typedef struct
203{ 174{
175 struct thread_entry *thread; /* Stream's thread */
176 int status; /* Current stream status */
177 struct event ev; /* Event sent to steam */
178 int have_msg; /* 1=event pending */
179 int replied; /* 1=replied to last event */
180 int reply; /* reply value */
181 struct mutex msg_lock; /* serialization for event senders */
204 uint8_t* curr_packet; /* Current stream packet beginning */ 182 uint8_t* curr_packet; /* Current stream packet beginning */
205 uint8_t* curr_packet_end; /* Current stream packet end */ 183 uint8_t* curr_packet_end; /* Current stream packet end */
206 184
@@ -219,6 +197,138 @@ typedef struct
219static Stream audio_str IBSS_ATTR; 197static Stream audio_str IBSS_ATTR;
220static Stream video_str IBSS_ATTR; 198static Stream video_str IBSS_ATTR;
221 199
200/* Messages */
201enum
202{
203 STREAM_STOP,
204 STREAM_PLAY,
205 STREAM_PAUSE,
206};
207
208/* Status */
209enum
210{
211 STREAM_ERROR = -4,
212 STREAM_STOPPED = -3,
213 STREAM_TERMINATED = -2,
214 STREAM_DONE = -1,
215 STREAM_PLAYING = 0,
216 STREAM_PAUSED,
217 STREAM_BUFFERING
218};
219
220/* Returns true if a message is waiting */
221static inline bool str_have_msg(Stream *str)
222{
223 return str->have_msg != 0;
224}
225
226/* Waits until a message is sent */
227static void str_wait_msg(Stream *str)
228{
229 /* NOTE: sleep(0) caused a prefectch abort at C0EDBABE on e200 -
230 will look into this oddness */
231#if 0
232 int spin_count = 0;
233#endif
234
235 while (str->have_msg == 0)
236 {
237#if 0
238 if (spin_count < 100)
239 {
240 rb->yield();
241 spin_count++;
242 continue;
243 }
244
245 rb->sleep(0);
246#endif
247 rb->yield();
248 }
249}
250
251/* Returns a message waiting or blocks until one is available - removes the
252 event */
253static bool str_get_msg(Stream *str, struct event *ev)
254{
255 str_wait_msg(str);
256 ev->id = str->ev.id;
257 ev->data = str->ev.data;
258 str->have_msg = 0;
259 return true;
260}
261
262/* Peeks at the current message without blocking, returns the data but
263 does not remove the event */
264static bool str_look_msg(Stream *str, struct event *ev)
265{
266 if (!str_have_msg(str))
267 return false;
268
269 ev->id = str->ev.id;
270 ev->data = str->ev.data;
271 return true;
272}
273
274/* Replies to the last message pulled - has no effect if last message has not
275 been pulled or already replied */
276static void str_reply_msg(Stream *str, int reply)
277{
278 if (str->replied == 1 || str->have_msg != 0)
279 return;
280
281 str->reply = reply;
282 str->replied = 1;
283}
284
285/* Sends a message to a stream and waits for a reply */
286static intptr_t str_send_msg(Stream *str, int id, intptr_t data)
287{
288 /* NOTE: sleep(0) caused a prefectch abort at C0EDBABE on e200 -
289 will look into this oddness */
290#if 0
291 int spin_count = 0;
292#endif
293
294 intptr_t reply;
295
296#if 0
297 if (str->thread == rb->thread_get_current())
298 return str->dispatch_fn(str, msg);
299#endif
300
301 /* Only one thread at a time, please */
302 rb->spinlock_lock(&str->msg_lock);
303
304 str->ev.id = id;
305 str->ev.data = data;
306 str->reply = 0;
307 str->replied = 0;
308 str->have_msg = 1;
309
310 while (str->replied == 0 && str->status != STREAM_TERMINATED)
311 {
312#if 0
313 if (spin_count < 100)
314 {
315 rb->yield();
316 spin_count++;
317 continue;
318 }
319
320 rb->sleep(0);
321#endif
322 rb->yield();
323 }
324
325 reply = str->reply;
326
327 rb->spinlock_unlock(&str->msg_lock);
328
329 return reply;
330}
331
222/* NOTE: Putting the following variables in IRAM cause audio corruption 332/* NOTE: Putting the following variables in IRAM cause audio corruption
223 on the ipod (reason unknown) 333 on the ipod (reason unknown)
224*/ 334*/
@@ -251,26 +361,6 @@ static struct event_queue msg_queue IBSS_ATTR;
251#define MSG_BUFFER_NEARLY_EMPTY 1 361#define MSG_BUFFER_NEARLY_EMPTY 1
252#define MSG_EXIT_REQUESTED 2 362#define MSG_EXIT_REQUESTED 2
253 363
254/* Threads */
255static struct thread_entry* audiothread_id;
256static struct thread_entry* videothread_id;
257
258/* Status */
259enum
260{
261 STREAM_PLAYING = 0,
262 STREAM_DONE,
263 STREAM_PAUSING,
264 STREAM_BUFFERING,
265 STREAM_ERROR,
266 PLEASE_STOP,
267 PLEASE_PAUSE,
268 THREAD_TERMINATED,
269};
270
271volatile int audiostatus IBSS_ATTR;
272volatile int videostatus IBSS_ATTR;
273
274/* Various buffers */ 364/* Various buffers */
275/* TODO: Can we reduce the PCM buffer size? */ 365/* TODO: Can we reduce the PCM buffer size? */
276#define PCMBUFFER_SIZE ((512*1024)-PCMBUFFER_GUARD_SIZE) 366#define PCMBUFFER_SIZE ((512*1024)-PCMBUFFER_GUARD_SIZE)
@@ -700,7 +790,8 @@ struct pcm_frame_header /* Header added to pcm data every time a decoded
700 790
701#define PCMBUF_PLAY_ALL 1l /* Forces buffer to play back all data */ 791#define PCMBUF_PLAY_ALL 1l /* Forces buffer to play back all data */
702#define PCMBUF_PLAY_NONE LONG_MAX /* Keeps buffer from playing any data */ 792#define PCMBUF_PLAY_NONE LONG_MAX /* Keeps buffer from playing any data */
703static volatile ssize_t pcmbuf_used IBSS_ATTR; 793static volatile uint64_t pcmbuf_read IBSS_ATTR;
794static volatile uint64_t pcmbuf_written IBSS_ATTR;
704static volatile ssize_t pcmbuf_threshold IBSS_ATTR; 795static volatile ssize_t pcmbuf_threshold IBSS_ATTR;
705static struct pcm_frame_header *pcm_buffer IBSS_ATTR; 796static struct pcm_frame_header *pcm_buffer IBSS_ATTR;
706static struct pcm_frame_header *pcmbuf_end IBSS_ATTR; 797static struct pcm_frame_header *pcmbuf_end IBSS_ATTR;
@@ -711,6 +802,11 @@ static volatile uint32_t samplesplayed IBSS_ATTR; /* Our base clock */
711static volatile uint32_t samplestart IBSS_ATTR; /* Clock at playback start */ 802static volatile uint32_t samplestart IBSS_ATTR; /* Clock at playback start */
712static volatile int32_t sampleadjust IBSS_ATTR; /* Clock drift adjustment */ 803static volatile int32_t sampleadjust IBSS_ATTR; /* Clock drift adjustment */
713 804
805static ssize_t pcmbuf_used(void)
806{
807 return (ssize_t)(pcmbuf_written - pcmbuf_read);
808}
809
714static bool init_pcmbuf(void) 810static bool init_pcmbuf(void)
715{ 811{
716 pcm_buffer = mpeg2_malloc(PCMBUFFER_SIZE + PCMBUFFER_GUARD_SIZE, -2); 812 pcm_buffer = mpeg2_malloc(PCMBUFFER_SIZE + PCMBUFFER_GUARD_SIZE, -2);
@@ -721,7 +817,8 @@ static bool init_pcmbuf(void)
721 pcmbuf_head = pcm_buffer; 817 pcmbuf_head = pcm_buffer;
722 pcmbuf_tail = pcm_buffer; 818 pcmbuf_tail = pcm_buffer;
723 pcmbuf_end = SKIPBYTES(pcm_buffer, PCMBUFFER_SIZE); 819 pcmbuf_end = SKIPBYTES(pcm_buffer, PCMBUFFER_SIZE);
724 pcmbuf_used = 0; 820 pcmbuf_read = 0;
821 pcmbuf_written = 0;
725 822
726 return true; 823 return true;
727} 824}
@@ -741,7 +838,7 @@ static void get_more(unsigned char** start, size_t* size)
741 static unsigned char silence[4412] __attribute__((aligned (4))) = { 0 }; 838 static unsigned char silence[4412] __attribute__((aligned (4))) = { 0 };
742 size_t sz; 839 size_t sz;
743 840
744 if (pcmbuf_used >= pcmbuf_threshold) 841 if (pcmbuf_used() >= pcmbuf_threshold)
745 { 842 {
746 uint32_t time = pcmbuf_tail->time; 843 uint32_t time = pcmbuf_tail->time;
747 sz = pcmbuf_tail->size; 844 sz = pcmbuf_tail->size;
@@ -750,7 +847,7 @@ static void get_more(unsigned char** start, size_t* size)
750 847
751 pcm_advance_buffer(&pcmbuf_tail, sz); 848 pcm_advance_buffer(&pcmbuf_tail, sz);
752 849
753 pcmbuf_used -= sz; 850 pcmbuf_read += sz;
754 851
755 sz -= sizeof (*pcmbuf_tail); 852 sz -= sizeof (*pcmbuf_tail);
756 853
@@ -771,8 +868,8 @@ static void get_more(unsigned char** start, size_t* size)
771 868
772 samplesplayed += sz >> 2; 869 samplesplayed += sz >> 2;
773 870
774 if (pcmbuf_used < 0) 871 if (pcmbuf_read > pcmbuf_written)
775 pcmbuf_used = 0; 872 pcmbuf_read = pcmbuf_written;
776} 873}
777 874
778/* Flushes the buffer - clock keeps counting */ 875/* Flushes the buffer - clock keeps counting */
@@ -783,7 +880,8 @@ static void pcm_playback_flush(void)
783 if (was_playing) 880 if (was_playing)
784 rb->pcm_play_stop(); 881 rb->pcm_play_stop();
785 882
786 pcmbuf_used = 0; 883 pcmbuf_read = 0;
884 pcmbuf_written = 0;
787 pcmbuf_head = pcmbuf_tail; 885 pcmbuf_head = pcmbuf_tail;
788 886
789 if (was_playing) 887 if (was_playing)
@@ -855,11 +953,30 @@ static inline int32_t clip_sample(int32_t sample)
855 return sample; 953 return sample;
856} 954}
857 955
858static void button_loop(void) 956static int button_loop(void)
859{ 957{
860 bool result; 958 bool result;
861 int vol, minvol, maxvol; 959 int vol, minvol, maxvol;
862 int button = rb->button_get(false); 960 int button;
961
962 if (str_have_msg(&audio_str))
963 {
964 struct event ev;
965 str_get_msg(&audio_str, &ev);
966
967 if (ev.id == STREAM_STOP)
968 {
969 audio_str.status = STREAM_STOPPED;
970 str_reply_msg(&audio_str, 1);
971 goto quit;
972 }
973 else
974 {
975 str_reply_msg(&audio_str, 0);
976 }
977 }
978
979 button = rb->button_get(false);
863 980
864 switch (button) 981 switch (button)
865 { 982 {
@@ -897,13 +1014,8 @@ static void button_loop(void)
897 1014
898 case MPEG_MENU: 1015 case MPEG_MENU:
899 pcm_playback_play_pause(false); 1016 pcm_playback_play_pause(false);
900 if (videostatus != STREAM_DONE) { 1017 audio_str.status = STREAM_PAUSED;
901 videostatus=PLEASE_PAUSE; 1018 str_send_msg(&video_str, STREAM_PAUSE, 0);
902
903 /* Wait for video thread to stop */
904 while (videostatus == PLEASE_PAUSE) { rb->sleep(HZ/25); }
905 }
906
907#ifndef HAVE_LCD_COLOR 1019#ifndef HAVE_LCD_COLOR
908 gray_show(false); 1020 gray_show(false);
909#endif 1021#endif
@@ -919,21 +1031,23 @@ static void button_loop(void)
919 rb->lcd_setfont(FONT_SYSFIXED); 1031 rb->lcd_setfont(FONT_SYSFIXED);
920 1032
921 if (result) { 1033 if (result) {
922 audiostatus = PLEASE_STOP; 1034 str_send_msg(&video_str, STREAM_STOP, 0);
923 if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP; 1035 audio_str.status = STREAM_STOPPED;
924 } else { 1036 } else {
925 if (videostatus != STREAM_DONE) videostatus = STREAM_PLAYING; 1037 audio_str.status = STREAM_PLAYING;
1038 str_send_msg(&video_str, STREAM_PLAY, 0);
926 pcm_playback_play_pause(true); 1039 pcm_playback_play_pause(true);
927 } 1040 }
928 break; 1041 break;
929 1042
930 case MPEG_STOP: 1043 case MPEG_STOP:
931 audiostatus = PLEASE_STOP; 1044 str_send_msg(&video_str, STREAM_STOP, 0);
932 if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP; 1045 audio_str.status = STREAM_STOPPED;
933 break; 1046 break;
934 1047
935 case MPEG_PAUSE: 1048 case MPEG_PAUSE:
936 if (videostatus != STREAM_DONE) videostatus=PLEASE_PAUSE; 1049 str_send_msg(&video_str, STREAM_PAUSE, 0);
1050 audio_str.status = STREAM_PAUSED;
937 pcm_playback_play_pause(false); 1051 pcm_playback_play_pause(false);
938 1052
939 button = BUTTON_NONE; 1053 button = BUTTON_NONE;
@@ -943,13 +1057,14 @@ static void button_loop(void)
943 do { 1057 do {
944 button = rb->button_get(true); 1058 button = rb->button_get(true);
945 if (button == MPEG_STOP) { 1059 if (button == MPEG_STOP) {
946 audiostatus = PLEASE_STOP; 1060 str_send_msg(&video_str, STREAM_STOP, 0);
947 if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP; 1061 audio_str.status = STREAM_STOPPED;
948 return; 1062 goto quit;
949 } 1063 }
950 } while (button != MPEG_PAUSE); 1064 } while (button != MPEG_PAUSE);
951 1065
952 if (videostatus != STREAM_DONE) videostatus = STREAM_PLAYING; 1066 str_send_msg(&video_str, STREAM_PLAY, 0);
1067 audio_str.status = STREAM_PLAYING;
953 pcm_playback_play_pause(true); 1068 pcm_playback_play_pause(true);
954#ifdef HAVE_ADJUSTABLE_CPU_FREQ 1069#ifdef HAVE_ADJUSTABLE_CPU_FREQ
955 rb->cpu_boost(true); 1070 rb->cpu_boost(true);
@@ -958,10 +1073,13 @@ static void button_loop(void)
958 1073
959 default: 1074 default:
960 if(rb->default_event_handler(button) == SYS_USB_CONNECTED) { 1075 if(rb->default_event_handler(button) == SYS_USB_CONNECTED) {
961 audiostatus = PLEASE_STOP; 1076 str_send_msg(&video_str, STREAM_STOP, 0);
962 if (videostatus != STREAM_DONE) videostatus = PLEASE_STOP; 1077 audio_str.status = STREAM_STOPPED;
963 } 1078 }
964 } 1079 }
1080
1081quit:
1082 return audio_str.status;
965} 1083}
966 1084
967static void audio_thread(void) 1085static void audio_thread(void)
@@ -996,10 +1114,8 @@ static void audio_thread(void)
996 int mad_stat; 1114 int mad_stat;
997 size_t len; 1115 size_t len;
998 1116
999 button_loop(); 1117 if (button_loop() < 0)
1000 1118 goto done;
1001 if (audiostatus == PLEASE_STOP)
1002 goto done;
1003 1119
1004 if (pts->size <= 0) 1120 if (pts->size <= 0)
1005 { 1121 {
@@ -1146,10 +1262,21 @@ static void audio_thread(void)
1146 1262
1147 /* Leave at least 32KB free (this will be the currently 1263 /* Leave at least 32KB free (this will be the currently
1148 playing chunk) */ 1264 playing chunk) */
1149 while (pcmbuf_used + wait_for > PCMBUFFER_SIZE) 1265 while (pcmbuf_used() + wait_for > PCMBUFFER_SIZE)
1150 { 1266 {
1151 if (audiostatus == PLEASE_STOP) 1267 if (str_have_msg(&audio_str))
1152 goto done; 1268 {
1269 struct event ev;
1270 str_look_msg(&audio_str, &ev);
1271
1272 if (ev.id == STREAM_STOP)
1273 {
1274 str_get_msg(&audio_str, &ev);
1275 str_reply_msg(&audio_str, 1);
1276 goto stop_and_wait;
1277 }
1278 }
1279
1153 rb->priority_yield(); 1280 rb->priority_yield();
1154 } 1281 }
1155 1282
@@ -1192,56 +1319,56 @@ static void audio_thread(void)
1192 1319
1193 pcm_advance_buffer(&pcmbuf_head, size); 1320 pcm_advance_buffer(&pcmbuf_head, size);
1194 1321
1195 if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used >= 64*1024) 1322 if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used() >= 64*1024)
1196 { 1323 {
1197 /* We've reached our size treshold so start playing back the 1324 /* We've reached our size treshold so start playing back the
1198 audio in the buffer and set the buffer to play all data */ 1325 audio in the buffer and set the buffer to play all data */
1199 audiostatus = STREAM_PLAYING; 1326 audio_str.status = STREAM_PLAYING;
1200 pcmbuf_threshold = PCMBUF_PLAY_ALL; 1327 pcmbuf_threshold = PCMBUF_PLAY_ALL;
1201 pcm_playback_seek_time(pcmbuf_tail->time); 1328 pcm_playback_seek_time(pcmbuf_tail->time);
1202 } 1329 }
1203 1330
1204 /* Make this data available to DMA */ 1331 /* Make this data available to DMA */
1205 locked_add_long(&pcmbuf_used, size); 1332 pcmbuf_written += size;
1206 } 1333 }
1207 1334
1208 rb->yield(); 1335 rb->yield();
1209 } /* end decoding loop */ 1336 } /* end decoding loop */
1210 1337
1211done: 1338done:
1212 if (audiostatus != PLEASE_STOP) 1339 if (audio_str.status == STREAM_STOPPED)
1340 goto stop_and_wait;
1341
1342 /* Force any residue to play if audio ended before reaching the
1343 threshold */
1344 if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used() > 0)
1213 { 1345 {
1214 /* Force any residue to play if audio ended before reaching the 1346 pcm_playback_play(pcmbuf_tail->time);
1215 threshold */ 1347 pcmbuf_threshold = PCMBUF_PLAY_ALL;
1216 if (pcmbuf_threshold != PCMBUF_PLAY_ALL && pcmbuf_used > 0) 1348 }
1217 {
1218 pcm_playback_play(pcmbuf_tail->time);
1219 pcmbuf_threshold = PCMBUF_PLAY_ALL;
1220 }
1221 1349
1222 if (rb->pcm_is_playing() && !rb->pcm_is_paused()) 1350 if (rb->pcm_is_playing() && !rb->pcm_is_paused())
1351 {
1352 /* Wait for audio to finish */
1353 while (pcmbuf_used() > 0)
1223 { 1354 {
1224 /* Wait for audio to finish */ 1355 if (button_loop() == STREAM_STOPPED)
1225 while (pcmbuf_used > 0 && audiostatus != PLEASE_STOP) 1356 break;
1226 { 1357 rb->sleep(HZ/10);
1227 button_loop();
1228 rb->sleep(HZ/10);
1229 }
1230 } 1358 }
1231 } 1359 }
1232 1360
1233 audiostatus = STREAM_DONE; 1361stop_and_wait:
1362
1363 audio_str.status = STREAM_DONE;
1234 1364
1235 /* Process events until finished */ 1365 /* Process events until finished */
1236 while (audiostatus != PLEASE_STOP) 1366 while (button_loop() != STREAM_STOPPED)
1237 {
1238 button_loop();
1239 rb->sleep(HZ/4); 1367 rb->sleep(HZ/4);
1240 }
1241 1368
1242 pcm_playback_stop(); 1369 pcm_playback_stop();
1243 1370
1244 audiostatus = THREAD_TERMINATED; 1371 audio_str.status = STREAM_TERMINATED;
1245 rb->remove_thread(NULL); 1372 rb->remove_thread(NULL);
1246} 1373}
1247 1374
@@ -1260,6 +1387,7 @@ static uint32_t video_stack[VIDEO_STACKSIZE / sizeof(uint32_t)] IBSS_ATTR;
1260 1387
1261static void video_thread(void) 1388static void video_thread(void)
1262{ 1389{
1390 struct event ev;
1263 const mpeg2_info_t * info; 1391 const mpeg2_info_t * info;
1264 mpeg2_state_t state; 1392 mpeg2_state_t state;
1265 char str[80]; 1393 char str[80];
@@ -1280,7 +1408,7 @@ static void video_thread(void)
1280 { 1408 {
1281 rb->splash(0, "mpeg2_init failed"); 1409 rb->splash(0, "mpeg2_init failed");
1282 /* Commit suicide */ 1410 /* Commit suicide */
1283 videostatus = THREAD_TERMINATED; 1411 video_str.status = STREAM_TERMINATED;
1284 rb->remove_thread(NULL); 1412 rb->remove_thread(NULL);
1285 } 1413 }
1286 1414
@@ -1302,24 +1430,36 @@ static void video_thread(void)
1302 1430
1303 /* Wait if the audio thread is buffering - i.e. before 1431 /* Wait if the audio thread is buffering - i.e. before
1304 the first frames are decoded */ 1432 the first frames are decoded */
1305 while (audiostatus == STREAM_BUFFERING) 1433 while (audio_str.status == STREAM_BUFFERING)
1306 rb->priority_yield(); 1434 rb->priority_yield();
1307 1435
1308 while (1) 1436 while (1)
1309 { 1437 {
1310 if (videostatus == PLEASE_STOP) 1438 /* quickly check mailbox first */
1311 { 1439 if (str_have_msg(&video_str))
1312 break;
1313 }
1314 else if (videostatus == PLEASE_PAUSE)
1315 { 1440 {
1316 videostatus = STREAM_PAUSING; 1441 while (1)
1317 flush_icache(); 1442 {
1443 str_get_msg(&video_str, &ev);
1318 1444
1319 while (videostatus == STREAM_PAUSING) 1445 switch (ev.id)
1320 rb->sleep(HZ/10); 1446 {
1447 case STREAM_STOP:
1448 video_str.status = STREAM_STOPPED;
1449 str_reply_msg(&video_str, 1);
1450 goto done;
1451 case STREAM_PAUSE:
1452 flush_icache();
1453 video_str.status = STREAM_PAUSED;
1454 str_reply_msg(&video_str, 1);
1455 continue;
1456 }
1321 1457
1322 continue; 1458 break;
1459 }
1460
1461 video_str.status = STREAM_PLAYING;
1462 str_reply_msg(&video_str, 1);
1323 } 1463 }
1324 1464
1325 state = mpeg2_parse (mpeg2dec); 1465 state = mpeg2_parse (mpeg2dec);
@@ -1551,8 +1691,16 @@ static void video_thread(void)
1551 rb->priority_yield(); 1691 rb->priority_yield();
1552 1692
1553 /* Make sure not to get stuck waiting here forever */ 1693 /* Make sure not to get stuck waiting here forever */
1554 if (videostatus != STREAM_PLAYING) 1694 if (str_have_msg(&video_str))
1555 goto rendering_finished; 1695 {
1696 str_look_msg(&video_str, &ev);
1697
1698 if (ev.id != STREAM_PLAY)
1699 goto rendering_finished;
1700
1701 str_get_msg(&video_str, &ev);
1702 str_reply_msg(&video_str, 1);
1703 }
1556 1704
1557 eta_audio = get_stream_time(); 1705 eta_audio = get_stream_time();
1558 } 1706 }
@@ -1599,13 +1747,21 @@ static void video_thread(void)
1599done: 1747done:
1600 flush_icache(); 1748 flush_icache();
1601 1749
1602 videostatus = STREAM_DONE; 1750 video_str.status = STREAM_DONE;
1603 1751
1604 while (videostatus != PLEASE_STOP) 1752 while (1)
1605 rb->sleep(HZ/5); 1753 {
1754 str_get_msg(&video_str, &ev);
1755
1756 if (ev.id == STREAM_STOP)
1757 break;
1758
1759 str_reply_msg(&video_str, 0);
1760 }
1606 1761
1607 videostatus = THREAD_TERMINATED;
1608 /* Commit suicide */ 1762 /* Commit suicide */
1763 str_reply_msg(&video_str, 1);
1764 video_str.status = STREAM_TERMINATED;
1609 rb->remove_thread(NULL); 1765 rb->remove_thread(NULL);
1610} 1766}
1611 1767
@@ -1756,8 +1912,10 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1756 video_str.buffer_remaining = disk_buf_len; 1912 video_str.buffer_remaining = disk_buf_len;
1757 audio_str.buffer_remaining = disk_buf_len; 1913 audio_str.buffer_remaining = disk_buf_len;
1758 1914
1759 audiostatus = STREAM_BUFFERING; 1915 rb->spinlock_init(&audio_str.msg_lock);
1760 videostatus = STREAM_PLAYING; 1916 rb->spinlock_init(&video_str.msg_lock);
1917 audio_str.status = STREAM_BUFFERING;
1918 video_str.status = STREAM_PLAYING;
1761 1919
1762#ifndef HAVE_LCD_COLOR 1920#ifndef HAVE_LCD_COLOR
1763 gray_show(true); 1921 gray_show(true);
@@ -1766,13 +1924,13 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1766 init_stream_lock(); 1924 init_stream_lock();
1767 1925
1768 /* We put the video thread on the second processor for multi-core targets. */ 1926 /* We put the video thread on the second processor for multi-core targets. */
1769 if ((videothread_id = rb->create_thread(video_thread, 1927 if ((video_str.thread = rb->create_thread(video_thread,
1770 (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK) 1928 (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" IF_PRIO(,PRIORITY_PLAYBACK)
1771 IF_COP(, COP, true))) == NULL) 1929 IF_COP(, COP, true))) == NULL)
1772 { 1930 {
1773 rb->splash(HZ, "Cannot create video thread!"); 1931 rb->splash(HZ, "Cannot create video thread!");
1774 } 1932 }
1775 else if ((audiothread_id = rb->create_thread(audio_thread, 1933 else if ((audio_str.thread = rb->create_thread(audio_thread,
1776 (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK) 1934 (uint8_t*)audio_stack,AUDIO_STACKSIZE,"mpgaudio" IF_PRIO(,PRIORITY_PLAYBACK)
1777 IF_COP(, CPU, false))) == NULL) 1935 IF_COP(, CPU, false))) == NULL)
1778 { 1936 {
@@ -1784,7 +1942,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1784 rb->lcd_setfont(FONT_SYSFIXED); 1942 rb->lcd_setfont(FONT_SYSFIXED);
1785 1943
1786 /* Wait until both threads have finished their work */ 1944 /* Wait until both threads have finished their work */
1787 while ((audiostatus != STREAM_DONE) || (videostatus != STREAM_DONE)) 1945 while ((audio_str.status >= 0) || (video_str.status >= 0))
1788 { 1946 {
1789 size_t audio_remaining = audio_str.buffer_remaining; 1947 size_t audio_remaining = audio_str.buffer_remaining;
1790 size_t video_remaining = video_str.buffer_remaining; 1948 size_t video_remaining = video_str.buffer_remaining;
@@ -1797,7 +1955,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1797 bytes_to_read = MIN(bytes_to_read,(size_t)(disk_buf_end-disk_buf_tail)); 1955 bytes_to_read = MIN(bytes_to_read,(size_t)(disk_buf_end-disk_buf_tail));
1798 1956
1799 while (( bytes_to_read > 0) && (file_remaining > 0) && 1957 while (( bytes_to_read > 0) && (file_remaining > 0) &&
1800 ((audiostatus != STREAM_DONE) || (videostatus != STREAM_DONE))) { 1958 ((audio_str.status >= 0) || (video_str.status >= 0))) {
1801 size_t n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read)); 1959 size_t n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read));
1802 1960
1803 bytes_to_read -= n; 1961 bytes_to_read -= n;
@@ -1825,19 +1983,11 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1825 } 1983 }
1826 1984
1827 /* Stop the threads and wait for them to terminate */ 1985 /* Stop the threads and wait for them to terminate */
1828 if (videothread_id != NULL && videostatus != THREAD_TERMINATED) 1986 if (video_str.thread != NULL)
1829 { 1987 str_send_msg(&video_str, STREAM_STOP, 0);
1830 videostatus = PLEASE_STOP;
1831 while (videostatus != THREAD_TERMINATED)
1832 rb->yield();
1833 }
1834 1988
1835 if (audiothread_id != NULL && audiostatus != THREAD_TERMINATED) 1989 if (audio_str.thread != NULL)
1836 { 1990 str_send_msg(&audio_str, STREAM_STOP, 0);
1837 audiostatus = PLEASE_STOP;
1838 while (audiostatus != THREAD_TERMINATED)
1839 rb->yield();
1840 }
1841 1991
1842 rb->sleep(HZ/10); 1992 rb->sleep(HZ/10);
1843 1993