summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2010-12-22 11:20:07 +0000
committerMichael Sevakis <jethead71@rockbox.org>2010-12-22 11:20:07 +0000
commit9b4522bacec8cf1eb8ff69684cf959c0bb732c0d (patch)
treea939f4cd549f7def0feed75d9d5728a213bd5c22
parent303aefc406a99cb47f41ed39283a3881f4c7f401 (diff)
downloadrockbox-9b4522bacec8cf1eb8ff69684cf959c0bb732c0d.tar.gz
rockbox-9b4522bacec8cf1eb8ff69684cf959c0bb732c0d.zip
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
-rw-r--r--apps/plugins/mpegplayer/mpeg_misc.c55
-rw-r--r--apps/plugins/mpegplayer/mpeg_misc.h26
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.c79
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.h5
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c403
5 files changed, 353 insertions, 215 deletions
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,
162 list++; /* Item still there */ 162 list++; /* Item still there */
163 } 163 }
164} 164}
165
166
167/** System events **/
168static long mpeg_sysevent_id;
169
170void mpeg_sysevent_clear(void)
171{
172 mpeg_sysevent_id = 0;
173}
174
175void mpeg_sysevent_set(void)
176{
177 /* Nonzero and won't invoke anything in default event handler */
178 mpeg_sysevent_id = ACTION_STD_CANCEL;
179}
180
181long mpeg_sysevent(void)
182{
183 return mpeg_sysevent_id;
184}
185
186int mpeg_sysevent_callback(int btn, const struct menu_item_ex *menu)
187{
188 switch (btn)
189 {
190 case SYS_USB_CONNECTED:
191 case SYS_POWEROFF:
192 mpeg_sysevent_id = btn;
193 return ACTION_STD_CANCEL;
194 }
195
196 return btn;
197 (void)menu;
198}
199
200void mpeg_sysevent_handle(void)
201{
202 long id = mpeg_sysevent();
203 if (id != 0)
204 rb->default_event_handler(id);
205}
206
207
208/** Buttons **/
209
210int mpeg_button_get(int timeout)
211{
212 int button;
213
214 mpeg_sysevent_clear();
215 button = timeout == TIMEOUT_BLOCK ? rb->button_get(true) :
216 rb->button_get_w_tmo(timeout);
217 return mpeg_sysevent_callback(button, NULL);
218}
219
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,
228 list_enum_callback_t callback, 228 list_enum_callback_t callback,
229 intptr_t data); 229 intptr_t data);
230 230
231
232/** System events **/
233
234/* Clear event */
235void mpeg_sysevent_clear(void);
236
237/* Set to ACTION_STD_CANCEL */
238void mpeg_sysevent_set(void);
239
240/* Get event code */
241long mpeg_sysevent(void);
242
243/* Call with a system event code and used as menu callback */
244int mpeg_sysevent_callback(int btn, const struct menu_item_ex *menu);
245
246/* Handle recorded event */
247void mpeg_sysevent_handle(void);
248
249
250/** Buttons **/
251
252/* Get button codes while remembering important events for later
253 * processing; return of ACTION_STD_CANCEL means plugin should
254 * abort and handle the event */
255int mpeg_button_get(int timeout);
256
231#endif /* MPEG_MISC_H */ 257#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] = {
315#endif 315#endif
316 316
317static void mpeg_settings(void); 317static void mpeg_settings(void);
318static long mpeg_menu_sysevent_id;
319
320void mpeg_menu_sysevent_clear(void)
321{
322 mpeg_menu_sysevent_id = 0;
323}
324
325int mpeg_menu_sysevent_callback(int btn, const struct menu_item_ex *menu)
326{
327 switch (btn)
328 {
329 case SYS_USB_CONNECTED:
330 case SYS_POWEROFF:
331 mpeg_menu_sysevent_id = btn;
332 return ACTION_STD_CANCEL;
333 }
334
335 return btn;
336 (void)menu;
337}
338
339long mpeg_menu_sysevent(void)
340{
341 return mpeg_menu_sysevent_id;
342}
343
344void mpeg_menu_sysevent_handle(void)
345{
346 long id = mpeg_menu_sysevent();
347 if (id != 0)
348 rb->default_event_handler(id);
349}
350
351static bool mpeg_set_option(const char* string, 318static bool mpeg_set_option(const char* string,
352 void* variable, 319 void* variable,
353 enum optiontype type, 320 enum optiontype type,
@@ -355,14 +322,14 @@ static bool mpeg_set_option(const char* string,
355 int numoptions, 322 int numoptions,
356 void (*function)(int)) 323 void (*function)(int))
357{ 324{
358 mpeg_menu_sysevent_clear(); 325 mpeg_sysevent_clear();
359 326
360 /* This eats SYS_POWEROFF - :\ */ 327 /* This eats SYS_POWEROFF - :\ */
361 bool usb = rb->set_option(string, variable, type, options, numoptions, 328 bool usb = rb->set_option(string, variable, type, options, numoptions,
362 function); 329 function);
363 330
364 if (usb) 331 if (usb)
365 mpeg_menu_sysevent_id = ACTION_STD_CANCEL; 332 mpeg_sysevent_set();
366 333
367 return usb; 334 return usb;
368} 335}
@@ -375,13 +342,13 @@ static bool mpeg_set_int(const char *string, const char *unit,
375 int max, 342 int max,
376 const char* (*formatter)(char*, size_t, int, const char*)) 343 const char* (*formatter)(char*, size_t, int, const char*))
377{ 344{
378 mpeg_menu_sysevent_clear(); 345 mpeg_sysevent_clear();
379 346
380 bool usb = rb->set_int(string, unit, voice_unit, variable, function, 347 bool usb = rb->set_int(string, unit, voice_unit, variable, function,
381 step, min, max, formatter); 348 step, min, max, formatter);
382 349
383 if (usb) 350 if (usb)
384 mpeg_menu_sysevent_id = ACTION_STD_CANCEL; 351 mpeg_sysevent_set();
385 352
386 return usb; 353 return usb;
387} 354}
@@ -778,11 +745,7 @@ static int get_start_time(uint32_t duration)
778 745
779 while (slider_state < STATE9) 746 while (slider_state < STATE9)
780 { 747 {
781 mpeg_menu_sysevent_clear(); 748 button = mpeg_button_get(tmo);
782 button = tmo == TIMEOUT_BLOCK ?
783 rb->button_get(true) : rb->button_get_w_tmo(tmo);
784
785 button = mpeg_menu_sysevent_callback(button, NULL);
786 749
787 switch (button) 750 switch (button)
788 { 751 {
@@ -922,7 +885,7 @@ static int show_start_menu(uint32_t duration)
922 char hms_str[32]; 885 char hms_str[32];
923 struct hms hms; 886 struct hms hms;
924 887
925 MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_menu_sysevent_callback, 888 MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_sysevent_callback,
926 "Play from beginning", resume_str, "Set start time", 889 "Play from beginning", resume_str, "Set start time",
927 "Settings", "Quit mpegplayer"); 890 "Settings", "Quit mpegplayer");
928 891
@@ -935,7 +898,7 @@ static int show_start_menu(uint32_t duration)
935 898
936 while (!menu_quit) 899 while (!menu_quit)
937 { 900 {
938 mpeg_menu_sysevent_clear(); 901 mpeg_sysevent_clear();
939 result = rb->do_menu(&menu, &selected, NULL, false); 902 result = rb->do_menu(&menu, &selected, NULL, false);
940 903
941 switch (result) 904 switch (result)
@@ -972,7 +935,7 @@ static int show_start_menu(uint32_t duration)
972 break; 935 break;
973 } 936 }
974 937
975 if (mpeg_menu_sysevent() != 0) 938 if (mpeg_sysevent() != 0)
976 { 939 {
977 result = MPEG_START_QUIT; 940 result = MPEG_START_QUIT;
978 menu_quit = true; 941 menu_quit = true;
@@ -985,7 +948,7 @@ static int show_start_menu(uint32_t duration)
985/* Return the desired resume action */ 948/* Return the desired resume action */
986int mpeg_start_menu(uint32_t duration) 949int mpeg_start_menu(uint32_t duration)
987{ 950{
988 mpeg_menu_sysevent_clear(); 951 mpeg_sysevent_clear();
989 952
990 switch (settings.resume_options) 953 switch (settings.resume_options)
991 { 954 {
@@ -1008,12 +971,12 @@ int mpeg_menu(void)
1008{ 971{
1009 int result; 972 int result;
1010 973
1011 MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_menu_sysevent_callback, 974 MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_sysevent_callback,
1012 "Settings", "Resume playback", "Quit mpegplayer"); 975 "Settings", "Resume playback", "Quit mpegplayer");
1013 976
1014 rb->button_clear_queue(); 977 rb->button_clear_queue();
1015 978
1016 mpeg_menu_sysevent_clear(); 979 mpeg_sysevent_clear();
1017 980
1018 result = rb->do_menu(&menu, NULL, NULL, false); 981 result = rb->do_menu(&menu, NULL, NULL, false);
1019 982
@@ -1033,7 +996,7 @@ int mpeg_menu(void)
1033 break; 996 break;
1034 } 997 }
1035 998
1036 if (mpeg_menu_sysevent() != 0) 999 if (mpeg_sysevent() != 0)
1037 result = MPEG_MENU_QUIT; 1000 result = MPEG_MENU_QUIT;
1038 1001
1039 return result; 1002 return result;
@@ -1045,7 +1008,7 @@ static void display_options(void)
1045 int result; 1008 int result;
1046 bool menu_quit = false; 1009 bool menu_quit = false;
1047 1010
1048 MENUITEM_STRINGLIST(menu, "Display Options", mpeg_menu_sysevent_callback, 1011 MENUITEM_STRINGLIST(menu, "Display Options", mpeg_sysevent_callback,
1049#if MPEG_OPTION_DITHERING_ENABLED 1012#if MPEG_OPTION_DITHERING_ENABLED
1050 "Dithering", 1013 "Dithering",
1051#endif 1014#endif
@@ -1059,7 +1022,7 @@ static void display_options(void)
1059 1022
1060 while (!menu_quit) 1023 while (!menu_quit)
1061 { 1024 {
1062 mpeg_menu_sysevent_clear(); 1025 mpeg_sysevent_clear();
1063 result = rb->do_menu(&menu, &selected, NULL, false); 1026 result = rb->do_menu(&menu, &selected, NULL, false);
1064 1027
1065 switch (result) 1028 switch (result)
@@ -1108,7 +1071,7 @@ static void display_options(void)
1108 break; 1071 break;
1109 } 1072 }
1110 1073
1111 if (mpeg_menu_sysevent() != 0) 1074 if (mpeg_sysevent() != 0)
1112 menu_quit = true; 1075 menu_quit = true;
1113 } 1076 }
1114} 1077}
@@ -1119,7 +1082,7 @@ static void audio_options(void)
1119 int result; 1082 int result;
1120 bool menu_quit = false; 1083 bool menu_quit = false;
1121 1084
1122 MENUITEM_STRINGLIST(menu, "Audio Options", mpeg_menu_sysevent_callback, 1085 MENUITEM_STRINGLIST(menu, "Audio Options", mpeg_sysevent_callback,
1123 "Tone Controls", "Channel Modes", "Crossfeed", 1086 "Tone Controls", "Channel Modes", "Crossfeed",
1124 "Equalizer", "Dithering"); 1087 "Equalizer", "Dithering");
1125 1088
@@ -1127,7 +1090,7 @@ static void audio_options(void)
1127 1090
1128 while (!menu_quit) 1091 while (!menu_quit)
1129 { 1092 {
1130 mpeg_menu_sysevent_clear(); 1093 mpeg_sysevent_clear();
1131 result = rb->do_menu(&menu, &selected, NULL, false); 1094 result = rb->do_menu(&menu, &selected, NULL, false);
1132 1095
1133 switch (result) 1096 switch (result)
@@ -1167,7 +1130,7 @@ static void audio_options(void)
1167 break; 1130 break;
1168 } 1131 }
1169 1132
1170 if (mpeg_menu_sysevent() != 0) 1133 if (mpeg_sysevent() != 0)
1171 menu_quit = true; 1134 menu_quit = true;
1172 } 1135 }
1173} 1136}
@@ -1203,7 +1166,7 @@ static void mpeg_settings(void)
1203 bool menu_quit = false; 1166 bool menu_quit = false;
1204 static char clear_str[32]; 1167 static char clear_str[32];
1205 1168
1206 MENUITEM_STRINGLIST(menu, "Settings", mpeg_menu_sysevent_callback, 1169 MENUITEM_STRINGLIST(menu, "Settings", mpeg_sysevent_callback,
1207 "Display Options", "Audio Options", 1170 "Display Options", "Audio Options",
1208 "Resume Options", "Play Mode", clear_str); 1171 "Resume Options", "Play Mode", clear_str);
1209 1172
@@ -1211,7 +1174,7 @@ static void mpeg_settings(void)
1211 1174
1212 while (!menu_quit) 1175 while (!menu_quit)
1213 { 1176 {
1214 mpeg_menu_sysevent_clear(); 1177 mpeg_sysevent_clear();
1215 1178
1216 /* Format and add resume option to the menu display */ 1179 /* Format and add resume option to the menu display */
1217 rb->snprintf(clear_str, sizeof(clear_str), 1180 rb->snprintf(clear_str, sizeof(clear_str),
@@ -1247,7 +1210,7 @@ static void mpeg_settings(void)
1247 break; 1210 break;
1248 } 1211 }
1249 1212
1250 if (mpeg_menu_sysevent() != 0) 1213 if (mpeg_sysevent() != 0)
1251 menu_quit = true; 1214 menu_quit = true;
1252 } 1215 }
1253} 1216}
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;
102int mpeg_start_menu(uint32_t duration); 102int mpeg_start_menu(uint32_t duration);
103int mpeg_menu(void); 103int mpeg_menu(void);
104 104
105void mpeg_menu_sysevent_clear(void);
106long mpeg_menu_sysevent(void);
107int mpeg_menu_sysevent_callback(int btn, const struct menu_item_ex *menu);
108void mpeg_menu_sysevent_handle(void);
109
110void init_settings(const char* filename); 105void init_settings(const char* filename);
111void save_settings(void); 106void save_settings(void);
112 107
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
412 OSD_REFRESH_RESUME = 0x0020, /* Resume playback upon timeout */ 412 OSD_REFRESH_RESUME = 0x0020, /* Resume playback upon timeout */
413 OSD_NODRAW = 0x8000, /* OR bitflag - don't draw anything */ 413 OSD_NODRAW = 0x8000, /* OR bitflag - don't draw anything */
414 OSD_SHOW = 0x4000, /* OR bitflag - show the OSD */ 414 OSD_SHOW = 0x4000, /* OR bitflag - show the OSD */
415 OSD_HP_PAUSE = 0x2000, 415#ifdef HAVE_HEADPHONE_DETECTION
416 OSD_HP_PAUSE = 0x2000, /* OR bitflag - headphones caused pause */
417#endif
416 OSD_HIDE = 0x0000, /* hide the OSD (aid readability) */ 418 OSD_HIDE = 0x0000, /* hide the OSD (aid readability) */
417 OSD_REFRESH_ALL = 0x000f, /* Only immediate graphical elements */ 419 OSD_REFRESH_ALL = 0x000f, /* Only immediate graphical elements */
418}; 420};
@@ -835,6 +837,18 @@ static void osd_init(void)
835 osd_text_init(); 837 osd_text_init();
836} 838}
837 839
840#ifdef HAVE_HEADPHONE_DETECTION
841static void osd_set_hp_pause_flag(bool set)
842{
843 if (set)
844 osd.flags |= OSD_HP_PAUSE;
845 else
846 osd.flags &= ~OSD_HP_PAUSE;
847}
848#else
849#define osd_set_hp_pause_flag(set)
850#endif /* HAVE_HEADPHONE_DETECTION */
851
838static void osd_schedule_refresh(unsigned refresh) 852static void osd_schedule_refresh(unsigned refresh)
839{ 853{
840 long tick = *rb->current_tick; 854 long tick = *rb->current_tick;
@@ -1213,8 +1227,10 @@ static int osd_get_status(void)
1213 return osd.status & OSD_STATUS_MASK; 1227 return osd.status & OSD_STATUS_MASK;
1214} 1228}
1215 1229
1216/* Handle Fast-forward/Rewind keys using WPS settings (and some nicked code ;) */ 1230/* Handle Fast-forward/Rewind keys using WPS settings (and some nicked code ;)
1217static uint32_t osd_ff_rw(int btn, unsigned refresh) 1231 * Returns last button code
1232 */
1233static int osd_ff_rw(int btn, unsigned refresh, uint32_t *new_time)
1218{ 1234{
1219 unsigned int step = TS_SECOND*rb->global_settings->ff_rewind_min_step; 1235 unsigned int step = TS_SECOND*rb->global_settings->ff_rewind_min_step;
1220 const long ff_rw_accel = (rb->global_settings->ff_rewind_accel + 3); 1236 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)
1224 unsigned int max_step = 0; 1240 unsigned int max_step = 0;
1225 uint32_t ff_rw_count = 0; 1241 uint32_t ff_rw_count = 0;
1226 unsigned status = osd.status; 1242 unsigned status = osd.status;
1243 int new_btn;
1227 1244
1228 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME | 1245 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME |
1229 OSD_REFRESH_TIME); 1246 OSD_REFRESH_TIME);
@@ -1239,9 +1256,8 @@ static uint32_t osd_ff_rw(int btn, unsigned refresh)
1239#ifdef MPEG_RC_FF 1256#ifdef MPEG_RC_FF
1240 case MPEG_RC_FF: 1257 case MPEG_RC_FF:
1241#endif 1258#endif
1242 if (!(btn & BUTTON_REPEAT)) 1259 osd_set_status(OSD_STATUS_FF);
1243 osd_set_status(OSD_STATUS_FF); 1260 new_btn = btn | BUTTON_REPEAT; /* simplify code below */
1244 btn = MPEG_FF | BUTTON_REPEAT; /* simplify code below */
1245 break; 1261 break;
1246 case MPEG_RW: 1262 case MPEG_RW:
1247#ifdef MPEG_RW2 1263#ifdef MPEG_RW2
@@ -1250,103 +1266,75 @@ static uint32_t osd_ff_rw(int btn, unsigned refresh)
1250#ifdef MPEG_RC_RW 1266#ifdef MPEG_RC_RW
1251 case MPEG_RC_RW: 1267 case MPEG_RC_RW:
1252#endif 1268#endif
1253 if (!(btn & BUTTON_REPEAT)) 1269 osd_set_status(OSD_STATUS_RW);
1254 osd_set_status(OSD_STATUS_RW); 1270 new_btn = btn | BUTTON_REPEAT; /* simplify code below */
1255 btn = MPEG_RW | BUTTON_REPEAT; /* simplify code below */
1256 break; 1271 break;
1257 default: 1272 default:
1258 btn = -1; 1273 new_btn = BUTTON_NONE; /* Fail tests below but still do proper exit */
1259 } 1274 }
1260 1275
1261 while (1) 1276 while (1)
1262 { 1277 {
1263 stream_keep_disk_active(); 1278 stream_keep_disk_active();
1264 1279
1265 switch (btn) 1280 if (new_btn == (btn | BUTTON_REPEAT)) {
1266 { 1281 if (osd.status == OSD_STATUS_FF) {
1267 case BUTTON_NONE: 1282 /* fast forwarding, calc max step relative to end */
1268 osd_refresh(OSD_REFRESH_DEFAULT); 1283 max_step = muldiv_uint32(duration - (time + ff_rw_count),
1269 break; 1284 FF_REWIND_MAX_PERCENT, 100);
1270 1285 } else {
1271 case MPEG_FF | BUTTON_REPEAT: 1286 /* rewinding, calc max step relative to start */
1272 case MPEG_RW | BUTTON_REPEAT: 1287 max_step = muldiv_uint32(time - ff_rw_count,
1273#ifdef MPEG_FF2 1288 FF_REWIND_MAX_PERCENT, 100);
1274 case MPEG_FF2 | BUTTON_REPEAT: 1289 }
1275#endif
1276#ifdef MPEG_RW2
1277 case MPEG_RW2 | BUTTON_REPEAT:
1278#endif
1279#ifdef MPEG_RC_FF
1280 case MPEG_RC_FF | BUTTON_REPEAT:
1281 case MPEG_RC_RW | BUTTON_REPEAT:
1282#endif
1283 break;
1284 1290
1285 case MPEG_FF | BUTTON_REL: 1291 max_step = MAX(max_step, MIN_FF_REWIND_STEP);
1286 case MPEG_RW | BUTTON_REL:
1287#ifdef MPEG_FF2
1288 case MPEG_FF2 | BUTTON_REL:
1289#endif
1290#ifdef MPEG_RW2
1291 case MPEG_RW2 | BUTTON_REL:
1292#endif
1293#ifdef MPEG_RC_FF
1294 case MPEG_RC_FF | BUTTON_REL:
1295 case MPEG_RC_RW | BUTTON_REL:
1296#endif
1297 if (osd.status == OSD_STATUS_FF)
1298 time += ff_rw_count;
1299 else if (osd.status == OSD_STATUS_RW)
1300 time -= ff_rw_count;
1301 1292
1302 /* Fall-through */ 1293 if (step > max_step)
1303 case -1: 1294 step = max_step;
1304 default:
1305 osd_schedule_refresh(refresh);
1306 osd_set_status(status);
1307 osd_schedule_refresh(OSD_REFRESH_TIME);
1308 return time;
1309 }
1310 1295
1311 if (osd.status == OSD_STATUS_FF) { 1296 ff_rw_count += step;
1312 /* fast forwarding, calc max step relative to end */
1313 max_step = muldiv_uint32(duration - (time + ff_rw_count),
1314 FF_REWIND_MAX_PERCENT, 100);
1315 } else {
1316 /* rewinding, calc max step relative to start */
1317 max_step = muldiv_uint32(time - ff_rw_count,
1318 FF_REWIND_MAX_PERCENT, 100);
1319 }
1320 1297
1321 max_step = MAX(max_step, MIN_FF_REWIND_STEP); 1298 /* smooth seeking by multiplying step by: 1 + (2 ^ -accel) */
1299 step += step >> ff_rw_accel;
1322 1300
1323 if (step > max_step) 1301 if (osd.status == OSD_STATUS_FF) {
1324 step = max_step; 1302 if (duration - time <= ff_rw_count)
1303 ff_rw_count = duration - time;
1325 1304
1326 ff_rw_count += step; 1305 osd.curr_time = time + ff_rw_count;
1306 } else {
1307 if (time <= ff_rw_count)
1308 ff_rw_count = time;
1327 1309
1328 /* smooth seeking by multiplying step by: 1 + (2 ^ -accel) */ 1310 osd.curr_time = time - ff_rw_count;
1329 step += step >> ff_rw_accel; 1311 }
1330 1312
1331 if (osd.status == OSD_STATUS_FF) { 1313 osd_refresh(OSD_REFRESH_TIME);
1332 if (duration - time <= ff_rw_count)
1333 ff_rw_count = duration - time;
1334 1314
1335 osd.curr_time = time + ff_rw_count; 1315 new_btn = mpeg_button_get(TIMEOUT_BLOCK);
1336 } else {
1337 if (time <= ff_rw_count)
1338 ff_rw_count = time;
1339
1340 osd.curr_time = time - ff_rw_count;
1341 } 1316 }
1317 else {
1318 if (new_btn == (btn | BUTTON_REL)) {
1319 if (osd.status == OSD_STATUS_FF)
1320 time += ff_rw_count;
1321 else if (osd.status == OSD_STATUS_RW)
1322 time -= ff_rw_count;
1323 }
1342 1324
1343 osd_refresh(OSD_REFRESH_TIME); 1325 *new_time = time;
1326
1327 osd_schedule_refresh(refresh);
1328 osd_set_status(status);
1329 osd_schedule_refresh(OSD_REFRESH_TIME);
1344 1330
1345 btn = rb->button_get_w_tmo(OSD_MIN_UPDATE_INTERVAL); 1331 return new_btn;
1332 }
1346 } 1333 }
1347} 1334}
1348 1335
1349static int osd_status(void) 1336/* Return adjusted STREAM_* status */
1337static int osd_stream_status(void)
1350{ 1338{
1351 int status = stream_status(); 1339 int status = stream_status();
1352 1340
@@ -1394,6 +1382,7 @@ static int osd_play(uint32_t time)
1394{ 1382{
1395 int retval; 1383 int retval;
1396 1384
1385 osd_set_hp_pause_flag(false);
1397 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); 1386 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME);
1398 1387
1399 retval = stream_seek(time, SEEK_SET); 1388 retval = stream_seek(time, SEEK_SET);
@@ -1436,6 +1425,8 @@ static int osd_pause(void)
1436 unsigned refresh = osd.auto_refresh; 1425 unsigned refresh = osd.auto_refresh;
1437 int status = osd_halt(); 1426 int status = osd_halt();
1438 1427
1428 osd_set_hp_pause_flag(false);
1429
1439 if (status == STREAM_PLAYING && (refresh & OSD_REFRESH_RESUME)) { 1430 if (status == STREAM_PLAYING && (refresh & OSD_REFRESH_RESUME)) {
1440 /* Resume pending - change to a still video frame update */ 1431 /* Resume pending - change to a still video frame update */
1441 osd_schedule_refresh(OSD_REFRESH_VIDEO); 1432 osd_schedule_refresh(OSD_REFRESH_VIDEO);
@@ -1454,6 +1445,7 @@ static void osd_resume(void)
1454{ 1445{
1455 /* Cancel video and resume auto refresh - the resyc when starting 1446 /* Cancel video and resume auto refresh - the resyc when starting
1456 * playback will perform those tasks */ 1447 * playback will perform those tasks */
1448 osd_set_hp_pause_flag(false);
1457 osd_backlight_on_video_mode(true); 1449 osd_backlight_on_video_mode(true);
1458 osd_backlight_brightness_video_mode(true); 1450 osd_backlight_brightness_video_mode(true);
1459 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); 1451 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME);
@@ -1466,6 +1458,7 @@ static void osd_stop(void)
1466{ 1458{
1467 uint32_t resume_time; 1459 uint32_t resume_time;
1468 1460
1461 osd_set_hp_pause_flag(false);
1469 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); 1462 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME);
1470 osd_set_status(OSD_STATUS_STOPPED | OSD_NODRAW); 1463 osd_set_status(OSD_STATUS_STOPPED | OSD_NODRAW);
1471 osd_show(OSD_HIDE); 1464 osd_show(OSD_HIDE);
@@ -1481,35 +1474,81 @@ static void osd_stop(void)
1481 osd_backlight_brightness_video_mode(false); 1474 osd_backlight_brightness_video_mode(false);
1482} 1475}
1483 1476
1484/* Perform a seek if seeking is possible for this stream - if playing, a delay 1477/* Perform a seek by button if seeking is possible for this stream.
1485 * will be inserted before restarting in case the user decides to seek again */ 1478 *
1486static void osd_seek(int btn) 1479 * A delay will be inserted before restarting in case the user decides to
1480 * seek again soon after.
1481 *
1482 * Returns last button code
1483 */
1484static int osd_seek_btn(int btn)
1487{ 1485{
1488 int status; 1486 int status;
1489 unsigned refresh; 1487 unsigned refresh = 0;
1490 uint32_t time; 1488 uint32_t time;
1491 1489
1492 if (!stream_can_seek()) 1490 if (!stream_can_seek())
1493 return; 1491 return true;
1494 1492
1495 /* Halt playback - not strictly nescessary but nice */ 1493 /* Halt playback - not strictly necessary but nice when doing
1494 * buttons */
1496 status = osd_halt(); 1495 status = osd_halt();
1497 1496
1498 if (status == STREAM_STOPPED) 1497 if (status == STREAM_STOPPED)
1499 return; 1498 return true;
1500 1499
1501 osd_show(OSD_SHOW); 1500 osd_show(OSD_SHOW);
1502 1501
1502 /* Obtain a new playback point according to the buttons */
1503 if (status == STREAM_PLAYING) 1503 if (status == STREAM_PLAYING)
1504 refresh = OSD_REFRESH_RESUME; /* delay resume if playing */ 1504 refresh = OSD_REFRESH_RESUME; /* delay resume if playing */
1505 else 1505 else
1506 refresh = OSD_REFRESH_VIDEO; /* refresh if paused */ 1506 refresh = OSD_REFRESH_VIDEO; /* refresh if paused */
1507 1507
1508 /* Obtain a new playback point */ 1508 btn = osd_ff_rw(btn, refresh, &time);
1509 time = osd_ff_rw(btn, refresh);
1510 1509
1511 /* Tell engine to resume at that time */ 1510 /* Tell engine to resume at that time */
1512 stream_seek(time, SEEK_SET); 1511 stream_seek(time, SEEK_SET);
1512
1513 return btn;
1514}
1515
1516/* Perform a seek by time if seeking is possible for this stream
1517 *
1518 * If playing, the seeking is immediate, otherise a delay is added to showing
1519 * a still if paused in case the user does another seek soon after.
1520 *
1521 * If seeking isn't possible, a time of zero performs a skip to the
1522 * beginning.
1523 */
1524static void osd_seek_time(uint32_t time)
1525{
1526 int status;
1527 unsigned refresh = 0;
1528
1529 if (!stream_can_seek() && time != 0)
1530 return;
1531
1532 stream_wait_status();
1533 status = osd_stream_status();
1534
1535 if (status == STREAM_STOPPED)
1536 return;
1537
1538 if (status == STREAM_PLAYING) /* merely preserve resume */
1539 refresh = osd.auto_refresh & OSD_REFRESH_RESUME;
1540 else
1541 refresh = OSD_REFRESH_VIDEO; /* refresh if paused */
1542
1543 /* Cancel print or resume if pending */
1544 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME);
1545
1546 /* Tell engine to seek to the given time - no state change */
1547 stream_seek(time, SEEK_SET);
1548
1549 osd_update_time();
1550 osd_refresh(OSD_REFRESH_TIME);
1551 osd_schedule_refresh(refresh);
1513} 1552}
1514 1553
1515/* Has this file one of the supported extensions? */ 1554/* Has this file one of the supported extensions? */
@@ -1537,7 +1576,7 @@ static bool is_videofile(const char* file)
1537} 1576}
1538 1577
1539/* deliver the next/previous video file in the current directory. 1578/* deliver the next/previous video file in the current directory.
1540 returns 0 if there is none. */ 1579 returns false if there is none. */
1541static bool get_videofile(int direction, char* videofile, size_t bufsize) 1580static bool get_videofile(int direction, char* videofile, size_t bufsize)
1542{ 1581{
1543 struct tree_context *tree = rb->tree_get_context(); 1582 struct tree_context *tree = rb->tree_get_context();
@@ -1583,11 +1622,12 @@ static void osd_handle_phone_plug(bool inserted)
1583 /* Wait for any incomplete state transition to complete first */ 1622 /* Wait for any incomplete state transition to complete first */
1584 stream_wait_status(); 1623 stream_wait_status();
1585 1624
1586 int status = osd_status(); 1625 int status = osd_stream_status();
1587 1626
1588 if (inserted) { 1627 if (inserted) {
1589 if (rb->global_settings->unplug_mode > 1) { 1628 if (rb->global_settings->unplug_mode > 1) {
1590 if (status == STREAM_PAUSED) { 1629 if (status == STREAM_PAUSED &&
1630 (osd.flags & OSD_HP_PAUSE)) {
1591 osd_resume(); 1631 osd_resume();
1592 } 1632 }
1593 } 1633 }
@@ -1595,6 +1635,8 @@ static void osd_handle_phone_plug(bool inserted)
1595 if (status == STREAM_PLAYING) { 1635 if (status == STREAM_PLAYING) {
1596 osd_pause(); 1636 osd_pause();
1597 1637
1638 osd_set_hp_pause_flag(true);
1639
1598 if (stream_can_seek() && rb->global_settings->unplug_rw) { 1640 if (stream_can_seek() && rb->global_settings->unplug_rw) {
1599 stream_seek(-rb->global_settings->unplug_rw*TS_SECOND, 1641 stream_seek(-rb->global_settings->unplug_rw*TS_SECOND,
1600 SEEK_CUR); 1642 SEEK_CUR);
@@ -1635,12 +1677,7 @@ static int button_loop(void)
1635 /* Gently poll the video player for EOS and handle UI */ 1677 /* Gently poll the video player for EOS and handle UI */
1636 while (stream_status() != STREAM_STOPPED) 1678 while (stream_status() != STREAM_STOPPED)
1637 { 1679 {
1638 int button; 1680 int button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL/2);
1639
1640 mpeg_menu_sysevent_clear();
1641 button = rb->button_get_w_tmo(OSD_MIN_UPDATE_INTERVAL/2);
1642
1643 button = mpeg_menu_sysevent_callback(button, NULL);
1644 1681
1645 switch (button) 1682 switch (button)
1646 { 1683 {
@@ -1761,6 +1798,7 @@ static int button_loop(void)
1761#endif 1798#endif
1762 case ACTION_STD_CANCEL: 1799 case ACTION_STD_CANCEL:
1763 { 1800 {
1801 cancel_playback:
1764 next_action = VIDEO_STOP; 1802 next_action = VIDEO_STOP;
1765 osd_stop(); 1803 osd_stop();
1766 break; 1804 break;
@@ -1774,7 +1812,7 @@ static int button_loop(void)
1774 case MPEG_RC_PAUSE: 1812 case MPEG_RC_PAUSE:
1775#endif 1813#endif
1776 { 1814 {
1777 int status = osd_status(); 1815 int status = osd_stream_status();
1778 1816
1779 if (status == STREAM_PLAYING) { 1817 if (status == STREAM_PLAYING) {
1780 /* Playing => Paused */ 1818 /* Playing => Paused */
@@ -1789,54 +1827,72 @@ static int button_loop(void)
1789 } /* MPEG_PAUSE*: */ 1827 } /* MPEG_PAUSE*: */
1790 1828
1791 case MPEG_RW: 1829 case MPEG_RW:
1792 case MPEG_FF:
1793#ifdef MPEG_RW2 1830#ifdef MPEG_RW2
1794 case MPEG_RW2: 1831 case MPEG_RW2:
1795#endif 1832#endif
1833#ifdef MPEG_RC_RW
1834 case MPEG_RC_RW:
1835#endif
1836 {
1837 int old_button = button;
1838
1839 /* If button has been released: skip to next/previous file */
1840 button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL);
1841
1842 if ((old_button | BUTTON_REL) == button) {
1843 /* Check current playback position */
1844 osd_update_time();
1845
1846 if (settings.play_mode == 0 || osd.curr_time >= 3*TS_SECOND) {
1847 /* Start the current video from the beginning */
1848 osd_seek_time(0*TS_SECOND);
1849 }
1850 else {
1851 /* Release within 3 seconds of start: skip to previous
1852 * file */
1853 osd_stop();
1854 next_action = VIDEO_PREV;
1855 }
1856 }
1857 else if ((button & ~BUTTON_REPEAT) == old_button) {
1858 button = osd_seek_btn(old_button);
1859 }
1860
1861 if (button == ACTION_STD_CANCEL)
1862 goto cancel_playback; /* jump to stop handling above */
1863
1864 rb->default_event_handler(button);
1865 break;
1866 } /* MPEG_RW: */
1867
1868 case MPEG_FF:
1796#ifdef MPEG_FF2 1869#ifdef MPEG_FF2
1797 case MPEG_FF2: 1870 case MPEG_FF2:
1798#endif 1871#endif
1799#ifdef MPEG_RC_RW 1872#ifdef MPEG_RC_FF
1800 case MPEG_RC_RW:
1801 case MPEG_RC_FF: 1873 case MPEG_RC_FF:
1802#endif 1874#endif
1803 { 1875 {
1804 int old_button = button; 1876 int old_button = button;
1877
1805 if (settings.play_mode != 0) 1878 if (settings.play_mode != 0)
1806 { 1879 button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL);
1807 /* if button has been released: skip to next/previous file */ 1880
1808 button = rb->button_get_w_tmo(OSD_MIN_UPDATE_INTERVAL); 1881 if ((old_button | BUTTON_REL) == button) {
1809 } 1882 /* If button has been released: skip to next file */
1810 switch (button)
1811 {
1812 case MPEG_RW | BUTTON_REL:
1813 {
1814 /* release within 3 seconds: skip to previous file, else
1815 start the current video from the beginning */
1816 osd_stop();
1817 if ( stream_get_resume_time() > 3*TS_SECOND ) {
1818 osd_play(0);
1819 osd_show(OSD_SHOW);
1820 } else {
1821 next_action = VIDEO_PREV;
1822 }
1823 break;
1824 }
1825 case MPEG_FF | BUTTON_REL:
1826 {
1827 osd_stop(); 1883 osd_stop();
1828 next_action = VIDEO_NEXT; 1884 next_action = VIDEO_NEXT;
1829 break;
1830 }
1831 default:
1832 {
1833 button = old_button;
1834 osd_seek(button);
1835 break;
1836 }
1837 } 1885 }
1886 else if ((button & ~BUTTON_REPEAT) == old_button) {
1887 button = osd_seek_btn(old_button);
1888 }
1889
1890 if (button == ACTION_STD_CANCEL)
1891 goto cancel_playback; /* jump to stop handling above */
1892
1893 rb->default_event_handler(button);
1838 break; 1894 break;
1839 } /* MPEG_RW: MPEG_FF: */ 1895 } /* MPEG_FF: */
1840 1896
1841#ifdef HAVE_HEADPHONE_DETECTION 1897#ifdef HAVE_HEADPHONE_DETECTION
1842 case SYS_PHONE_PLUGGED: 1898 case SYS_PHONE_PLUGGED:
@@ -1849,6 +1905,7 @@ static int button_loop(void)
1849 1905
1850 default: 1906 default:
1851 { 1907 {
1908 osd_refresh(OSD_REFRESH_DEFAULT);
1852 rb->default_event_handler(button); 1909 rb->default_event_handler(button);
1853 break; 1910 break;
1854 } /* default: */ 1911 } /* default: */
@@ -1874,10 +1931,7 @@ enum plugin_status plugin_start(const void* parameter)
1874{ 1931{
1875 static char videofile[MAX_PATH]; 1932 static char videofile[MAX_PATH];
1876 int status = PLUGIN_OK; /* assume success */ 1933 int status = PLUGIN_OK; /* assume success */
1877 int result;
1878 int err;
1879 bool quit = false; 1934 bool quit = false;
1880 const char *errstring;
1881 1935
1882 if (parameter == NULL) { 1936 if (parameter == NULL) {
1883 /* No file = GTFO */ 1937 /* No file = GTFO */
@@ -1904,19 +1958,24 @@ enum plugin_status plugin_start(const void* parameter)
1904 DEBUGF("Could not initialize streams\n"); 1958 DEBUGF("Could not initialize streams\n");
1905 status = PLUGIN_ERROR; 1959 status = PLUGIN_ERROR;
1906 } else { 1960 } else {
1961 int next_action = VIDEO_STOP;
1962 bool get_videofile_says = true;
1963
1907 while (!quit) 1964 while (!quit)
1908 { 1965 {
1909 int next_action = VIDEO_STOP; 1966 int result;
1910 1967
1911 init_settings(videofile); 1968 init_settings(videofile);
1912 err = stream_open(videofile);
1913 1969
1914 if (err >= STREAM_OK) { 1970 result = stream_open(videofile);
1971
1972 if (result >= STREAM_OK) {
1915 /* start menu */ 1973 /* start menu */
1916 rb->lcd_clear_display(); 1974 rb->lcd_clear_display();
1917 rb->lcd_update(); 1975 rb->lcd_update();
1918 result = mpeg_start_menu(stream_get_duration()); 1976 result = mpeg_start_menu(stream_get_duration());
1919 1977
1978 next_action = VIDEO_STOP;
1920 if (result != MPEG_START_QUIT) { 1979 if (result != MPEG_START_QUIT) {
1921 /* Enter button loop and process UI */ 1980 /* Enter button loop and process UI */
1922 next_action = button_loop(); 1981 next_action = button_loop();
@@ -1928,13 +1987,14 @@ enum plugin_status plugin_start(const void* parameter)
1928 rb->lcd_update(); 1987 rb->lcd_update();
1929 1988
1930 save_settings(); 1989 save_settings();
1931
1932 mpeg_menu_sysevent_handle();
1933 } else { 1990 } else {
1934 /* Problem with file; display message about it - not 1991 /* Problem with file; display message about it - not
1935 * considered a plugin error */ 1992 * considered a plugin error */
1993 long tick;
1994 const char *errstring;
1995
1936 DEBUGF("Could not open %s\n", videofile); 1996 DEBUGF("Could not open %s\n", videofile);
1937 switch (err) 1997 switch (result)
1938 { 1998 {
1939 case STREAM_UNSUPPORTED: 1999 case STREAM_UNSUPPORTED:
1940 errstring = "Unsupported format"; 2000 errstring = "Unsupported format";
@@ -1943,12 +2003,45 @@ enum plugin_status plugin_start(const void* parameter)
1943 errstring = "Error opening file: %d"; 2003 errstring = "Error opening file: %d";
1944 } 2004 }
1945 2005
1946 rb->splashf(HZ*2, errstring, err); 2006 tick = *rb->current_tick + HZ*2;
1947 2007
1948 if (settings.play_mode != 0) { 2008 rb->splashf(0, errstring, result);
1949 /* Try the next file if the play mode is not single play */ 2009
1950 next_action = VIDEO_NEXT; 2010 /* Be sure it doesn't get stuck in an unbreakable loop of bad
1951 } 2011 * files, just in case! Otherwise, keep searching in the
2012 * chosen direction until a good one is found. */
2013 while (!quit && TIME_BEFORE(*rb->current_tick, tick))
2014 {
2015 int button = mpeg_button_get(HZ*2);
2016
2017 switch (button)
2018 {
2019 case MPEG_STOP:
2020 case ACTION_STD_CANCEL:
2021 /* Abort the search and exit */
2022 next_action = VIDEO_STOP;
2023 quit = true;
2024 break;
2025
2026 case BUTTON_NONE:
2027 if (settings.play_mode != 0) {
2028 if (next_action == VIDEO_STOP) {
2029 /* Default to next file */
2030 next_action = VIDEO_NEXT;
2031 }
2032 else if (next_action == VIDEO_PREV &&
2033 !get_videofile_says) {
2034 /* Was first file already; avoid endlessly
2035 * retrying it */
2036 next_action = VIDEO_STOP;
2037 }
2038 }
2039 break;
2040
2041 default:
2042 rb->default_event_handler(button);
2043 } /* switch */
2044 } /* while */
1952 } 2045 }
1953 2046
1954 /* return value of button_loop says, what's next */ 2047 /* return value of button_loop says, what's next */
@@ -1956,15 +2049,16 @@ enum plugin_status plugin_start(const void* parameter)
1956 { 2049 {
1957 case VIDEO_NEXT: 2050 case VIDEO_NEXT:
1958 { 2051 {
1959 if (!get_videofile(VIDEO_NEXT, videofile, sizeof(videofile))) { 2052 get_videofile_says = get_videofile(VIDEO_NEXT, videofile,
1960 /* quit after finished the last videofile */ 2053 sizeof(videofile));
1961 quit = true; 2054 /* quit after finished the last videofile */
1962 } 2055 quit = !get_videofile_says;
1963 break; 2056 break;
1964 } 2057 }
1965 case VIDEO_PREV: 2058 case VIDEO_PREV:
1966 { 2059 {
1967 get_videofile(VIDEO_PREV, videofile, sizeof(videofile)); 2060 get_videofile_says = get_videofile(VIDEO_PREV, videofile,
2061 sizeof(videofile));
1968 /* if there is no previous file, play the same videofile */ 2062 /* if there is no previous file, play the same videofile */
1969 break; 2063 break;
1970 } 2064 }
@@ -1974,7 +2068,7 @@ enum plugin_status plugin_start(const void* parameter)
1974 break; 2068 break;
1975 } 2069 }
1976 } 2070 }
1977 } 2071 } /* while */
1978 } 2072 }
1979 2073
1980#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) 2074#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV)
@@ -1984,5 +2078,10 @@ enum plugin_status plugin_start(const void* parameter)
1984 stream_exit(); 2078 stream_exit();
1985 2079
1986 rb->talk_disable(false); 2080 rb->talk_disable(false);
2081
2082 /* Actually handle delayed processing of system events of interest
2083 * that were captured in other button loops */
2084 mpeg_sysevent_handle();
2085
1987 return status; 2086 return status;
1988} 2087}