Index: apps/plugins/mpegplayer/mpegplayer.c =================================================================== --- apps/plugins/mpegplayer/mpegplayer.c (revision 22520) +++ apps/plugins/mpegplayer/mpegplayer.c (working copy) @@ -330,6 +330,12 @@ #define MIN_FF_REWIND_STEP (TS_SECOND/2) #define WVS_MIN_UPDATE_INTERVAL (HZ/2) +#define VIDEO_PREV 0 +#define VIDEO_NEXT 1 +#define VIDEO_STOP 2 +#define VIDEO_SAME 3 +#define VIDEO_CONT 4 + /* WVS status - same order as icon array */ enum wvs_status_enum { @@ -1444,6 +1450,92 @@ stream_seek(time, SEEK_SET); } +/* has this file the extension .mpg ? */ +bool is_videofile (char* file) +{ + const char* mpg = ".mpg"; + char *extension = rb->strrchr(file, '.'); + if ( extension && !rb->strcasecmp(extension, mpg )) return true; + + return false; +} + +/* deliver the (lexically) next video file in the current directory + (or \0 if there is none) */ +static void get_next_video( char* videofile, char* nextfile ) +{ + DIR* dir; + struct dirent *entry; + char dirname[MAX_PATH]; + char* ptr; + int dirlen; + + ptr = rb->strrchr(videofile, '/') + 1; + dirlen = (ptr - videofile); + rb->strlcpy(dirname, videofile, dirlen+1); + + dir = rb->opendir(dirname); + nextfile[0] = '\0'; + if (dir) + { + while(0 != (entry = rb->readdir(dir))) { + if( is_videofile( entry->d_name ) && + rb->strcmp(entry->d_name, ptr) > 0 ) { + if( nextfile[0] == '\0' || + rb->strcmp(entry->d_name, nextfile) < 0 ) { + rb->strcpy(nextfile, entry->d_name); + } + } + } + rb->closedir(dir); + } + if( nextfile[0] != '\0' ) { + ptr = dirname + dirlen; + rb->strcpy( ptr, nextfile ); + rb->strcpy( nextfile, dirname ); + } + + return; +} + +/* deliver the (lexically) previous video file in the current directory + (or \0 if there is none) */ +static void get_prev_video( char* videofile, char* prevfile ) +{ + DIR* dir; + struct dirent *entry; + char dirname[MAX_PATH]; + char* ptr; + int dirlen; + + ptr = rb->strrchr(videofile, '/') + 1; + dirlen = (ptr - videofile); + rb->strlcpy(dirname, videofile, dirlen+1); + + dir = rb->opendir(dirname); + prevfile[0] = '\0'; + if (dir) + { + while(0 != (entry = rb->readdir(dir))) { + if( is_videofile(entry->d_name) && + ( rb->strcmp(entry->d_name, ptr) < 0 ) ) { + if( prevfile[0] == '\0' || + rb->strcmp(entry->d_name, prevfile) > 0 ) { + rb->strcpy(prevfile, entry->d_name); + } + } + } + rb->closedir(dir); + } + if( prevfile[0] != '\0' ) { + ptr = dirname + dirlen; + rb->strcpy( ptr, prevfile ); + rb->strcpy( prevfile, dirname ); + } + + return; +} + #ifdef HAVE_HEADPHONE_DETECTION /* Handle SYS_PHONE_PLUGGED/UNPLUGGED */ static void wvs_handle_phone_plug(bool inserted) @@ -1479,8 +1571,14 @@ } #endif -static void button_loop(void) +static int button_loop(void) { + int button = MPEG_STOP; + int old_button; + int next_action; + + next_action = ( settings.play_mode == 0 ) ? VIDEO_STOP : VIDEO_CONT; + rb->lcd_setfont(FONT_SYSFIXED); rb->lcd_clear_display(); rb->lcd_update(); @@ -1494,14 +1592,12 @@ /* 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 */ while (stream_status() != STREAM_STOPPED) { - int button; - mpeg_menu_sysevent_clear(); button = rb->button_get_w_tmo(WVS_MIN_UPDATE_INTERVAL); @@ -1573,12 +1669,16 @@ result = mpeg_menu(); + next_action = ( settings.play_mode == 0 ) ? + VIDEO_STOP : VIDEO_CONT; + /* The menu can change the font, so restore */ rb->lcd_setfont(FONT_SYSFIXED); switch (result) { case MPEG_MENU_QUIT: + next_action = VIDEO_STOP; wvs_stop(); break; @@ -1607,6 +1707,7 @@ #endif case ACTION_STD_CANCEL: { + next_action = VIDEO_STOP; wvs_stop(); break; } /* MPEG_STOP: */ @@ -1640,7 +1741,37 @@ case MPEG_RC_FF: #endif { - wvs_seek(button); + /* if button has been released: skip to next/previous file */ + old_button = button; + 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: */ @@ -1672,15 +1803,20 @@ #endif rb->lcd_setfont(FONT_UI); + + return next_action; } enum plugin_status plugin_start(const void* parameter) { int status = PLUGIN_ERROR; /* assume failure */ - int result; + int result = VIDEO_STOP; 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"); @@ -1702,55 +1838,91 @@ rb->lcd_clear_display(); rb->lcd_update(); - if (stream_init() < STREAM_OK) { - DEBUGF("Could not initialize streams\n"); - } else { - rb->splash(0, "Loading..."); - init_settings((char*)parameter); + rb->strcpy(videofile, (char*) parameter); - err = stream_open((char *)parameter); + /* loop */ + while( videofile[0] != '\0' ) { - if (err >= STREAM_OK) { - /* start menu */ - rb->lcd_clear_display(); - rb->lcd_update(); - result = mpeg_start_menu(stream_get_duration()); + if (stream_init() < STREAM_OK) { + DEBUGF("Could not initialize streams\n"); + } else { + init_settings(videofile); - if (result != MPEG_START_QUIT) { - /* Enter button loop and process UI */ - button_loop(); - } + err = stream_open(videofile); - stream_close(); + if (err >= STREAM_OK) { + /* start menu */ + rb->lcd_clear_display(); + rb->lcd_update(); + result = mpeg_start_menu(stream_get_duration()); - rb->lcd_clear_display(); - rb->lcd_update(); + if (result != MPEG_START_QUIT) { + /* Enter button loop and process UI */ + result = button_loop(); + } else { + result = VIDEO_STOP; + } - save_settings(); /* Save settings (if they have changed) */ - status = PLUGIN_OK; + stream_close(); - mpeg_menu_sysevent_handle(); - } else { - DEBUGF("Could not open %s\n", (char*)parameter); - switch (err) - { - case STREAM_UNSUPPORTED: - errstring = "Unsupported format"; - break; - default: - errstring = "Error opening file: %d"; + rb->lcd_clear_display(); + rb->lcd_update(); + + save_settings(); /* Save settings (if they have changed) */ + status = PLUGIN_OK; + + mpeg_menu_sysevent_handle(); + } else { + DEBUGF("Could not open %s\n", (char*)parameter); + switch (err) + { + case STREAM_UNSUPPORTED: + errstring = "Unsupported format"; + break; + default: + errstring = "Error opening file: %d"; + } + + rb->splashf(HZ*2, errstring, err); } + } - rb->splashf(HZ*2, errstring, err); + stream_exit(); + + /* return value of button_loop says, what's next */ + switch (result) + { + case VIDEO_CONT: + case VIDEO_NEXT: + { + get_next_video( videofile, nextfile ); + rb->strcpy( videofile, nextfile ); + break; + } + case VIDEO_PREV: + { + get_prev_video( 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; + } + case VIDEO_SAME: + { + /* let the videofile unchanged */ + break; + } } } - + #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) rb->lcd_set_mode(LCD_MODE_RGB565); #endif - stream_exit(); - rb->talk_disable(false); return status; } Index: apps/plugins/mpegplayer/mpeg_settings.c =================================================================== --- apps/plugins/mpegplayer/mpeg_settings.c (revision 22520) +++ apps/plugins/mpegplayer/mpeg_settings.c (working copy) @@ -234,6 +234,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}, @@ -245,6 +246,11 @@ { "Yes", -1 }, }; +static const struct opt_items dirfile[2] = { + { "File", -1 }, + { "Directory", -1 }, +}; + static const struct opt_items enabledisable[2] = { { "Disable", -1 }, { "Enable", -1 }, @@ -1125,7 +1131,7 @@ MENUITEM_STRINGLIST(menu, "Settings", mpeg_menu_sysevent_callback, "Display Options", "Audio Options", - "Resume Options", clear_str); + "Resume Options", clear_str, "Play Mode"); rb->button_clear_queue(); @@ -1157,6 +1163,11 @@ clear_resume_count(); break; + case MPEG_SETTING_PLAY_MODE: + mpeg_set_option("Play mode", &settings.play_mode, + INT, dirfile, 2, NULL); + break; + default: menu_quit = true; break; @@ -1173,6 +1184,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 = -1; #ifdef HAVE_BACKLIGHT_BRIGHTNESS @@ -1234,6 +1246,8 @@ settings.limitfps); configfile_update_entry(SETTINGS_FILENAME, "Skip frames", settings.skipframes); + configfile_update_entry(SETTINGS_FILENAME, "Play mode", + settings.play_mode); configfile_update_entry(SETTINGS_FILENAME, "Resume options", settings.resume_options); Index: apps/plugins/mpegplayer/mpeg_settings.h =================================================================== --- apps/plugins/mpegplayer/mpeg_settings.h (revision 22520) +++ apps/plugins/mpegplayer/mpeg_settings.h (working copy) @@ -62,6 +62,7 @@ MPEG_SETTING_AUDIO_SETTINGS, MPEG_SETTING_ENABLE_START_MENU, MPEG_SETTING_CLEAR_RESUMES, + MPEG_SETTING_PLAY_MODE, }; enum mpeg_menu_id @@ -78,6 +79,7 @@ int resume_options; /* type of resume action at start */ int resume_count; /* total # of resumes in config file */ int resume_time; /* resume time for current mpeg (in half minutes) */ + int play_mode; /* play single file or all files in directory */ char resume_filename[MAX_PATH]; /* filename of current mpeg */ #if MPEG_OPTION_DITHERING_ENABLED int displayoptions;