diff options
Diffstat (limited to 'apps/plugins/mpegplayer/mpegplayer.c')
-rw-r--r-- | apps/plugins/mpegplayer/mpegplayer.c | 1066 |
1 files changed, 1019 insertions, 47 deletions
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index 03ec5ba821..e9f6b9011f 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c | |||
@@ -116,6 +116,8 @@ PLUGIN_IRAM_DECLARE | |||
116 | #define MPEG_PAUSE BUTTON_ON | 116 | #define MPEG_PAUSE BUTTON_ON |
117 | #define MPEG_VOLDOWN BUTTON_DOWN | 117 | #define MPEG_VOLDOWN BUTTON_DOWN |
118 | #define MPEG_VOLUP BUTTON_UP | 118 | #define MPEG_VOLUP BUTTON_UP |
119 | #define MPEG_RW BUTTON_LEFT | ||
120 | #define MPEG_FF BUTTON_RIGHT | ||
119 | 121 | ||
120 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ | 122 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ |
121 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) | 123 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) |
@@ -124,6 +126,8 @@ PLUGIN_IRAM_DECLARE | |||
124 | #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) | 126 | #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) |
125 | #define MPEG_VOLDOWN BUTTON_SCROLL_BACK | 127 | #define MPEG_VOLDOWN BUTTON_SCROLL_BACK |
126 | #define MPEG_VOLUP BUTTON_SCROLL_FWD | 128 | #define MPEG_VOLUP BUTTON_SCROLL_FWD |
129 | #define MPEG_RW BUTTON_LEFT | ||
130 | #define MPEG_FF BUTTON_RIGHT | ||
127 | 131 | ||
128 | #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD | 132 | #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD |
129 | #define MPEG_MENU (BUTTON_REC | BUTTON_REL) | 133 | #define MPEG_MENU (BUTTON_REC | BUTTON_REL) |
@@ -131,6 +135,8 @@ PLUGIN_IRAM_DECLARE | |||
131 | #define MPEG_PAUSE BUTTON_PLAY | 135 | #define MPEG_PAUSE BUTTON_PLAY |
132 | #define MPEG_VOLDOWN BUTTON_DOWN | 136 | #define MPEG_VOLDOWN BUTTON_DOWN |
133 | #define MPEG_VOLUP BUTTON_UP | 137 | #define MPEG_VOLUP BUTTON_UP |
138 | #define MPEG_RW BUTTON_LEFT | ||
139 | #define MPEG_FF BUTTON_RIGHT | ||
134 | 140 | ||
135 | #elif CONFIG_KEYPAD == GIGABEAT_PAD | 141 | #elif CONFIG_KEYPAD == GIGABEAT_PAD |
136 | #define MPEG_MENU BUTTON_MENU | 142 | #define MPEG_MENU BUTTON_MENU |
@@ -141,13 +147,17 @@ PLUGIN_IRAM_DECLARE | |||
141 | #define MPEG_VOLUP BUTTON_RIGHT | 147 | #define MPEG_VOLUP BUTTON_RIGHT |
142 | #define MPEG_VOLDOWN2 BUTTON_VOL_DOWN | 148 | #define MPEG_VOLDOWN2 BUTTON_VOL_DOWN |
143 | #define MPEG_VOLUP2 BUTTON_VOL_UP | 149 | #define MPEG_VOLUP2 BUTTON_VOL_UP |
150 | #define MPEG_RW BUTTON_UP | ||
151 | #define MPEG_FF BUTTON_DOWN | ||
144 | 152 | ||
145 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD | 153 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD |
146 | #define MPEG_MENU (BUTTON_REW | BUTTON_REL) | 154 | #define MPEG_MENU BUTTON_LEFT |
147 | #define MPEG_STOP BUTTON_POWER | 155 | #define MPEG_STOP BUTTON_POWER |
148 | #define MPEG_PAUSE BUTTON_PLAY | 156 | #define MPEG_PAUSE BUTTON_PLAY |
149 | #define MPEG_VOLDOWN BUTTON_SCROLL_DOWN | 157 | #define MPEG_VOLDOWN BUTTON_SCROLL_DOWN |
150 | #define MPEG_VOLUP BUTTON_SCROLL_UP | 158 | #define MPEG_VOLUP BUTTON_SCROLL_UP |
159 | #define MPEG_RW BUTTON_REW | ||
160 | #define MPEG_FF BUTTON_FF | ||
151 | 161 | ||
152 | #elif CONFIG_KEYPAD == SANSA_E200_PAD | 162 | #elif CONFIG_KEYPAD == SANSA_E200_PAD |
153 | #define MPEG_MENU BUTTON_SELECT | 163 | #define MPEG_MENU BUTTON_SELECT |
@@ -155,6 +165,8 @@ PLUGIN_IRAM_DECLARE | |||
155 | #define MPEG_PAUSE BUTTON_UP | 165 | #define MPEG_PAUSE BUTTON_UP |
156 | #define MPEG_VOLDOWN BUTTON_SCROLL_UP | 166 | #define MPEG_VOLDOWN BUTTON_SCROLL_UP |
157 | #define MPEG_VOLUP BUTTON_SCROLL_DOWN | 167 | #define MPEG_VOLUP BUTTON_SCROLL_DOWN |
168 | #define MPEG_RW BUTTON_LEFT | ||
169 | #define MPEG_FF BUTTON_RIGHT | ||
158 | 170 | ||
159 | #elif CONFIG_KEYPAD == SANSA_C200_PAD | 171 | #elif CONFIG_KEYPAD == SANSA_C200_PAD |
160 | #define MPEG_MENU BUTTON_SELECT | 172 | #define MPEG_MENU BUTTON_SELECT |
@@ -162,6 +174,8 @@ PLUGIN_IRAM_DECLARE | |||
162 | #define MPEG_PAUSE BUTTON_UP | 174 | #define MPEG_PAUSE BUTTON_UP |
163 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | 175 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN |
164 | #define MPEG_VOLUP BUTTON_VOL_UP | 176 | #define MPEG_VOLUP BUTTON_VOL_UP |
177 | #define MPEG_RW BUTTON_LEFT | ||
178 | #define MPEG_FF BUTTON_RIGHT | ||
165 | 179 | ||
166 | #elif CONFIG_KEYPAD == MROBE500_PAD | 180 | #elif CONFIG_KEYPAD == MROBE500_PAD |
167 | #define MPEG_MENU BUTTON_RC_HEART | 181 | #define MPEG_MENU BUTTON_RC_HEART |
@@ -169,6 +183,8 @@ PLUGIN_IRAM_DECLARE | |||
169 | #define MPEG_PAUSE BUTTON_TOUCHPAD | 183 | #define MPEG_PAUSE BUTTON_TOUCHPAD |
170 | #define MPEG_VOLDOWN BUTTON_RC_VOL_DOWN | 184 | #define MPEG_VOLDOWN BUTTON_RC_VOL_DOWN |
171 | #define MPEG_VOLUP BUTTON_RC_VOL_UP | 185 | #define MPEG_VOLUP BUTTON_RC_VOL_UP |
186 | #define MPEG_RW BUTTON_RC_REW | ||
187 | #define MPEG_FF BUTTON_RC_FF | ||
172 | 188 | ||
173 | #else | 189 | #else |
174 | #error MPEGPLAYER: Unsupported keypad | 190 | #error MPEGPLAYER: Unsupported keypad |
@@ -179,31 +195,997 @@ struct plugin_api* rb; | |||
179 | CACHE_FUNCTION_WRAPPERS(rb); | 195 | CACHE_FUNCTION_WRAPPERS(rb); |
180 | ALIGN_BUFFER_WRAPPER(rb); | 196 | ALIGN_BUFFER_WRAPPER(rb); |
181 | 197 | ||
182 | static bool button_loop(void) | 198 | /* One thing we can do here for targets with remotes is having a display |
199 | * always on the remote instead of always forcing a popup on the main display */ | ||
200 | |||
201 | #define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */ | ||
202 | /* 3% of 30min file == 54s step size */ | ||
203 | #define MIN_FF_REWIND_STEP (TS_SECOND/2) | ||
204 | #define WVS_MIN_UPDATE_INTERVAL (HZ/2) | ||
205 | |||
206 | /* WVS status - same order as icon array */ | ||
207 | enum wvs_status_enum | ||
208 | { | ||
209 | WVS_STATUS_STOPPED = 0, | ||
210 | WVS_STATUS_PAUSED, | ||
211 | WVS_STATUS_PLAYING, | ||
212 | WVS_STATUS_FF, | ||
213 | WVS_STATUS_RW, | ||
214 | WVS_STATUS_COUNT, | ||
215 | WVS_STATUS_MASK = 0x7 | ||
216 | }; | ||
217 | |||
218 | enum wvs_bits | ||
183 | { | 219 | { |
184 | bool ret = true; | 220 | WVS_REFRESH_DEFAULT = 0x0000, |
221 | WVS_REFRESH_VOLUME = 0x0001, | ||
222 | WVS_REFRESH_TIME = 0x0002, | ||
223 | WVS_REFRESH_STATUS = 0x0004, | ||
224 | WVS_REFRESH_BACKGROUND = 0x0008, | ||
225 | WVS_REFRESH_VIDEO = 0x0010, | ||
226 | WVS_REFRESH_RESUME = 0x0020, | ||
227 | WVS_NODRAW = 0x8000, | ||
228 | WVS_SHOW = 0x4000, | ||
229 | WVS_HIDE = 0x0000, | ||
230 | WVS_REFRESH_ALL = 0x001f, | ||
231 | }; | ||
232 | |||
233 | extern const unsigned char mpegplayer_status_icons_8x8x1[]; | ||
234 | extern const unsigned char mpegplayer_status_icons_12x12x1[]; | ||
235 | extern const unsigned char mpegplayer_status_icons_16x16x1[]; | ||
236 | |||
237 | #define WVS_BDR_L 2 | ||
238 | #define WVS_BDR_T 2 | ||
239 | #define WVS_BDR_R 2 | ||
240 | #define WVS_BDR_B 2 | ||
241 | |||
242 | struct wvs | ||
243 | { | ||
244 | long hide_tick; | ||
245 | long show_for; | ||
246 | long print_tick; | ||
247 | long print_delay; | ||
248 | long resume_tick; | ||
249 | long resume_delay; | ||
250 | long next_auto_refresh; | ||
251 | int x; | ||
252 | int y; | ||
253 | int width; | ||
254 | int height; | ||
255 | unsigned fgcolor; | ||
256 | unsigned bgcolor; | ||
257 | #ifdef HAVE_LCD_COLOR | ||
258 | unsigned prog_fillcolor; | ||
259 | struct vo_rect update_rect; | ||
260 | #endif | ||
261 | struct vo_rect prog_rect; | ||
262 | struct vo_rect time_rect; | ||
263 | struct vo_rect dur_rect; | ||
264 | struct vo_rect vol_rect; | ||
265 | const unsigned char *icons; | ||
266 | struct vo_rect stat_rect; | ||
267 | int status; | ||
268 | uint32_t curr_time; | ||
269 | unsigned auto_refresh; | ||
270 | unsigned flags; | ||
271 | }; | ||
272 | |||
273 | static struct wvs wvs; | ||
274 | |||
275 | static void wvs_show(unsigned show); | ||
276 | |||
277 | #ifdef LCD_LANDSCAPE | ||
278 | #define _X (x + wvs.x) | ||
279 | #define _Y (y + wvs.y) | ||
280 | #define _W width | ||
281 | #define _H height | ||
282 | #else | ||
283 | #define _X (LCD_WIDTH - (y + wvs.y) - height) | ||
284 | #define _Y (x + wvs.x) | ||
285 | #define _W height | ||
286 | #define _H width | ||
287 | #endif | ||
288 | |||
289 | #ifdef HAVE_LCD_COLOR | ||
290 | static unsigned draw_blendcolor(unsigned c1, unsigned c2, unsigned char amount) | ||
291 | { | ||
292 | int r1 = RGB_UNPACK_RED(c1); | ||
293 | int g1 = RGB_UNPACK_GREEN(c1); | ||
294 | int b1 = RGB_UNPACK_BLUE(c1); | ||
295 | |||
296 | int r2 = RGB_UNPACK_RED(c2); | ||
297 | int g2 = RGB_UNPACK_GREEN(c2); | ||
298 | int b2 = RGB_UNPACK_BLUE(c2); | ||
299 | |||
300 | return LCD_RGBPACK(amount*(r2 - r1) / 255 + r1, | ||
301 | amount*(g2 - g1) / 255 + g1, | ||
302 | amount*(b2 - b1) / 255 + b1); | ||
303 | } | ||
304 | #endif | ||
305 | |||
306 | static void draw_fill_rect(int x, int y, int width, int height) | ||
307 | { | ||
308 | rb->lcd_fillrect(_X, _Y, _W, _H); | ||
309 | } | ||
310 | |||
311 | #ifdef HAVE_LCD_COLOR | ||
312 | static void draw_update_rect(int x, int y, int width, int height) | ||
313 | { | ||
314 | rb->lcd_update_rect(_X, _Y, _W, _H); | ||
315 | } | ||
316 | #endif | ||
317 | |||
318 | static void draw_clear_area(int x, int y, int width, int height) | ||
319 | { | ||
320 | rb->screen_clear_area(rb->screens[SCREEN_MAIN], _X, _Y, _W, _H); | ||
321 | } | ||
322 | |||
323 | static void draw_clear_area_rect(const struct vo_rect *rc) | ||
324 | { | ||
325 | int x = rc->l; | ||
326 | int y = rc->t; | ||
327 | int width = rc->r - rc->l; | ||
328 | int height = rc->b - rc->t; | ||
329 | rb->screen_clear_area(rb->screens[SCREEN_MAIN], _X, _Y, _W, _H); | ||
330 | } | ||
331 | |||
332 | static void draw_scrollbar_draw(int x, int y, int width, int height, | ||
333 | int items, int min_shown, int max_shown) | ||
334 | { | ||
335 | #ifdef HAVE_LCD_COLOR | ||
336 | int oldbg = rb->lcd_get_background(); | ||
337 | rb->lcd_set_background(wvs.prog_fillcolor); | ||
338 | #endif | ||
339 | |||
340 | rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN], _X, _Y, | ||
341 | _W, _H, items, min_shown, max_shown, | ||
342 | 0 | ||
343 | #ifdef LCD_LANDSCAPE | ||
344 | | HORIZONTAL | ||
345 | #endif | ||
346 | #ifdef HAVE_LCD_COLOR | ||
347 | | INNER_BGFILL | FOREGROUND | ||
348 | #endif | ||
349 | ); | ||
350 | |||
351 | #ifdef HAVE_LCD_COLOR | ||
352 | rb->lcd_set_background(oldbg); | ||
353 | #endif | ||
354 | } | ||
355 | |||
356 | static void draw_scrollbar_draw_rect(const struct vo_rect *rc, int items, | ||
357 | int min_shown, int max_shown) | ||
358 | { | ||
359 | draw_scrollbar_draw(rc->l, rc->t, rc->r - rc->l, rc->b - rc->t, | ||
360 | items, min_shown, max_shown); | ||
361 | } | ||
362 | |||
363 | static void draw_hline(int x1, int x2, int y) | ||
364 | { | ||
365 | #ifdef LCD_LANDSCAPE | ||
366 | rb->lcd_hline(x1 + wvs.x, x2 + wvs.x, y + wvs.y); | ||
367 | #else | ||
368 | y = LCD_WIDTH - (y + wvs.y) - 1; | ||
369 | rb->lcd_vline(y, x1 + wvs.x, x2 + wvs.x); | ||
370 | #endif | ||
371 | } | ||
372 | |||
373 | #ifdef LCD_PORTRAIT | ||
374 | /* Portrait displays need rotated text rendering */ | ||
375 | |||
376 | /* Limited function that only renders in DRMODE_FG */ | ||
377 | static void draw_oriented_mono_bitmap_part(const unsigned char *src, | ||
378 | int src_x, int src_y, | ||
379 | int stride, int x, int y, | ||
380 | int width, int height) | ||
381 | { | ||
382 | const unsigned char *src_end; | ||
383 | fb_data *dst, *dst_end; | ||
384 | unsigned fg_pattern, bg_pattern; | ||
385 | |||
386 | if (x + width > SCREEN_WIDTH) | ||
387 | width = SCREEN_WIDTH - x; /* Clip right */ | ||
388 | if (x < 0) | ||
389 | width += x, x = 0; /* Clip left */ | ||
390 | if (width <= 0) | ||
391 | return; /* nothing left to do */ | ||
392 | |||
393 | if (y + height > SCREEN_HEIGHT) | ||
394 | height = SCREEN_HEIGHT - y; /* Clip bottom */ | ||
395 | if (y < 0) | ||
396 | height += y, y = 0; /* Clip top */ | ||
397 | if (height <= 0) | ||
398 | return; /* nothing left to do */ | ||
399 | |||
400 | fg_pattern = rb->lcd_get_foreground(); | ||
401 | bg_pattern = rb->lcd_get_background(); | ||
402 | |||
403 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
404 | src_y &= 7; | ||
405 | src_end = src + width; | ||
406 | |||
407 | dst = rb->lcd_framebuffer + (LCD_WIDTH - y) + x*LCD_WIDTH; | ||
408 | do | ||
409 | { | ||
410 | const unsigned char *src_col = src++; | ||
411 | unsigned data = *src_col >> src_y; | ||
412 | int numbits = 8 - src_y; | ||
413 | |||
414 | fb_data *dst_col = dst; | ||
415 | dst_end = dst_col - height; | ||
416 | dst += LCD_WIDTH; | ||
417 | |||
418 | do | ||
419 | { | ||
420 | dst_col--; | ||
421 | |||
422 | if (data & 1) | ||
423 | *dst_col = fg_pattern; | ||
424 | #if 0 | ||
425 | else | ||
426 | *dst_col = bg_pattern; | ||
427 | #endif | ||
428 | data >>= 1; | ||
429 | if (--numbits == 0) { | ||
430 | src_col += stride; | ||
431 | data = *src_col; | ||
432 | numbits = 8; | ||
433 | } | ||
434 | } | ||
435 | while (dst_col > dst_end); | ||
436 | } | ||
437 | while (src < src_end); | ||
438 | } | ||
439 | |||
440 | static void draw_putsxy_oriented(int x, int y, const char *str) | ||
441 | { | ||
442 | unsigned short ch; | ||
443 | unsigned short *ucs; | ||
444 | int ofs = MIN(x, 0); | ||
445 | struct font* pf = rb->font_get(FONT_UI); | ||
446 | |||
447 | ucs = rb->bidi_l2v(str, 1); | ||
448 | |||
449 | x += wvs.x; | ||
450 | y += wvs.y; | ||
451 | |||
452 | while ((ch = *ucs++) != 0 && x < SCREEN_WIDTH) | ||
453 | { | ||
454 | int width; | ||
455 | const unsigned char *bits; | ||
456 | |||
457 | /* get proportional width and glyph bits */ | ||
458 | width = rb->font_get_width(pf, ch); | ||
459 | |||
460 | if (ofs > width) { | ||
461 | ofs -= width; | ||
462 | continue; | ||
463 | } | ||
464 | |||
465 | bits = rb->font_get_bits(pf, ch); | ||
466 | |||
467 | draw_oriented_mono_bitmap_part(bits, ofs, 0, width, x, y, | ||
468 | width - ofs, pf->height); | ||
469 | |||
470 | x += width - ofs; | ||
471 | ofs = 0; | ||
472 | } | ||
473 | } | ||
474 | #else | ||
475 | static void draw_oriented_mono_bitmap_part(const unsigned char *src, | ||
476 | int src_x, int src_y, | ||
477 | int stride, int x, int y, | ||
478 | int width, int height) | ||
479 | { | ||
480 | int mode = rb->lcd_get_drawmode(); | ||
481 | rb->lcd_set_drawmode(DRMODE_FG); | ||
482 | rb->lcd_mono_bitmap_part(src, src_x, src_y, stride, x, y, width, height); | ||
483 | rb->lcd_set_drawmode(mode); | ||
484 | } | ||
485 | |||
486 | static void draw_putsxy_oriented(int x, int y, const char *str) | ||
487 | { | ||
488 | int mode = rb->lcd_get_drawmode(); | ||
489 | rb->lcd_set_drawmode(DRMODE_FG); | ||
490 | rb->lcd_putsxy(x + wvs.x, y + wvs.y, str); | ||
491 | rb->lcd_set_drawmode(mode); | ||
492 | } | ||
493 | #endif /* LCD_PORTRAIT */ | ||
494 | |||
495 | |||
496 | static void wvs_text_init(void) | ||
497 | { | ||
498 | struct hms hms; | ||
499 | char buf[32]; | ||
500 | int phys; | ||
501 | int spc_width; | ||
502 | |||
503 | rb->lcd_setfont(FONT_UI); | ||
504 | |||
505 | wvs.x = 0; | ||
506 | wvs.width = SCREEN_WIDTH; | ||
507 | |||
508 | vo_rect_clear(&wvs.time_rect); | ||
509 | vo_rect_clear(&wvs.stat_rect); | ||
510 | vo_rect_clear(&wvs.prog_rect); | ||
511 | vo_rect_clear(&wvs.vol_rect); | ||
512 | |||
513 | ts_to_hms(stream_get_duration(), &hms); | ||
514 | hms_format(buf, sizeof (buf), &hms); | ||
515 | rb->lcd_getstringsize(buf, &wvs.time_rect.r, | ||
516 | &wvs.time_rect.b); | ||
517 | |||
518 | /* Choose well-sized bitmap images relative to font height */ | ||
519 | if (wvs.time_rect.b < 12) { | ||
520 | wvs.icons = mpegplayer_status_icons_8x8x1; | ||
521 | wvs.stat_rect.r = wvs.stat_rect.b = 8; | ||
522 | } else if (wvs.time_rect.b < 16) { | ||
523 | wvs.icons = mpegplayer_status_icons_12x12x1; | ||
524 | wvs.stat_rect.r = wvs.stat_rect.b = 12; | ||
525 | } else { | ||
526 | wvs.icons = mpegplayer_status_icons_16x16x1; | ||
527 | wvs.stat_rect.r = wvs.stat_rect.b = 16; | ||
528 | } | ||
529 | |||
530 | if (wvs.stat_rect.b < wvs.time_rect.b) { | ||
531 | vo_rect_offset(&wvs.stat_rect, 0, | ||
532 | (wvs.time_rect.b - wvs.stat_rect.b) / 2 + WVS_BDR_T); | ||
533 | vo_rect_offset(&wvs.time_rect, WVS_BDR_L, WVS_BDR_T); | ||
534 | } else { | ||
535 | vo_rect_offset(&wvs.time_rect, WVS_BDR_L, | ||
536 | wvs.stat_rect.b - wvs.time_rect.b + WVS_BDR_T); | ||
537 | vo_rect_offset(&wvs.stat_rect, 0, WVS_BDR_T); | ||
538 | } | ||
539 | |||
540 | wvs.dur_rect = wvs.time_rect; | ||
541 | |||
542 | phys = rb->sound_val2phys(SOUND_VOLUME, rb->sound_min(SOUND_VOLUME)); | ||
543 | rb->snprintf(buf, sizeof(buf), "%d%s", phys, | ||
544 | rb->sound_unit(SOUND_VOLUME)); | ||
545 | |||
546 | rb->lcd_getstringsize(" ", &spc_width, NULL); | ||
547 | rb->lcd_getstringsize(buf, &wvs.vol_rect.r, &wvs.vol_rect.b); | ||
548 | |||
549 | wvs.prog_rect.r = SCREEN_WIDTH - WVS_BDR_L - spc_width - | ||
550 | wvs.vol_rect.r - WVS_BDR_R; | ||
551 | wvs.prog_rect.b = 3*wvs.stat_rect.b / 4; | ||
552 | vo_rect_offset(&wvs.prog_rect, wvs.time_rect.l, | ||
553 | wvs.time_rect.b); | ||
554 | |||
555 | vo_rect_offset(&wvs.stat_rect, | ||
556 | (wvs.prog_rect.r + wvs.prog_rect.l - wvs.stat_rect.r) / 2, | ||
557 | 0); | ||
558 | |||
559 | vo_rect_offset(&wvs.dur_rect, | ||
560 | wvs.prog_rect.r - wvs.dur_rect.r, 0); | ||
561 | |||
562 | vo_rect_offset(&wvs.vol_rect, wvs.prog_rect.r + spc_width, | ||
563 | (wvs.prog_rect.b + wvs.prog_rect.t - wvs.vol_rect.b) / 2); | ||
564 | |||
565 | wvs.height = WVS_BDR_T + MAX(wvs.prog_rect.b, wvs.vol_rect.b) - | ||
566 | MIN(wvs.time_rect.t, wvs.stat_rect.t) + WVS_BDR_B; | ||
567 | |||
568 | #if LCD_PIXELFORMAT == VERTICAL_PACKING | ||
569 | wvs.height = ALIGN_UP(wvs.height, 8); | ||
570 | #else | ||
571 | wvs.height = ALIGN_UP(wvs.height, 2); | ||
572 | #endif | ||
573 | wvs.y = SCREEN_HEIGHT - wvs.height; | ||
185 | 574 | ||
186 | rb->lcd_setfont(FONT_SYSFIXED); | 575 | rb->lcd_setfont(FONT_SYSFIXED); |
576 | } | ||
577 | |||
578 | static void wvs_init(void) | ||
579 | { | ||
580 | wvs.flags = 0; | ||
581 | wvs.show_for = HZ*4; | ||
582 | wvs.print_delay = 75*HZ/100; | ||
583 | wvs.resume_delay = HZ/2; | ||
584 | #ifdef HAVE_LCD_COLOR | ||
585 | wvs.bgcolor = LCD_RGBPACK(0x73, 0x75, 0xbd); | ||
586 | wvs.fgcolor = LCD_WHITE; | ||
587 | wvs.prog_fillcolor = LCD_BLACK; | ||
588 | #else | ||
589 | wvs.bgcolor = LCD_LIGHTGRAY; | ||
590 | wvs.fgcolor = LCD_BLACK; | ||
591 | #endif | ||
592 | wvs.curr_time = 0; | ||
593 | wvs.status = WVS_STATUS_STOPPED; | ||
594 | wvs.auto_refresh = WVS_REFRESH_TIME; | ||
595 | wvs.next_auto_refresh = *rb->current_tick; | ||
596 | wvs_text_init(); | ||
597 | } | ||
598 | |||
599 | static void wvs_schedule_refresh(unsigned refresh) | ||
600 | { | ||
601 | long tick = *rb->current_tick; | ||
602 | |||
603 | if (refresh & WVS_REFRESH_VIDEO) | ||
604 | wvs.print_tick = tick + wvs.print_delay; | ||
605 | |||
606 | if (refresh & WVS_REFRESH_RESUME) | ||
607 | wvs.resume_tick = tick + wvs.resume_delay; | ||
608 | |||
609 | wvs.auto_refresh |= refresh; | ||
610 | } | ||
611 | |||
612 | static void wvs_cancel_refresh(unsigned refresh) | ||
613 | { | ||
614 | wvs.auto_refresh &= ~refresh; | ||
615 | } | ||
616 | |||
617 | static void wvs_refresh_background(void) | ||
618 | { | ||
619 | char buf[32]; | ||
620 | struct hms hms; | ||
621 | |||
622 | int bg = rb->lcd_get_background(); | ||
623 | rb->lcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID); | ||
624 | |||
625 | #ifdef HAVE_LCD_COLOR | ||
626 | rb->lcd_set_background(draw_blendcolor(bg, LCD_WHITE, 192)); | ||
627 | draw_hline(0, wvs.width, 0); | ||
628 | |||
629 | rb->lcd_set_background(draw_blendcolor(bg, LCD_WHITE, 80)); | ||
630 | draw_hline(0, wvs.width, 1); | ||
631 | |||
632 | rb->lcd_set_background(draw_blendcolor(bg, LCD_BLACK, 48)); | ||
633 | draw_hline(0, wvs.width, wvs.height-2); | ||
634 | |||
635 | rb->lcd_set_background(draw_blendcolor(bg, LCD_BLACK, 128)); | ||
636 | draw_hline(0, wvs.width, wvs.height-1); | ||
637 | |||
638 | rb->lcd_set_background(bg); | ||
639 | draw_clear_area(0, 2, wvs.width, wvs.height - 4); | ||
640 | |||
641 | vo_rect_set_ext(&wvs.update_rect, 0, 0, wvs.width, wvs.height); | ||
642 | #else | ||
643 | rb->lcd_set_background(LCD_DARKGRAY); | ||
644 | draw_hline(0, wvs.width, 0); | ||
645 | |||
646 | rb->lcd_set_background(bg); | ||
647 | draw_clear_area(0, 1, wvs.width, wvs.height - 1); | ||
648 | #endif | ||
649 | |||
650 | rb->lcd_set_drawmode(DRMODE_SOLID); | ||
651 | |||
652 | if (stream_get_duration() != INVALID_TIMESTAMP) { | ||
653 | /* Don't know the duration */ | ||
654 | ts_to_hms(stream_get_duration(), &hms); | ||
655 | hms_format(buf, sizeof (buf), &hms); | ||
656 | draw_putsxy_oriented(wvs.dur_rect.l, wvs.dur_rect.t, buf); | ||
657 | } | ||
658 | } | ||
659 | |||
660 | static void wvs_refresh_time(void) | ||
661 | { | ||
662 | char buf[32]; | ||
663 | struct hms hms; | ||
664 | |||
665 | uint32_t duration = stream_get_duration(); | ||
666 | |||
667 | draw_scrollbar_draw_rect(&wvs.prog_rect, duration, 0, | ||
668 | wvs.curr_time); | ||
669 | |||
670 | ts_to_hms(wvs.curr_time, &hms); | ||
671 | hms_format(buf, sizeof (buf), &hms); | ||
672 | |||
673 | draw_clear_area_rect(&wvs.time_rect); | ||
674 | draw_putsxy_oriented(wvs.time_rect.l, wvs.time_rect.t, buf); | ||
675 | |||
676 | #ifdef HAVE_LCD_COLOR | ||
677 | vo_rect_union(&wvs.update_rect, &wvs.update_rect, | ||
678 | &wvs.prog_rect); | ||
679 | vo_rect_union(&wvs.update_rect, &wvs.update_rect, | ||
680 | &wvs.time_rect); | ||
681 | #endif | ||
682 | } | ||
683 | |||
684 | static void wvs_refresh_volume(void) | ||
685 | { | ||
686 | char buf[32]; | ||
687 | int width; | ||
688 | |||
689 | int volume = rb->global_settings->volume; | ||
690 | rb->snprintf(buf, sizeof (buf), "%d%s", | ||
691 | rb->sound_val2phys(SOUND_VOLUME, volume), | ||
692 | rb->sound_unit(SOUND_VOLUME)); | ||
693 | rb->lcd_getstringsize(buf, &width, NULL); | ||
694 | |||
695 | /* Right-justified */ | ||
696 | draw_clear_area_rect(&wvs.vol_rect); | ||
697 | draw_putsxy_oriented(wvs.vol_rect.r - width, wvs.vol_rect.t, buf); | ||
698 | |||
699 | #ifdef HAVE_LCD_COLOR | ||
700 | vo_rect_union(&wvs.update_rect, &wvs.update_rect, &wvs.vol_rect); | ||
701 | #endif | ||
702 | } | ||
703 | |||
704 | static void wvs_refresh_status(void) | ||
705 | { | ||
706 | int icon_size = wvs.stat_rect.r - wvs.stat_rect.l; | ||
707 | |||
708 | draw_clear_area_rect(&wvs.stat_rect); | ||
709 | |||
710 | #ifdef HAVE_LCD_COLOR | ||
711 | /* Draw status icon with a drop shadow */ | ||
712 | unsigned oldfg = rb->lcd_get_foreground(); | ||
713 | int i = 1; | ||
714 | |||
715 | rb->lcd_set_foreground(draw_blendcolor(rb->lcd_get_background(), | ||
716 | LCD_BLACK, 96)); | ||
717 | |||
718 | while (1) | ||
719 | { | ||
720 | draw_oriented_mono_bitmap_part(wvs.icons, | ||
721 | icon_size*wvs.status, | ||
722 | 0, | ||
723 | icon_size*WVS_STATUS_COUNT, | ||
724 | wvs.stat_rect.l + wvs.x + i, | ||
725 | wvs.stat_rect.t + wvs.y + i, | ||
726 | icon_size, icon_size); | ||
727 | |||
728 | if (--i < 0) | ||
729 | break; | ||
730 | |||
731 | rb->lcd_set_foreground(oldfg); | ||
732 | } | ||
733 | |||
734 | vo_rect_union(&wvs.update_rect, &wvs.update_rect, &wvs.stat_rect); | ||
735 | #else | ||
736 | draw_oriented_mono_bitmap_part(wvs.icons, | ||
737 | icon_size*wvs.status, | ||
738 | 0, | ||
739 | icon_size*WVS_STATUS_COUNT, | ||
740 | wvs.stat_rect.l + wvs.x, | ||
741 | wvs.stat_rect.t + wvs.y, | ||
742 | icon_size, icon_size); | ||
743 | #endif | ||
744 | } | ||
745 | |||
746 | static bool wvs_update_status(void) | ||
747 | { | ||
748 | int status; | ||
749 | |||
750 | switch (stream_status()) | ||
751 | { | ||
752 | default: | ||
753 | status = WVS_STATUS_STOPPED; | ||
754 | break; | ||
755 | case STREAM_PAUSED: | ||
756 | status = (wvs.auto_refresh & WVS_REFRESH_RESUME) ? | ||
757 | WVS_STATUS_PLAYING : WVS_STATUS_PAUSED; | ||
758 | break; | ||
759 | case STREAM_PLAYING: | ||
760 | status = WVS_STATUS_PLAYING; | ||
761 | break; | ||
762 | } | ||
763 | |||
764 | if (status != wvs.status) { | ||
765 | wvs.status = status; | ||
766 | return true; | ||
767 | } | ||
768 | |||
769 | return false; | ||
770 | } | ||
771 | |||
772 | static void wvs_update_time(void) | ||
773 | { | ||
774 | uint32_t start; | ||
775 | wvs.curr_time = stream_get_seek_time(&start); | ||
776 | wvs.curr_time -= start; | ||
777 | } | ||
778 | |||
779 | static void wvs_refresh(int hint) | ||
780 | { | ||
781 | long tick; | ||
782 | unsigned oldbg, oldfg; | ||
783 | |||
784 | tick = *rb->current_tick; | ||
785 | |||
786 | if (hint == WVS_REFRESH_DEFAULT) { | ||
787 | |||
788 | if ((wvs.auto_refresh & WVS_REFRESH_VIDEO) && | ||
789 | TIME_AFTER(tick, wvs.print_tick)) { | ||
790 | wvs.auto_refresh &= ~WVS_REFRESH_VIDEO; | ||
791 | stream_draw_frame(false); | ||
792 | } | ||
793 | |||
794 | if ((wvs.auto_refresh & WVS_REFRESH_RESUME) && | ||
795 | TIME_AFTER(tick, wvs.resume_tick)) { | ||
796 | wvs.auto_refresh &= ~(WVS_REFRESH_RESUME | WVS_REFRESH_VIDEO); | ||
797 | stream_resume(); | ||
798 | } | ||
799 | |||
800 | if (!(wvs.flags & WVS_SHOW)) | ||
801 | return; | ||
802 | |||
803 | if (TIME_AFTER(tick, wvs.hide_tick)) { | ||
804 | wvs_show(WVS_HIDE); | ||
805 | return; | ||
806 | } | ||
807 | } else { | ||
808 | if (!(wvs.flags & WVS_SHOW)) { | ||
809 | wvs_show(WVS_SHOW | WVS_NODRAW); | ||
810 | hint = WVS_REFRESH_ALL; | ||
811 | } | ||
812 | |||
813 | wvs.print_tick = tick + wvs.print_delay; | ||
814 | wvs.hide_tick = tick + wvs.show_for; | ||
815 | } | ||
816 | |||
817 | if (TIME_AFTER(tick, wvs.next_auto_refresh)) { | ||
818 | wvs.next_auto_refresh = tick + WVS_MIN_UPDATE_INTERVAL; | ||
819 | |||
820 | if (wvs.auto_refresh & WVS_REFRESH_STATUS) { | ||
821 | if (wvs_update_status()) | ||
822 | hint |= WVS_REFRESH_STATUS; | ||
823 | } | ||
824 | |||
825 | if (wvs.auto_refresh & WVS_REFRESH_TIME) { | ||
826 | wvs_update_time(); | ||
827 | hint |= WVS_REFRESH_TIME; | ||
828 | } | ||
829 | } | ||
830 | |||
831 | if (hint == 0) | ||
832 | return; | ||
833 | |||
834 | oldfg = rb->lcd_get_foreground(); | ||
835 | oldbg = rb->lcd_get_background(); | ||
836 | |||
837 | rb->lcd_setfont(FONT_UI); | ||
838 | rb->lcd_set_foreground(wvs.fgcolor); | ||
839 | rb->lcd_set_background(wvs.bgcolor); | ||
840 | |||
841 | #ifdef HAVE_LCD_COLOR | ||
842 | vo_rect_clear(&wvs.update_rect); | ||
843 | #endif | ||
844 | |||
845 | if (hint & WVS_REFRESH_BACKGROUND) { | ||
846 | wvs_refresh_background(); | ||
847 | hint |= WVS_REFRESH_ALL; /* Requires a redraw of everything */ | ||
848 | } | ||
849 | |||
850 | if (hint & WVS_REFRESH_TIME) { | ||
851 | wvs_refresh_time(); | ||
852 | } | ||
853 | |||
854 | if (hint & WVS_REFRESH_VOLUME) { | ||
855 | wvs_refresh_volume(); | ||
856 | } | ||
857 | |||
858 | if (hint & WVS_REFRESH_STATUS) { | ||
859 | wvs_refresh_status(); | ||
860 | } | ||
861 | |||
862 | rb->lcd_setfont(FONT_SYSFIXED); | ||
863 | rb->lcd_set_foreground(oldfg); | ||
864 | rb->lcd_set_background(oldbg); | ||
865 | |||
866 | #ifdef HAVE_LCD_COLOR | ||
867 | vo_lock(); | ||
868 | |||
869 | draw_update_rect(wvs.update_rect.l, | ||
870 | wvs.update_rect.t, | ||
871 | wvs.update_rect.r - wvs.update_rect.l, | ||
872 | wvs.update_rect.b - wvs.update_rect.t); | ||
873 | |||
874 | vo_unlock(); | ||
875 | #else | ||
876 | gray_deferred_lcd_update(); | ||
877 | #endif | ||
878 | } | ||
879 | |||
880 | static void wvs_show(unsigned show) | ||
881 | { | ||
882 | if (((show ^ wvs.flags) & WVS_SHOW) == 0) | ||
883 | return; | ||
884 | |||
885 | if (show & WVS_SHOW) { | ||
886 | struct vo_rect rc = { 0, 0, SCREEN_WIDTH, wvs.y }; | ||
887 | |||
888 | wvs.flags |= WVS_SHOW; | ||
889 | |||
890 | stream_vo_set_clip(&rc); | ||
891 | |||
892 | if (!(show & WVS_NODRAW)) | ||
893 | wvs_refresh(WVS_REFRESH_ALL); | ||
894 | } else { | ||
895 | wvs.flags &= ~WVS_SHOW; | ||
896 | |||
897 | stream_vo_set_clip(NULL); | ||
898 | |||
899 | draw_clear_area(0, 0, wvs.width, wvs.height); | ||
900 | |||
901 | if (!(show & WVS_NODRAW)) { | ||
902 | #ifdef HAVE_LCD_COLOR | ||
903 | vo_lock(); | ||
904 | draw_update_rect(0, 0, wvs.width, wvs.height); | ||
905 | vo_unlock(); | ||
906 | #endif | ||
907 | stream_draw_frame(false); | ||
908 | } | ||
909 | } | ||
910 | } | ||
911 | |||
912 | static void wvs_set_status(int status) | ||
913 | { | ||
914 | bool draw = (status & WVS_NODRAW) == 0; | ||
915 | |||
916 | status &= WVS_STATUS_MASK; | ||
917 | |||
918 | if (wvs.status != status) { | ||
919 | |||
920 | wvs.status = status; | ||
921 | |||
922 | if (draw) | ||
923 | wvs_refresh(WVS_REFRESH_STATUS); | ||
924 | } | ||
925 | } | ||
926 | |||
927 | /* Handle Fast-forward/Rewind keys using WPS settings (and some nicked code ;) */ | ||
928 | static uint32_t wvs_ff_rw(int btn, unsigned refresh) | ||
929 | { | ||
930 | unsigned int step = TS_SECOND*rb->global_settings->ff_rewind_min_step; | ||
931 | const long ff_rw_accel = rb->global_settings->ff_rewind_accel; | ||
932 | long accel_tick = *rb->current_tick + ff_rw_accel*HZ; | ||
933 | uint32_t start; | ||
934 | uint32_t time = stream_get_seek_time(&start); | ||
935 | const uint32_t duration = stream_get_duration(); | ||
936 | unsigned int max_step = 0; | ||
937 | uint32_t ff_rw_count = 0; | ||
938 | unsigned status = wvs.status; | ||
939 | |||
940 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME | | ||
941 | WVS_REFRESH_TIME); | ||
942 | |||
943 | time -= start; /* Absolute clock => stream-relative */ | ||
944 | |||
945 | switch (btn) | ||
946 | { | ||
947 | case MPEG_FF: | ||
948 | wvs_set_status(WVS_STATUS_FF); | ||
949 | break; | ||
950 | case MPEG_RW: | ||
951 | wvs_set_status(WVS_STATUS_RW); | ||
952 | break; | ||
953 | default: | ||
954 | btn = -1; | ||
955 | } | ||
956 | |||
957 | btn |= BUTTON_REPEAT; | ||
958 | |||
959 | while (1) | ||
960 | { | ||
961 | long tick = *rb->current_tick; | ||
962 | stream_keep_disk_active(); | ||
963 | |||
964 | switch (btn) | ||
965 | { | ||
966 | case BUTTON_NONE: | ||
967 | wvs_refresh(WVS_REFRESH_DEFAULT); | ||
968 | break; | ||
969 | |||
970 | case MPEG_FF | BUTTON_REPEAT: | ||
971 | case MPEG_RW | BUTTON_REPEAT: | ||
972 | break; | ||
973 | |||
974 | case MPEG_FF | BUTTON_REL: | ||
975 | case MPEG_RW | BUTTON_REL: | ||
976 | if (wvs.status == WVS_STATUS_FF) | ||
977 | time += ff_rw_count; | ||
978 | else if (wvs.status == WVS_STATUS_RW) | ||
979 | time -= ff_rw_count; | ||
980 | |||
981 | /* Fall-through */ | ||
982 | case -1: | ||
983 | default: | ||
984 | wvs_schedule_refresh(refresh); | ||
985 | wvs_set_status(status); | ||
986 | wvs_schedule_refresh(WVS_REFRESH_TIME); | ||
987 | return time; | ||
988 | } | ||
989 | |||
990 | if (wvs.status == WVS_STATUS_FF) { | ||
991 | /* fast forwarding, calc max step relative to end */ | ||
992 | max_step = muldiv_uint32(duration - (time + ff_rw_count), | ||
993 | FF_REWIND_MAX_PERCENT, 100); | ||
994 | } else { | ||
995 | /* rewinding, calc max step relative to start */ | ||
996 | max_step = muldiv_uint32(time - ff_rw_count, | ||
997 | FF_REWIND_MAX_PERCENT, 100); | ||
998 | } | ||
999 | |||
1000 | max_step = MAX(max_step, MIN_FF_REWIND_STEP); | ||
1001 | |||
1002 | if (step > max_step) | ||
1003 | step = max_step; | ||
1004 | |||
1005 | ff_rw_count += step; | ||
1006 | |||
1007 | if (ff_rw_accel != 0 && TIME_AFTER(tick, accel_tick)) { | ||
1008 | step *= 2; | ||
1009 | accel_tick = tick + ff_rw_accel*HZ; | ||
1010 | } | ||
1011 | |||
1012 | if (wvs.status == WVS_STATUS_FF) { | ||
1013 | if (duration - time <= ff_rw_count) | ||
1014 | ff_rw_count = duration - time; | ||
1015 | |||
1016 | wvs.curr_time = time + ff_rw_count; | ||
1017 | } else { | ||
1018 | if (time <= ff_rw_count) | ||
1019 | ff_rw_count = time; | ||
1020 | |||
1021 | wvs.curr_time = time - ff_rw_count; | ||
1022 | } | ||
1023 | |||
1024 | wvs_refresh(WVS_REFRESH_TIME); | ||
1025 | |||
1026 | btn = rb->button_get_w_tmo(WVS_MIN_UPDATE_INTERVAL); | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | static int wvs_status(void) | ||
1031 | { | ||
1032 | int status = stream_status(); | ||
1033 | |||
1034 | /* Coerce to STREAM_PLAYING if paused with a pending resume */ | ||
1035 | if (status == STREAM_PAUSED) { | ||
1036 | if (wvs.auto_refresh & WVS_REFRESH_RESUME) | ||
1037 | status = STREAM_PLAYING; | ||
1038 | } | ||
1039 | |||
1040 | return status; | ||
1041 | } | ||
1042 | |||
1043 | static void wvs_set_volume(int delta) | ||
1044 | { | ||
1045 | int vol = rb->global_settings->volume; | ||
1046 | int limit; | ||
1047 | |||
1048 | vol += delta; | ||
1049 | |||
1050 | if (delta < 0) { | ||
1051 | limit = rb->sound_min(SOUND_VOLUME); | ||
1052 | if (vol < limit) | ||
1053 | vol = limit; | ||
1054 | } else { | ||
1055 | limit = rb->sound_max(SOUND_VOLUME); | ||
1056 | if (vol > limit) | ||
1057 | vol = limit; | ||
1058 | } | ||
1059 | |||
1060 | if (vol != rb->global_settings->volume) { | ||
1061 | rb->sound_set(SOUND_VOLUME, vol); | ||
1062 | rb->global_settings->volume = vol; | ||
1063 | } | ||
1064 | |||
1065 | wvs_refresh(WVS_REFRESH_VOLUME); | ||
1066 | } | ||
1067 | |||
1068 | static int wvs_play(uint32_t time) | ||
1069 | { | ||
1070 | int retval; | ||
1071 | |||
1072 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME); | ||
1073 | |||
1074 | retval = stream_seek(time, SEEK_SET); | ||
1075 | |||
1076 | if (retval >= STREAM_OK) { | ||
1077 | stream_show_vo(true); | ||
1078 | retval = stream_play(); | ||
1079 | |||
1080 | if (retval >= STREAM_OK) | ||
1081 | wvs_set_status(WVS_STATUS_PLAYING | WVS_NODRAW); | ||
1082 | } | ||
1083 | |||
1084 | return retval; | ||
1085 | } | ||
1086 | |||
1087 | static int wvs_halt(void) | ||
1088 | { | ||
1089 | int status = stream_pause(); | ||
1090 | |||
1091 | /* Coerce to STREAM_PLAYING if paused with a pending resume */ | ||
1092 | if (status == STREAM_PAUSED) { | ||
1093 | if (wvs.auto_refresh & WVS_REFRESH_RESUME) | ||
1094 | status = STREAM_PLAYING; | ||
1095 | } | ||
1096 | |||
1097 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME); | ||
1098 | |||
1099 | return status; | ||
1100 | } | ||
1101 | |||
1102 | static int wvs_pause(void) | ||
1103 | { | ||
1104 | unsigned refresh = wvs.auto_refresh; | ||
1105 | int status = wvs_halt(); | ||
1106 | |||
1107 | if (status == STREAM_PLAYING && (refresh & WVS_REFRESH_RESUME)) { | ||
1108 | wvs_cancel_refresh(WVS_REFRESH_RESUME); | ||
1109 | wvs_schedule_refresh(WVS_REFRESH_VIDEO); | ||
1110 | } | ||
1111 | |||
1112 | wvs_set_status(WVS_STATUS_PAUSED); | ||
1113 | |||
1114 | return status; | ||
1115 | } | ||
1116 | |||
1117 | static void wvs_resume(void) | ||
1118 | { | ||
1119 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME); | ||
1120 | wvs_set_status(WVS_STATUS_PLAYING); | ||
1121 | stream_resume(); | ||
1122 | } | ||
1123 | |||
1124 | static void wvs_stop(void) | ||
1125 | { | ||
1126 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME); | ||
1127 | wvs_show(WVS_HIDE | WVS_NODRAW); | ||
1128 | |||
1129 | if (stream_stop() != STREAM_STOPPED) | ||
1130 | settings.resume_time = stream_get_resume_time(); | ||
1131 | } | ||
1132 | |||
1133 | static void wvs_seek(int btn) | ||
1134 | { | ||
1135 | int status; | ||
1136 | unsigned refresh; | ||
1137 | uint32_t time; | ||
1138 | |||
1139 | if (!stream_can_seek()) | ||
1140 | return; | ||
1141 | |||
1142 | status = wvs_halt(); | ||
1143 | |||
1144 | if (status == STREAM_STOPPED) | ||
1145 | return; | ||
1146 | |||
1147 | wvs_show(WVS_SHOW); | ||
1148 | |||
1149 | if (status == STREAM_PLAYING) | ||
1150 | refresh = WVS_REFRESH_RESUME; /* delay resume if playing */ | ||
1151 | else | ||
1152 | refresh = WVS_REFRESH_VIDEO; /* refresh if paused */ | ||
1153 | |||
1154 | time = wvs_ff_rw(btn, refresh); | ||
1155 | |||
1156 | stream_seek(time, SEEK_SET); | ||
1157 | } | ||
1158 | |||
1159 | static void button_loop(void) | ||
1160 | { | ||
1161 | rb->lcd_setfont(FONT_SYSFIXED); | ||
187 | rb->lcd_clear_display(); | 1162 | rb->lcd_clear_display(); |
188 | rb->lcd_update(); | 1163 | rb->lcd_update(); |
189 | 1164 | ||
1165 | /* Turn off backlight timeout */ | ||
1166 | /* backlight control in lib/helper.c */ | ||
1167 | backlight_force_on(rb); | ||
1168 | |||
1169 | wvs_init(); | ||
1170 | |||
190 | /* Start playback at the specified starting time */ | 1171 | /* Start playback at the specified starting time */ |
191 | if (stream_seek(settings.resume_time, SEEK_SET) < STREAM_OK || | 1172 | if (wvs_play(settings.resume_time) < STREAM_OK) { |
192 | (stream_show_vo(true), stream_play()) < STREAM_OK) | ||
193 | { | ||
194 | rb->splash(HZ*2, "Playback failed"); | 1173 | rb->splash(HZ*2, "Playback failed"); |
195 | return false; | 1174 | return; |
196 | } | 1175 | } |
197 | 1176 | ||
198 | /* Gently poll the video player for EOS and handle UI */ | 1177 | /* Gently poll the video player for EOS and handle UI */ |
199 | while (stream_status() != STREAM_STOPPED) | 1178 | while (stream_status() != STREAM_STOPPED) |
200 | { | 1179 | { |
201 | int button = rb->button_get_w_tmo(HZ/2); | 1180 | int button = rb->button_get_w_tmo(WVS_MIN_UPDATE_INTERVAL); |
202 | 1181 | ||
203 | switch (button) | 1182 | switch (button) |
204 | { | 1183 | { |
205 | case BUTTON_NONE: | 1184 | case BUTTON_NONE: |
1185 | { | ||
1186 | wvs_refresh(WVS_REFRESH_DEFAULT); | ||
206 | continue; | 1187 | continue; |
1188 | } /* BUTTON_NONE: */ | ||
207 | 1189 | ||
208 | case MPEG_VOLUP: | 1190 | case MPEG_VOLUP: |
209 | case MPEG_VOLUP|BUTTON_REPEAT: | 1191 | case MPEG_VOLUP|BUTTON_REPEAT: |
@@ -212,14 +1194,7 @@ static bool button_loop(void) | |||
212 | case MPEG_VOLUP2|BUTTON_REPEAT: | 1194 | case MPEG_VOLUP2|BUTTON_REPEAT: |
213 | #endif | 1195 | #endif |
214 | { | 1196 | { |
215 | int vol = rb->global_settings->volume; | 1197 | wvs_set_volume(+1); |
216 | int maxvol = rb->sound_max(SOUND_VOLUME); | ||
217 | |||
218 | if (vol < maxvol) { | ||
219 | vol++; | ||
220 | rb->sound_set(SOUND_VOLUME, vol); | ||
221 | rb->global_settings->volume = vol; | ||
222 | } | ||
223 | break; | 1198 | break; |
224 | } /* MPEG_VOLUP*: */ | 1199 | } /* MPEG_VOLUP*: */ |
225 | 1200 | ||
@@ -230,23 +1205,17 @@ static bool button_loop(void) | |||
230 | case MPEG_VOLDOWN2|BUTTON_REPEAT: | 1205 | case MPEG_VOLDOWN2|BUTTON_REPEAT: |
231 | #endif | 1206 | #endif |
232 | { | 1207 | { |
233 | int vol = rb->global_settings->volume; | 1208 | wvs_set_volume(-1); |
234 | int minvol = rb->sound_min(SOUND_VOLUME); | ||
235 | |||
236 | if (vol > minvol) { | ||
237 | vol--; | ||
238 | rb->sound_set(SOUND_VOLUME, vol); | ||
239 | rb->global_settings->volume = vol; | ||
240 | } | ||
241 | break; | 1209 | break; |
242 | } /* MPEG_VOLDOWN*: */ | 1210 | } /* MPEG_VOLDOWN*: */ |
243 | 1211 | ||
244 | case MPEG_MENU: | 1212 | case MPEG_MENU: |
245 | { | 1213 | { |
246 | int state = stream_pause(); /* save previous state */ | 1214 | int state = wvs_halt(); /* save previous state */ |
247 | int result; | 1215 | int result; |
248 | 1216 | ||
249 | /* Hide video output */ | 1217 | /* Hide video output */ |
1218 | wvs_show(WVS_HIDE | WVS_NODRAW); | ||
250 | stream_show_vo(false); | 1219 | stream_show_vo(false); |
251 | backlight_use_settings(rb); | 1220 | backlight_use_settings(rb); |
252 | 1221 | ||
@@ -258,17 +1227,19 @@ static bool button_loop(void) | |||
258 | switch (result) | 1227 | switch (result) |
259 | { | 1228 | { |
260 | case MPEG_MENU_QUIT: | 1229 | case MPEG_MENU_QUIT: |
261 | stream_stop(); | 1230 | wvs_stop(); |
262 | break; | 1231 | break; |
263 | default: | 1232 | default: |
264 | /* If not stopped, show video again */ | 1233 | /* If not stopped, show video again */ |
265 | if (state != STREAM_STOPPED) | 1234 | if (state != STREAM_STOPPED) { |
1235 | wvs_show(WVS_SHOW); | ||
266 | stream_show_vo(true); | 1236 | stream_show_vo(true); |
1237 | } | ||
267 | 1238 | ||
268 | /* If stream was playing, restart it */ | 1239 | /* If stream was playing, restart it */ |
269 | if (state == STREAM_PLAYING) { | 1240 | if (state == STREAM_PLAYING) { |
270 | backlight_force_on(rb); | 1241 | backlight_force_on(rb); |
271 | stream_resume(); | 1242 | wvs_resume(); |
272 | } | 1243 | } |
273 | break; | 1244 | break; |
274 | } | 1245 | } |
@@ -277,7 +1248,7 @@ static bool button_loop(void) | |||
277 | 1248 | ||
278 | case MPEG_STOP: | 1249 | case MPEG_STOP: |
279 | { | 1250 | { |
280 | stream_stop(); | 1251 | wvs_stop(); |
281 | break; | 1252 | break; |
282 | } /* MPEG_STOP: */ | 1253 | } /* MPEG_STOP: */ |
283 | 1254 | ||
@@ -286,27 +1257,34 @@ static bool button_loop(void) | |||
286 | case MPEG_PAUSE2: | 1257 | case MPEG_PAUSE2: |
287 | #endif | 1258 | #endif |
288 | { | 1259 | { |
289 | if (stream_status() == STREAM_PLAYING) { | 1260 | int status = wvs_status(); |
1261 | |||
1262 | if (status == STREAM_PLAYING) { | ||
290 | /* Playing => Paused */ | 1263 | /* Playing => Paused */ |
291 | stream_pause(); | 1264 | wvs_pause(); |
292 | backlight_use_settings(rb); | 1265 | backlight_use_settings(rb); |
293 | } | 1266 | } |
294 | else if (stream_status() == STREAM_PAUSED) { | 1267 | else if (status == STREAM_PAUSED) { |
295 | /* Paused => Playing */ | 1268 | /* Paused => Playing */ |
296 | backlight_force_on(rb); | 1269 | backlight_force_on(rb); |
297 | stream_resume(); | 1270 | wvs_resume(); |
298 | } | 1271 | } |
299 | 1272 | ||
300 | break; | 1273 | break; |
301 | } /* MPEG_PAUSE*: */ | 1274 | } /* MPEG_PAUSE*: */ |
302 | 1275 | ||
1276 | case MPEG_RW: | ||
1277 | case MPEG_FF: | ||
1278 | { | ||
1279 | wvs_seek(button); | ||
1280 | break; | ||
1281 | } /* MPEG_RW: MPEG_FF: */ | ||
1282 | |||
303 | case SYS_POWEROFF: | 1283 | case SYS_POWEROFF: |
304 | case SYS_USB_CONNECTED: | 1284 | case SYS_USB_CONNECTED: |
305 | /* Stop and get the resume time before closing the file early */ | 1285 | /* Stop and get the resume time before closing the file early */ |
306 | stream_stop(); | 1286 | wvs_stop(); |
307 | settings.resume_time = stream_get_resume_time(); | ||
308 | stream_close(); | 1287 | stream_close(); |
309 | ret = false; | ||
310 | /* Fall-through */ | 1288 | /* Fall-through */ |
311 | default: | 1289 | default: |
312 | rb->default_event_handler(button); | 1290 | rb->default_event_handler(button); |
@@ -316,9 +1294,12 @@ static bool button_loop(void) | |||
316 | rb->yield(); | 1294 | rb->yield(); |
317 | } /* end while */ | 1295 | } /* end while */ |
318 | 1296 | ||
1297 | wvs_stop(); | ||
1298 | |||
319 | rb->lcd_setfont(FONT_UI); | 1299 | rb->lcd_setfont(FONT_UI); |
320 | 1300 | ||
321 | return ret; | 1301 | /* Turn on backlight timeout (revert to settings) */ |
1302 | backlight_use_settings(rb); | ||
322 | } | 1303 | } |
323 | 1304 | ||
324 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | 1305 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) |
@@ -367,17 +1348,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
367 | result = mpeg_start_menu(stream_get_duration()); | 1348 | result = mpeg_start_menu(stream_get_duration()); |
368 | 1349 | ||
369 | if (result != MPEG_START_QUIT) { | 1350 | if (result != MPEG_START_QUIT) { |
370 | /* Turn off backlight timeout */ | ||
371 | /* backlight control in lib/helper.c */ | ||
372 | backlight_force_on(rb); | ||
373 | |||
374 | /* Enter button loop and process UI */ | 1351 | /* Enter button loop and process UI */ |
375 | if (button_loop()) { | 1352 | button_loop(); |
376 | settings.resume_time = stream_get_resume_time(); | ||
377 | } | ||
378 | |||
379 | /* Turn on backlight timeout (revert to settings) */ | ||
380 | backlight_use_settings(rb); | ||
381 | } | 1353 | } |
382 | 1354 | ||
383 | stream_close(); | 1355 | stream_close(); |