From d25d24812e8120c0eb133a412287ac030eb185c9 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Wed, 4 Aug 2021 09:49:56 -0400 Subject: RFC: Get rid of mpegplayer plugin It might have made sense once upon a time, but in today's world... Change-Id: I5d638e6f7a2308c50ab12bd901338f02cf426aae --- apps/plugins/mpegplayer/mpegplayer.c | 2638 ---------------------------------- 1 file changed, 2638 deletions(-) delete mode 100644 apps/plugins/mpegplayer/mpegplayer.c (limited to 'apps/plugins/mpegplayer/mpegplayer.c') diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c deleted file mode 100644 index e66b4df146..0000000000 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ /dev/null @@ -1,2638 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * mpegplayer main entrypoint and UI implementation - * - * Copyright (c) 2007 Michael Sevakis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -/**************************************************************************** - * NOTES: - * - * mpegplayer is structured as follows: - * - * +-->Video Thread-->Video Output-->LCD - * | - * UI-->Stream Manager-->+-->Audio Thread-->PCM buffer--Audio Device - * | | | | (ref. clock) - * | | +-->Buffer Thread | - * Stream Data | | (clock intf./ - * Requests | File Cache drift adj.) - * | Disk I/O - * Stream services - * (timing, etc.) - * - * Thread list: - * 1) The main thread - Handles user input, settings, basic playback control - * and USB connect. - * - * 2) Stream Manager thread - Handles playback state, events from streams - * such as when a stream is finished, stream commands, PCM state. The - * layer in which this thread run also handles arbitration of data - * requests between the streams and the disk buffer. The actual specific - * transport layer code may get moved out to support multiple container - * formats. - * - * 3) Buffer thread - Buffers data in the background, generates notifications - * to streams when their data has been buffered, and watches streams' - * progress to keep data available during playback. Handles synchronous - * random access requests when the file cache is missed. - * - * 4) Video thread (running on the COP for PortalPlayer targets) - Decodes - * the video stream and renders video frames to the LCD. Handles - * miscellaneous video tasks like frame and thumbnail printing. - * - * 5) Audio thread (running on the main CPU to maintain consistency with the - * audio FIQ hander on PP) - Decodes audio frames and places them into - * the PCM buffer for rendering by the audio device. - * - * Streams are neither aware of one another nor care about one another. All - * streams shall have their own thread (unless it is _really_ efficient to - * have a single thread handle a couple minor streams). All coordination of - * the streams is done through the stream manager. The clocking is controlled - * by and exposed by the stream manager to other streams and implemented at - * the PCM level. - * - * Notes about MPEG files: - * - * MPEG System Clock is 27MHz - i.e. 27000000 ticks/second. - * - * FPS is represented in terms of a frame period - this is always an - * integer number of 27MHz ticks. - * - * e.g. 29.97fps (30000/1001) NTSC video has an exact frame period of - * 900900 27MHz ticks. - * - * In libmpeg2, info->sequence->frame_period contains the frame_period. - * - * Working with Rockbox's 100Hz tick, the common frame rates would need - * to be as follows (1): - * - * FPS | 27Mhz | 100Hz | 44.1KHz | 48KHz - * --------|----------------------------------------------------------- - * 10* | 2700000 | 10 | 4410 | 4800 - * 12* | 2250000 | 8.3333 | 3675 | 4000 - * 15* | 1800000 | 6.6667 | 2940 | 3200 - * 23.9760 | 1126125 | 4.170833333 | 1839.3375 | 2002 - * 24 | 1125000 | 4.166667 | 1837.5 | 2000 - * 25 | 1080000 | 4 | 1764 | 1920 - * 29.9700 | 900900 | 3.336667 | 1471,47 | 1601.6 - * 30 | 900000 | 3.333333 | 1470 | 1600 - * - * *Unofficial framerates - * - * (1) But we don't really care since the audio clock is used anyway and has - * very fine resolution ;-) - *****************************************************************************/ -#include "plugin.h" -#include "mpegplayer.h" -#include "lib/helper.h" -#include "mpeg_settings.h" -#include "video_out.h" -#include "stream_thread.h" -#include "stream_mgr.h" - - -/* button definitions */ -#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) -#define MPEG_MENU BUTTON_MODE -#define MPEG_STOP BUTTON_OFF -#define MPEG_PAUSE BUTTON_ON -#define MPEG_VOLDOWN BUTTON_DOWN -#define MPEG_VOLUP BUTTON_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ - (CONFIG_KEYPAD == IPOD_1G2G_PAD) -#define MPEG_MENU BUTTON_MENU -#define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL) -#define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) -#define MPEG_VOLDOWN BUTTON_SCROLL_BACK -#define MPEG_VOLUP BUTTON_SCROLL_FWD -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD -#define MPEG_MENU (BUTTON_REC | BUTTON_REL) -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_DOWN -#define MPEG_VOLUP BUTTON_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == GIGABEAT_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_SELECT -#define MPEG_PAUSE2 BUTTON_A -#define MPEG_VOLDOWN BUTTON_LEFT -#define MPEG_VOLUP BUTTON_RIGHT -#define MPEG_VOLDOWN2 BUTTON_VOL_DOWN -#define MPEG_VOLUP2 BUTTON_VOL_UP -#define MPEG_RW BUTTON_UP -#define MPEG_FF BUTTON_DOWN - -#define MPEG_RC_MENU BUTTON_RC_DSP -#define MPEG_RC_STOP (BUTTON_RC_PLAY | BUTTON_REPEAT) -#define MPEG_RC_PAUSE (BUTTON_RC_PLAY | BUTTON_REL) -#define MPEG_RC_VOLDOWN BUTTON_RC_VOL_DOWN -#define MPEG_RC_VOLUP BUTTON_RC_VOL_UP -#define MPEG_RC_RW BUTTON_RC_REW -#define MPEG_RC_FF BUTTON_RC_FF - -#elif CONFIG_KEYPAD == GIGABEAT_S_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_SELECT -#define MPEG_PAUSE2 BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_LEFT -#define MPEG_VOLUP BUTTON_RIGHT -#define MPEG_VOLDOWN2 BUTTON_VOL_DOWN -#define MPEG_VOLUP2 BUTTON_VOL_UP -#define MPEG_RW BUTTON_UP -#define MPEG_RW2 BUTTON_PREV -#define MPEG_FF BUTTON_DOWN -#define MPEG_FF2 BUTTON_NEXT -#define MPEG_SHOW_OSD BUTTON_BACK - -#define MPEG_RC_MENU BUTTON_RC_DSP -#define MPEG_RC_STOP (BUTTON_RC_PLAY | BUTTON_REPEAT) -#define MPEG_RC_PAUSE (BUTTON_RC_PLAY | BUTTON_REL) -#define MPEG_RC_VOLDOWN BUTTON_RC_VOL_DOWN -#define MPEG_RC_VOLUP BUTTON_RC_VOL_UP -#define MPEG_RC_RW BUTTON_RC_REW -#define MPEG_RC_FF BUTTON_RC_FF - -#elif CONFIG_KEYPAD == IRIVER_H10_PAD -#define MPEG_MENU BUTTON_LEFT -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_SCROLL_DOWN -#define MPEG_VOLUP BUTTON_SCROLL_UP -#define MPEG_RW BUTTON_REW -#define MPEG_FF BUTTON_FF - -#elif CONFIG_KEYPAD == SANSA_E200_PAD -#define MPEG_MENU BUTTON_SELECT -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_RIGHT -#define MPEG_VOLDOWN BUTTON_SCROLL_BACK -#define MPEG_VOLUP BUTTON_SCROLL_FWD -#define MPEG_RW BUTTON_UP -#define MPEG_FF BUTTON_DOWN - -#elif CONFIG_KEYPAD == SANSA_FUZE_PAD -#define MPEG_MENU BUTTON_SELECT -#define MPEG_STOP (BUTTON_HOME|BUTTON_REPEAT) -#define MPEG_PAUSE BUTTON_UP -#define MPEG_VOLDOWN BUTTON_SCROLL_BACK -#define MPEG_VOLUP BUTTON_SCROLL_FWD -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - - -#elif CONFIG_KEYPAD == SANSA_C200_PAD || \ -CONFIG_KEYPAD == SANSA_CLIP_PAD || \ -CONFIG_KEYPAD == SANSA_M200_PAD -#define MPEG_MENU BUTTON_SELECT -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_UP -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == MROBE500_PAD -#define MPEG_STOP BUTTON_POWER - -#define MPEG_RC_MENU BUTTON_RC_HEART -#define MPEG_RC_STOP BUTTON_RC_DOWN -#define MPEG_RC_PAUSE BUTTON_RC_PLAY -#define MPEG_RC_VOLDOWN BUTTON_RC_VOL_DOWN -#define MPEG_RC_VOLUP BUTTON_RC_VOL_UP -#define MPEG_RC_RW BUTTON_RC_REW -#define MPEG_RC_FF BUTTON_RC_FF - -#elif CONFIG_KEYPAD == MROBE100_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_DOWN -#define MPEG_VOLUP BUTTON_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == IAUDIO_M3_PAD -#define MPEG_MENU BUTTON_RC_MENU -#define MPEG_STOP BUTTON_RC_REC -#define MPEG_PAUSE BUTTON_RC_PLAY -#define MPEG_VOLDOWN BUTTON_RC_VOL_DOWN -#define MPEG_VOLUP BUTTON_RC_VOL_UP -#define MPEG_RW BUTTON_RC_REW -#define MPEG_FF BUTTON_RC_FF - -#elif CONFIG_KEYPAD == COWON_D2_PAD -#define MPEG_MENU (BUTTON_MENU|BUTTON_REL) -//#define MPEG_STOP BUTTON_POWER -#define MPEG_VOLDOWN BUTTON_MINUS -#define MPEG_VOLUP BUTTON_PLUS - -#elif CONFIG_KEYPAD == CREATIVEZVM_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_BACK -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_UP -#define MPEG_VOLUP BUTTON_DOWN -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP (BUTTON_PLAY|BUTTON_REPEAT) -#define MPEG_PAUSE (BUTTON_PLAY|BUTTON_REL) -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_DOWN -#define MPEG_FF BUTTON_UP - -#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_SELECT -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_PREV -#define MPEG_FF BUTTON_NEXT - -#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_UP -#define MPEG_FF BUTTON_DOWN - -#elif CONFIG_KEYPAD == ONDAVX747_PAD -#define MPEG_MENU (BUTTON_MENU|BUTTON_REL) -//#define MPEG_STOP BUTTON_POWER -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP - -#elif CONFIG_KEYPAD == ONDAVX777_PAD -#define MPEG_MENU BUTTON_POWER - -#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \ - (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) -#define MPEG_MENU BUTTON_REW -#define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) -#define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL) -#define MPEG_VOLDOWN BUTTON_DOWN -#define MPEG_VOLUP BUTTON_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT -#define MPEG_SHOW_OSD BUTTON_FFWD - -#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_REC -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_DOWN -#define MPEG_VOLUP BUTTON_UP -#define MPEG_RW BUTTON_PREV -#define MPEG_FF BUTTON_NEXT - -#elif CONFIG_KEYPAD == MPIO_HD200_PAD -#define MPEG_MENU BUTTON_FUNC -#define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL) -#define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_REW -#define MPEG_FF BUTTON_FF - -#elif CONFIG_KEYPAD == MPIO_HD300_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_PAUSE (BUTTON_PLAY | BUTTON_REL) -#define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) -#define MPEG_VOLDOWN BUTTON_DOWN -#define MPEG_VOLUP BUTTON_UP -#define MPEG_RW BUTTON_REW -#define MPEG_FF BUTTON_FF - -#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD -#define MPEG_MENU BUTTON_POWER -#define MPEG_PAUSE (BUTTON_PLAYPAUSE | BUTTON_REL) -#define MPEG_STOP (BUTTON_PLAYPAUSE | BUTTON_REPEAT) -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD -#define MPEG_MENU BUTTON_POWER -#define MPEG_PAUSE (BUTTON_SELECT | BUTTON_REL) -#define MPEG_STOP (BUTTON_SELECT | BUTTON_REPEAT) -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_PAUSE BUTTON_SELECT -#define MPEG_STOP BUTTON_POWER -#define MPEG_VOLDOWN BUTTON_DOWN -#define MPEG_VOLUP BUTTON_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == HM60X_PAD -#define MPEG_MENU BUTTON_POWER -#define MPEG_PAUSE BUTTON_SELECT -#define MPEG_STOP (BUTTON_SELECT | BUTTON_POWER) -#define MPEG_VOLDOWN (BUTTON_POWER | BUTTON_DOWN) -#define MPEG_VOLUP (BUTTON_POWER | BUTTON_UP) -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == HM801_PAD -#define MPEG_MENU BUTTON_POWER -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_STOP (BUTTON_POWER | BUTTON_PLAY) -#define MPEG_VOLDOWN (BUTTON_POWER | BUTTON_DOWN) -#define MPEG_VOLUP (BUTTON_POWER | BUTTON_UP) -#define MPEG_RW BUTTON_PREV -#define MPEG_FF BUTTON_NEXT - -#elif CONFIG_KEYPAD == SONY_NWZ_PAD -#define MPEG_MENU BUTTON_BACK -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_STOP BUTTON_POWER -#define MPEG_VOLDOWN BUTTON_UP -#define MPEG_VOLUP BUTTON_DOWN -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_PAUSE BUTTON_PLAYPAUSE -#define MPEG_STOP BUTTON_BACK -#define MPEG_VOLDOWN BUTTON_DOWN -#define MPEG_VOLUP BUTTON_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == DX50_PAD -#define MPEG_MENU BUTTON_POWER -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_STOP (BUTTON_PLAY|BUTTON_REPEAT) - -#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD -#define MPEG_MENU BUTTON_POWER -#define MPEG_PAUSE BUTTON_MENU -#define MPEG_STOP (BUTTON_MENU|BUTTON_REPEAT) - -#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD -#define MPEG_MENU BUTTON_POWER -#define MPEG_PAUSE BUTTON_SELECT -#define MPEG_STOP BUTTON_DOWN -#define MPEG_VOLDOWN BUTTON_VOLDOWN -#define MPEG_VOLUP BUTTON_VOLUP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == XDUOO_X3_PAD -#define MPEG_MENU BUTTON_PLAY -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_HOME -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_PREV -#define MPEG_FF BUTTON_NEXT - -#elif CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD -#define MPEG_MENU BUTTON_PLAY -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_HOME -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_PREV -#define MPEG_FF BUTTON_NEXT - -#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD -#define MPEG_MENU BUTTON_PLAY -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_HOME -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_PREV -#define MPEG_FF BUTTON_NEXT - -#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD -#define MPEG_MENU BUTTON_PLAY -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_HOME -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_PREV -#define MPEG_FF BUTTON_NEXT - -#elif CONFIG_KEYPAD == EROSQ_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_PREV -#define MPEG_FF BUTTON_NEXT - -#elif CONFIG_KEYPAD == FIIO_M3K_PAD -#define MPEG_MENU BUTTON_MENU -#define MPEG_STOP BUTTON_POWER -#define MPEG_PAUSE BUTTON_PLAY -#define MPEG_VOLDOWN BUTTON_VOL_DOWN -#define MPEG_VOLUP BUTTON_VOL_UP -#define MPEG_RW BUTTON_LEFT -#define MPEG_FF BUTTON_RIGHT - -#elif CONFIG_KEYPAD == SHANLING_Q1_PAD -/* use touchscreen */ - -#else -#error No keymap defined! -#endif - -#ifdef HAVE_TOUCHSCREEN -#ifndef MPEG_MENU -#define MPEG_MENU (BUTTON_TOPRIGHT|BUTTON_REL) -#endif -#ifndef MPEG_STOP -#define MPEG_STOP BUTTON_TOPLEFT -#endif -#ifndef MPEG_PAUSE -#define MPEG_PAUSE BUTTON_CENTER -#endif -#ifndef MPEG_VOLDOWN -#define MPEG_VOLDOWN BUTTON_BOTTOMMIDDLE -#endif -#ifndef MPEG_VOLUP -#define MPEG_VOLUP BUTTON_TOPMIDDLE -#endif -#ifndef MPEG_RW -#define MPEG_RW BUTTON_MIDLEFT -#endif -#ifndef MPEG_FF -#define MPEG_FF BUTTON_MIDRIGHT -#endif -#endif - -/* One thing we can do here for targets with remotes is having a display - * always on the remote instead of always forcing a popup on the main display */ - -#define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */ - /* 3% of 30min file == 54s step size */ -#define MIN_FF_REWIND_STEP (TS_SECOND/2) -#define OSD_MIN_UPDATE_INTERVAL (HZ/2) -#define FPS_UPDATE_INTERVAL (HZ) /* Get new FPS reading each second */ - -enum video_action -{ - VIDEO_STOP = 0, - VIDEO_PREV, - VIDEO_NEXT, - VIDEO_ACTION_MANUAL = 0x8000, /* Flag that says user did it */ -}; - -/* OSD status - same order as icon array */ -enum osd_status_enum -{ - OSD_STATUS_STOPPED = 0, - OSD_STATUS_PAUSED, - OSD_STATUS_PLAYING, - OSD_STATUS_FF, - OSD_STATUS_RW, - OSD_STATUS_COUNT, - OSD_STATUS_MASK = 0x7 -}; - -enum osd_bits -{ - OSD_REFRESH_DEFAULT = 0x0000, /* Only refresh elements when due */ - /* Refresh the... */ - OSD_REFRESH_VOLUME = 0x0001, /* ...volume display */ - OSD_REFRESH_TIME = 0x0002, /* ...time display+progress */ - OSD_REFRESH_STATUS = 0x0004, /* ...playback status icon */ - OSD_REFRESH_BACKGROUND = 0x0008, /* ...background (implies ALL) */ - OSD_REFRESH_VIDEO = 0x0010, /* ...video image upon timeout */ - OSD_REFRESH_RESUME = 0x0020, /* Resume playback upon timeout */ - OSD_NODRAW = 0x8000, /* OR bitflag - don't draw anything */ - OSD_SHOW = 0x4000, /* OR bitflag - show the OSD */ -#ifdef HAVE_HEADPHONE_DETECTION - OSD_HP_PAUSE = 0x2000, /* OR bitflag - headphones caused pause */ -#endif - OSD_HIDE = 0x0000, /* hide the OSD (aid readability) */ - OSD_REFRESH_ALL = 0x000f, /* Only immediate graphical elements */ -}; - -/* Status icons selected according to font height */ -extern const unsigned char mpegplayer_status_icons_8x8x1[]; -extern const unsigned char mpegplayer_status_icons_12x12x1[]; -extern const unsigned char mpegplayer_status_icons_16x16x1[]; - -/* Main border areas that contain OSD elements */ -#define OSD_BDR_L 2 -#define OSD_BDR_T 2 -#define OSD_BDR_R 2 -#define OSD_BDR_B 2 - -struct osd -{ - long hide_tick; - long show_for; - long print_tick; - long print_delay; - long resume_tick; - long resume_delay; - long next_auto_refresh; - int x; - int y; - int width; - int height; - unsigned fgcolor; - unsigned bgcolor; - unsigned prog_fillcolor; - struct vo_rect update_rect; - struct vo_rect prog_rect; - struct vo_rect time_rect; - struct vo_rect dur_rect; - struct vo_rect vol_rect; - const unsigned char *icons; - struct vo_rect stat_rect; - int status; - uint32_t curr_time; - unsigned auto_refresh; - unsigned flags; - int font; -}; - -struct fps -{ - /* FPS Display */ - struct vo_rect rect; /* OSD coordinates */ - int pf_x; /* Screen coordinates */ - int pf_y; - int pf_width; - int pf_height; - long update_tick; /* When to next update FPS reading */ - #define FPS_FORMAT "%d.%02d" - #define FPS_DIMSTR "999.99" /* For establishing rect size */ - #define FPS_BUFSIZE sizeof("999.99") -}; - -static struct osd osd; -static struct fps fps NOCACHEBSS_ATTR; /* Accessed on other processor */ - -#ifdef LCD_PORTRAIT -static fb_data* get_framebuffer(void) -{ - struct viewport *vp_main = *(rb->screens[SCREEN_MAIN]->current_viewport); - return vp_main->buffer->fb_ptr; -} -#endif - -static void osd_show(unsigned show); - -#ifdef LCD_LANDSCAPE - #define __X (x + osd.x) - #define __Y (y + osd.y) - #define __W width - #define __H height -#else - #define __X (LCD_WIDTH - (y + osd.y) - height) - #define __Y (x + osd.x) - #define __W height - #define __H width -#endif - -#ifdef HAVE_LCD_COLOR -/* Blend two colors in 0-100% (0-255) mix of c2 into c1 */ -static unsigned draw_blendcolor(unsigned c1, unsigned c2, unsigned char amount) -{ - int r1 = RGB_UNPACK_RED(c1); - int g1 = RGB_UNPACK_GREEN(c1); - int b1 = RGB_UNPACK_BLUE(c1); - - int r2 = RGB_UNPACK_RED(c2); - int g2 = RGB_UNPACK_GREEN(c2); - int b2 = RGB_UNPACK_BLUE(c2); - - return LCD_RGBPACK(amount*(r2 - r1) / 255 + r1, - amount*(g2 - g1) / 255 + g1, - amount*(b2 - b1) / 255 + b1); -} -#endif - -#ifdef PLUGIN_USE_IRAM -/* IRAM preserving mechanism to enable talking menus */ -static char *iram_saved_copy; -extern char iramstart[], iramend[]; - -static void iram_saving_init(void) -{ -#ifndef SIMULATOR - size_t size; - iram_saved_copy = (char *)rb->plugin_get_buffer(&size); - - if (size >= (size_t)(iramend-iramstart)) - iram_saved_copy += size - (size_t)(iramend - iramstart); - else -#endif - iram_saved_copy = NULL; - - return; -} - -void mpegplayer_iram_preserve(void) -{ - if (iram_saved_copy) - { - rb->memcpy(iram_saved_copy, iramstart, iramend-iramstart); -#ifdef HAVE_CPUCACHE_INVALIDATE - /* make the icache (if it exists) up to date with the new code */ - rb->cpucache_invalidate(); -#endif /* HAVE_CPUCACHE_INVALIDATE */ - } - return; -} - -void mpegplayer_iram_restore(void) -{ - if (iram_saved_copy) - { - rb->audio_hard_stop(); - rb->memcpy(iramstart, iram_saved_copy, iramend-iramstart); -#ifdef HAVE_CPUCACHE_INVALIDATE - /* make the icache (if it exists) up to date with the new code */ - rb->cpucache_invalidate(); -#endif /* HAVE_CPUCACHE_INVALIDATE */ - } - return; -} -#endif - -/* Drawing functions that operate rotated on LCD_PORTRAIT displays - - * most are just wrappers of lcd_* functions with transforms applied. - * The origin is the upper-left corner of the OSD area */ -static void draw_update_rect(int x, int y, int width, int height) -{ - mylcd_update_rect(__X, __Y, __W, __H); -} - -static void draw_clear_area(int x, int y, int width, int height) -{ -#ifdef HAVE_LCD_COLOR - rb->screen_clear_area(rb->screens[SCREEN_MAIN], __X, __Y, __W, __H); -#else - int oldmode = grey_get_drawmode(); - grey_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID); - grey_fillrect(__X, __Y, __W, __H); - grey_set_drawmode(oldmode); -#endif -} - -static void draw_clear_area_rect(const struct vo_rect *rc) -{ - draw_clear_area(rc->l, rc->t, rc->r - rc->l, rc->b - rc->t); -} - -static void draw_fillrect(int x, int y, int width, int height) -{ - mylcd_fillrect(__X, __Y, __W, __H); -} - -static void draw_hline(int x1, int x2, int y) -{ -#ifdef LCD_LANDSCAPE - mylcd_hline(x1 + osd.x, x2 + osd.x, y + osd.y); -#else - y = LCD_WIDTH - (y + osd.y) - 1; - mylcd_vline(y, x1 + osd.x, x2 + osd.x); -#endif -} - -static void draw_vline(int x, int y1, int y2) -{ -#ifdef LCD_LANDSCAPE - mylcd_vline(x + osd.x, y1 + osd.y, y2 + osd.y); -#else - y1 = LCD_WIDTH - (y1 + osd.y) - 1; - y2 = LCD_WIDTH - (y2 + osd.y) - 1; - mylcd_hline(y1, y2, x + osd.x); -#endif -} - -static void draw_scrollbar_draw(int x, int y, int width, int height, - uint32_t min, uint32_t max, uint32_t val) -{ - unsigned oldfg = mylcd_get_foreground(); - - draw_hline(x + 1, x + width - 2, y); - draw_hline(x + 1, x + width - 2, y + height - 1); - draw_vline(x, y + 1, y + height - 2); - draw_vline(x + width - 1, y + 1, y + height - 2); - - val = muldiv_uint32(width - 2, val, max - min); - val = MIN(val, (uint32_t)(width - 2)); - - draw_fillrect(x + 1, y + 1, val, height - 2); - - mylcd_set_foreground(osd.prog_fillcolor); - - draw_fillrect(x + 1 + val, y + 1, width - 2 - val, height - 2); - - mylcd_set_foreground(oldfg); -} - -static void draw_scrollbar_draw_rect(const struct vo_rect *rc, int min, - int max, int val) -{ - draw_scrollbar_draw(rc->l, rc->t, rc->r - rc->l, rc->b - rc->t, - min, max, val); -} - -static void draw_setfont(int font) -{ - osd.font = font; - mylcd_setfont(font); -} - -#ifdef LCD_PORTRAIT -/* Portrait displays need rotated text rendering */ - -/* Limited function that only renders in DRMODE_FG and uses absolute screen - * coordinates */ -static void draw_oriented_mono_bitmap_part(const unsigned char *src, - int src_x, int src_y, - int stride, int x, int y, - int width, int height) -{ - const unsigned char *src_end; - fb_data *dst, *dst_end; - unsigned fg_pattern; - - if (x + width > SCREEN_WIDTH) - width = SCREEN_WIDTH - x; /* Clip right */ - if (x < 0) - width += x, x = 0; /* Clip left */ - if (width <= 0) - return; /* nothing left to do */ - - if (y + height > SCREEN_HEIGHT) - height = SCREEN_HEIGHT - y; /* Clip bottom */ - if (y < 0) - height += y, y = 0; /* Clip top */ - if (height <= 0) - return; /* nothing left to do */ - - fg_pattern = rb->lcd_get_foreground(); - /*bg_pattern =*/ rb->lcd_get_background(); - - src += stride * (src_y >> 3) + src_x; /* move starting point */ - src_y &= 7; - src_end = src + width; - - dst = get_framebuffer() + (LCD_WIDTH - y) + x*LCD_WIDTH; - do - { - const unsigned char *src_col = src++; - unsigned data = *src_col >> src_y; - int numbits = 8 - src_y; - - fb_data *dst_col = dst; - dst_end = dst_col - height; - dst += LCD_WIDTH; - - do - { - dst_col--; - - if (data & 1) - *dst_col = FB_SCALARPACK(fg_pattern); -#if 0 - else - *dst_col = bg_pattern; -#endif - data >>= 1; - if (--numbits == 0) { - src_col += stride; - data = *src_col; - numbits = 8; - } - } - while (dst_col > dst_end); - } - while (src < src_end); -} - - -#define ALPHA_COLOR_FONT_DEPTH 2 -#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH) -#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1) -#define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH) -#define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH) -#ifdef CPU_ARM -#define BLEND_INIT do {} while (0) -#define BLEND_FINISH do {} while(0) -#define BLEND_START(acc, color, alpha) \ - asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha)) -#define BLEND_CONT(acc, color, alpha) \ - asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha)) -#define BLEND_OUT(acc) do {} while (0) -#elif defined(CPU_COLDFIRE) -#define ALPHA_BITMAP_READ_WORDS -#define BLEND_INIT \ - unsigned long _macsr = coldfire_get_macsr(); \ - coldfire_set_macsr(EMAC_UNSIGNED) -#define BLEND_FINISH \ - coldfire_set_macsr(_macsr) -#define BLEND_START(acc, color, alpha) \ - asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha)) -#define BLEND_CONT BLEND_START -#define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc)) -#else -#define BLEND_INIT do {} while (0) -#define BLEND_FINISH do {} while(0) -#define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha)) -#define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha)) -#define BLEND_OUT(acc) do {} while (0) -#endif - -/* Blend the given two colors */ -static inline unsigned blend_two_colors(unsigned c1, unsigned c2, unsigned a) -{ -#if LCD_DEPTH == 16 - a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1); -#if (LCD_PIXELFORMAT == RGB565SWAPPED) - c1 = swap16(c1); - c2 = swap16(c2); -#endif - unsigned c1l = (c1 | (c1 << 16)) & 0x07e0f81f; - unsigned c2l = (c2 | (c2 << 16)) & 0x07e0f81f; - unsigned p; - BLEND_START(p, c1l, a); - BLEND_CONT(p, c2l, ALPHA_COLOR_LOOKUP_SIZE + 1 - a); - BLEND_OUT(p); - p = (p >> ALPHA_COLOR_LOOKUP_SHIFT) & 0x07e0f81f; - p |= (p >> 16); -#if (LCD_PIXELFORMAT == RGB565SWAPPED) - return swap16(p); -#else - return p; -#endif - -#else /* LCD_DEPTH == 24 */ - unsigned s = c1; - unsigned d = c2; - unsigned s1 = s & 0xff00ff; - unsigned d1 = d & 0xff00ff; - a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1); - d1 = (d1 + ((s1 - d1) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00ff; - s &= 0xff00; - d &= 0xff00; - d = (d + ((s - d) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00; - - return d1 | d; -#endif -} - -static void draw_oriented_alpha_bitmap_part(const unsigned char *src, - int src_x, int src_y, - int stride, int x, int y, - int width, int height) -{ - fb_data *dst, *dst_start; - unsigned fg_pattern; - - if (x + width > SCREEN_WIDTH) - width = SCREEN_WIDTH - x; /* Clip right */ - if (x < 0) - width += x, x = 0; /* Clip left */ - if (width <= 0) - return; /* nothing left to do */ - - if (y + height > SCREEN_HEIGHT) - height = SCREEN_HEIGHT - y; /* Clip bottom */ - if (y < 0) - height += y, y = 0; /* Clip top */ - if (height <= 0) - return; /* nothing left to do */ - - /* initialize blending */ - BLEND_INIT; - - fg_pattern = rb->lcd_get_foreground(); - /*bg_pattern=*/ rb->lcd_get_background(); - - dst_start = get_framebuffer() + (LCD_WIDTH - y - 1) + x*LCD_WIDTH; - int col, row = height; - unsigned data, pixels; - unsigned skip_end = (stride - width); - unsigned skip_start = src_y * stride + src_x; - -#ifdef ALPHA_BITMAP_READ_WORDS - uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3); - skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3); - src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD; - data = letoh32(*src_w++); -#else - src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE; - data = *src; -#endif - pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD; - data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; -#ifdef ALPHA_BITMAP_READ_WORDS - pixels = 8 - pixels; -#endif - - do - { - col = width; - dst = dst_start--; -#ifdef ALPHA_BITMAP_READ_WORDS -#define UPDATE_SRC_ALPHA do { \ - if (--pixels) \ - data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ - else \ - { \ - data = letoh32(*src_w++); \ - pixels = ALPHA_COLOR_PIXEL_PER_WORD; \ - } \ - } while (0) -#elif ALPHA_COLOR_PIXEL_PER_BYTE == 2 -#define UPDATE_SRC_ALPHA do { \ - if (pixels ^= 1) \ - data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ - else \ - data = *(++src); \ - } while (0) -#else -#define UPDATE_SRC_ALPHA do { \ - if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \ - data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ - else \ - data = *(++src); \ - } while (0) -#endif - do - { - unsigned color = blend_two_colors(FB_UNPACK_SCALAR_LCD(*dst), fg_pattern, - data & ALPHA_COLOR_LOOKUP_SIZE ); - *dst= FB_SCALARPACK(color); - dst += LCD_WIDTH; - UPDATE_SRC_ALPHA; - } - while (--col); -#ifdef ALPHA_BITMAP_READ_WORDS - if (skip_end < pixels) - { - pixels -= skip_end; - data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; - } else { - pixels = skip_end - pixels; - src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD; - pixels %= ALPHA_COLOR_PIXEL_PER_WORD; - data = letoh32(*src_w++); - data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; - pixels = 8 - pixels; - } -#else - if (skip_end) - { - pixels += skip_end; - if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE) - { - src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE; - pixels %= ALPHA_COLOR_PIXEL_PER_BYTE; - data = *src; - data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; - } else - data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; - } -#endif - } while (--row); -} - -static void draw_putsxy_oriented(int x, int y, const char *str) -{ - unsigned short ch; - unsigned short *ucs; - int ofs = MIN(x, 0); - struct font* pf = rb->font_get(osd.font); - - ucs = rb->bidi_l2v(str, 1); - - x += osd.x; - y += osd.y; - - while ((ch = *ucs++) != 0 && x < SCREEN_WIDTH) - { - int width; - const unsigned char *bits; - - /* get proportional width and glyph bits */ - width = rb->font_get_width(pf, ch); - - if (ofs > width) { - ofs -= width; - continue; - } - - bits = rb->font_get_bits(pf, ch); - - if (pf->depth) - draw_oriented_alpha_bitmap_part(bits, ofs, 0, width, x, y, - width - ofs, pf->height); - else - draw_oriented_mono_bitmap_part(bits, ofs, 0, width, x, y, - width - ofs, pf->height); - - x += width - ofs; - ofs = 0; - } -} -#else -static void draw_oriented_mono_bitmap_part(const unsigned char *src, - int src_x, int src_y, - int stride, int x, int y, - int width, int height) -{ - int mode = mylcd_get_drawmode(); - mylcd_set_drawmode(DRMODE_FG); - mylcd_mono_bitmap_part(src, src_x, src_y, stride, x, y, width, height); - mylcd_set_drawmode(mode); -} - -static void draw_putsxy_oriented(int x, int y, const char *str) -{ - int mode = mylcd_get_drawmode(); - mylcd_set_drawmode(DRMODE_FG); - mylcd_putsxy(x + osd.x, y + osd.y, str); - mylcd_set_drawmode(mode); -} -#endif /* LCD_PORTRAIT */ - -/** FPS Display **/ - -/* Post-frame callback (on video thread) - update the FPS rectangle from the - * framebuffer */ -static void fps_post_frame_callback(void) -{ - vo_lock(); - mylcd_update_rect(fps.pf_x, fps.pf_y, - fps.pf_width, fps.pf_height); - vo_unlock(); -} - -/* Set up to have the callback only update the intersection of the video - * rectangle and the FPS text rectangle - if they don't intersect, then - * the callback is set to NULL */ -static void fps_update_post_frame_callback(void) -{ - void (*cb)(void) = NULL; - - if (settings.showfps) { - struct vo_rect cliprect; - - if (stream_vo_get_clip(&cliprect)) { - /* Oriented screen coordinates -> OSD coordinates */ - vo_rect_offset(&cliprect, -osd.x, -osd.y); - - if (vo_rect_intersect(&cliprect, &cliprect, &fps.rect)) { - int x = cliprect.l; - int y = cliprect.t; - int width = cliprect.r - cliprect.l; - int height = cliprect.b - cliprect.t; - - /* OSD coordinates -> framebuffer coordinates */ - fps.pf_x = __X; - fps.pf_y = __Y; - fps.pf_width = __W; - fps.pf_height = __H; - - cb = fps_post_frame_callback; - } - } - } - - stream_set_callback(VIDEO_SET_POST_FRAME_CALLBACK, cb); -} - -/* Refresh the FPS display */ -static void fps_refresh(void) -{ - char str[FPS_BUFSIZE]; - struct video_output_stats stats; - int w, h, sw; - long tick; - - tick = *rb->current_tick; - - if (TIME_BEFORE(tick, fps.update_tick)) - return; - - fps.update_tick = tick + FPS_UPDATE_INTERVAL; - - stream_video_stats(&stats); - - rb->snprintf(str, FPS_BUFSIZE, FPS_FORMAT, - stats.fps / 100, stats.fps % 100); - - w = fps.rect.r - fps.rect.l; - h = fps.rect.b - fps.rect.t; - - draw_clear_area(fps.rect.l, fps.rect.t, w, h); - mylcd_getstringsize(str, &sw, NULL); - draw_putsxy_oriented(fps.rect.r - sw, fps.rect.t, str); - - vo_lock(); - draw_update_rect(fps.rect.l, fps.rect.t, w, h); - vo_unlock(); -} - -/* Initialize the FPS display */ -static void fps_init(void) -{ - fps.update_tick = *rb->current_tick; - fps.rect.l = fps.rect.t = 0; - mylcd_getstringsize(FPS_DIMSTR, &fps.rect.r, &fps.rect.b); - vo_rect_offset(&fps.rect, -osd.x, -osd.y); - fps_update_post_frame_callback(); -} - -/** OSD **/ - -#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) -/* So we can refresh the overlay */ -static void osd_lcd_enable_hook(unsigned short id, void* param) -{ - (void)id; - (void)param; - rb->queue_post(rb->button_queue, LCD_ENABLE_EVENT_1, 0); -} -#endif - -static void osdbacklight_hw_on_video_mode(bool video_on) -{ - if (video_on) { -#ifdef HAVE_BACKLIGHT - /* Turn off backlight timeout */ - backlight_ignore_timeout(); -#endif -#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) - rb->remove_event(LCD_EVENT_ACTIVATION, osd_lcd_enable_hook); -#endif - } else { -#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) - rb->add_event(LCD_EVENT_ACTIVATION, osd_lcd_enable_hook); -#endif -#ifdef HAVE_BACKLIGHT - /* Revert to user's backlight settings */ - backlight_use_settings(); -#endif - } -} - -#ifdef HAVE_BACKLIGHT_BRIGHTNESS -static void osd_backlight_brightness_video_mode(bool video_on) -{ - if (settings.backlight_brightness < 0) - return; - - mpeg_backlight_update_brightness( - video_on ? settings.backlight_brightness : -1); -} -#else -#define osd_backlight_brightness_video_mode(video_on) -#endif /* HAVE_BACKLIGHT_BRIGHTNESS */ - -static void osd_text_init(void) -{ - struct hms hms; - char buf[32]; - int phys; - int spc_width; - - draw_setfont(FONT_UI); - - osd.x = 0; - osd.width = SCREEN_WIDTH; - - vo_rect_clear(&osd.time_rect); - vo_rect_clear(&osd.stat_rect); - vo_rect_clear(&osd.prog_rect); - vo_rect_clear(&osd.vol_rect); - - ts_to_hms(stream_get_duration(), &hms); - hms_format(buf, sizeof (buf), &hms); - mylcd_getstringsize(buf, &osd.time_rect.r, &osd.time_rect.b); - - /* Choose well-sized bitmap images relative to font height */ - if (osd.time_rect.b < 12) { - osd.icons = mpegplayer_status_icons_8x8x1; - osd.stat_rect.r = osd.stat_rect.b = 8; - } else if (osd.time_rect.b < 16) { - osd.icons = mpegplayer_status_icons_12x12x1; - osd.stat_rect.r = osd.stat_rect.b = 12; - } else { - osd.icons = mpegplayer_status_icons_16x16x1; - osd.stat_rect.r = osd.stat_rect.b = 16; - } - - if (osd.stat_rect.b < osd.time_rect.b) { - vo_rect_offset(&osd.stat_rect, 0, - (osd.time_rect.b - osd.stat_rect.b) / 2 + OSD_BDR_T); - vo_rect_offset(&osd.time_rect, OSD_BDR_L, OSD_BDR_T); - } else { - vo_rect_offset(&osd.time_rect, OSD_BDR_L, - osd.stat_rect.b - osd.time_rect.b + OSD_BDR_T); - vo_rect_offset(&osd.stat_rect, 0, OSD_BDR_T); - } - - osd.dur_rect = osd.time_rect; - - phys = rb->sound_val2phys(SOUND_VOLUME, rb->sound_min(SOUND_VOLUME)); - rb->snprintf(buf, sizeof(buf), "%d%s", phys, - rb->sound_unit(SOUND_VOLUME)); - - mylcd_getstringsize(" ", &spc_width, NULL); - mylcd_getstringsize(buf, &osd.vol_rect.r, &osd.vol_rect.b); - - osd.prog_rect.r = SCREEN_WIDTH - OSD_BDR_L - spc_width - - osd.vol_rect.r - OSD_BDR_R; - osd.prog_rect.b = 3*osd.stat_rect.b / 4; - vo_rect_offset(&osd.prog_rect, osd.time_rect.l, - osd.time_rect.b); - - vo_rect_offset(&osd.stat_rect, - (osd.prog_rect.r + osd.prog_rect.l - osd.stat_rect.r) / 2, - 0); - - vo_rect_offset(&osd.dur_rect, - osd.prog_rect.r - osd.dur_rect.r, 0); - - vo_rect_offset(&osd.vol_rect, osd.prog_rect.r + spc_width, - (osd.prog_rect.b + osd.prog_rect.t - osd.vol_rect.b) / 2); - - osd.height = OSD_BDR_T + MAX(osd.prog_rect.b, osd.vol_rect.b) - - MIN(osd.time_rect.t, osd.stat_rect.t) + OSD_BDR_B; - -#ifdef HAVE_LCD_COLOR - osd.height = ALIGN_UP(osd.height, 2); -#endif - osd.y = SCREEN_HEIGHT - osd.height; - - draw_setfont(FONT_SYSFIXED); -} - -static void osd_init(void) -{ - osd.flags = 0; - osd.show_for = HZ*4; - osd.print_delay = 75*HZ/100; - osd.resume_delay = HZ/2; -#ifdef HAVE_LCD_COLOR - osd.bgcolor = LCD_RGBPACK(0x73, 0x75, 0xbd); - osd.fgcolor = LCD_WHITE; - osd.prog_fillcolor = LCD_BLACK; -#else - osd.bgcolor = GREY_LIGHTGRAY; - osd.fgcolor = GREY_BLACK; - osd.prog_fillcolor = GREY_WHITE; -#endif - osd.curr_time = 0; - osd.status = OSD_STATUS_STOPPED; - osd.auto_refresh = OSD_REFRESH_TIME; - osd.next_auto_refresh = *rb->current_tick; - osd_text_init(); - fps_init(); -} - -#ifdef HAVE_HEADPHONE_DETECTION -static void osd_set_hp_pause_flag(bool set) -{ - if (set) - osd.flags |= OSD_HP_PAUSE; - else - osd.flags &= ~OSD_HP_PAUSE; -} -#else -#define osd_set_hp_pause_flag(set) -#endif /* HAVE_HEADPHONE_DETECTION */ - -static void osd_schedule_refresh(unsigned refresh) -{ - long tick = *rb->current_tick; - - if (refresh & OSD_REFRESH_VIDEO) - osd.print_tick = tick + osd.print_delay; - - if (refresh & OSD_REFRESH_RESUME) - osd.resume_tick = tick + osd.resume_delay; - - osd.auto_refresh |= refresh; -} - -static void osd_cancel_refresh(unsigned refresh) -{ - osd.auto_refresh &= ~refresh; -} - -/* Refresh the background area */ -static void osd_refresh_background(void) -{ - char buf[32]; - struct hms hms; - - unsigned bg = mylcd_get_background(); - mylcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID); - -#ifdef HAVE_LCD_COLOR - /* Draw a "raised" area for our graphics */ - mylcd_set_background(draw_blendcolor(bg, MYLCD_WHITE, 192)); - draw_hline(0, osd.width, 0); - - mylcd_set_background(draw_blendcolor(bg, MYLCD_WHITE, 80)); - draw_hline(0, osd.width, 1); - - mylcd_set_background(draw_blendcolor(bg, MYLCD_BLACK, 48)); - draw_hline(0, osd.width, osd.height-2); - - mylcd_set_background(draw_blendcolor(bg, MYLCD_BLACK, 128)); - draw_hline(0, osd.width, osd.height-1); - - mylcd_set_background(bg); - draw_clear_area(0, 2, osd.width, osd.height - 4); -#else - /* Give contrast with the main background */ - mylcd_set_background(MYLCD_WHITE); - draw_hline(0, osd.width, 0); - - mylcd_set_background(MYLCD_DARKGRAY); - draw_hline(0, osd.width, osd.height-1); - - mylcd_set_background(bg); - draw_clear_area(0, 1, osd.width, osd.height - 2); -#endif - - vo_rect_set_ext(&osd.update_rect, 0, 0, osd.width, osd.height); - mylcd_set_drawmode(DRMODE_SOLID); - - if (stream_get_duration() != INVALID_TIMESTAMP) { - /* Draw the movie duration */ - ts_to_hms(stream_get_duration(), &hms); - hms_format(buf, sizeof (buf), &hms); - draw_putsxy_oriented(osd.dur_rect.l, osd.dur_rect.t, buf); - } - /* else don't know the duration */ -} - -/* Refresh the current time display + the progress bar */ -static void osd_refresh_time(void) -{ - char buf[32]; - struct hms hms; - - uint32_t duration = stream_get_duration(); - - draw_scrollbar_draw_rect(&osd.prog_rect, 0, duration, - osd.curr_time); - - ts_to_hms(osd.curr_time, &hms); - hms_format(buf, sizeof (buf), &hms); - - draw_clear_area_rect(&osd.time_rect); - draw_putsxy_oriented(osd.time_rect.l, osd.time_rect.t, buf); - - vo_rect_union(&osd.update_rect, &osd.update_rect, - &osd.prog_rect); - vo_rect_union(&osd.update_rect, &osd.update_rect, - &osd.time_rect); -} - -/* Refresh the volume display area */ -static void osd_refresh_volume(void) -{ - char buf[32]; - int width; - - int volume = rb->global_settings->volume; - rb->snprintf(buf, sizeof (buf), "%d%s", - rb->sound_val2phys(SOUND_VOLUME, volume), - rb->sound_unit(SOUND_VOLUME)); - mylcd_getstringsize(buf, &width, NULL); - - /* Right-justified */ - draw_clear_area_rect(&osd.vol_rect); - draw_putsxy_oriented(osd.vol_rect.r - width, osd.vol_rect.t, buf); - - vo_rect_union(&osd.update_rect, &osd.update_rect, &osd.vol_rect); -} - -/* Refresh the status icon */ -static void osd_refresh_status(void) -{ - int icon_size = osd.stat_rect.r - osd.stat_rect.l; - - draw_clear_area_rect(&osd.stat_rect); - -#ifdef HAVE_LCD_COLOR - /* Draw status icon with a drop shadow */ - unsigned oldfg = mylcd_get_foreground(); - int i = 1; - - mylcd_set_foreground(draw_blendcolor(mylcd_get_background(), - MYLCD_BLACK, 96)); - - while (1) - { - draw_oriented_mono_bitmap_part(osd.icons, - icon_size*osd.status, - 0, - icon_size*OSD_STATUS_COUNT, - osd.stat_rect.l + osd.x + i, - osd.stat_rect.t + osd.y + i, - icon_size, icon_size); - - if (--i < 0) - break; - - mylcd_set_foreground(oldfg); - } - - vo_rect_union(&osd.update_rect, &osd.update_rect, &osd.stat_rect); -#else - draw_oriented_mono_bitmap_part(osd.icons, - icon_size*osd.status, - 0, - icon_size*OSD_STATUS_COUNT, - osd.stat_rect.l + osd.x, - osd.stat_rect.t + osd.y, - icon_size, icon_size); - vo_rect_union(&osd.update_rect, &osd.update_rect, &osd.stat_rect); -#endif -} - -/* Update the current status which determines which icon is displayed */ -static bool osd_update_status(void) -{ - int status; - - switch (stream_status()) - { - default: - status = OSD_STATUS_STOPPED; - break; - case STREAM_PAUSED: - /* If paused with a pending resume, coerce it to OSD_STATUS_PLAYING */ - status = (osd.auto_refresh & OSD_REFRESH_RESUME) ? - OSD_STATUS_PLAYING : OSD_STATUS_PAUSED; - break; - case STREAM_PLAYING: - status = OSD_STATUS_PLAYING; - break; - } - - if (status != osd.status) { - /* A refresh is needed */ - osd.status = status; - return true; - } - - return false; -} - -/* Update the current time that will be displayed */ -static void osd_update_time(void) -{ - uint32_t start; - osd.curr_time = stream_get_seek_time(&start); - osd.curr_time -= start; -} - -/* Refresh various parts of the OSD - showing it if it is hidden */ -static void osd_refresh(int hint) -{ - long tick; - unsigned oldbg, oldfg; - - tick = *rb->current_tick; - - if (settings.showfps) - fps_refresh(); - - if (hint == OSD_REFRESH_DEFAULT) { - /* The default which forces no updates */ - - /* Make sure Rockbox doesn't turn off the player because of - too little activity */ - if (osd.status == OSD_STATUS_PLAYING) - rb->reset_poweroff_timer(); - - /* Redraw the current or possibly extract a new video frame */ - if ((osd.auto_refresh & OSD_REFRESH_VIDEO) && - TIME_AFTER(tick, osd.print_tick)) { - osd.auto_refresh &= ~OSD_REFRESH_VIDEO; - stream_draw_frame(false); - } - - /* Restart playback if the timout was reached */ - if ((osd.auto_refresh & OSD_REFRESH_RESUME) && - TIME_AFTER(tick, osd.resume_tick)) { - osd.auto_refresh &= ~(OSD_REFRESH_RESUME | OSD_REFRESH_VIDEO); - stream_resume(); - } - - /* If not visible, return */ - if (!(osd.flags & OSD_SHOW)) - return; - - /* Hide if the visibility duration was reached */ - if (TIME_AFTER(tick, osd.hide_tick)) { - osd_show(OSD_HIDE); - return; - } - } else { - /* A forced update of some region */ - - /* Show if currently invisible */ - if (!(osd.flags & OSD_SHOW)) { - /* Avoid call back into this function - it will be drawn */ - osd_show(OSD_SHOW | OSD_NODRAW); - hint = OSD_REFRESH_ALL; - } - - /* Move back timeouts for frame print and hide */ - osd.print_tick = tick + osd.print_delay; - osd.hide_tick = tick + osd.show_for; - } - - if (TIME_AFTER(tick, osd.next_auto_refresh)) { - /* Refresh whatever graphical elements are due automatically */ - osd.next_auto_refresh = tick + OSD_MIN_UPDATE_INTERVAL; - - if (osd.auto_refresh & OSD_REFRESH_STATUS) { - if (osd_update_status()) - hint |= OSD_REFRESH_STATUS; - } - - if (osd.auto_refresh & OSD_REFRESH_TIME) { - osd_update_time(); - hint |= OSD_REFRESH_TIME; - } - } - - if (hint == 0) - return; /* No drawing needed */ - - /* Set basic drawing params that are used. Elements that perform variations - * will restore them. */ - oldfg = mylcd_get_foreground(); - oldbg = mylcd_get_background(); - - draw_setfont(FONT_UI); - mylcd_set_foreground(osd.fgcolor); - mylcd_set_background(osd.bgcolor); - - vo_rect_clear(&osd.update_rect); - - if (hint & OSD_REFRESH_BACKGROUND) { - osd_refresh_background(); - hint |= OSD_REFRESH_ALL; /* Requires a redraw of everything */ - } - - if (hint & OSD_REFRESH_TIME) { - osd_refresh_time(); - } - - if (hint & OSD_REFRESH_VOLUME) { - osd_refresh_volume(); - } - - if (hint & OSD_REFRESH_STATUS) { - osd_refresh_status(); - } - - /* Go back to defaults */ - draw_setfont(FONT_SYSFIXED); - mylcd_set_foreground(oldfg); - mylcd_set_background(oldbg); - - /* Update the dirty rectangle */ - vo_lock(); - - draw_update_rect(osd.update_rect.l, - osd.update_rect.t, - osd.update_rect.r - osd.update_rect.l, - osd.update_rect.b - osd.update_rect.t); - - vo_unlock(); -} - -/* Show/Hide the OSD */ -static void osd_show(unsigned show) -{ - if (((show ^ osd.flags) & OSD_SHOW) == 0) - { - if (show & OSD_SHOW) { - osd.hide_tick = *rb->current_tick + osd.show_for; - } - return; - } - - if (show & OSD_SHOW) { - /* Clip away the part of video that is covered */ - struct vo_rect rc = { 0, 0, SCREEN_WIDTH, osd.y }; - - osd.flags |= OSD_SHOW; - - if (osd.status != OSD_STATUS_PLAYING) { - /* Not playing - set brightness to mpegplayer setting */ - osd_backlight_brightness_video_mode(true); - } - - stream_vo_set_clip(&rc); - - if (!(show & OSD_NODRAW)) - osd_refresh(OSD_REFRESH_ALL); - } else { - /* Uncover clipped video area and redraw it */ - osd.flags &= ~OSD_SHOW; - - draw_clear_area(0, 0, osd.width, osd.height); - - if (!(show & OSD_NODRAW)) { - vo_lock(); - draw_update_rect(0, 0, osd.width, osd.height); - vo_unlock(); - - stream_vo_set_clip(NULL); - stream_draw_frame(false); - } else { - stream_vo_set_clip(NULL); - } - - if (osd.status != OSD_STATUS_PLAYING) { - /* Not playing - restore backlight brightness */ - osd_backlight_brightness_video_mode(false); - } - } -} - -/* Set the current status - update screen if specified */ -static void osd_set_status(int status) -{ - bool draw = (status & OSD_NODRAW) == 0; - - status &= OSD_STATUS_MASK; - - if (osd.status != status) { - - osd.status = status; - - if (draw) - osd_refresh(OSD_REFRESH_STATUS); - } -} - -/* Get the current status value */ -static int osd_get_status(void) -{ - return osd.status & OSD_STATUS_MASK; -} - -/* Handle Fast-forward/Rewind keys using WPS settings (and some nicked code ;) - * Returns last button code - */ -static int osd_ff_rw(int btn, unsigned refresh, uint32_t *new_time) -{ - unsigned int step = TS_SECOND*rb->global_settings->ff_rewind_min_step; - const long ff_rw_accel = (rb->global_settings->ff_rewind_accel + 3); - uint32_t start; - uint32_t time = stream_get_seek_time(&start); - const uint32_t duration = stream_get_duration(); - unsigned int max_step = 0; - uint32_t ff_rw_count = 0; - unsigned status = osd.status; - int new_btn; - - osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME | - OSD_REFRESH_TIME); - - time -= start; /* Absolute clock => stream-relative */ - - switch (btn) - { - case MPEG_FF: -#ifdef MPEG_FF2 - case MPEG_FF2: -#endif -#ifdef MPEG_RC_FF - case MPEG_RC_FF: -#endif - osd_set_status(OSD_STATUS_FF); - new_btn = btn | BUTTON_REPEAT; /* simplify code below */ - break; - case MPEG_RW: -#ifdef MPEG_RW2 - case MPEG_RW2: -#endif -#ifdef MPEG_RC_RW - case MPEG_RC_RW: -#endif - osd_set_status(OSD_STATUS_RW); - new_btn = btn | BUTTON_REPEAT; /* simplify code below */ - break; - default: - new_btn = BUTTON_NONE; /* Fail tests below but still do proper exit */ - } - - while (1) - { - stream_keep_disk_active(); - - if (new_btn == (btn | BUTTON_REPEAT)) { - if (osd.status == OSD_STATUS_FF) { - /* fast forwarding, calc max step relative to end */ - max_step = muldiv_uint32(duration - (time + ff_rw_count), - FF_REWIND_MAX_PERCENT, 100); - } else { - /* rewinding, calc max step relative to start */ - max_step = muldiv_uint32(time - ff_rw_count, - FF_REWIND_MAX_PERCENT, 100); - } - - max_step = MAX(max_step, MIN_FF_REWIND_STEP); - - if (step > max_step) - step = max_step; - - ff_rw_count += step; - - /* smooth seeking by multiplying step by: 1 + (2 ^ -accel) */ - step += step >> ff_rw_accel; - - if (osd.status == OSD_STATUS_FF) { - if (duration - time <= ff_rw_count) - ff_rw_count = duration - time; - - osd.curr_time = time + ff_rw_count; - } else { - if (time <= ff_rw_count) - ff_rw_count = time; - - osd.curr_time = time - ff_rw_count; - } - - osd_refresh(OSD_REFRESH_TIME); - - new_btn = mpeg_button_get(TIMEOUT_BLOCK); - } - else { - if (new_btn == (btn | BUTTON_REL)) { - if (osd.status == OSD_STATUS_FF) - time += ff_rw_count; - else if (osd.status == OSD_STATUS_RW) - time -= ff_rw_count; - } - - *new_time = time; - - osd_schedule_refresh(refresh); - osd_set_status(status); - osd_schedule_refresh(OSD_REFRESH_TIME); - - return new_btn; - } - } -} - -/* Return adjusted STREAM_* status */ -static int osd_stream_status(void) -{ - int status = stream_status(); - - /* Coerce to STREAM_PLAYING if paused with a pending resume */ - if (status == STREAM_PAUSED) { - if (osd.auto_refresh & OSD_REFRESH_RESUME) - status = STREAM_PLAYING; - } - - return status; -} - -/* Change the current audio volume by a specified amount */ -static void osd_set_volume(int delta) -{ - int vol = rb->global_settings->volume; - int limit; - - vol += delta; - - if (delta < 0) { - /* Volume down - clip to lower limit */ - limit = rb->sound_min(SOUND_VOLUME); - if (vol < limit) - vol = limit; - } else { - /* Volume up - clip to upper limit */ - limit = rb->sound_max(SOUND_VOLUME); - if (vol > limit) - vol = limit; - } - - /* Sync the global settings */ - if (vol != rb->global_settings->volume) { - rb->sound_set(SOUND_VOLUME, vol); - rb->global_settings->volume = vol; - } - - /* Update the volume display */ - osd_refresh(OSD_REFRESH_VOLUME); -} - -/* Begin playback at the specified time */ -static int osd_play(uint32_t time) -{ - int retval; - - osd_set_hp_pause_flag(false); - osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); - - retval = stream_seek(time, SEEK_SET); - - if (retval >= STREAM_OK) { - osdbacklight_hw_on_video_mode(true); - osd_backlight_brightness_video_mode(true); - stream_show_vo(true); - - retval = stream_play(); - - if (retval >= STREAM_OK) - osd_set_status(OSD_STATUS_PLAYING | OSD_NODRAW); - } - - return retval; -} - -/* Halt playback - pause engine and return logical state */ -static int osd_halt(void) -{ - int status = stream_pause(); - - /* Coerce to STREAM_PLAYING if paused with a pending resume */ - if (status == STREAM_PAUSED) { - if (osd_get_status() == OSD_STATUS_PLAYING) - status = STREAM_PLAYING; - } - - /* Cancel some auto refreshes - caller will restart them if desired */ - osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); - - /* No backlight fiddling here - callers does the right thing */ - - return status; -} - -/* Pause playback if playing */ -static int osd_pause(void) -{ - unsigned refresh = osd.auto_refresh; - int status = osd_halt(); - - osd_set_hp_pause_flag(false); - - if (status == STREAM_PLAYING && (refresh & OSD_REFRESH_RESUME)) { - /* Resume pending - change to a still video frame update */ - osd_schedule_refresh(OSD_REFRESH_VIDEO); - } - - osd_set_status(OSD_STATUS_PAUSED); - - osdbacklight_hw_on_video_mode(false); - /* Leave brightness alone and restore it when OSD is hidden */ - - if (stream_can_seek() && rb->global_settings->pause_rewind) { - stream_seek(-rb->global_settings->pause_rewind*TS_SECOND, - SEEK_CUR); - osd_schedule_refresh(OSD_REFRESH_VIDEO); - /* Update time display now */ - osd_update_time(); - osd_refresh(OSD_REFRESH_TIME); - } - - return status; -} - -/* Resume playback if halted or paused */ -static void osd_resume(void) -{ - /* Cancel video and resume auto refresh - the resyc when starting - * playback will perform those tasks */ - osd_set_hp_pause_flag(false); - osdbacklight_hw_on_video_mode(true); - osd_backlight_brightness_video_mode(true); - osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); - osd_set_status(OSD_STATUS_PLAYING); - stream_resume(); -} - -/* Stop playback - remember the resume point if not closed */ -static void osd_stop(void) -{ - uint32_t resume_time; - - osd_set_hp_pause_flag(false); - osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); - osd_set_status(OSD_STATUS_STOPPED | OSD_NODRAW); - osd_show(OSD_HIDE); - - stream_stop(); - - resume_time = stream_get_resume_time(); - - if (resume_time != INVALID_TIMESTAMP) - settings.resume_time = resume_time; - - osdbacklight_hw_on_video_mode(false); - osd_backlight_brightness_video_mode(false); -} - -/* Perform a seek by button if seeking is possible for this stream. - * - * A delay will be inserted before restarting in case the user decides to - * seek again soon after. - * - * Returns last button code - */ -static int osd_seek_btn(int btn) -{ - int status; - unsigned refresh = 0; - uint32_t time; - - if (!stream_can_seek()) - return true; - - /* Halt playback - not strictly necessary but nice when doing - * buttons */ - status = osd_halt(); - - if (status == STREAM_STOPPED) - return true; - - osd_show(OSD_SHOW); - - /* Obtain a new playback point according to the buttons */ - if (status == STREAM_PLAYING) - refresh = OSD_REFRESH_RESUME; /* delay resume if playing */ - else - refresh = OSD_REFRESH_VIDEO; /* refresh if paused */ - - btn = osd_ff_rw(btn, refresh, &time); - - /* Tell engine to resume at that time */ - stream_seek(time, SEEK_SET); - - return btn; -} - -/* Perform a seek by time if seeking is possible for this stream - * - * If playing, the seeking is immediate, otherise a delay is added to showing - * a still if paused in case the user does another seek soon after. - * - * If seeking isn't possible, a time of zero performs a skip to the - * beginning. - */ -static void osd_seek_time(uint32_t time) -{ - int status; - unsigned refresh = 0; - - if (!stream_can_seek() && time != 0) - return; - - stream_wait_status(); - status = osd_stream_status(); - - if (status == STREAM_STOPPED) - return; - - if (status == STREAM_PLAYING) /* merely preserve resume */ - refresh = osd.auto_refresh & OSD_REFRESH_RESUME; - else - refresh = OSD_REFRESH_VIDEO; /* refresh if paused */ - - /* Cancel print or resume if pending */ - osd_cancel_refresh(OSD_REFRESH_VIDEO | OSD_REFRESH_RESUME); - - /* Tell engine to seek to the given time - no state change */ - stream_seek(time, SEEK_SET); - - osd_update_time(); - osd_refresh(OSD_REFRESH_TIME); - osd_schedule_refresh(refresh); -} - -/* Has this file one of the supported extensions? */ -static bool is_videofile(const char* file) -{ - static const char * const extensions[] = - { - /* Should match apps/plugins/viewers.config */ - "mpg", "mpeg", "mpv", "m2v" - }; - - const char* ext = rb->strrchr(file, '.'); - int i; - - if (!ext) - return false; - - for (i = ARRAYLEN(extensions) - 1; i >= 0; i--) - { - if (!rb->strcasecmp(ext + 1, extensions[i])) - break; - } - - return i >= 0; -} - -/* deliver the next/previous video file in the current directory. - returns false 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 = rb->tree_get_entries(tree); - 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) -{ - if (rb->global_settings->unplug_mode == 0) - return; - - /* Wait for any incomplete state transition to complete first */ - stream_wait_status(); - - int status = osd_stream_status(); - - if (inserted) { - if (rb->global_settings->unplug_mode > 1) { - if (status == STREAM_PAUSED && - (osd.flags & OSD_HP_PAUSE)) { - osd_resume(); - } - } - } else { - if (status == STREAM_PLAYING) { - osd_pause(); - - osd_set_hp_pause_flag(true); - } - } -} -#endif - -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); - rb->lcd_set_background(LCD_BLACK); -#endif - rb->lcd_clear_display(); - rb->lcd_update(); - -#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) - rb->lcd_set_mode(LCD_MODE_YUV); -#endif - - osd_init(); - - /* Start playback at the specified starting time */ - if (osd_play(settings.resume_time) < STREAM_OK) { - rb->splash(HZ*2, "Playback failed"); - return VIDEO_STOP; - } - - /* Gently poll the video player for EOS and handle UI */ - while (stream_status() != STREAM_STOPPED) - { - int button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL/2); - - switch (button) - { - case BUTTON_NONE: - { - osd_refresh(OSD_REFRESH_DEFAULT); - continue; - } /* BUTTON_NONE: */ - -#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) - case LCD_ENABLE_EVENT_1: - { - /* Draw the current frame if prepared already */ - stream_draw_frame(true); - break; - } /* LCD_ENABLE_EVENT_1: */ -#endif - - case MPEG_VOLUP: - case MPEG_VOLUP|BUTTON_REPEAT: -#ifdef MPEG_VOLUP2 - case MPEG_VOLUP2: - case MPEG_VOLUP2|BUTTON_REPEAT: -#endif -#ifdef MPEG_RC_VOLUP - case MPEG_RC_VOLUP: - case MPEG_RC_VOLUP|BUTTON_REPEAT: -#endif - { - osd_set_volume(+1); - break; - } /* MPEG_VOLUP*: */ - - case MPEG_VOLDOWN: - case MPEG_VOLDOWN|BUTTON_REPEAT: -#ifdef MPEG_VOLDOWN2 - case MPEG_VOLDOWN2: - case MPEG_VOLDOWN2|BUTTON_REPEAT: -#endif -#ifdef MPEG_RC_VOLDOWN - case MPEG_RC_VOLDOWN: - case MPEG_RC_VOLDOWN|BUTTON_REPEAT: -#endif - { - osd_set_volume(-1); - break; - } /* MPEG_VOLDOWN*: */ - - case MPEG_MENU: -#ifdef MPEG_RC_MENU - case MPEG_RC_MENU: -#endif - { - int state = osd_halt(); /* save previous state */ - int result; - - /* Hide video output */ - osd_show(OSD_HIDE | OSD_NODRAW); - stream_show_vo(false); - osd_backlight_brightness_video_mode(false); - -#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) - rb->lcd_set_mode(LCD_MODE_RGB565); -#endif - - result = mpeg_menu(); - - next_action = (settings.play_mode == 0) ? VIDEO_STOP : VIDEO_NEXT; - - fps_update_post_frame_callback(); - - /* The menu can change the font, so restore */ - rb->lcd_setfont(FONT_SYSFIXED); -#ifdef HAVE_LCD_COLOR - rb->lcd_set_foreground(LCD_WHITE); - rb->lcd_set_background(LCD_BLACK); -#endif - rb->lcd_clear_display(); - rb->lcd_update(); - - switch (result) - { - case MPEG_MENU_QUIT: - next_action = VIDEO_STOP; - osd_stop(); - break; - - default: -#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) - rb->lcd_set_mode(LCD_MODE_YUV); -#endif - /* If not stopped, show video again */ - if (state != STREAM_STOPPED) { - osd_show(OSD_SHOW); - stream_show_vo(true); - } - - /* If stream was playing, restart it */ - if (state == STREAM_PLAYING) { - osd_resume(); - } - break; - } - break; - } /* MPEG_MENU: */ - -#ifdef MPEG_SHOW_OSD - case MPEG_SHOW_OSD: - case MPEG_SHOW_OSD | BUTTON_REPEAT: - /* Show if not visible */ - osd_show(OSD_SHOW); - /* Make sure it refreshes */ - osd_refresh(OSD_REFRESH_DEFAULT); - break; -#endif - - case MPEG_STOP: -#ifdef MPEG_RC_STOP - case MPEG_RC_STOP: -#endif - case ACTION_STD_CANCEL: - { - cancel_playback: - next_action = VIDEO_STOP; - osd_stop(); - break; - } /* MPEG_STOP: */ - - case MPEG_PAUSE: -#ifdef MPEG_PAUSE2 - case MPEG_PAUSE2: -#endif -#ifdef MPEG_RC_PAUSE - case MPEG_RC_PAUSE: -#endif - { - int status = osd_stream_status(); - - if (status == STREAM_PLAYING) { - /* Playing => Paused */ - osd_pause(); - } - else if (status == STREAM_PAUSED) { - /* Paused => Playing */ - osd_resume(); - } - - break; - } /* MPEG_PAUSE*: */ - - case MPEG_RW: -#ifdef MPEG_RW2 - case MPEG_RW2: -#endif -#ifdef MPEG_RC_RW - case MPEG_RC_RW: -#endif - { - int old_button = button; - - /* If button has been released: skip to next/previous file */ - button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL); - - if ((old_button | BUTTON_REL) == button) { - /* Check current playback position */ - osd_update_time(); - - if (settings.play_mode == 0 || osd.curr_time >= 3*TS_SECOND) { - /* Start the current video from the beginning */ - osd_seek_time(0*TS_SECOND); - } - else { - /* Release within 3 seconds of start: skip to previous - * file */ - osd_stop(); - next_action = VIDEO_PREV | VIDEO_ACTION_MANUAL; - } - } - else if ((button & ~BUTTON_REPEAT) == old_button) { - button = osd_seek_btn(old_button); - } - - if (button == ACTION_STD_CANCEL) - goto cancel_playback; /* jump to stop handling above */ - - rb->default_event_handler(button); - break; - } /* MPEG_RW: */ - - case MPEG_FF: -#ifdef MPEG_FF2 - case MPEG_FF2: -#endif -#ifdef MPEG_RC_FF - case MPEG_RC_FF: -#endif - { - int old_button = button; - - if (settings.play_mode != 0) - button = mpeg_button_get(OSD_MIN_UPDATE_INTERVAL); - - if ((old_button | BUTTON_REL) == button) { - /* If button has been released: skip to next file */ - osd_stop(); - next_action = VIDEO_NEXT | VIDEO_ACTION_MANUAL; - } - else if ((button & ~BUTTON_REPEAT) == old_button) { - button = osd_seek_btn(old_button); - } - - if (button == ACTION_STD_CANCEL) - goto cancel_playback; /* jump to stop handling above */ - - rb->default_event_handler(button); - break; - } /* MPEG_FF: */ - -#ifdef HAVE_HEADPHONE_DETECTION - case SYS_PHONE_PLUGGED: - case SYS_PHONE_UNPLUGGED: - { - osd_handle_phone_plug(button == SYS_PHONE_PLUGGED); - break; - } /* SYS_PHONE_*: */ -#endif - - default: - { - osd_refresh(OSD_REFRESH_DEFAULT); - rb->default_event_handler(button); - break; - } /* default: */ - } - - rb->yield(); - } /* end while */ - - osd_stop(); - -#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) - /* Be sure hook is removed before exiting since the stop will put it - * back because of the backlight restore. */ - rb->remove_event(LCD_EVENT_ACTIVATION, osd_lcd_enable_hook); -#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_OK; /* assume success */ - bool quit = false; - -#if defined(PLUGIN_USE_IRAM) && !defined(SIMULATOR) - bool preserved_talk_state; -#endif - - if (parameter == NULL) { - /* No file = GTFO */ - rb->splash(HZ*2, "No File"); - return PLUGIN_ERROR; - } - - /* Disable all talking before initializing IRAM */ - rb->talk_disable(true); - -#ifdef PLUGIN_USE_IRAM - iram_saving_init(); - -#ifndef SIMULATOR - preserved_talk_state = rb->global_settings->talk_menu; - if (!iram_saved_copy) - rb->global_settings->talk_menu = false; -#endif -#endif - -#ifdef HAVE_LCD_COLOR - rb->lcd_set_backdrop(NULL); - rb->lcd_set_foreground(LCD_WHITE); - rb->lcd_set_background(LCD_BLACK); -#endif - - rb->lcd_clear_display(); - rb->lcd_update(); - - rb->strcpy(videofile, (const char*) parameter); - - if (stream_init() < STREAM_OK) { - /* Fatal because this should not fail */ - DEBUGF("Could not initialize streams\n"); - status = PLUGIN_ERROR; - } else { - int next_action = VIDEO_STOP; - bool get_videofile_says = true; - - while (!quit) - { - init_settings(videofile); - - int result = stream_open(videofile); - bool manual_skip = false; - - if (result >= STREAM_OK) { - /* start menu */ - rb->lcd_clear_display(); - rb->lcd_update(); - result = mpeg_start_menu(stream_get_duration()); - - next_action = VIDEO_STOP; - if (result != MPEG_START_QUIT) { - /* Enter button loop and process UI */ - next_action = button_loop(); - manual_skip = next_action & VIDEO_ACTION_MANUAL; - next_action &= ~VIDEO_ACTION_MANUAL; - } - - stream_close(); - - rb->lcd_clear_display(); - rb->lcd_update(); - - save_settings(); - } else { - /* Problem with file; display message about it - not - * considered a plugin error */ - long tick; - const char *errstring; - - DEBUGF("Could not open %s\n", videofile); - switch (result) - { - case STREAM_UNSUPPORTED: - errstring = "Unsupported format"; - break; - default: - errstring = "Error opening file: %d"; - } - - tick = *rb->current_tick + HZ*2; - - rb->splashf(0, errstring, result); - - /* Be sure it doesn't get stuck in an unbreakable loop of bad - * files, just in case! Otherwise, keep searching in the - * chosen direction until a good one is found. */ - while (!quit && TIME_BEFORE(*rb->current_tick, tick)) - { - int button = mpeg_button_get(HZ*2); - - switch (button) - { - case MPEG_STOP: - case ACTION_STD_CANCEL: - /* Abort the search and exit */ - next_action = VIDEO_STOP; - quit = true; - break; - - case BUTTON_NONE: - if (settings.play_mode != 0) { - if (next_action == VIDEO_STOP) { - /* Default to next file */ - next_action = VIDEO_NEXT; - } - else if (next_action == VIDEO_PREV && - !get_videofile_says) { - /* Was first file already; avoid endlessly - * retrying it */ - next_action = VIDEO_STOP; - } - } - break; - - default: - rb->default_event_handler(button); - } /* switch */ - } /* while */ - } - - /* return value of button_loop says, what's next */ - switch (next_action) - { - case VIDEO_NEXT: - { - get_videofile_says = get_videofile(VIDEO_NEXT, videofile, - sizeof(videofile)); - /* quit after finished the last videofile */ - quit = !get_videofile_says; - - if (manual_skip) - { - rb->system_sound_play(get_videofile_says ? - SOUND_TRACK_SKIP : SOUND_TRACK_NO_MORE); - } - - break; - } - case VIDEO_PREV: - { - get_videofile_says = get_videofile(VIDEO_PREV, videofile, - sizeof(videofile)); - /* if there is no previous file, play the same videofile */ - - if (manual_skip) - { - rb->system_sound_play(get_videofile_says ? - SOUND_TRACK_SKIP : SOUND_TRACK_NO_MORE); - } - - break; - } - case VIDEO_STOP: - { - quit = true; - break; - } - } - } /* while */ - } - -#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_YUV) - rb->lcd_set_mode(LCD_MODE_RGB565); -#endif - - stream_exit(); - -#if defined(PLUGIN_USE_IRAM) && !defined(SIMULATOR) - if (!iram_saved_copy) - rb->global_settings->talk_menu = preserved_talk_state; -#endif - - rb->talk_disable(false); - - /* Actually handle delayed processing of system events of interest - * that were captured in other button loops */ - mpeg_sysevent_handle(); - - return status; -} -- cgit v1.2.3