From 043ebca136cfb38fc9ff1610540100729b4c96db Mon Sep 17 00:00:00 2001 From: Teruaki Kawashima Date: Fri, 26 Nov 2010 12:32:00 +0000 Subject: FS#8607: MPEG video playlist Add mode to play multiple mpeg files in the same directory in the order the file browser shows. In this mode, Mpegplayer exits after finishing the last .mpg file. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28667 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/mpegplayer/mpeg_parser.c | 1 + apps/plugins/mpegplayer/mpeg_settings.c | 14 ++- apps/plugins/mpegplayer/mpeg_settings.h | 2 + apps/plugins/mpegplayer/mpegplayer.c | 190 ++++++++++++++++++++++++++------ apps/plugins/mpegplayer/video_thread.c | 6 + 5 files changed, 181 insertions(+), 32 deletions(-) diff --git a/apps/plugins/mpegplayer/mpeg_parser.c b/apps/plugins/mpegplayer/mpeg_parser.c index 6883916149..5821bd57ab 100644 --- a/apps/plugins/mpegplayer/mpeg_parser.c +++ b/apps/plugins/mpegplayer/mpeg_parser.c @@ -1213,6 +1213,7 @@ int parser_init_stream(void) void parser_close_stream(void) { + str_send_msg(&video_str, STREAM_CLOSE, 0); stream_remove_streams(); parser_init_state(); } diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c index 2a5c4be617..94a375d866 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.c +++ b/apps/plugins/mpegplayer/mpeg_settings.c @@ -275,6 +275,7 @@ static struct configdata config[] = {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}, @@ -286,6 +287,11 @@ static const struct opt_items noyes[2] = { { "Yes", -1 }, }; +static const struct opt_items singleall[2] = { + { "Single", -1 }, + { "All", -1 }, +}; + static const struct opt_items enabledisable[2] = { { "Disable", -1 }, { "Enable", -1 }, @@ -1191,7 +1197,7 @@ static void mpeg_settings(void) 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(); @@ -1219,6 +1225,11 @@ static void mpeg_settings(void) 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; @@ -1239,6 +1250,7 @@ void init_settings(const char* filename) 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 diff --git a/apps/plugins/mpegplayer/mpeg_settings.h b/apps/plugins/mpegplayer/mpeg_settings.h index 6c8b69a4ce..0910116615 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.h +++ b/apps/plugins/mpegplayer/mpeg_settings.h @@ -62,6 +62,7 @@ enum mpeg_setting_id 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 @@ struct mpeg_settings { #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; diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index 513c2f0863..2314d96889 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c @@ -372,6 +372,13 @@ CONFIG_KEYPAD == SANSA_M200_PAD #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 { @@ -1452,7 +1459,7 @@ static void osd_stop(void) 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(); @@ -1496,6 +1503,53 @@ static void osd_seek(int btn) 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 0 if there is none. */ +static bool get_videofile(int direction, char* videofile, size_t bufsize) +{ + struct tree_context *tree = rb->tree_get_context(); + struct entry *dircache = tree->dircache; + int i, step, end, found = 0; + char *videoname = rb->strrchr(videofile, '/') + 1; + size_t rest = bufsize - (videoname - videofile) - 1; + + if (direction == VIDEO_NEXT) { + i = 0; + step = 1; + end = tree->filesindir; + } else { + i = tree->filesindir-1; + step = -1; + end = -1; + } + for (; i != end; i += step) + { + const char* name = dircache[i].name; + if (!rb->strcmp(name, videoname)) { + found = 1; + continue; + } + if (found && rb->strlen(name) <= rest && + !(dircache[i].attr & ATTR_DIRECTORY) && is_videofile(name)) + { + rb->strcpy(videoname, name); + return true; + } + } + + return false; +} + #ifdef HAVE_HEADPHONE_DETECTION /* Handle SYS_PHONE_PLUGGED/UNPLUGGED */ static void osd_handle_phone_plug(bool inserted) @@ -1531,8 +1585,10 @@ static void osd_handle_phone_plug(bool inserted) } #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); @@ -1550,7 +1606,7 @@ static void button_loop(void) /* 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 */ @@ -1629,6 +1685,8 @@ static void button_loop(void) 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 @@ -1641,6 +1699,7 @@ static void button_loop(void) switch (result) { case MPEG_MENU_QUIT: + next_action = VIDEO_STOP; osd_stop(); break; @@ -1679,6 +1738,7 @@ static void button_loop(void) #endif case ACTION_STD_CANCEL: { + next_action = VIDEO_STOP; osd_stop(); break; } /* MPEG_STOP: */ @@ -1718,7 +1778,40 @@ static void button_loop(void) 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: */ @@ -1750,13 +1843,18 @@ static void button_loop(void) #endif rb->lcd_setfont(FONT_UI); + + return next_action; } enum plugin_status plugin_start(const void* parameter) { + static char videofile[MAX_PATH]; + int status = PLUGIN_ERROR; /* assume failure */ int result; int err; + bool quit = false; const char *errstring; if (parameter == NULL) { @@ -1777,46 +1875,76 @@ enum plugin_status plugin_start(const void* parameter) 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); + while (!quit) + { + int next_action = VIDEO_STOP; - err = stream_open((char *)parameter); + init_settings(videofile); + err = stream_open(videofile); - if (err >= STREAM_OK) { - /* start menu */ - rb->lcd_clear_display(); - rb->lcd_update(); - result = mpeg_start_menu(stream_get_duration()); + if (err >= STREAM_OK) { + /* start menu */ + rb->lcd_clear_display(); + rb->lcd_update(); + result = mpeg_start_menu(stream_get_duration()); - if (result != MPEG_START_QUIT) { - /* Enter button loop and process UI */ - button_loop(); - } + if (result != MPEG_START_QUIT) { + /* Enter button loop and process UI */ + next_action = button_loop(); + } - stream_close(); + stream_close(); - rb->lcd_clear_display(); - rb->lcd_update(); + rb->lcd_clear_display(); + rb->lcd_update(); - save_settings(); - status = PLUGIN_OK; + save_settings(); + status = PLUGIN_OK; - mpeg_menu_sysevent_handle(); - } else { - DEBUGF("Could not open %s\n", (char*)parameter); - switch (err) + mpeg_menu_sysevent_handle(); + } else { + DEBUGF("Could not open %s\n", videofile); + switch (err) + { + case STREAM_UNSUPPORTED: + errstring = "Unsupported format"; + break; + default: + errstring = "Error opening file: %d"; + } + + rb->splashf(HZ*2, errstring, err); + status = PLUGIN_ERROR; + } + + /* return value of button_loop says, what's next */ + switch (next_action) + { + case VIDEO_NEXT: { - case STREAM_UNSUPPORTED: - errstring = "Unsupported format"; + if (!get_videofile(VIDEO_NEXT, videofile, sizeof(videofile))) { + /* quit after finished the last videofile */ + quit = true; + } break; - default: - errstring = "Error opening file: %d"; + } + case VIDEO_PREV: + { + get_videofile(VIDEO_PREV, videofile, sizeof(videofile)); + /* if there is no previous file, play the same videofile */ + break; + } + case VIDEO_STOP: + { + quit = true; + break; + } } - - rb->splashf(HZ*2, errstring, err); } } diff --git a/apps/plugins/mpegplayer/video_thread.c b/apps/plugins/mpegplayer/video_thread.c index 8feacbdef2..4ccdc8b844 100644 --- a/apps/plugins/mpegplayer/video_thread.c +++ b/apps/plugins/mpegplayer/video_thread.c @@ -503,6 +503,12 @@ static void video_thread_msg(struct video_thread_data *td) 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; -- cgit v1.2.3