Index: apps/plugins/mpegplayer/mpegplayer.c =================================================================== --- apps/plugins/mpegplayer/mpegplayer.c (revision 24224) +++ apps/plugins/mpegplayer/mpegplayer.c (working copy) @@ -344,6 +344,13 @@ #define MIN_FF_REWIND_STEP (TS_SECOND/2) #define WVS_MIN_UPDATE_INTERVAL (HZ/2) +enum video_action +{ + VIDEO_STOP = 0, + VIDEO_PREV, + VIDEO_NEXT, +}; + /* WVS status - same order as icon array */ enum wvs_status_enum { @@ -1448,6 +1455,50 @@ stream_seek(time, SEEK_SET); } +/* has this file the extension .mpg ? */ +static bool is_videofile (const char* file) +{ + const char* ext = rb->strrchr(file, '.'); + if (ext && !rb->strcasecmp(ext, ".mpg")) + return true; + + return false; +} + +/* deliver the (lexically) next/previous video file in the current directory + (or \0 if there is none) */ +static void get_next_video(int direction, char* videofile, char* nextfile) +{ + DIR* dir; + struct dirent *entry; + char *videoname, *nextname; + int dirlen; + + videoname = rb->strrchr(videofile, '/') + 1; + dirlen = (videoname - videofile); + rb->strlcpy(nextfile, videofile, dirlen+1); + nextname = nextfile + dirlen; + + dir = rb->opendir(nextfile); + if (dir) { + while(NULL != (entry = rb->readdir(dir))) { + const char* name = entry->d_name; + if(!(entry->attribute & ATTR_DIRECTORY) && is_videofile(name) && + rb->strcmp(name, videoname) * direction > 0 ) { + if(nextname[0] == '\0' || + rb->strcmp(name, nextname) * direction < 0 ) { + rb->strcpy(nextname, name); + } + } + } + rb->closedir(dir); + } + if (nextname[0] == '\0') + nextfile[0] = '\0'; + + return; +} + #ifdef HAVE_HEADPHONE_DETECTION /* Handle SYS_PHONE_PLUGGED/UNPLUGGED */ static void wvs_handle_phone_plug(bool inserted) @@ -1483,8 +1534,10 @@ } #endif -static void button_loop(void) +static int button_loop(void) { + int next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT; + rb->lcd_setfont(FONT_SYSFIXED); rb->lcd_clear_display(); rb->lcd_update(); @@ -1498,7 +1551,7 @@ /* Start playback at the specified starting time */ if (wvs_play(settings.resume_time) < STREAM_OK) { rb->splash(HZ*2, "Playback failed"); - return; + return VIDEO_STOP; } /* Gently poll the video player for EOS and handle UI */ @@ -1577,6 +1630,8 @@ result = mpeg_menu(); + next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT; + /* The menu can change the font, so restore */ rb->lcd_setfont(FONT_SYSFIXED); #ifdef HAVE_LCD_COLOR @@ -1587,9 +1642,20 @@ switch (result) { case MPEG_MENU_QUIT: + next_action = VIDEO_STOP; wvs_stop(); break; + case MPEG_MENU_PREV: + next_action = VIDEO_PREV; + wvs_stop(); + break; + + case MPEG_MENU_NEXT: + next_action = VIDEO_NEXT; + wvs_stop(); + break; + default: #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) rb->lcd_set_mode(LCD_MODE_YUV); @@ -1615,6 +1681,7 @@ #endif case ACTION_STD_CANCEL: { + next_action = VIDEO_STOP; wvs_stop(); break; } /* MPEG_STOP: */ @@ -1648,7 +1715,40 @@ case MPEG_RC_FF: #endif { - wvs_seek(button); + 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(WVS_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 */ + wvs_stop(); + if ( stream_get_resume_time() > 3*TS_SECOND ) { + wvs_play(0); + wvs_show(WVS_SHOW); + } else { + next_action = VIDEO_PREV; + } + break; + } + case MPEG_FF | BUTTON_REL: + { + wvs_stop(); + next_action = VIDEO_NEXT; + break; + } + default: + { + button = old_button; + wvs_seek(button); + break; + } + } break; } /* MPEG_RW: MPEG_FF: */ @@ -1680,6 +1780,8 @@ #endif rb->lcd_setfont(FONT_UI); + + return next_action; } enum plugin_status plugin_start(const void* parameter) @@ -1689,6 +1791,9 @@ int err; const char *errstring; + char nextfile[MAX_PATH]; + char videofile[MAX_PATH]; + if (parameter == NULL) { /* No file = GTFO */ rb->splash(HZ*2, "No File"); @@ -1710,13 +1815,17 @@ rb->lcd_clear_display(); rb->lcd_update(); + rb->strcpy(videofile, (const char*) parameter); + if (stream_init() < STREAM_OK) { DEBUGF("Could not initialize streams\n"); - } else { - rb->splash(0, "Loading..."); - init_settings((char*)parameter); + } + /* loop */ + else while (videofile[0] != '\0') { + int next_action = VIDEO_STOP; - err = stream_open((char *)parameter); + init_settings(videofile); + err = stream_open(videofile); if (err >= STREAM_OK) { /* start menu */ @@ -1726,7 +1835,7 @@ if (result != MPEG_START_QUIT) { /* Enter button loop and process UI */ - button_loop(); + next_action = button_loop(); } stream_close(); @@ -1739,7 +1848,7 @@ mpeg_menu_sysevent_handle(); } else { - DEBUGF("Could not open %s\n", (char*)parameter); + DEBUGF("Could not open %s\n", videofile); switch (err) { case STREAM_UNSUPPORTED: @@ -1751,6 +1860,30 @@ rb->splashf(HZ*2, errstring, err); } + + /* return value of button_loop says, what's next */ + switch (next_action) + { + case VIDEO_NEXT: + { + get_next_video(1, videofile, nextfile); + rb->strcpy(videofile, nextfile); + break; + } + case VIDEO_PREV: + { + get_next_video(-1, videofile, nextfile); + /* if there is no previous file, play the same videofile */ + if (nextfile[0] != 0) + rb->strcpy(videofile, nextfile); + break; + } + case VIDEO_STOP: + { + videofile[0] = '\0'; + break; + } + } } #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) Index: apps/plugins/mpegplayer/mpeg_settings.c =================================================================== --- apps/plugins/mpegplayer/mpeg_settings.c (revision 24224) +++ apps/plugins/mpegplayer/mpeg_settings.c (working copy) @@ -247,6 +247,7 @@ {TYPE_INT, 0, 2, { .int_p = &settings.crossfeed }, "Crossfeed", NULL}, {TYPE_INT, 0, 2, { .int_p = &settings.equalizer }, "Equalizer", NULL}, {TYPE_INT, 0, 2, { .int_p = &settings.dithering }, "Dithering", NULL}, + {TYPE_INT, 0, 2, { .int_p = &settings.play_mode }, "Play mode", NULL}, #ifdef HAVE_BACKLIGHT_BRIGHTNESS {TYPE_INT, -1, INT_MAX, { .int_p = &settings.backlight_brightness }, "Backlight brightness", NULL}, @@ -258,6 +259,11 @@ { "Yes", -1 }, }; +static const struct opt_items singleall[2] = { + { "Single", -1 }, + { "All", -1 }, +}; + static const struct opt_items enabledisable[2] = { { "Disable", -1 }, { "Enable", -1 }, @@ -935,7 +941,9 @@ int result; MENUITEM_STRINGLIST(menu, "Mpegplayer Menu", mpeg_menu_sysevent_callback, - "Settings", "Resume playback", "Quit mpegplayer"); + "Settings", "Resume playback", + "Previous video", "Next video", + "Quit mpegplayer"); rb->button_clear_queue(); @@ -950,11 +958,9 @@ break; case MPEG_MENU_RESUME: - break; - + case MPEG_MENU_PREV: + case MPEG_MENU_NEXT: case MPEG_MENU_QUIT: - break; - default: break; } @@ -1134,7 +1140,7 @@ MENUITEM_STRINGLIST(menu, "Settings", mpeg_menu_sysevent_callback, "Display Options", "Audio Options", - "Resume Options", clear_str); + "Resume Options", "Play Mode", clear_str); rb->button_clear_queue(); @@ -1162,6 +1168,11 @@ resume_options(); break; + case MPEG_SETTING_PLAY_MODE: + mpeg_set_option("Play mode", &settings.play_mode, + INT, singleall, 2, NULL); + break; + case MPEG_SETTING_CLEAR_RESUMES: clear_resume_count(); break; @@ -1182,6 +1193,7 @@ settings.showfps = 0; /* Do not show FPS */ settings.limitfps = 1; /* Limit FPS */ settings.skipframes = 1; /* Skip frames */ + settings.play_mode = 0; /* Play single video */ settings.resume_options = MPEG_RESUME_MENU_ALWAYS; /* Enable start menu */ settings.resume_count = 0; #ifdef HAVE_BACKLIGHT_BRIGHTNESS Index: apps/plugins/mpegplayer/mpeg_settings.h =================================================================== --- apps/plugins/mpegplayer/mpeg_settings.h (revision 24224) +++ apps/plugins/mpegplayer/mpeg_settings.h (working copy) @@ -61,6 +61,7 @@ MPEG_SETTING_DISPLAY_SETTINGS, MPEG_SETTING_AUDIO_SETTINGS, MPEG_SETTING_ENABLE_START_MENU, + MPEG_SETTING_PLAY_MODE, MPEG_SETTING_CLEAR_RESUMES, }; @@ -68,6 +69,8 @@ { MPEG_MENU_SETTINGS, MPEG_MENU_RESUME, + MPEG_MENU_PREV, + MPEG_MENU_NEXT, MPEG_MENU_QUIT, }; @@ -82,6 +85,7 @@ #if MPEG_OPTION_DITHERING_ENABLED int displayoptions; #endif + int play_mode; /* play single file or all files in directory */ /* Audio options - simple on/off specification */ int tone_controls; int channel_modes; Index: apps/plugins/mpegplayer/mpeg_parser.c =================================================================== --- apps/plugins/mpegplayer/mpeg_parser.c (revision 24224) +++ apps/plugins/mpegplayer/mpeg_parser.c (working copy) @@ -1201,6 +1201,7 @@ void parser_close_stream(void) { + str_send_msg(&video_str, STREAM_CLOSE, 0); stream_remove_streams(); parser_init_state(); } Index: apps/plugins/mpegplayer/video_thread.c =================================================================== --- apps/plugins/mpegplayer/video_thread.c (revision 24224) +++ apps/plugins/mpegplayer/video_thread.c (working copy) @@ -503,6 +503,12 @@ reply = true; break; + case STREAM_CLOSE: + vo_cleanup(); + mpeg2_close(td->mpeg2dec); + reply = true; + break; + case VIDEO_DISPLAY_IS_VISIBLE: reply = vo_is_visible(); break;