diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/mpegplayer/mpeg_parser.c | 1 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpeg_settings.c | 14 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpeg_settings.h | 2 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpegplayer.c | 190 | ||||
-rw-r--r-- | 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) | |||
1213 | 1213 | ||
1214 | void parser_close_stream(void) | 1214 | void 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 | ||
290 | static const struct opt_items singleall[2] = { | ||
291 | { "Single", -1 }, | ||
292 | { "All", -1 }, | ||
293 | }; | ||
294 | |||
289 | static const struct opt_items enabledisable[2] = { | 295 | static 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 | ||
375 | enum 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 */ |
376 | enum osd_status_enum | 383 | enum 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 ? */ | ||
1507 | static 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. */ | ||
1518 | static 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 */ |
1501 | static void osd_handle_phone_plug(bool inserted) | 1555 | static 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 | ||
1534 | static void button_loop(void) | 1588 | static 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 | ||
1755 | enum plugin_status plugin_start(const void* parameter) | 1850 | enum 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; |