From 9b4522bacec8cf1eb8ff69684cf959c0bb732c0d Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Wed, 22 Dec 2010 11:20:07 +0000 Subject: MPEGPlayer: Some UI tweaking and bugfixing * Allow skip-to-beginning in single-play mode; there is no 3-second delay in that case. * Properly handle and keep track of pauses caused by headphone removal. * Improve skipping over bad files - search in skip direction and allow it to be ended with the stop key. * Add the system message processing done elsewhere to all button queue waits. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28875 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/mpegplayer/mpeg_misc.c | 55 +++++ apps/plugins/mpegplayer/mpeg_misc.h | 26 +++ apps/plugins/mpegplayer/mpeg_settings.c | 79 ++----- apps/plugins/mpegplayer/mpeg_settings.h | 5 - apps/plugins/mpegplayer/mpegplayer.c | 403 ++++++++++++++++++++------------ 5 files changed, 353 insertions(+), 215 deletions(-) (limited to 'apps/plugins/mpegplayer') diff --git a/apps/plugins/mpegplayer/mpeg_misc.c b/apps/plugins/mpegplayer/mpeg_misc.c index e201aa69c7..d9e033322e 100644 --- a/apps/plugins/mpegplayer/mpeg_misc.c +++ b/apps/plugins/mpegplayer/mpeg_misc.c @@ -162,3 +162,58 @@ void list_enum_items(void **list, list++; /* Item still there */ } } + + +/** System events **/ +static long mpeg_sysevent_id; + +void mpeg_sysevent_clear(void) +{ + mpeg_sysevent_id = 0; +} + +void mpeg_sysevent_set(void) +{ + /* Nonzero and won't invoke anything in default event handler */ + mpeg_sysevent_id = ACTION_STD_CANCEL; +} + +long mpeg_sysevent(void) +{ + return mpeg_sysevent_id; +} + +int mpeg_sysevent_callback(int btn, const struct menu_item_ex *menu) +{ + switch (btn) + { + case SYS_USB_CONNECTED: + case SYS_POWEROFF: + mpeg_sysevent_id = btn; + return ACTION_STD_CANCEL; + } + + return btn; + (void)menu; +} + +void mpeg_sysevent_handle(void) +{ + long id = mpeg_sysevent(); + if (id != 0) + rb->default_event_handler(id); +} + + +/** Buttons **/ + +int mpeg_button_get(int timeout) +{ + int button; + + mpeg_sysevent_clear(); + button = timeout == TIMEOUT_BLOCK ? rb->button_get(true) : + rb->button_get_w_tmo(timeout); + return mpeg_sysevent_callback(button, NULL); +} + diff --git a/apps/plugins/mpegplayer/mpeg_misc.h b/apps/plugins/mpegplayer/mpeg_misc.h index c36f4faddc..6996f27987 100644 --- a/apps/plugins/mpegplayer/mpeg_misc.h +++ b/apps/plugins/mpegplayer/mpeg_misc.h @@ -228,4 +228,30 @@ void list_enum_items(void **list, list_enum_callback_t callback, intptr_t data); + +/** System events **/ + +/* Clear event */ +void mpeg_sysevent_clear(void); + +/* Set to ACTION_STD_CANCEL */ +void mpeg_sysevent_set(void); + +/* Get event code */ +long mpeg_sysevent(void); + +/* Call with a system event code and used as menu callback */ +int mpeg_sysevent_callback(int btn, const struct menu_item_ex *menu); + +/* Handle recorded event */ +void mpeg_sysevent_handle(void); + + +/** Buttons **/ + +/* Get button codes while remembering important events for later + * processing; return of ACTION_STD_CANCEL means plugin should + * abort and handle the event */ +int mpeg_button_get(int timeout); + #endif /* MPEG_MISC_H */ diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c index 3daba2c928..f84a30ddfe 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.c +++ b/apps/plugins/mpegplayer/mpeg_settings.c @@ -315,39 +315,6 @@ static const struct opt_items globaloff[2] = { #endif static void mpeg_settings(void); -static long mpeg_menu_sysevent_id; - -void mpeg_menu_sysevent_clear(void) -{ - mpeg_menu_sysevent_id = 0; -} - -int mpeg_menu_sysevent_callback(int btn, const struct menu_item_ex *menu) -{ - switch (btn) - { - case SYS_USB_CONNECTED: - case SYS_POWEROFF: - mpeg_menu_sysevent_id = btn; - return ACTION_STD_CANCEL; - } - - return btn; - (void)menu; -} - -long mpeg_menu_sysevent(void) -{ - return mpeg_menu_sysevent_id; -} - -void mpeg_menu_sysevent_handle(void) -{ - long id = mpeg_menu_sysevent(); - if (id != 0) - rb->default_event_handler(id); -} - static bool mpeg_set_option(const char* string, void* variable, enum optiontype type, @@ -355,14 +322,14 @@ static bool mpeg_set_option(const char* string, int numoptions, void (*function)(int)) { - mpeg_menu_sysevent_clear(); + mpeg_sysevent_clear(); /* This eats SYS_POWEROFF - :\ */ bool usb = rb->set_option(string, variable, type, options, numoptions, function); if (usb) - mpeg_menu_sysevent_id = ACTION_STD_CANCEL; + mpeg_sysevent_set(); return usb; } @@ -375,13 +342,13 @@ static bool mpeg_set_int(const char *string, const char *unit, int max, const char* (*formatter)(char*, size_t, int, const char*)) { - mpeg_menu_sysevent_clear(); + mpeg_sysevent_clear(); bool usb = rb->set_int(string, unit, voice_unit, variable, function, step, min, max, formatter); if (usb) - mpeg_menu_sysevent_id = ACTION_STD_CANCEL; + mpeg_sysevent_set(); return usb; } @@ -778,11 +745,7 @@ static int get_start_time(uint32_t duration) while (slider_state < STATE9) { - mpeg_menu_sysevent_clear(); - button = tmo == TIMEOUT_BLOCK ? - rb->button_get(true) : rb->button_get_w_tmo(tmo); - - button = mpeg_menu_sysevent_callback(button, NULL); + button = mpeg_button_get(tmo); switch (button) { @@ -922,7 +885,7 @@ static int show_start_menu(uint32_t duration) char hms_str[32]; struct hms hms; - MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_menu_sysevent_callback, + MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_sysevent_callback, "Play from beginning", resume_str, "Set start time", "Settings", "Quit mpegplayer"); @@ -935,7 +898,7 @@ static int show_start_menu(uint32_t duration) while (!menu_quit) { - mpeg_menu_sysevent_clear(); + mpeg_sysevent_clear(); result = rb->do_menu(&menu, &selected, NULL, false); switch (result) @@ -972,7 +935,7 @@ static int show_start_menu(uint32_t duration) break; } - if (mpeg_menu_sysevent() != 0) + if (mpeg_sysevent() != 0) { result = MPEG_START_QUIT; menu_quit = true; @@ -985,7 +948,7 @@ static int show_start_menu(uint32_t duration) /* Return the desired resume action */ int mpeg_start_menu(uint32_t duration) { - mpeg_menu_sysevent_clear(); + mpeg_sysevent_clear(); switch (settings.resume_options) { @@ -1008,12 +971,12 @@ int mpeg_menu(void) { int result; - MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_menu_sysevent_callback, + MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_sysevent_callback, "Settings", "Resume playback", "Quit mpegplayer"); rb->button_clear_queue(); - mpeg_menu_sysevent_clear(); + mpeg_sysevent_clear(); result = rb->do_menu(&menu, NULL, NULL, false); @@ -1033,7 +996,7 @@ int mpeg_menu(void) break; } - if (mpeg_menu_sysevent() != 0) + if (mpeg_sysevent() != 0) result = MPEG_MENU_QUIT; return result; @@ -1045,7 +1008,7 @@ static void display_options(void) int result; bool menu_quit = false; - MENUITEM_STRINGLIST(menu, "Display Options", mpeg_menu_sysevent_callback, + MENUITEM_STRINGLIST(menu, "Display Options", mpeg_sysevent_callback, #if MPEG_OPTION_DITHERING_ENABLED "Dithering", #endif @@ -1059,7 +1022,7 @@ static void display_options(void) while (!menu_quit) { - mpeg_menu_sysevent_clear(); + mpeg_sysevent_clear(); result = rb->do_menu(&menu, &selected, NULL, false); switch (result) @@ -1108,7 +1071,7 @@ static void display_options(void) break; } - if (mpeg_menu_sysevent() != 0) + if (mpeg_sysevent() != 0) menu_quit = true; } } @@ -1119,7 +1082,7 @@ static void audio_options(void) int result; bool menu_quit = false; - MENUITEM_STRINGLIST(menu, "Audio Options", mpeg_menu_sysevent_callback, + MENUITEM_STRINGLIST(menu, "Audio Options", mpeg_sysevent_callback, "Tone Controls", "Channel Modes", "Crossfeed", "Equalizer", "Dithering"); @@ -1127,7 +1090,7 @@ static void audio_options(void) while (!menu_quit) { - mpeg_menu_sysevent_clear(); + mpeg_sysevent_clear(); result = rb->do_menu(&menu, &selected, NULL, false); switch (result) @@ -1167,7 +1130,7 @@ static void audio_options(void) break; } - if (mpeg_menu_sysevent() != 0) + if (mpeg_sysevent() != 0) menu_quit = true; } } @@ -1203,7 +1166,7 @@ static void mpeg_settings(void) bool menu_quit = false; static char clear_str[32]; - MENUITEM_STRINGLIST(menu, "Settings", mpeg_menu_sysevent_callback, + MENUITEM_STRINGLIST(menu, "Settings", mpeg_sysevent_callback, "Display Options", "Audio Options", "Resume Options", "Play Mode", clear_str); @@ -1211,7 +1174,7 @@ static void mpeg_settings(void) while (!menu_quit) { - mpeg_menu_sysevent_clear(); + mpeg_sysevent_clear(); /* Format and add resume option to the menu display */ rb->snprintf(clear_str, sizeof(clear_str), @@ -1247,7 +1210,7 @@ static void mpeg_settings(void) break; } - if (mpeg_menu_sysevent() != 0) + if (mpeg_sysevent() != 0) menu_quit = true; } } diff --git a/apps/plugins/mpegplayer/mpeg_settings.h b/apps/plugins/mpegplayer/mpeg_settings.h index 0910116615..6287f664d3 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.h +++ b/apps/plugins/mpegplayer/mpeg_settings.h @@ -102,11 +102,6 @@ extern struct mpeg_settings settings; int mpeg_start_menu(uint32_t duration); int mpeg_menu(void); -void mpeg_menu_sysevent_clear(void); -long mpeg_menu_sysevent(void); -int mpeg_menu_sysevent_callback(int btn, const struct menu_item_ex *menu); -void mpeg_menu_sysevent_handle(void); - void init_settings(const char* filename); void save_settings(void); diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index 7a2b457aec..d21907f607 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c @@ -412,7 +412,9 @@ enum osd_bits OSD_REFRESH_RESUME = 0x0020, /* Resume playback upon timeout */ OSD_NODRAW = 0x8000, /* OR bitflag - don't draw anything */ OSD_SHOW = 0x4000, /* OR bitflag - show the OSD */ - OSD_HP_PAUSE = 0x2000, +#ifdef HAVE_HEADPHONE_DETECTION + OSD_HP_PAUSE = 0x2000, /* OR bitflag - headphones caused pause */ +#endif OSD_HIDE = 0x0000, /* hide the OSD (aid readability) */ OSD_REFRESH_ALL = 0x000f, /* Only immediate graphical elements */ }; @@ -835,6 +837,18 @@ static void osd_init(void) osd_text_init(); } +#ifdef HAVE_HEADPHONE_DETECTION +static void osd_set_hp_pause_flag(bool set) +{ + if (set) + osd.flags |= OSD_HP_PAUSE; + else + osd.flags &= ~OSD_HP_PAUSE; +} +#else +#define osd_set_hp_pause_flag(set) +#endif /* HAVE_HEADPHONE_DETECTION */ + static void osd_schedule_refresh(unsigned refresh) { long tick = *rb->current_tick; @@ -1213,8 +1227,10 @@ static int osd_get_status(void) return osd.status & OSD_STATUS_MASK; } -/* Handle Fast-forward/Rewind keys using WPS settings (and some nicked code ;) */ -static uint32_t osd_ff_rw(int btn, unsigned refresh) +/* Handle Fast-forward/Rewind keys using WPS settings (and some nicked code ;) + * Returns last button code + */ +static int osd_ff_rw(int btn, unsigned refresh, uint32_t *new_time) { unsigned int step = TS_SECOND*rb->global_settings->ff_rewind_min_step; const long ff_rw_accel = (rb->global_settings->ff_rewind_accel + 3); @@ -1224,6 +1240,7 @@ static uint32_t osd_ff_rw(int btn, unsigned refresh) unsigned int max_step = 0; uint32_t ff_rw_count = 0; unsigned status = osd.status; + int new_btn; osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME | OSD_REFRESH_TIME); @@ -1239,9 +1256,8 @@ static uint32_t osd_ff_rw(int btn, unsigned refresh) #ifdef MPEG_RC_FF case MPEG_RC_FF: #endif - if (!(btn & BUTTON_REPEAT)) - osd_set_status(OSD_STATUS_FF); - btn = MPEG_FF | BUTTON_REPEAT; /* simplify code below */ + osd_set_status(OSD_STATUS_FF); + new_btn = btn | BUTTON_REPEAT; /* simplify code below */ break; case MPEG_RW: #ifdef MPEG_RW2 @@ -1250,103 +1266,75 @@ static uint32_t osd_ff_rw(int btn, unsigned refresh) #ifdef MPEG_RC_RW case MPEG_RC_RW: #endif - if (!(btn & BUTTON_REPEAT)) - osd_set_status(OSD_STATUS_RW); - btn = MPEG_RW | BUTTON_REPEAT; /* simplify code below */ + osd_set_status(OSD_STATUS_RW); + new_btn = btn | BUTTON_REPEAT; /* simplify code below */ break; default: - btn = -1; + new_btn = BUTTON_NONE; /* Fail tests below but still do proper exit */ } while (1) { stream_keep_disk_active(); - switch (btn) - { - case BUTTON_NONE: - osd_refresh(OSD_REFRESH_DEFAULT); - break; - - case MPEG_FF | BUTTON_REPEAT: - case MPEG_RW | BUTTON_REPEAT: -#ifdef MPEG_FF2 - case MPEG_FF2 | BUTTON_REPEAT: -#endif -#ifdef MPEG_RW2 - case MPEG_RW2 | BUTTON_REPEAT: -#endif -#ifdef MPEG_RC_FF - case MPEG_RC_FF | BUTTON_REPEAT: - case MPEG_RC_RW | BUTTON_REPEAT: -#endif - break; + if (new_btn == (btn | BUTTON_REPEAT)) { + if (osd.status == OSD_STATUS_FF) { + /* fast forwarding, calc max step relative to end */ + max_step = muldiv_uint32(duration - (time + ff_rw_count), + FF_REWIND_MAX_PERCENT, 100); + } else { + /* rewinding, calc max step relative to start */ + max_step = muldiv_uint32(time - ff_rw_count, + FF_REWIND_MAX_PERCENT, 100); + } - case MPEG_FF | BUTTON_REL: - case MPEG_RW | BUTTON_REL: -#ifdef MPEG_FF2 - case MPEG_FF2 | BUTTON_REL: -#endif -#ifdef MPEG_RW2 - case MPEG_RW2 | BUTTON_REL: -#endif -#ifdef MPEG_RC_FF - case MPEG_RC_FF | BUTTON_REL: - case MPEG_RC_RW | BUTTON_REL: -#endif - if (osd.status == OSD_STATUS_FF) - time += ff_rw_count; - else if (osd.status == OSD_STATUS_RW) - time -= ff_rw_count; + max_step = MAX(max_step, MIN_FF_REWIND_STEP); - /* Fall-through */ - case -1: - default: - osd_schedule_refresh(refresh); - osd_set_status(status); - osd_schedule_refresh(OSD_REFRESH_TIME); - return time; - } + if (step > max_step) + step = max_step; - if (osd.status == OSD_STATUS_FF) { - /* fast forwarding, calc max step relative to end */ - max_step = muldiv_uint32(duration - (time + ff_rw_count), - FF_REWIND_MAX_PERCENT, 100); - } else { - /* rewinding, calc max step relative to start */ - max_step = muldiv_uint32(time - ff_rw_count, - FF_REWIND_MAX_PERCENT, 100); - } + ff_rw_count += step; - max_step = MAX(max_step, MIN_FF_REWIND_STEP); + /* smooth seeking by multiplying step by: 1 + (2 ^ -accel) */ + step += step >> ff_rw_accel; - if (step > max_step) - step = max_step; + if (osd.status == OSD_STATUS_FF) { + if (duration - time <= ff_rw_count) + ff_rw_count = duration - time; - ff_rw_count += step; + osd.curr_time = time + ff_rw_count; + } else { + if (time <= ff_rw_count) + ff_rw_count = time; - /* smooth seeking by multiplying step by: 1 + (2 ^ -accel) */ - step += step >> ff_rw_accel; + osd.curr_time = time - ff_rw_count; + } - if (osd.status == OSD_STATUS_FF) { - if (duration - time <= ff_rw_count) - ff_rw_count = duration - time; + osd_refresh(OSD_REFRESH_TIME); - osd.curr_time = time + ff_rw_count; - } else { - if (time <= ff_rw_count) - ff_rw_count = time; - - osd.curr_time = time - ff_rw_count; + new_btn = mpeg_button_get(TIMEOUT_BLOCK); } + else { + if (new_btn == (btn | BUTTON_REL)) { + if (osd.status == OSD_STATUS_FF) + time += ff_rw_count; + else if (osd.status == OSD_STATUS_RW) + time -= ff_rw_count; + } - osd_refresh(OSD_REFRESH_TIME); + *new_time = time; + + osd_schedule_refresh(refresh); + osd_set_status(status); + osd_schedule_refresh(OSD_REFRESH_TIME); - btn = rb->button_get_w_tmo(OSD_MIN_UPDATE_INTERVAL); + return new_btn; + } } } -static int osd_status(void) +/* Return adjusted STREAM_* status */ +static int osd_stream_status(void) { int status = stream_status(); @@ -1394,6 +1382,7 @@ static int osd_play(uint32_t time) { int retval; + osd_set_hp_pause_flag(false); osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); retval = stream_seek(time, SEEK_SET); @@ -1436,6 +1425,8 @@ static int osd_pause(void) unsigned refresh = osd.auto_refresh; int status = osd_halt(); + osd_set_hp_pause_flag(false); + if (status == STREAM_PLAYING && (refresh & OSD_REFRESH_RESUME)) { /* Resume pending - change to a still video frame update */ osd_schedule_refresh(OSD_REFRESH_VIDEO); @@ -1454,6 +1445,7 @@ static void osd_resume(void) { /* Cancel video and resume auto refresh - the resyc when starting * playback will perform those tasks */ + osd_set_hp_pause_flag(false); osd_backlight_on_video_mode(true); osd_backlight_brightness_video_mode(true); osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); @@ -1466,6 +1458,7 @@ static void osd_stop(void) { uint32_t resume_time; + osd_set_hp_pause_flag(false); osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); osd_set_status(OSD_STATUS_STOPPED | OSD_NODRAW); osd_show(OSD_HIDE); @@ -1481,35 +1474,81 @@ static void osd_stop(void) osd_backlight_brightness_video_mode(false); } -/* Perform a seek if seeking is possible for this stream - if playing, a delay - * will be inserted before restarting in case the user decides to seek again */ -static void osd_seek(int btn) +/* Perform a seek by button if seeking is possible for this stream. + * + * A delay will be inserted before restarting in case the user decides to + * seek again soon after. + * + * Returns last button code + */ +static int osd_seek_btn(int btn) { int status; - unsigned refresh; + unsigned refresh = 0; uint32_t time; if (!stream_can_seek()) - return; + return true; - /* Halt playback - not strictly nescessary but nice */ + /* Halt playback - not strictly necessary but nice when doing + * buttons */ status = osd_halt(); if (status == STREAM_STOPPED) - return; + return true; osd_show(OSD_SHOW); + /* Obtain a new playback point according to the buttons */ if (status == STREAM_PLAYING) refresh = OSD_REFRESH_RESUME; /* delay resume if playing */ else refresh = OSD_REFRESH_VIDEO; /* refresh if paused */ - /* Obtain a new playback point */ - time = osd_ff_rw(btn, refresh); + btn = osd_ff_rw(btn, refresh, &time); /* Tell engine to resume at that time */ stream_seek(time, SEEK_SET); + + return btn; +} + +/* Perform a seek by time if seeking is possible for this stream + * + * If playing, the seeking is immediate, otherise a delay is added to showing + * a still if paused in case the user does another seek soon after. + * + * If seeking isn't possible, a time of zero performs a skip to the + * beginning. + */ +static void osd_seek_time(uint32_t time) +{ + int status; + unsigned refresh = 0; + + if (!stream_can_seek() && time != 0) + return; + + stream_wait_status(); + status = osd_stream_status(); + + if (status == STREAM_STOPPED) + return; + + if (status == STREAM_PLAYING) /* merely preserve resume */ + refresh = osd.auto_refresh & OSD_REFRESH_RESUME; + else + refresh = OSD_REFRESH_VIDEO; /* refresh if paused */ + + /* Cancel print or resume if pending */ + osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); + + /* Tell engine to seek to the given time - no state change */ + stream_seek(time, SEEK_SET); + + osd_update_time(); + osd_refresh(OSD_REFRESH_TIME); + osd_schedule_refresh(refresh); } /* Has this file one of the supported extensions? */ @@ -1537,7 +1576,7 @@ static bool is_videofile(const char* file) } /* deliver the next/previous video file in the current directory. - returns 0 if there is none. */ + returns false if there is none. */ static bool get_videofile(int direction, char* videofile, size_t bufsize) { struct tree_context *tree = rb->tree_get_context(); @@ -1583,11 +1622,12 @@ static void osd_handle_phone_plug(bool inserted) /* Wait for any incomplete state transition to complete first */ stream_wait_status(); - int status = osd_status(); + int status = osd_stream_status(); if (inserted) { if (rb->global_settings->unplug_mode > 1) { - if (status == STREAM_PAUSED) { + if (status == STREAM_PAUSED && + (osd.flags & OSD_HP_PAUSE)) { osd_resume(); } } @@ -1595,6 +1635,8 @@ static void osd_handle_phone_plug(bool inserted) if (status == STREAM_PLAYING) { osd_pause(); + osd_set_hp_pause_flag(true); + if (stream_can_seek() && rb->global_settings->unplug_rw) { stream_seek(-rb->global_settings->unplug_rw*TS_SECOND, SEEK_CUR); @@ -1635,12 +1677,7 @@ static int button_loop(void) /* Gently poll the video player for EOS and handle UI */ while (stream_status() != STREAM_STOPPED) { - int button; - - mpeg_menu_sysevent_clear(); - button = rb->button_get_w_tmo(OSD_MIN_UPDATE_INTERVAL/2); - - button = mpeg_menu_sysevent_callback(button, NULL); + int button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL/2); switch (button) { @@ -1761,6 +1798,7 @@ static int button_loop(void) #endif case ACTION_STD_CANCEL: { + cancel_playback: next_action = VIDEO_STOP; osd_stop(); break; @@ -1774,7 +1812,7 @@ static int button_loop(void) case MPEG_RC_PAUSE: #endif { - int status = osd_status(); + int status = osd_stream_status(); if (status == STREAM_PLAYING) { /* Playing => Paused */ @@ -1789,54 +1827,72 @@ static int button_loop(void) } /* MPEG_PAUSE*: */ case MPEG_RW: - case MPEG_FF: #ifdef MPEG_RW2 case MPEG_RW2: #endif +#ifdef MPEG_RC_RW + case MPEG_RC_RW: +#endif + { + int old_button = button; + + /* If button has been released: skip to next/previous file */ + button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL); + + if ((old_button | BUTTON_REL) == button) { + /* Check current playback position */ + osd_update_time(); + + if (settings.play_mode == 0 || osd.curr_time >= 3*TS_SECOND) { + /* Start the current video from the beginning */ + osd_seek_time(0*TS_SECOND); + } + else { + /* Release within 3 seconds of start: skip to previous + * file */ + osd_stop(); + next_action = VIDEO_PREV; + } + } + else if ((button & ~BUTTON_REPEAT) == old_button) { + button = osd_seek_btn(old_button); + } + + if (button == ACTION_STD_CANCEL) + goto cancel_playback; /* jump to stop handling above */ + + rb->default_event_handler(button); + break; + } /* MPEG_RW: */ + + case MPEG_FF: #ifdef MPEG_FF2 case MPEG_FF2: #endif -#ifdef MPEG_RC_RW - case MPEG_RC_RW: +#ifdef MPEG_RC_FF case MPEG_RC_FF: #endif { int old_button = button; + if (settings.play_mode != 0) - { - /* if button has been released: skip to next/previous file */ - button = rb->button_get_w_tmo(OSD_MIN_UPDATE_INTERVAL); - } - switch (button) - { - case MPEG_RW | BUTTON_REL: - { - /* release within 3 seconds: skip to previous file, else - start the current video from the beginning */ - osd_stop(); - if ( stream_get_resume_time() > 3*TS_SECOND ) { - osd_play(0); - osd_show(OSD_SHOW); - } else { - next_action = VIDEO_PREV; - } - break; - } - case MPEG_FF | BUTTON_REL: - { + button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL); + + if ((old_button | BUTTON_REL) == button) { + /* If button has been released: skip to next file */ osd_stop(); next_action = VIDEO_NEXT; - break; - } - default: - { - button = old_button; - osd_seek(button); - break; - } } + else if ((button & ~BUTTON_REPEAT) == old_button) { + button = osd_seek_btn(old_button); + } + + if (button == ACTION_STD_CANCEL) + goto cancel_playback; /* jump to stop handling above */ + + rb->default_event_handler(button); break; - } /* MPEG_RW: MPEG_FF: */ + } /* MPEG_FF: */ #ifdef HAVE_HEADPHONE_DETECTION case SYS_PHONE_PLUGGED: @@ -1849,6 +1905,7 @@ static int button_loop(void) default: { + osd_refresh(OSD_REFRESH_DEFAULT); rb->default_event_handler(button); break; } /* default: */ @@ -1874,10 +1931,7 @@ enum plugin_status plugin_start(const void* parameter) { static char videofile[MAX_PATH]; int status = PLUGIN_OK; /* assume success */ - int result; - int err; bool quit = false; - const char *errstring; if (parameter == NULL) { /* No file = GTFO */ @@ -1904,19 +1958,24 @@ enum plugin_status plugin_start(const void* parameter) DEBUGF("Could not initialize streams\n"); status = PLUGIN_ERROR; } else { + int next_action = VIDEO_STOP; + bool get_videofile_says = true; + while (!quit) { - int next_action = VIDEO_STOP; + int result; init_settings(videofile); - err = stream_open(videofile); - if (err >= STREAM_OK) { + result = stream_open(videofile); + + if (result >= STREAM_OK) { /* start menu */ rb->lcd_clear_display(); rb->lcd_update(); result = mpeg_start_menu(stream_get_duration()); + next_action = VIDEO_STOP; if (result != MPEG_START_QUIT) { /* Enter button loop and process UI */ next_action = button_loop(); @@ -1928,13 +1987,14 @@ enum plugin_status plugin_start(const void* parameter) rb->lcd_update(); save_settings(); - - mpeg_menu_sysevent_handle(); } else { /* Problem with file; display message about it - not * considered a plugin error */ + long tick; + const char *errstring; + DEBUGF("Could not open %s\n", videofile); - switch (err) + switch (result) { case STREAM_UNSUPPORTED: errstring = "Unsupported format"; @@ -1943,12 +2003,45 @@ enum plugin_status plugin_start(const void* parameter) errstring = "Error opening file: %d"; } - rb->splashf(HZ*2, errstring, err); + tick = *rb->current_tick + HZ*2; - if (settings.play_mode != 0) { - /* Try the next file if the play mode is not single play */ - next_action = VIDEO_NEXT; - } + rb->splashf(0, errstring, result); + + /* Be sure it doesn't get stuck in an unbreakable loop of bad + * files, just in case! Otherwise, keep searching in the + * chosen direction until a good one is found. */ + while (!quit && TIME_BEFORE(*rb->current_tick, tick)) + { + int button = mpeg_button_get(HZ*2); + + switch (button) + { + case MPEG_STOP: + case ACTION_STD_CANCEL: + /* Abort the search and exit */ + next_action = VIDEO_STOP; + quit = true; + break; + + case BUTTON_NONE: + if (settings.play_mode != 0) { + if (next_action == VIDEO_STOP) { + /* Default to next file */ + next_action = VIDEO_NEXT; + } + else if (next_action == VIDEO_PREV && + !get_videofile_says) { + /* Was first file already; avoid endlessly + * retrying it */ + next_action = VIDEO_STOP; + } + } + break; + + default: + rb->default_event_handler(button); + } /* switch */ + } /* while */ } /* return value of button_loop says, what's next */ @@ -1956,15 +2049,16 @@ enum plugin_status plugin_start(const void* parameter) { case VIDEO_NEXT: { - if (!get_videofile(VIDEO_NEXT, videofile, sizeof(videofile))) { - /* quit after finished the last videofile */ - quit = true; - } + get_videofile_says = get_videofile(VIDEO_NEXT, videofile, + sizeof(videofile)); + /* quit after finished the last videofile */ + quit = !get_videofile_says; break; } case VIDEO_PREV: { - get_videofile(VIDEO_PREV, videofile, sizeof(videofile)); + get_videofile_says = get_videofile(VIDEO_PREV, videofile, + sizeof(videofile)); /* if there is no previous file, play the same videofile */ break; } @@ -1974,7 +2068,7 @@ enum plugin_status plugin_start(const void* parameter) break; } } - } + } /* while */ } #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) @@ -1984,5 +2078,10 @@ enum plugin_status plugin_start(const void* parameter) stream_exit(); rb->talk_disable(false); + + /* Actually handle delayed processing of system events of interest + * that were captured in other button loops */ + mpeg_sysevent_handle(); + return status; } -- cgit v1.2.3