Index: apps/plugins/mpegplayer/mpegplayer.c =================================================================== --- apps/plugins/mpegplayer/mpegplayer.c (リビジョン 28430) +++ apps/plugins/mpegplayer/mpegplayer.c (作業コピー) @@ -363,6 +363,13 @@ #define MIN_FF_REWIND_STEP (TS_SECOND/2) #define OSD_MIN_UPDATE_INTERVAL (HZ/2) +enum video_action +{ + VIDEO_STOP = 0, + VIDEO_PREV, + VIDEO_NEXT, +}; + /* OSD status - same order as icon array */ enum osd_status_enum { @@ -1443,7 +1450,7 @@ osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); osd_set_status(OSD_STATUS_STOPPED | OSD_NODRAW); - osd_show(OSD_HIDE | OSD_NODRAW); + osd_show(OSD_HIDE); stream_stop(); @@ -1487,6 +1494,47 @@ 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 next/previous video file in the current directory. + returns its index or -1 if there is none. */ +static int get_videofile(int direction, int current, char* videofile) +{ + struct tree_context *tree = rb->tree_get_context(); + struct entry *dircache = tree->dircache; + int i = current, step = (direction >= 0? 1: -1); + char *videoname = rb->strrchr(videofile, '/') + 1; + + current = -1; + for (; i >= 0 && i < tree->filesindir; i += step) + { + const char* name = dircache[i].name; + if (!(dircache[i].attr & ATTR_DIRECTORY) && is_videofile(name)) + { + if (!rb->strcmp(name, videoname)) { + if (direction == 0) { + current = i; + break; + } + } else if (direction != 0) { + rb->strcpy(videoname, name); + current = i; + break; + } + } + } + + return current; +} + #ifdef HAVE_HEADPHONE_DETECTION /* Handle SYS_PHONE_PLUGGED/UNPLUGGED */ static void osd_handle_phone_plug(bool inserted) @@ -1522,8 +1570,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); #ifdef HAVE_LCD_COLOR rb->lcd_set_foreground(LCD_WHITE); @@ -1541,7 +1591,7 @@ /* Start playback at the specified starting time */ if (osd_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 */ @@ -1620,6 +1670,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 @@ -1632,6 +1684,7 @@ switch (result) { case MPEG_MENU_QUIT: + next_action = VIDEO_STOP; osd_stop(); break; @@ -1670,6 +1723,7 @@ #endif case ACTION_STD_CANCEL: { + next_action = VIDEO_STOP; osd_stop(); break; } /* MPEG_STOP: */ @@ -1709,7 +1763,40 @@ case MPEG_RC_FF: #endif { - osd_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(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: + { + osd_stop(); + next_action = VIDEO_NEXT; + break; + } + default: + { + button = old_button; + osd_seek(button); + break; + } + } break; } /* MPEG_RW: MPEG_FF: */ @@ -1741,10 +1828,15 @@ #endif rb->lcd_setfont(FONT_UI); + + return next_action; } enum plugin_status plugin_start(const void* parameter) { + static char videofile[MAX_PATH]; + int current; + int status = PLUGIN_ERROR; /* assume failure */ int result; int err; @@ -1768,13 +1860,17 @@ rb->lcd_clear_display(); rb->lcd_update(); + rb->strcpy(videofile, (const char*) parameter); + current = get_videofile(0, 0, videofile); + if (stream_init() < STREAM_OK) { DEBUGF("Could not initialize streams\n"); - } else { - rb->splash(0, "Loading..."); - init_settings((char*)parameter); + } + else while (current >= 0) { + int next_action = VIDEO_STOP; - err = stream_open((char *)parameter); + init_settings(videofile); + err = stream_open(videofile); if (err >= STREAM_OK) { /* start menu */ @@ -1784,7 +1880,7 @@ if (result != MPEG_START_QUIT) { /* Enter button loop and process UI */ - button_loop(); + next_action = button_loop(); } stream_close(); @@ -1797,7 +1893,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: @@ -1808,7 +1904,32 @@ } rb->splashf(HZ*2, errstring, err); + status = PLUGIN_ERROR; } + + /* return value of button_loop says, what's next */ + switch (next_action) + { + case VIDEO_NEXT: + { + current = get_videofile(1, current, videofile); + break; + } + case VIDEO_PREV: + { + int prev = get_videofile(-1, current, videofile); + if (prev >= 0) { + current = prev; + } + /* if there is no previous file, play the same videofile */ + break; + } + case VIDEO_STOP: + { + current = -1; + 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 (リビジョン 28430) +++ apps/plugins/mpegplayer/mpeg_settings.c (作業コピー) @@ -265,6 +265,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}, @@ -276,6 +277,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 }, @@ -1181,7 +1187,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(); @@ -1209,6 +1215,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; @@ -1229,6 +1240,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 (リビジョン 28430) +++ apps/plugins/mpegplayer/mpeg_settings.h (作業コピー) @@ -62,6 +62,7 @@ MPEG_SETTING_DISPLAY_SETTINGS, MPEG_SETTING_AUDIO_SETTINGS, MPEG_SETTING_ENABLE_START_MENU, + MPEG_SETTING_PLAY_MODE, MPEG_SETTING_CLEAR_RESUMES, }; @@ -83,6 +84,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 (リビジョン 28430) +++ apps/plugins/mpegplayer/mpeg_parser.c (作業コピー) @@ -1213,6 +1213,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 (リビジョン 28430) +++ apps/plugins/mpegplayer/video_thread.c (作業コピー) @@ -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;