summaryrefslogtreecommitdiff
path: root/apps/plugins/mpegplayer
diff options
context:
space:
mode:
authorTeruaki Kawashima <teru@rockbox.org>2010-11-26 12:32:00 +0000
committerTeruaki Kawashima <teru@rockbox.org>2010-11-26 12:32:00 +0000
commit043ebca136cfb38fc9ff1610540100729b4c96db (patch)
tree3f12b7aced03d439223ee14a65e1cf7e45c44b1b /apps/plugins/mpegplayer
parentb397fe5ae373e3b62fee9150ab786c344c2084cd (diff)
downloadrockbox-043ebca136cfb38fc9ff1610540100729b4c96db.tar.gz
rockbox-043ebca136cfb38fc9ff1610540100729b4c96db.zip
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
Diffstat (limited to 'apps/plugins/mpegplayer')
-rw-r--r--apps/plugins/mpegplayer/mpeg_parser.c1
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.c14
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.h2
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c190
-rw-r--r--apps/plugins/mpegplayer/video_thread.c6
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)
1213 1213
1214void parser_close_stream(void) 1214void parser_close_stream(void)
1215{ 1215{
1216 str_send_msg(&video_str, STREAM_CLOSE, 0);
1216 stream_remove_streams(); 1217 stream_remove_streams();
1217 parser_init_state(); 1218 parser_init_state();
1218} 1219}
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[] =
275 {TYPE_INT, 0, 2, { .int_p = &settings.crossfeed }, "Crossfeed", NULL}, 275 {TYPE_INT, 0, 2, { .int_p = &settings.crossfeed }, "Crossfeed", NULL},
276 {TYPE_INT, 0, 2, { .int_p = &settings.equalizer }, "Equalizer", NULL}, 276 {TYPE_INT, 0, 2, { .int_p = &settings.equalizer }, "Equalizer", NULL},
277 {TYPE_INT, 0, 2, { .int_p = &settings.dithering }, "Dithering", NULL}, 277 {TYPE_INT, 0, 2, { .int_p = &settings.dithering }, "Dithering", NULL},
278 {TYPE_INT, 0, 2, { .int_p = &settings.play_mode }, "Play mode", NULL},
278#ifdef HAVE_BACKLIGHT_BRIGHTNESS 279#ifdef HAVE_BACKLIGHT_BRIGHTNESS
279 {TYPE_INT, -1, INT_MAX, { .int_p = &settings.backlight_brightness }, 280 {TYPE_INT, -1, INT_MAX, { .int_p = &settings.backlight_brightness },
280 "Backlight brightness", NULL}, 281 "Backlight brightness", NULL},
@@ -286,6 +287,11 @@ static const struct opt_items noyes[2] = {
286 { "Yes", -1 }, 287 { "Yes", -1 },
287}; 288};
288 289
290static const struct opt_items singleall[2] = {
291 { "Single", -1 },
292 { "All", -1 },
293};
294
289static const struct opt_items enabledisable[2] = { 295static const struct opt_items enabledisable[2] = {
290 { "Disable", -1 }, 296 { "Disable", -1 },
291 { "Enable", -1 }, 297 { "Enable", -1 },
@@ -1191,7 +1197,7 @@ static void mpeg_settings(void)
1191 1197
1192 MENUITEM_STRINGLIST(menu, "Settings", mpeg_menu_sysevent_callback, 1198 MENUITEM_STRINGLIST(menu, "Settings", mpeg_menu_sysevent_callback,
1193 "Display Options", "Audio Options", 1199 "Display Options", "Audio Options",
1194 "Resume Options", clear_str); 1200 "Resume Options", "Play Mode", clear_str);
1195 1201
1196 rb->button_clear_queue(); 1202 rb->button_clear_queue();
1197 1203
@@ -1219,6 +1225,11 @@ static void mpeg_settings(void)
1219 resume_options(); 1225 resume_options();
1220 break; 1226 break;
1221 1227
1228 case MPEG_SETTING_PLAY_MODE:
1229 mpeg_set_option("Play mode", &settings.play_mode,
1230 INT, singleall, 2, NULL);
1231 break;
1232
1222 case MPEG_SETTING_CLEAR_RESUMES: 1233 case MPEG_SETTING_CLEAR_RESUMES:
1223 clear_resume_count(); 1234 clear_resume_count();
1224 break; 1235 break;
@@ -1239,6 +1250,7 @@ void init_settings(const char* filename)
1239 settings.showfps = 0; /* Do not show FPS */ 1250 settings.showfps = 0; /* Do not show FPS */
1240 settings.limitfps = 1; /* Limit FPS */ 1251 settings.limitfps = 1; /* Limit FPS */
1241 settings.skipframes = 1; /* Skip frames */ 1252 settings.skipframes = 1; /* Skip frames */
1253 settings.play_mode = 0; /* Play single video */
1242 settings.resume_options = MPEG_RESUME_MENU_ALWAYS; /* Enable start menu */ 1254 settings.resume_options = MPEG_RESUME_MENU_ALWAYS; /* Enable start menu */
1243 settings.resume_count = 0; 1255 settings.resume_count = 0;
1244#ifdef HAVE_BACKLIGHT_BRIGHTNESS 1256#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
62 MPEG_SETTING_DISPLAY_SETTINGS, 62 MPEG_SETTING_DISPLAY_SETTINGS,
63 MPEG_SETTING_AUDIO_SETTINGS, 63 MPEG_SETTING_AUDIO_SETTINGS,
64 MPEG_SETTING_ENABLE_START_MENU, 64 MPEG_SETTING_ENABLE_START_MENU,
65 MPEG_SETTING_PLAY_MODE,
65 MPEG_SETTING_CLEAR_RESUMES, 66 MPEG_SETTING_CLEAR_RESUMES,
66}; 67};
67 68
@@ -83,6 +84,7 @@ struct mpeg_settings {
83#if MPEG_OPTION_DITHERING_ENABLED 84#if MPEG_OPTION_DITHERING_ENABLED
84 int displayoptions; 85 int displayoptions;
85#endif 86#endif
87 int play_mode; /* play single file or all files in directory */
86 /* Audio options - simple on/off specification */ 88 /* Audio options - simple on/off specification */
87 int tone_controls; 89 int tone_controls;
88 int channel_modes; 90 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
372#define MIN_FF_REWIND_STEP (TS_SECOND/2) 372#define MIN_FF_REWIND_STEP (TS_SECOND/2)
373#define OSD_MIN_UPDATE_INTERVAL (HZ/2) 373#define OSD_MIN_UPDATE_INTERVAL (HZ/2)
374 374
375enum video_action
376{
377 VIDEO_STOP = 0,
378 VIDEO_PREV,
379 VIDEO_NEXT,
380};
381
375/* OSD status - same order as icon array */ 382/* OSD status - same order as icon array */
376enum osd_status_enum 383enum osd_status_enum
377{ 384{
@@ -1452,7 +1459,7 @@ static void osd_stop(void)
1452 1459
1453 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); 1460 osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME);
1454 osd_set_status(OSD_STATUS_STOPPED | OSD_NODRAW); 1461 osd_set_status(OSD_STATUS_STOPPED | OSD_NODRAW);
1455 osd_show(OSD_HIDE | OSD_NODRAW); 1462 osd_show(OSD_HIDE);
1456 1463
1457 stream_stop(); 1464 stream_stop();
1458 1465
@@ -1496,6 +1503,53 @@ static void osd_seek(int btn)
1496 stream_seek(time, SEEK_SET); 1503 stream_seek(time, SEEK_SET);
1497} 1504}
1498 1505
1506/* has this file the extension .mpg ? */
1507static bool is_videofile(const char* file)
1508{
1509 const char* ext = rb->strrchr(file, '.');
1510 if (ext && !rb->strcasecmp(ext, ".mpg"))
1511 return true;
1512
1513 return false;
1514}
1515
1516/* deliver the next/previous video file in the current directory.
1517 returns 0 if there is none. */
1518static bool get_videofile(int direction, char* videofile, size_t bufsize)
1519{
1520 struct tree_context *tree = rb->tree_get_context();
1521 struct entry *dircache = tree->dircache;
1522 int i, step, end, found = 0;
1523 char *videoname = rb->strrchr(videofile, '/') + 1;
1524 size_t rest = bufsize - (videoname - videofile) - 1;
1525
1526 if (direction == VIDEO_NEXT) {
1527 i = 0;
1528 step = 1;
1529 end = tree->filesindir;
1530 } else {
1531 i = tree->filesindir-1;
1532 step = -1;
1533 end = -1;
1534 }
1535 for (; i != end; i += step)
1536 {
1537 const char* name = dircache[i].name;
1538 if (!rb->strcmp(name, videoname)) {
1539 found = 1;
1540 continue;
1541 }
1542 if (found && rb->strlen(name) <= rest &&
1543 !(dircache[i].attr & ATTR_DIRECTORY) && is_videofile(name))
1544 {
1545 rb->strcpy(videoname, name);
1546 return true;
1547 }
1548 }
1549
1550 return false;
1551}
1552
1499#ifdef HAVE_HEADPHONE_DETECTION 1553#ifdef HAVE_HEADPHONE_DETECTION
1500/* Handle SYS_PHONE_PLUGGED/UNPLUGGED */ 1554/* Handle SYS_PHONE_PLUGGED/UNPLUGGED */
1501static void osd_handle_phone_plug(bool inserted) 1555static void osd_handle_phone_plug(bool inserted)
@@ -1531,8 +1585,10 @@ static void osd_handle_phone_plug(bool inserted)
1531} 1585}
1532#endif 1586#endif
1533 1587
1534static void button_loop(void) 1588static int button_loop(void)
1535{ 1589{
1590 int next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT;
1591
1536 rb->lcd_setfont(FONT_SYSFIXED); 1592 rb->lcd_setfont(FONT_SYSFIXED);
1537#ifdef HAVE_LCD_COLOR 1593#ifdef HAVE_LCD_COLOR
1538 rb->lcd_set_foreground(LCD_WHITE); 1594 rb->lcd_set_foreground(LCD_WHITE);
@@ -1550,7 +1606,7 @@ static void button_loop(void)
1550 /* Start playback at the specified starting time */ 1606 /* Start playback at the specified starting time */
1551 if (osd_play(settings.resume_time) < STREAM_OK) { 1607 if (osd_play(settings.resume_time) < STREAM_OK) {
1552 rb->splash(HZ*2, "Playback failed"); 1608 rb->splash(HZ*2, "Playback failed");
1553 return; 1609 return VIDEO_STOP;
1554 } 1610 }
1555 1611
1556 /* Gently poll the video player for EOS and handle UI */ 1612 /* Gently poll the video player for EOS and handle UI */
@@ -1629,6 +1685,8 @@ static void button_loop(void)
1629 1685
1630 result = mpeg_menu(); 1686 result = mpeg_menu();
1631 1687
1688 next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT;
1689
1632 /* The menu can change the font, so restore */ 1690 /* The menu can change the font, so restore */
1633 rb->lcd_setfont(FONT_SYSFIXED); 1691 rb->lcd_setfont(FONT_SYSFIXED);
1634#ifdef HAVE_LCD_COLOR 1692#ifdef HAVE_LCD_COLOR
@@ -1641,6 +1699,7 @@ static void button_loop(void)
1641 switch (result) 1699 switch (result)
1642 { 1700 {
1643 case MPEG_MENU_QUIT: 1701 case MPEG_MENU_QUIT:
1702 next_action = VIDEO_STOP;
1644 osd_stop(); 1703 osd_stop();
1645 break; 1704 break;
1646 1705
@@ -1679,6 +1738,7 @@ static void button_loop(void)
1679#endif 1738#endif
1680 case ACTION_STD_CANCEL: 1739 case ACTION_STD_CANCEL:
1681 { 1740 {
1741 next_action = VIDEO_STOP;
1682 osd_stop(); 1742 osd_stop();
1683 break; 1743 break;
1684 } /* MPEG_STOP: */ 1744 } /* MPEG_STOP: */
@@ -1718,7 +1778,40 @@ static void button_loop(void)
1718 case MPEG_RC_FF: 1778 case MPEG_RC_FF:
1719#endif 1779#endif
1720 { 1780 {
1721 osd_seek(button); 1781 int old_button = button;
1782 if (settings.play_mode != 0)
1783 {
1784 /* if button has been released: skip to next/previous file */
1785 button = rb->button_get_w_tmo(OSD_MIN_UPDATE_INTERVAL);
1786 }
1787 switch (button)
1788 {
1789 case MPEG_RW | BUTTON_REL:
1790 {
1791 /* release within 3 seconds: skip to previous file, else
1792 start the current video from the beginning */
1793 osd_stop();
1794 if ( stream_get_resume_time() > 3*TS_SECOND ) {
1795 osd_play(0);
1796 osd_show(OSD_SHOW);
1797 } else {
1798 next_action = VIDEO_PREV;
1799 }
1800 break;
1801 }
1802 case MPEG_FF | BUTTON_REL:
1803 {
1804 osd_stop();
1805 next_action = VIDEO_NEXT;
1806 break;
1807 }
1808 default:
1809 {
1810 button = old_button;
1811 osd_seek(button);
1812 break;
1813 }
1814 }
1722 break; 1815 break;
1723 } /* MPEG_RW: MPEG_FF: */ 1816 } /* MPEG_RW: MPEG_FF: */
1724 1817
@@ -1750,13 +1843,18 @@ static void button_loop(void)
1750#endif 1843#endif
1751 1844
1752 rb->lcd_setfont(FONT_UI); 1845 rb->lcd_setfont(FONT_UI);
1846
1847 return next_action;
1753} 1848}
1754 1849
1755enum plugin_status plugin_start(const void* parameter) 1850enum plugin_status plugin_start(const void* parameter)
1756{ 1851{
1852 static char videofile[MAX_PATH];
1853
1757 int status = PLUGIN_ERROR; /* assume failure */ 1854 int status = PLUGIN_ERROR; /* assume failure */
1758 int result; 1855 int result;
1759 int err; 1856 int err;
1857 bool quit = false;
1760 const char *errstring; 1858 const char *errstring;
1761 1859
1762 if (parameter == NULL) { 1860 if (parameter == NULL) {
@@ -1777,46 +1875,76 @@ enum plugin_status plugin_start(const void* parameter)
1777 rb->lcd_clear_display(); 1875 rb->lcd_clear_display();
1778 rb->lcd_update(); 1876 rb->lcd_update();
1779 1877
1878 rb->strcpy(videofile, (const char*) parameter);
1879
1780 if (stream_init() < STREAM_OK) { 1880 if (stream_init() < STREAM_OK) {
1781 DEBUGF("Could not initialize streams\n"); 1881 DEBUGF("Could not initialize streams\n");
1782 } else { 1882 } else {
1783 rb->splash(0, "Loading..."); 1883 while (!quit)
1784 init_settings((char*)parameter); 1884 {
1885 int next_action = VIDEO_STOP;
1785 1886
1786 err = stream_open((char *)parameter); 1887 init_settings(videofile);
1888 err = stream_open(videofile);
1787 1889
1788 if (err >= STREAM_OK) { 1890 if (err >= STREAM_OK) {
1789 /* start menu */ 1891 /* start menu */
1790 rb->lcd_clear_display(); 1892 rb->lcd_clear_display();
1791 rb->lcd_update(); 1893 rb->lcd_update();
1792 result = mpeg_start_menu(stream_get_duration()); 1894 result = mpeg_start_menu(stream_get_duration());
1793 1895
1794 if (result != MPEG_START_QUIT) { 1896 if (result != MPEG_START_QUIT) {
1795 /* Enter button loop and process UI */ 1897 /* Enter button loop and process UI */
1796 button_loop(); 1898 next_action = button_loop();
1797 } 1899 }
1798 1900
1799 stream_close(); 1901 stream_close();
1800 1902
1801 rb->lcd_clear_display(); 1903 rb->lcd_clear_display();
1802 rb->lcd_update(); 1904 rb->lcd_update();
1803 1905
1804 save_settings(); 1906 save_settings();
1805 status = PLUGIN_OK; 1907 status = PLUGIN_OK;
1806 1908
1807 mpeg_menu_sysevent_handle(); 1909 mpeg_menu_sysevent_handle();
1808 } else { 1910 } else {
1809 DEBUGF("Could not open %s\n", (char*)parameter); 1911 DEBUGF("Could not open %s\n", videofile);
1810 switch (err) 1912 switch (err)
1913 {
1914 case STREAM_UNSUPPORTED:
1915 errstring = "Unsupported format";
1916 break;
1917 default:
1918 errstring = "Error opening file: %d";
1919 }
1920
1921 rb->splashf(HZ*2, errstring, err);
1922 status = PLUGIN_ERROR;
1923 }
1924
1925 /* return value of button_loop says, what's next */
1926 switch (next_action)
1927 {
1928 case VIDEO_NEXT:
1811 { 1929 {
1812 case STREAM_UNSUPPORTED: 1930 if (!get_videofile(VIDEO_NEXT, videofile, sizeof(videofile))) {
1813 errstring = "Unsupported format"; 1931 /* quit after finished the last videofile */
1932 quit = true;
1933 }
1814 break; 1934 break;
1815 default: 1935 }
1816 errstring = "Error opening file: %d"; 1936 case VIDEO_PREV:
1937 {
1938 get_videofile(VIDEO_PREV, videofile, sizeof(videofile));
1939 /* if there is no previous file, play the same videofile */
1940 break;
1941 }
1942 case VIDEO_STOP:
1943 {
1944 quit = true;
1945 break;
1946 }
1817 } 1947 }
1818
1819 rb->splashf(HZ*2, errstring, err);
1820 } 1948 }
1821 } 1949 }
1822 1950
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)
503 reply = true; 503 reply = true;
504 break; 504 break;
505 505
506 case STREAM_CLOSE:
507 vo_cleanup();
508 mpeg2_close(td->mpeg2dec);
509 reply = true;
510 break;
511
506 case VIDEO_DISPLAY_IS_VISIBLE: 512 case VIDEO_DISPLAY_IS_VISIBLE:
507 reply = vo_is_visible(); 513 reply = vo_is_visible();
508 break; 514 break;