diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-01-03 17:14:28 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-01-03 17:14:28 +0000 |
commit | a5fc3f4df4bec2b6ae1c22fb83cf495f31773122 (patch) | |
tree | ba78abac0ee9e5d564907d9e8bee4020d98cb9a8 /apps/plugins/mpegplayer | |
parent | d1cb32a93f26ef42ae864b911bbd425c49cc4109 (diff) | |
download | rockbox-a5fc3f4df4bec2b6ae1c22fb83cf495f31773122.tar.gz rockbox-a5fc3f4df4bec2b6ae1c22fb83cf495f31773122.zip |
Initial WVS for mpegplayer. Adjusts to the user's preferred font and uses FF/RW preferences set for playback. Picked a random color for the base WVS color but it could be configured. Some engine tweaks to accomodate it since certain nescessities are clearer now. Fix a clipped YUV output bug in the SIM.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15991 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/mpegplayer')
-rw-r--r-- | apps/plugins/mpegplayer/Makefile | 4 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/audio_thread.c | 3 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/disk_buf.h | 3 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpeg_parser.c | 6 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/mpegplayer.c | 1066 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/stream_mgr.c | 133 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/stream_mgr.h | 10 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/stream_thread.h | 1 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/video_out.h | 25 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/video_out_rockbox.c | 171 | ||||
-rw-r--r-- | apps/plugins/mpegplayer/video_thread.c | 9 |
11 files changed, 1329 insertions, 102 deletions
diff --git a/apps/plugins/mpegplayer/Makefile b/apps/plugins/mpegplayer/Makefile index c43dde04bc..97c9e6a919 100644 --- a/apps/plugins/mpegplayer/Makefile +++ b/apps/plugins/mpegplayer/Makefile | |||
@@ -43,7 +43,7 @@ libmad-mpegplayer: | |||
43 | ifndef SIMVER | 43 | ifndef SIMVER |
44 | $(OBJDIR)/mpegplayer.elf: $(OBJS) $(LINKFILE) $(BUILDDIR)/libmad-mpegplayer.a | 44 | $(OBJDIR)/mpegplayer.elf: $(OBJS) $(LINKFILE) $(BUILDDIR)/libmad-mpegplayer.a |
45 | $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lmad-mpegplayer -lgcc\ | 45 | $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lmad-mpegplayer -lgcc\ |
46 | -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/mpegplayer.map | 46 | $(LINKBITMAPS) -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/mpegplayer.map |
47 | 47 | ||
48 | $(OUTPUT): $(OBJDIR)/mpegplayer.elf | 48 | $(OUTPUT): $(OBJDIR)/mpegplayer.elf |
49 | $(call PRINTS,OBJCOPY $(@F))$(OC) -O binary $< $@ | 49 | $(call PRINTS,OBJCOPY $(@F))$(OC) -O binary $< $@ |
@@ -51,7 +51,7 @@ else | |||
51 | # This is the SDL simulator version | 51 | # This is the SDL simulator version |
52 | 52 | ||
53 | $(OUTPUT): $(OBJS) $(BUILDDIR)/libmad-mpegplayer.a | 53 | $(OUTPUT): $(OBJS) $(BUILDDIR)/libmad-mpegplayer.a |
54 | $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin -lmad-mpegplayer -o $@ | 54 | $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) $(SHARED_FLAG) $(OBJS) -L$(BUILDDIR) -lplugin $(LINKBITMAPS) -lmad-mpegplayer -o $@ |
55 | ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) | 55 | ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) |
56 | # 'x' must be kept or you'll have "Win32 error 5" | 56 | # 'x' must be kept or you'll have "Win32 error 5" |
57 | # $ fgrep 5 /usr/include/w32api/winerror.h | head -1 | 57 | # $ fgrep 5 /usr/include/w32api/winerror.h | head -1 |
diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c index ee6ff05d2d..78d28e40c5 100644 --- a/apps/plugins/mpegplayer/audio_thread.c +++ b/apps/plugins/mpegplayer/audio_thread.c | |||
@@ -140,9 +140,8 @@ static void audio_queue_reset(void) | |||
140 | audio_queue.used = 0; | 140 | audio_queue.used = 0; |
141 | audio_queue.read = 0; | 141 | audio_queue.read = 0; |
142 | audio_queue.write = 0; | 142 | audio_queue.write = 0; |
143 | rb->memset(audio_queue.descs, 0, sizeof (audio_queue.descs)); | ||
143 | audio_queue.curr = audiodesc_queue_head(); | 144 | audio_queue.curr = audiodesc_queue_head(); |
144 | audio_queue.curr->time = 0; | ||
145 | audio_queue.curr->size = 0; | ||
146 | } | 145 | } |
147 | 146 | ||
148 | static void audio_queue_advance_pos(ssize_t len) | 147 | static void audio_queue_advance_pos(ssize_t len) |
diff --git a/apps/plugins/mpegplayer/disk_buf.h b/apps/plugins/mpegplayer/disk_buf.h index 90e72fac2f..79c3328535 100644 --- a/apps/plugins/mpegplayer/disk_buf.h +++ b/apps/plugins/mpegplayer/disk_buf.h | |||
@@ -104,6 +104,9 @@ static inline bool disk_buf_is_data_ready(struct stream_hdr *sh, | |||
104 | bool disk_buf_init(void); | 104 | bool disk_buf_init(void); |
105 | void disk_buf_exit(void); | 105 | void disk_buf_exit(void); |
106 | 106 | ||
107 | static inline int disk_buf_status(void) | ||
108 | { return disk_buf.status; } | ||
109 | |||
107 | int disk_buf_open(const char *filename); | 110 | int disk_buf_open(const char *filename); |
108 | void disk_buf_close(void); | 111 | void disk_buf_close(void); |
109 | ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap, | 112 | ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap, |
diff --git a/apps/plugins/mpegplayer/mpeg_parser.c b/apps/plugins/mpegplayer/mpeg_parser.c index d4b0ff10fb..5b863dabac 100644 --- a/apps/plugins/mpegplayer/mpeg_parser.c +++ b/apps/plugins/mpegplayer/mpeg_parser.c | |||
@@ -1012,15 +1012,17 @@ intptr_t parser_send_video_msg(long id, intptr_t data) | |||
1012 | switch (id) | 1012 | switch (id) |
1013 | { | 1013 | { |
1014 | case VIDEO_DISPLAY_SHOW: | 1014 | case VIDEO_DISPLAY_SHOW: |
1015 | if (data != 0 && stream_status() != STREAM_PLAYING) | 1015 | if (data != 0 && disk_buf_status() == STREAM_STOPPED) |
1016 | { /* Only prepare image if showing and not playing */ | 1016 | { /* Only prepare image if showing and not playing */ |
1017 | prepare_image(str_parser.last_seek_time); | 1017 | prepare_image(str_parser.last_seek_time); |
1018 | } | 1018 | } |
1019 | break; | 1019 | break; |
1020 | 1020 | ||
1021 | case VIDEO_PRINT_FRAME: | 1021 | case VIDEO_PRINT_FRAME: |
1022 | if (data) | ||
1023 | break; | ||
1022 | case VIDEO_PRINT_THUMBNAIL: | 1024 | case VIDEO_PRINT_THUMBNAIL: |
1023 | if (stream_status() == STREAM_PLAYING) | 1025 | if (disk_buf_status() != STREAM_STOPPED) |
1024 | break; /* Prepare image if not playing */ | 1026 | break; /* Prepare image if not playing */ |
1025 | 1027 | ||
1026 | if (!prepare_image(str_parser.last_seek_time)) | 1028 | if (!prepare_image(str_parser.last_seek_time)) |
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index 03ec5ba821..e9f6b9011f 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c | |||
@@ -116,6 +116,8 @@ PLUGIN_IRAM_DECLARE | |||
116 | #define MPEG_PAUSE BUTTON_ON | 116 | #define MPEG_PAUSE BUTTON_ON |
117 | #define MPEG_VOLDOWN BUTTON_DOWN | 117 | #define MPEG_VOLDOWN BUTTON_DOWN |
118 | #define MPEG_VOLUP BUTTON_UP | 118 | #define MPEG_VOLUP BUTTON_UP |
119 | #define MPEG_RW BUTTON_LEFT | ||
120 | #define MPEG_FF BUTTON_RIGHT | ||
119 | 121 | ||
120 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ | 122 | #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ |
121 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) | 123 | (CONFIG_KEYPAD == IPOD_1G2G_PAD) |
@@ -124,6 +126,8 @@ PLUGIN_IRAM_DECLARE | |||
124 | #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) | 126 | #define MPEG_STOP (BUTTON_PLAY | BUTTON_REPEAT) |
125 | #define MPEG_VOLDOWN BUTTON_SCROLL_BACK | 127 | #define MPEG_VOLDOWN BUTTON_SCROLL_BACK |
126 | #define MPEG_VOLUP BUTTON_SCROLL_FWD | 128 | #define MPEG_VOLUP BUTTON_SCROLL_FWD |
129 | #define MPEG_RW BUTTON_LEFT | ||
130 | #define MPEG_FF BUTTON_RIGHT | ||
127 | 131 | ||
128 | #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD | 132 | #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD |
129 | #define MPEG_MENU (BUTTON_REC | BUTTON_REL) | 133 | #define MPEG_MENU (BUTTON_REC | BUTTON_REL) |
@@ -131,6 +135,8 @@ PLUGIN_IRAM_DECLARE | |||
131 | #define MPEG_PAUSE BUTTON_PLAY | 135 | #define MPEG_PAUSE BUTTON_PLAY |
132 | #define MPEG_VOLDOWN BUTTON_DOWN | 136 | #define MPEG_VOLDOWN BUTTON_DOWN |
133 | #define MPEG_VOLUP BUTTON_UP | 137 | #define MPEG_VOLUP BUTTON_UP |
138 | #define MPEG_RW BUTTON_LEFT | ||
139 | #define MPEG_FF BUTTON_RIGHT | ||
134 | 140 | ||
135 | #elif CONFIG_KEYPAD == GIGABEAT_PAD | 141 | #elif CONFIG_KEYPAD == GIGABEAT_PAD |
136 | #define MPEG_MENU BUTTON_MENU | 142 | #define MPEG_MENU BUTTON_MENU |
@@ -141,13 +147,17 @@ PLUGIN_IRAM_DECLARE | |||
141 | #define MPEG_VOLUP BUTTON_RIGHT | 147 | #define MPEG_VOLUP BUTTON_RIGHT |
142 | #define MPEG_VOLDOWN2 BUTTON_VOL_DOWN | 148 | #define MPEG_VOLDOWN2 BUTTON_VOL_DOWN |
143 | #define MPEG_VOLUP2 BUTTON_VOL_UP | 149 | #define MPEG_VOLUP2 BUTTON_VOL_UP |
150 | #define MPEG_RW BUTTON_UP | ||
151 | #define MPEG_FF BUTTON_DOWN | ||
144 | 152 | ||
145 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD | 153 | #elif CONFIG_KEYPAD == IRIVER_H10_PAD |
146 | #define MPEG_MENU (BUTTON_REW | BUTTON_REL) | 154 | #define MPEG_MENU BUTTON_LEFT |
147 | #define MPEG_STOP BUTTON_POWER | 155 | #define MPEG_STOP BUTTON_POWER |
148 | #define MPEG_PAUSE BUTTON_PLAY | 156 | #define MPEG_PAUSE BUTTON_PLAY |
149 | #define MPEG_VOLDOWN BUTTON_SCROLL_DOWN | 157 | #define MPEG_VOLDOWN BUTTON_SCROLL_DOWN |
150 | #define MPEG_VOLUP BUTTON_SCROLL_UP | 158 | #define MPEG_VOLUP BUTTON_SCROLL_UP |
159 | #define MPEG_RW BUTTON_REW | ||
160 | #define MPEG_FF BUTTON_FF | ||
151 | 161 | ||
152 | #elif CONFIG_KEYPAD == SANSA_E200_PAD | 162 | #elif CONFIG_KEYPAD == SANSA_E200_PAD |
153 | #define MPEG_MENU BUTTON_SELECT | 163 | #define MPEG_MENU BUTTON_SELECT |
@@ -155,6 +165,8 @@ PLUGIN_IRAM_DECLARE | |||
155 | #define MPEG_PAUSE BUTTON_UP | 165 | #define MPEG_PAUSE BUTTON_UP |
156 | #define MPEG_VOLDOWN BUTTON_SCROLL_UP | 166 | #define MPEG_VOLDOWN BUTTON_SCROLL_UP |
157 | #define MPEG_VOLUP BUTTON_SCROLL_DOWN | 167 | #define MPEG_VOLUP BUTTON_SCROLL_DOWN |
168 | #define MPEG_RW BUTTON_LEFT | ||
169 | #define MPEG_FF BUTTON_RIGHT | ||
158 | 170 | ||
159 | #elif CONFIG_KEYPAD == SANSA_C200_PAD | 171 | #elif CONFIG_KEYPAD == SANSA_C200_PAD |
160 | #define MPEG_MENU BUTTON_SELECT | 172 | #define MPEG_MENU BUTTON_SELECT |
@@ -162,6 +174,8 @@ PLUGIN_IRAM_DECLARE | |||
162 | #define MPEG_PAUSE BUTTON_UP | 174 | #define MPEG_PAUSE BUTTON_UP |
163 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN | 175 | #define MPEG_VOLDOWN BUTTON_VOL_DOWN |
164 | #define MPEG_VOLUP BUTTON_VOL_UP | 176 | #define MPEG_VOLUP BUTTON_VOL_UP |
177 | #define MPEG_RW BUTTON_LEFT | ||
178 | #define MPEG_FF BUTTON_RIGHT | ||
165 | 179 | ||
166 | #elif CONFIG_KEYPAD == MROBE500_PAD | 180 | #elif CONFIG_KEYPAD == MROBE500_PAD |
167 | #define MPEG_MENU BUTTON_RC_HEART | 181 | #define MPEG_MENU BUTTON_RC_HEART |
@@ -169,6 +183,8 @@ PLUGIN_IRAM_DECLARE | |||
169 | #define MPEG_PAUSE BUTTON_TOUCHPAD | 183 | #define MPEG_PAUSE BUTTON_TOUCHPAD |
170 | #define MPEG_VOLDOWN BUTTON_RC_VOL_DOWN | 184 | #define MPEG_VOLDOWN BUTTON_RC_VOL_DOWN |
171 | #define MPEG_VOLUP BUTTON_RC_VOL_UP | 185 | #define MPEG_VOLUP BUTTON_RC_VOL_UP |
186 | #define MPEG_RW BUTTON_RC_REW | ||
187 | #define MPEG_FF BUTTON_RC_FF | ||
172 | 188 | ||
173 | #else | 189 | #else |
174 | #error MPEGPLAYER: Unsupported keypad | 190 | #error MPEGPLAYER: Unsupported keypad |
@@ -179,31 +195,997 @@ struct plugin_api* rb; | |||
179 | CACHE_FUNCTION_WRAPPERS(rb); | 195 | CACHE_FUNCTION_WRAPPERS(rb); |
180 | ALIGN_BUFFER_WRAPPER(rb); | 196 | ALIGN_BUFFER_WRAPPER(rb); |
181 | 197 | ||
182 | static bool button_loop(void) | 198 | /* One thing we can do here for targets with remotes is having a display |
199 | * always on the remote instead of always forcing a popup on the main display */ | ||
200 | |||
201 | #define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */ | ||
202 | /* 3% of 30min file == 54s step size */ | ||
203 | #define MIN_FF_REWIND_STEP (TS_SECOND/2) | ||
204 | #define WVS_MIN_UPDATE_INTERVAL (HZ/2) | ||
205 | |||
206 | /* WVS status - same order as icon array */ | ||
207 | enum wvs_status_enum | ||
208 | { | ||
209 | WVS_STATUS_STOPPED = 0, | ||
210 | WVS_STATUS_PAUSED, | ||
211 | WVS_STATUS_PLAYING, | ||
212 | WVS_STATUS_FF, | ||
213 | WVS_STATUS_RW, | ||
214 | WVS_STATUS_COUNT, | ||
215 | WVS_STATUS_MASK = 0x7 | ||
216 | }; | ||
217 | |||
218 | enum wvs_bits | ||
183 | { | 219 | { |
184 | bool ret = true; | 220 | WVS_REFRESH_DEFAULT = 0x0000, |
221 | WVS_REFRESH_VOLUME = 0x0001, | ||
222 | WVS_REFRESH_TIME = 0x0002, | ||
223 | WVS_REFRESH_STATUS = 0x0004, | ||
224 | WVS_REFRESH_BACKGROUND = 0x0008, | ||
225 | WVS_REFRESH_VIDEO = 0x0010, | ||
226 | WVS_REFRESH_RESUME = 0x0020, | ||
227 | WVS_NODRAW = 0x8000, | ||
228 | WVS_SHOW = 0x4000, | ||
229 | WVS_HIDE = 0x0000, | ||
230 | WVS_REFRESH_ALL = 0x001f, | ||
231 | }; | ||
232 | |||
233 | extern const unsigned char mpegplayer_status_icons_8x8x1[]; | ||
234 | extern const unsigned char mpegplayer_status_icons_12x12x1[]; | ||
235 | extern const unsigned char mpegplayer_status_icons_16x16x1[]; | ||
236 | |||
237 | #define WVS_BDR_L 2 | ||
238 | #define WVS_BDR_T 2 | ||
239 | #define WVS_BDR_R 2 | ||
240 | #define WVS_BDR_B 2 | ||
241 | |||
242 | struct wvs | ||
243 | { | ||
244 | long hide_tick; | ||
245 | long show_for; | ||
246 | long print_tick; | ||
247 | long print_delay; | ||
248 | long resume_tick; | ||
249 | long resume_delay; | ||
250 | long next_auto_refresh; | ||
251 | int x; | ||
252 | int y; | ||
253 | int width; | ||
254 | int height; | ||
255 | unsigned fgcolor; | ||
256 | unsigned bgcolor; | ||
257 | #ifdef HAVE_LCD_COLOR | ||
258 | unsigned prog_fillcolor; | ||
259 | struct vo_rect update_rect; | ||
260 | #endif | ||
261 | struct vo_rect prog_rect; | ||
262 | struct vo_rect time_rect; | ||
263 | struct vo_rect dur_rect; | ||
264 | struct vo_rect vol_rect; | ||
265 | const unsigned char *icons; | ||
266 | struct vo_rect stat_rect; | ||
267 | int status; | ||
268 | uint32_t curr_time; | ||
269 | unsigned auto_refresh; | ||
270 | unsigned flags; | ||
271 | }; | ||
272 | |||
273 | static struct wvs wvs; | ||
274 | |||
275 | static void wvs_show(unsigned show); | ||
276 | |||
277 | #ifdef LCD_LANDSCAPE | ||
278 | #define _X (x + wvs.x) | ||
279 | #define _Y (y + wvs.y) | ||
280 | #define _W width | ||
281 | #define _H height | ||
282 | #else | ||
283 | #define _X (LCD_WIDTH - (y + wvs.y) - height) | ||
284 | #define _Y (x + wvs.x) | ||
285 | #define _W height | ||
286 | #define _H width | ||
287 | #endif | ||
288 | |||
289 | #ifdef HAVE_LCD_COLOR | ||
290 | static unsigned draw_blendcolor(unsigned c1, unsigned c2, unsigned char amount) | ||
291 | { | ||
292 | int r1 = RGB_UNPACK_RED(c1); | ||
293 | int g1 = RGB_UNPACK_GREEN(c1); | ||
294 | int b1 = RGB_UNPACK_BLUE(c1); | ||
295 | |||
296 | int r2 = RGB_UNPACK_RED(c2); | ||
297 | int g2 = RGB_UNPACK_GREEN(c2); | ||
298 | int b2 = RGB_UNPACK_BLUE(c2); | ||
299 | |||
300 | return LCD_RGBPACK(amount*(r2 - r1) / 255 + r1, | ||
301 | amount*(g2 - g1) / 255 + g1, | ||
302 | amount*(b2 - b1) / 255 + b1); | ||
303 | } | ||
304 | #endif | ||
305 | |||
306 | static void draw_fill_rect(int x, int y, int width, int height) | ||
307 | { | ||
308 | rb->lcd_fillrect(_X, _Y, _W, _H); | ||
309 | } | ||
310 | |||
311 | #ifdef HAVE_LCD_COLOR | ||
312 | static void draw_update_rect(int x, int y, int width, int height) | ||
313 | { | ||
314 | rb->lcd_update_rect(_X, _Y, _W, _H); | ||
315 | } | ||
316 | #endif | ||
317 | |||
318 | static void draw_clear_area(int x, int y, int width, int height) | ||
319 | { | ||
320 | rb->screen_clear_area(rb->screens[SCREEN_MAIN], _X, _Y, _W, _H); | ||
321 | } | ||
322 | |||
323 | static void draw_clear_area_rect(const struct vo_rect *rc) | ||
324 | { | ||
325 | int x = rc->l; | ||
326 | int y = rc->t; | ||
327 | int width = rc->r - rc->l; | ||
328 | int height = rc->b - rc->t; | ||
329 | rb->screen_clear_area(rb->screens[SCREEN_MAIN], _X, _Y, _W, _H); | ||
330 | } | ||
331 | |||
332 | static void draw_scrollbar_draw(int x, int y, int width, int height, | ||
333 | int items, int min_shown, int max_shown) | ||
334 | { | ||
335 | #ifdef HAVE_LCD_COLOR | ||
336 | int oldbg = rb->lcd_get_background(); | ||
337 | rb->lcd_set_background(wvs.prog_fillcolor); | ||
338 | #endif | ||
339 | |||
340 | rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN], _X, _Y, | ||
341 | _W, _H, items, min_shown, max_shown, | ||
342 | 0 | ||
343 | #ifdef LCD_LANDSCAPE | ||
344 | | HORIZONTAL | ||
345 | #endif | ||
346 | #ifdef HAVE_LCD_COLOR | ||
347 | | INNER_BGFILL | FOREGROUND | ||
348 | #endif | ||
349 | ); | ||
350 | |||
351 | #ifdef HAVE_LCD_COLOR | ||
352 | rb->lcd_set_background(oldbg); | ||
353 | #endif | ||
354 | } | ||
355 | |||
356 | static void draw_scrollbar_draw_rect(const struct vo_rect *rc, int items, | ||
357 | int min_shown, int max_shown) | ||
358 | { | ||
359 | draw_scrollbar_draw(rc->l, rc->t, rc->r - rc->l, rc->b - rc->t, | ||
360 | items, min_shown, max_shown); | ||
361 | } | ||
362 | |||
363 | static void draw_hline(int x1, int x2, int y) | ||
364 | { | ||
365 | #ifdef LCD_LANDSCAPE | ||
366 | rb->lcd_hline(x1 + wvs.x, x2 + wvs.x, y + wvs.y); | ||
367 | #else | ||
368 | y = LCD_WIDTH - (y + wvs.y) - 1; | ||
369 | rb->lcd_vline(y, x1 + wvs.x, x2 + wvs.x); | ||
370 | #endif | ||
371 | } | ||
372 | |||
373 | #ifdef LCD_PORTRAIT | ||
374 | /* Portrait displays need rotated text rendering */ | ||
375 | |||
376 | /* Limited function that only renders in DRMODE_FG */ | ||
377 | static void draw_oriented_mono_bitmap_part(const unsigned char *src, | ||
378 | int src_x, int src_y, | ||
379 | int stride, int x, int y, | ||
380 | int width, int height) | ||
381 | { | ||
382 | const unsigned char *src_end; | ||
383 | fb_data *dst, *dst_end; | ||
384 | unsigned fg_pattern, bg_pattern; | ||
385 | |||
386 | if (x + width > SCREEN_WIDTH) | ||
387 | width = SCREEN_WIDTH - x; /* Clip right */ | ||
388 | if (x < 0) | ||
389 | width += x, x = 0; /* Clip left */ | ||
390 | if (width <= 0) | ||
391 | return; /* nothing left to do */ | ||
392 | |||
393 | if (y + height > SCREEN_HEIGHT) | ||
394 | height = SCREEN_HEIGHT - y; /* Clip bottom */ | ||
395 | if (y < 0) | ||
396 | height += y, y = 0; /* Clip top */ | ||
397 | if (height <= 0) | ||
398 | return; /* nothing left to do */ | ||
399 | |||
400 | fg_pattern = rb->lcd_get_foreground(); | ||
401 | bg_pattern = rb->lcd_get_background(); | ||
402 | |||
403 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
404 | src_y &= 7; | ||
405 | src_end = src + width; | ||
406 | |||
407 | dst = rb->lcd_framebuffer + (LCD_WIDTH - y) + x*LCD_WIDTH; | ||
408 | do | ||
409 | { | ||
410 | const unsigned char *src_col = src++; | ||
411 | unsigned data = *src_col >> src_y; | ||
412 | int numbits = 8 - src_y; | ||
413 | |||
414 | fb_data *dst_col = dst; | ||
415 | dst_end = dst_col - height; | ||
416 | dst += LCD_WIDTH; | ||
417 | |||
418 | do | ||
419 | { | ||
420 | dst_col--; | ||
421 | |||
422 | if (data & 1) | ||
423 | *dst_col = fg_pattern; | ||
424 | #if 0 | ||
425 | else | ||
426 | *dst_col = bg_pattern; | ||
427 | #endif | ||
428 | data >>= 1; | ||
429 | if (--numbits == 0) { | ||
430 | src_col += stride; | ||
431 | data = *src_col; | ||
432 | numbits = 8; | ||
433 | } | ||
434 | } | ||
435 | while (dst_col > dst_end); | ||
436 | } | ||
437 | while (src < src_end); | ||
438 | } | ||
439 | |||
440 | static void draw_putsxy_oriented(int x, int y, const char *str) | ||
441 | { | ||
442 | unsigned short ch; | ||
443 | unsigned short *ucs; | ||
444 | int ofs = MIN(x, 0); | ||
445 | struct font* pf = rb->font_get(FONT_UI); | ||
446 | |||
447 | ucs = rb->bidi_l2v(str, 1); | ||
448 | |||
449 | x += wvs.x; | ||
450 | y += wvs.y; | ||
451 | |||
452 | while ((ch = *ucs++) != 0 && x < SCREEN_WIDTH) | ||
453 | { | ||
454 | int width; | ||
455 | const unsigned char *bits; | ||
456 | |||
457 | /* get proportional width and glyph bits */ | ||
458 | width = rb->font_get_width(pf, ch); | ||
459 | |||
460 | if (ofs > width) { | ||
461 | ofs -= width; | ||
462 | continue; | ||
463 | } | ||
464 | |||
465 | bits = rb->font_get_bits(pf, ch); | ||
466 | |||
467 | draw_oriented_mono_bitmap_part(bits, ofs, 0, width, x, y, | ||
468 | width - ofs, pf->height); | ||
469 | |||
470 | x += width - ofs; | ||
471 | ofs = 0; | ||
472 | } | ||
473 | } | ||
474 | #else | ||
475 | static void draw_oriented_mono_bitmap_part(const unsigned char *src, | ||
476 | int src_x, int src_y, | ||
477 | int stride, int x, int y, | ||
478 | int width, int height) | ||
479 | { | ||
480 | int mode = rb->lcd_get_drawmode(); | ||
481 | rb->lcd_set_drawmode(DRMODE_FG); | ||
482 | rb->lcd_mono_bitmap_part(src, src_x, src_y, stride, x, y, width, height); | ||
483 | rb->lcd_set_drawmode(mode); | ||
484 | } | ||
485 | |||
486 | static void draw_putsxy_oriented(int x, int y, const char *str) | ||
487 | { | ||
488 | int mode = rb->lcd_get_drawmode(); | ||
489 | rb->lcd_set_drawmode(DRMODE_FG); | ||
490 | rb->lcd_putsxy(x + wvs.x, y + wvs.y, str); | ||
491 | rb->lcd_set_drawmode(mode); | ||
492 | } | ||
493 | #endif /* LCD_PORTRAIT */ | ||
494 | |||
495 | |||
496 | static void wvs_text_init(void) | ||
497 | { | ||
498 | struct hms hms; | ||
499 | char buf[32]; | ||
500 | int phys; | ||
501 | int spc_width; | ||
502 | |||
503 | rb->lcd_setfont(FONT_UI); | ||
504 | |||
505 | wvs.x = 0; | ||
506 | wvs.width = SCREEN_WIDTH; | ||
507 | |||
508 | vo_rect_clear(&wvs.time_rect); | ||
509 | vo_rect_clear(&wvs.stat_rect); | ||
510 | vo_rect_clear(&wvs.prog_rect); | ||
511 | vo_rect_clear(&wvs.vol_rect); | ||
512 | |||
513 | ts_to_hms(stream_get_duration(), &hms); | ||
514 | hms_format(buf, sizeof (buf), &hms); | ||
515 | rb->lcd_getstringsize(buf, &wvs.time_rect.r, | ||
516 | &wvs.time_rect.b); | ||
517 | |||
518 | /* Choose well-sized bitmap images relative to font height */ | ||
519 | if (wvs.time_rect.b < 12) { | ||
520 | wvs.icons = mpegplayer_status_icons_8x8x1; | ||
521 | wvs.stat_rect.r = wvs.stat_rect.b = 8; | ||
522 | } else if (wvs.time_rect.b < 16) { | ||
523 | wvs.icons = mpegplayer_status_icons_12x12x1; | ||
524 | wvs.stat_rect.r = wvs.stat_rect.b = 12; | ||
525 | } else { | ||
526 | wvs.icons = mpegplayer_status_icons_16x16x1; | ||
527 | wvs.stat_rect.r = wvs.stat_rect.b = 16; | ||
528 | } | ||
529 | |||
530 | if (wvs.stat_rect.b < wvs.time_rect.b) { | ||
531 | vo_rect_offset(&wvs.stat_rect, 0, | ||
532 | (wvs.time_rect.b - wvs.stat_rect.b) / 2 + WVS_BDR_T); | ||
533 | vo_rect_offset(&wvs.time_rect, WVS_BDR_L, WVS_BDR_T); | ||
534 | } else { | ||
535 | vo_rect_offset(&wvs.time_rect, WVS_BDR_L, | ||
536 | wvs.stat_rect.b - wvs.time_rect.b + WVS_BDR_T); | ||
537 | vo_rect_offset(&wvs.stat_rect, 0, WVS_BDR_T); | ||
538 | } | ||
539 | |||
540 | wvs.dur_rect = wvs.time_rect; | ||
541 | |||
542 | phys = rb->sound_val2phys(SOUND_VOLUME, rb->sound_min(SOUND_VOLUME)); | ||
543 | rb->snprintf(buf, sizeof(buf), "%d%s", phys, | ||
544 | rb->sound_unit(SOUND_VOLUME)); | ||
545 | |||
546 | rb->lcd_getstringsize(" ", &spc_width, NULL); | ||
547 | rb->lcd_getstringsize(buf, &wvs.vol_rect.r, &wvs.vol_rect.b); | ||
548 | |||
549 | wvs.prog_rect.r = SCREEN_WIDTH - WVS_BDR_L - spc_width - | ||
550 | wvs.vol_rect.r - WVS_BDR_R; | ||
551 | wvs.prog_rect.b = 3*wvs.stat_rect.b / 4; | ||
552 | vo_rect_offset(&wvs.prog_rect, wvs.time_rect.l, | ||
553 | wvs.time_rect.b); | ||
554 | |||
555 | vo_rect_offset(&wvs.stat_rect, | ||
556 | (wvs.prog_rect.r + wvs.prog_rect.l - wvs.stat_rect.r) / 2, | ||
557 | 0); | ||
558 | |||
559 | vo_rect_offset(&wvs.dur_rect, | ||
560 | wvs.prog_rect.r - wvs.dur_rect.r, 0); | ||
561 | |||
562 | vo_rect_offset(&wvs.vol_rect, wvs.prog_rect.r + spc_width, | ||
563 | (wvs.prog_rect.b + wvs.prog_rect.t - wvs.vol_rect.b) / 2); | ||
564 | |||
565 | wvs.height = WVS_BDR_T + MAX(wvs.prog_rect.b, wvs.vol_rect.b) - | ||
566 | MIN(wvs.time_rect.t, wvs.stat_rect.t) + WVS_BDR_B; | ||
567 | |||
568 | #if LCD_PIXELFORMAT == VERTICAL_PACKING | ||
569 | wvs.height = ALIGN_UP(wvs.height, 8); | ||
570 | #else | ||
571 | wvs.height = ALIGN_UP(wvs.height, 2); | ||
572 | #endif | ||
573 | wvs.y = SCREEN_HEIGHT - wvs.height; | ||
185 | 574 | ||
186 | rb->lcd_setfont(FONT_SYSFIXED); | 575 | rb->lcd_setfont(FONT_SYSFIXED); |
576 | } | ||
577 | |||
578 | static void wvs_init(void) | ||
579 | { | ||
580 | wvs.flags = 0; | ||
581 | wvs.show_for = HZ*4; | ||
582 | wvs.print_delay = 75*HZ/100; | ||
583 | wvs.resume_delay = HZ/2; | ||
584 | #ifdef HAVE_LCD_COLOR | ||
585 | wvs.bgcolor = LCD_RGBPACK(0x73, 0x75, 0xbd); | ||
586 | wvs.fgcolor = LCD_WHITE; | ||
587 | wvs.prog_fillcolor = LCD_BLACK; | ||
588 | #else | ||
589 | wvs.bgcolor = LCD_LIGHTGRAY; | ||
590 | wvs.fgcolor = LCD_BLACK; | ||
591 | #endif | ||
592 | wvs.curr_time = 0; | ||
593 | wvs.status = WVS_STATUS_STOPPED; | ||
594 | wvs.auto_refresh = WVS_REFRESH_TIME; | ||
595 | wvs.next_auto_refresh = *rb->current_tick; | ||
596 | wvs_text_init(); | ||
597 | } | ||
598 | |||
599 | static void wvs_schedule_refresh(unsigned refresh) | ||
600 | { | ||
601 | long tick = *rb->current_tick; | ||
602 | |||
603 | if (refresh & WVS_REFRESH_VIDEO) | ||
604 | wvs.print_tick = tick + wvs.print_delay; | ||
605 | |||
606 | if (refresh & WVS_REFRESH_RESUME) | ||
607 | wvs.resume_tick = tick + wvs.resume_delay; | ||
608 | |||
609 | wvs.auto_refresh |= refresh; | ||
610 | } | ||
611 | |||
612 | static void wvs_cancel_refresh(unsigned refresh) | ||
613 | { | ||
614 | wvs.auto_refresh &= ~refresh; | ||
615 | } | ||
616 | |||
617 | static void wvs_refresh_background(void) | ||
618 | { | ||
619 | char buf[32]; | ||
620 | struct hms hms; | ||
621 | |||
622 | int bg = rb->lcd_get_background(); | ||
623 | rb->lcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID); | ||
624 | |||
625 | #ifdef HAVE_LCD_COLOR | ||
626 | rb->lcd_set_background(draw_blendcolor(bg, LCD_WHITE, 192)); | ||
627 | draw_hline(0, wvs.width, 0); | ||
628 | |||
629 | rb->lcd_set_background(draw_blendcolor(bg, LCD_WHITE, 80)); | ||
630 | draw_hline(0, wvs.width, 1); | ||
631 | |||
632 | rb->lcd_set_background(draw_blendcolor(bg, LCD_BLACK, 48)); | ||
633 | draw_hline(0, wvs.width, wvs.height-2); | ||
634 | |||
635 | rb->lcd_set_background(draw_blendcolor(bg, LCD_BLACK, 128)); | ||
636 | draw_hline(0, wvs.width, wvs.height-1); | ||
637 | |||
638 | rb->lcd_set_background(bg); | ||
639 | draw_clear_area(0, 2, wvs.width, wvs.height - 4); | ||
640 | |||
641 | vo_rect_set_ext(&wvs.update_rect, 0, 0, wvs.width, wvs.height); | ||
642 | #else | ||
643 | rb->lcd_set_background(LCD_DARKGRAY); | ||
644 | draw_hline(0, wvs.width, 0); | ||
645 | |||
646 | rb->lcd_set_background(bg); | ||
647 | draw_clear_area(0, 1, wvs.width, wvs.height - 1); | ||
648 | #endif | ||
649 | |||
650 | rb->lcd_set_drawmode(DRMODE_SOLID); | ||
651 | |||
652 | if (stream_get_duration() != INVALID_TIMESTAMP) { | ||
653 | /* Don't know the duration */ | ||
654 | ts_to_hms(stream_get_duration(), &hms); | ||
655 | hms_format(buf, sizeof (buf), &hms); | ||
656 | draw_putsxy_oriented(wvs.dur_rect.l, wvs.dur_rect.t, buf); | ||
657 | } | ||
658 | } | ||
659 | |||
660 | static void wvs_refresh_time(void) | ||
661 | { | ||
662 | char buf[32]; | ||
663 | struct hms hms; | ||
664 | |||
665 | uint32_t duration = stream_get_duration(); | ||
666 | |||
667 | draw_scrollbar_draw_rect(&wvs.prog_rect, duration, 0, | ||
668 | wvs.curr_time); | ||
669 | |||
670 | ts_to_hms(wvs.curr_time, &hms); | ||
671 | hms_format(buf, sizeof (buf), &hms); | ||
672 | |||
673 | draw_clear_area_rect(&wvs.time_rect); | ||
674 | draw_putsxy_oriented(wvs.time_rect.l, wvs.time_rect.t, buf); | ||
675 | |||
676 | #ifdef HAVE_LCD_COLOR | ||
677 | vo_rect_union(&wvs.update_rect, &wvs.update_rect, | ||
678 | &wvs.prog_rect); | ||
679 | vo_rect_union(&wvs.update_rect, &wvs.update_rect, | ||
680 | &wvs.time_rect); | ||
681 | #endif | ||
682 | } | ||
683 | |||
684 | static void wvs_refresh_volume(void) | ||
685 | { | ||
686 | char buf[32]; | ||
687 | int width; | ||
688 | |||
689 | int volume = rb->global_settings->volume; | ||
690 | rb->snprintf(buf, sizeof (buf), "%d%s", | ||
691 | rb->sound_val2phys(SOUND_VOLUME, volume), | ||
692 | rb->sound_unit(SOUND_VOLUME)); | ||
693 | rb->lcd_getstringsize(buf, &width, NULL); | ||
694 | |||
695 | /* Right-justified */ | ||
696 | draw_clear_area_rect(&wvs.vol_rect); | ||
697 | draw_putsxy_oriented(wvs.vol_rect.r - width, wvs.vol_rect.t, buf); | ||
698 | |||
699 | #ifdef HAVE_LCD_COLOR | ||
700 | vo_rect_union(&wvs.update_rect, &wvs.update_rect, &wvs.vol_rect); | ||
701 | #endif | ||
702 | } | ||
703 | |||
704 | static void wvs_refresh_status(void) | ||
705 | { | ||
706 | int icon_size = wvs.stat_rect.r - wvs.stat_rect.l; | ||
707 | |||
708 | draw_clear_area_rect(&wvs.stat_rect); | ||
709 | |||
710 | #ifdef HAVE_LCD_COLOR | ||
711 | /* Draw status icon with a drop shadow */ | ||
712 | unsigned oldfg = rb->lcd_get_foreground(); | ||
713 | int i = 1; | ||
714 | |||
715 | rb->lcd_set_foreground(draw_blendcolor(rb->lcd_get_background(), | ||
716 | LCD_BLACK, 96)); | ||
717 | |||
718 | while (1) | ||
719 | { | ||
720 | draw_oriented_mono_bitmap_part(wvs.icons, | ||
721 | icon_size*wvs.status, | ||
722 | 0, | ||
723 | icon_size*WVS_STATUS_COUNT, | ||
724 | wvs.stat_rect.l + wvs.x + i, | ||
725 | wvs.stat_rect.t + wvs.y + i, | ||
726 | icon_size, icon_size); | ||
727 | |||
728 | if (--i < 0) | ||
729 | break; | ||
730 | |||
731 | rb->lcd_set_foreground(oldfg); | ||
732 | } | ||
733 | |||
734 | vo_rect_union(&wvs.update_rect, &wvs.update_rect, &wvs.stat_rect); | ||
735 | #else | ||
736 | draw_oriented_mono_bitmap_part(wvs.icons, | ||
737 | icon_size*wvs.status, | ||
738 | 0, | ||
739 | icon_size*WVS_STATUS_COUNT, | ||
740 | wvs.stat_rect.l + wvs.x, | ||
741 | wvs.stat_rect.t + wvs.y, | ||
742 | icon_size, icon_size); | ||
743 | #endif | ||
744 | } | ||
745 | |||
746 | static bool wvs_update_status(void) | ||
747 | { | ||
748 | int status; | ||
749 | |||
750 | switch (stream_status()) | ||
751 | { | ||
752 | default: | ||
753 | status = WVS_STATUS_STOPPED; | ||
754 | break; | ||
755 | case STREAM_PAUSED: | ||
756 | status = (wvs.auto_refresh & WVS_REFRESH_RESUME) ? | ||
757 | WVS_STATUS_PLAYING : WVS_STATUS_PAUSED; | ||
758 | break; | ||
759 | case STREAM_PLAYING: | ||
760 | status = WVS_STATUS_PLAYING; | ||
761 | break; | ||
762 | } | ||
763 | |||
764 | if (status != wvs.status) { | ||
765 | wvs.status = status; | ||
766 | return true; | ||
767 | } | ||
768 | |||
769 | return false; | ||
770 | } | ||
771 | |||
772 | static void wvs_update_time(void) | ||
773 | { | ||
774 | uint32_t start; | ||
775 | wvs.curr_time = stream_get_seek_time(&start); | ||
776 | wvs.curr_time -= start; | ||
777 | } | ||
778 | |||
779 | static void wvs_refresh(int hint) | ||
780 | { | ||
781 | long tick; | ||
782 | unsigned oldbg, oldfg; | ||
783 | |||
784 | tick = *rb->current_tick; | ||
785 | |||
786 | if (hint == WVS_REFRESH_DEFAULT) { | ||
787 | |||
788 | if ((wvs.auto_refresh & WVS_REFRESH_VIDEO) && | ||
789 | TIME_AFTER(tick, wvs.print_tick)) { | ||
790 | wvs.auto_refresh &= ~WVS_REFRESH_VIDEO; | ||
791 | stream_draw_frame(false); | ||
792 | } | ||
793 | |||
794 | if ((wvs.auto_refresh & WVS_REFRESH_RESUME) && | ||
795 | TIME_AFTER(tick, wvs.resume_tick)) { | ||
796 | wvs.auto_refresh &= ~(WVS_REFRESH_RESUME | WVS_REFRESH_VIDEO); | ||
797 | stream_resume(); | ||
798 | } | ||
799 | |||
800 | if (!(wvs.flags & WVS_SHOW)) | ||
801 | return; | ||
802 | |||
803 | if (TIME_AFTER(tick, wvs.hide_tick)) { | ||
804 | wvs_show(WVS_HIDE); | ||
805 | return; | ||
806 | } | ||
807 | } else { | ||
808 | if (!(wvs.flags & WVS_SHOW)) { | ||
809 | wvs_show(WVS_SHOW | WVS_NODRAW); | ||
810 | hint = WVS_REFRESH_ALL; | ||
811 | } | ||
812 | |||
813 | wvs.print_tick = tick + wvs.print_delay; | ||
814 | wvs.hide_tick = tick + wvs.show_for; | ||
815 | } | ||
816 | |||
817 | if (TIME_AFTER(tick, wvs.next_auto_refresh)) { | ||
818 | wvs.next_auto_refresh = tick + WVS_MIN_UPDATE_INTERVAL; | ||
819 | |||
820 | if (wvs.auto_refresh & WVS_REFRESH_STATUS) { | ||
821 | if (wvs_update_status()) | ||
822 | hint |= WVS_REFRESH_STATUS; | ||
823 | } | ||
824 | |||
825 | if (wvs.auto_refresh & WVS_REFRESH_TIME) { | ||
826 | wvs_update_time(); | ||
827 | hint |= WVS_REFRESH_TIME; | ||
828 | } | ||
829 | } | ||
830 | |||
831 | if (hint == 0) | ||
832 | return; | ||
833 | |||
834 | oldfg = rb->lcd_get_foreground(); | ||
835 | oldbg = rb->lcd_get_background(); | ||
836 | |||
837 | rb->lcd_setfont(FONT_UI); | ||
838 | rb->lcd_set_foreground(wvs.fgcolor); | ||
839 | rb->lcd_set_background(wvs.bgcolor); | ||
840 | |||
841 | #ifdef HAVE_LCD_COLOR | ||
842 | vo_rect_clear(&wvs.update_rect); | ||
843 | #endif | ||
844 | |||
845 | if (hint & WVS_REFRESH_BACKGROUND) { | ||
846 | wvs_refresh_background(); | ||
847 | hint |= WVS_REFRESH_ALL; /* Requires a redraw of everything */ | ||
848 | } | ||
849 | |||
850 | if (hint & WVS_REFRESH_TIME) { | ||
851 | wvs_refresh_time(); | ||
852 | } | ||
853 | |||
854 | if (hint & WVS_REFRESH_VOLUME) { | ||
855 | wvs_refresh_volume(); | ||
856 | } | ||
857 | |||
858 | if (hint & WVS_REFRESH_STATUS) { | ||
859 | wvs_refresh_status(); | ||
860 | } | ||
861 | |||
862 | rb->lcd_setfont(FONT_SYSFIXED); | ||
863 | rb->lcd_set_foreground(oldfg); | ||
864 | rb->lcd_set_background(oldbg); | ||
865 | |||
866 | #ifdef HAVE_LCD_COLOR | ||
867 | vo_lock(); | ||
868 | |||
869 | draw_update_rect(wvs.update_rect.l, | ||
870 | wvs.update_rect.t, | ||
871 | wvs.update_rect.r - wvs.update_rect.l, | ||
872 | wvs.update_rect.b - wvs.update_rect.t); | ||
873 | |||
874 | vo_unlock(); | ||
875 | #else | ||
876 | gray_deferred_lcd_update(); | ||
877 | #endif | ||
878 | } | ||
879 | |||
880 | static void wvs_show(unsigned show) | ||
881 | { | ||
882 | if (((show ^ wvs.flags) & WVS_SHOW) == 0) | ||
883 | return; | ||
884 | |||
885 | if (show & WVS_SHOW) { | ||
886 | struct vo_rect rc = { 0, 0, SCREEN_WIDTH, wvs.y }; | ||
887 | |||
888 | wvs.flags |= WVS_SHOW; | ||
889 | |||
890 | stream_vo_set_clip(&rc); | ||
891 | |||
892 | if (!(show & WVS_NODRAW)) | ||
893 | wvs_refresh(WVS_REFRESH_ALL); | ||
894 | } else { | ||
895 | wvs.flags &= ~WVS_SHOW; | ||
896 | |||
897 | stream_vo_set_clip(NULL); | ||
898 | |||
899 | draw_clear_area(0, 0, wvs.width, wvs.height); | ||
900 | |||
901 | if (!(show & WVS_NODRAW)) { | ||
902 | #ifdef HAVE_LCD_COLOR | ||
903 | vo_lock(); | ||
904 | draw_update_rect(0, 0, wvs.width, wvs.height); | ||
905 | vo_unlock(); | ||
906 | #endif | ||
907 | stream_draw_frame(false); | ||
908 | } | ||
909 | } | ||
910 | } | ||
911 | |||
912 | static void wvs_set_status(int status) | ||
913 | { | ||
914 | bool draw = (status & WVS_NODRAW) == 0; | ||
915 | |||
916 | status &= WVS_STATUS_MASK; | ||
917 | |||
918 | if (wvs.status != status) { | ||
919 | |||
920 | wvs.status = status; | ||
921 | |||
922 | if (draw) | ||
923 | wvs_refresh(WVS_REFRESH_STATUS); | ||
924 | } | ||
925 | } | ||
926 | |||
927 | /* Handle Fast-forward/Rewind keys using WPS settings (and some nicked code ;) */ | ||
928 | static uint32_t wvs_ff_rw(int btn, unsigned refresh) | ||
929 | { | ||
930 | unsigned int step = TS_SECOND*rb->global_settings->ff_rewind_min_step; | ||
931 | const long ff_rw_accel = rb->global_settings->ff_rewind_accel; | ||
932 | long accel_tick = *rb->current_tick + ff_rw_accel*HZ; | ||
933 | uint32_t start; | ||
934 | uint32_t time = stream_get_seek_time(&start); | ||
935 | const uint32_t duration = stream_get_duration(); | ||
936 | unsigned int max_step = 0; | ||
937 | uint32_t ff_rw_count = 0; | ||
938 | unsigned status = wvs.status; | ||
939 | |||
940 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME | | ||
941 | WVS_REFRESH_TIME); | ||
942 | |||
943 | time -= start; /* Absolute clock => stream-relative */ | ||
944 | |||
945 | switch (btn) | ||
946 | { | ||
947 | case MPEG_FF: | ||
948 | wvs_set_status(WVS_STATUS_FF); | ||
949 | break; | ||
950 | case MPEG_RW: | ||
951 | wvs_set_status(WVS_STATUS_RW); | ||
952 | break; | ||
953 | default: | ||
954 | btn = -1; | ||
955 | } | ||
956 | |||
957 | btn |= BUTTON_REPEAT; | ||
958 | |||
959 | while (1) | ||
960 | { | ||
961 | long tick = *rb->current_tick; | ||
962 | stream_keep_disk_active(); | ||
963 | |||
964 | switch (btn) | ||
965 | { | ||
966 | case BUTTON_NONE: | ||
967 | wvs_refresh(WVS_REFRESH_DEFAULT); | ||
968 | break; | ||
969 | |||
970 | case MPEG_FF | BUTTON_REPEAT: | ||
971 | case MPEG_RW | BUTTON_REPEAT: | ||
972 | break; | ||
973 | |||
974 | case MPEG_FF | BUTTON_REL: | ||
975 | case MPEG_RW | BUTTON_REL: | ||
976 | if (wvs.status == WVS_STATUS_FF) | ||
977 | time += ff_rw_count; | ||
978 | else if (wvs.status == WVS_STATUS_RW) | ||
979 | time -= ff_rw_count; | ||
980 | |||
981 | /* Fall-through */ | ||
982 | case -1: | ||
983 | default: | ||
984 | wvs_schedule_refresh(refresh); | ||
985 | wvs_set_status(status); | ||
986 | wvs_schedule_refresh(WVS_REFRESH_TIME); | ||
987 | return time; | ||
988 | } | ||
989 | |||
990 | if (wvs.status == WVS_STATUS_FF) { | ||
991 | /* fast forwarding, calc max step relative to end */ | ||
992 | max_step = muldiv_uint32(duration - (time + ff_rw_count), | ||
993 | FF_REWIND_MAX_PERCENT, 100); | ||
994 | } else { | ||
995 | /* rewinding, calc max step relative to start */ | ||
996 | max_step = muldiv_uint32(time - ff_rw_count, | ||
997 | FF_REWIND_MAX_PERCENT, 100); | ||
998 | } | ||
999 | |||
1000 | max_step = MAX(max_step, MIN_FF_REWIND_STEP); | ||
1001 | |||
1002 | if (step > max_step) | ||
1003 | step = max_step; | ||
1004 | |||
1005 | ff_rw_count += step; | ||
1006 | |||
1007 | if (ff_rw_accel != 0 && TIME_AFTER(tick, accel_tick)) { | ||
1008 | step *= 2; | ||
1009 | accel_tick = tick + ff_rw_accel*HZ; | ||
1010 | } | ||
1011 | |||
1012 | if (wvs.status == WVS_STATUS_FF) { | ||
1013 | if (duration - time <= ff_rw_count) | ||
1014 | ff_rw_count = duration - time; | ||
1015 | |||
1016 | wvs.curr_time = time + ff_rw_count; | ||
1017 | } else { | ||
1018 | if (time <= ff_rw_count) | ||
1019 | ff_rw_count = time; | ||
1020 | |||
1021 | wvs.curr_time = time - ff_rw_count; | ||
1022 | } | ||
1023 | |||
1024 | wvs_refresh(WVS_REFRESH_TIME); | ||
1025 | |||
1026 | btn = rb->button_get_w_tmo(WVS_MIN_UPDATE_INTERVAL); | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | static int wvs_status(void) | ||
1031 | { | ||
1032 | int status = stream_status(); | ||
1033 | |||
1034 | /* Coerce to STREAM_PLAYING if paused with a pending resume */ | ||
1035 | if (status == STREAM_PAUSED) { | ||
1036 | if (wvs.auto_refresh & WVS_REFRESH_RESUME) | ||
1037 | status = STREAM_PLAYING; | ||
1038 | } | ||
1039 | |||
1040 | return status; | ||
1041 | } | ||
1042 | |||
1043 | static void wvs_set_volume(int delta) | ||
1044 | { | ||
1045 | int vol = rb->global_settings->volume; | ||
1046 | int limit; | ||
1047 | |||
1048 | vol += delta; | ||
1049 | |||
1050 | if (delta < 0) { | ||
1051 | limit = rb->sound_min(SOUND_VOLUME); | ||
1052 | if (vol < limit) | ||
1053 | vol = limit; | ||
1054 | } else { | ||
1055 | limit = rb->sound_max(SOUND_VOLUME); | ||
1056 | if (vol > limit) | ||
1057 | vol = limit; | ||
1058 | } | ||
1059 | |||
1060 | if (vol != rb->global_settings->volume) { | ||
1061 | rb->sound_set(SOUND_VOLUME, vol); | ||
1062 | rb->global_settings->volume = vol; | ||
1063 | } | ||
1064 | |||
1065 | wvs_refresh(WVS_REFRESH_VOLUME); | ||
1066 | } | ||
1067 | |||
1068 | static int wvs_play(uint32_t time) | ||
1069 | { | ||
1070 | int retval; | ||
1071 | |||
1072 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME); | ||
1073 | |||
1074 | retval = stream_seek(time, SEEK_SET); | ||
1075 | |||
1076 | if (retval >= STREAM_OK) { | ||
1077 | stream_show_vo(true); | ||
1078 | retval = stream_play(); | ||
1079 | |||
1080 | if (retval >= STREAM_OK) | ||
1081 | wvs_set_status(WVS_STATUS_PLAYING | WVS_NODRAW); | ||
1082 | } | ||
1083 | |||
1084 | return retval; | ||
1085 | } | ||
1086 | |||
1087 | static int wvs_halt(void) | ||
1088 | { | ||
1089 | int status = stream_pause(); | ||
1090 | |||
1091 | /* Coerce to STREAM_PLAYING if paused with a pending resume */ | ||
1092 | if (status == STREAM_PAUSED) { | ||
1093 | if (wvs.auto_refresh & WVS_REFRESH_RESUME) | ||
1094 | status = STREAM_PLAYING; | ||
1095 | } | ||
1096 | |||
1097 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME); | ||
1098 | |||
1099 | return status; | ||
1100 | } | ||
1101 | |||
1102 | static int wvs_pause(void) | ||
1103 | { | ||
1104 | unsigned refresh = wvs.auto_refresh; | ||
1105 | int status = wvs_halt(); | ||
1106 | |||
1107 | if (status == STREAM_PLAYING && (refresh & WVS_REFRESH_RESUME)) { | ||
1108 | wvs_cancel_refresh(WVS_REFRESH_RESUME); | ||
1109 | wvs_schedule_refresh(WVS_REFRESH_VIDEO); | ||
1110 | } | ||
1111 | |||
1112 | wvs_set_status(WVS_STATUS_PAUSED); | ||
1113 | |||
1114 | return status; | ||
1115 | } | ||
1116 | |||
1117 | static void wvs_resume(void) | ||
1118 | { | ||
1119 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME); | ||
1120 | wvs_set_status(WVS_STATUS_PLAYING); | ||
1121 | stream_resume(); | ||
1122 | } | ||
1123 | |||
1124 | static void wvs_stop(void) | ||
1125 | { | ||
1126 | wvs_cancel_refresh(WVS_REFRESH_VIDEO | WVS_REFRESH_RESUME); | ||
1127 | wvs_show(WVS_HIDE | WVS_NODRAW); | ||
1128 | |||
1129 | if (stream_stop() != STREAM_STOPPED) | ||
1130 | settings.resume_time = stream_get_resume_time(); | ||
1131 | } | ||
1132 | |||
1133 | static void wvs_seek(int btn) | ||
1134 | { | ||
1135 | int status; | ||
1136 | unsigned refresh; | ||
1137 | uint32_t time; | ||
1138 | |||
1139 | if (!stream_can_seek()) | ||
1140 | return; | ||
1141 | |||
1142 | status = wvs_halt(); | ||
1143 | |||
1144 | if (status == STREAM_STOPPED) | ||
1145 | return; | ||
1146 | |||
1147 | wvs_show(WVS_SHOW); | ||
1148 | |||
1149 | if (status == STREAM_PLAYING) | ||
1150 | refresh = WVS_REFRESH_RESUME; /* delay resume if playing */ | ||
1151 | else | ||
1152 | refresh = WVS_REFRESH_VIDEO; /* refresh if paused */ | ||
1153 | |||
1154 | time = wvs_ff_rw(btn, refresh); | ||
1155 | |||
1156 | stream_seek(time, SEEK_SET); | ||
1157 | } | ||
1158 | |||
1159 | static void button_loop(void) | ||
1160 | { | ||
1161 | rb->lcd_setfont(FONT_SYSFIXED); | ||
187 | rb->lcd_clear_display(); | 1162 | rb->lcd_clear_display(); |
188 | rb->lcd_update(); | 1163 | rb->lcd_update(); |
189 | 1164 | ||
1165 | /* Turn off backlight timeout */ | ||
1166 | /* backlight control in lib/helper.c */ | ||
1167 | backlight_force_on(rb); | ||
1168 | |||
1169 | wvs_init(); | ||
1170 | |||
190 | /* Start playback at the specified starting time */ | 1171 | /* Start playback at the specified starting time */ |
191 | if (stream_seek(settings.resume_time, SEEK_SET) < STREAM_OK || | 1172 | if (wvs_play(settings.resume_time) < STREAM_OK) { |
192 | (stream_show_vo(true), stream_play()) < STREAM_OK) | ||
193 | { | ||
194 | rb->splash(HZ*2, "Playback failed"); | 1173 | rb->splash(HZ*2, "Playback failed"); |
195 | return false; | 1174 | return; |
196 | } | 1175 | } |
197 | 1176 | ||
198 | /* Gently poll the video player for EOS and handle UI */ | 1177 | /* Gently poll the video player for EOS and handle UI */ |
199 | while (stream_status() != STREAM_STOPPED) | 1178 | while (stream_status() != STREAM_STOPPED) |
200 | { | 1179 | { |
201 | int button = rb->button_get_w_tmo(HZ/2); | 1180 | int button = rb->button_get_w_tmo(WVS_MIN_UPDATE_INTERVAL); |
202 | 1181 | ||
203 | switch (button) | 1182 | switch (button) |
204 | { | 1183 | { |
205 | case BUTTON_NONE: | 1184 | case BUTTON_NONE: |
1185 | { | ||
1186 | wvs_refresh(WVS_REFRESH_DEFAULT); | ||
206 | continue; | 1187 | continue; |
1188 | } /* BUTTON_NONE: */ | ||
207 | 1189 | ||
208 | case MPEG_VOLUP: | 1190 | case MPEG_VOLUP: |
209 | case MPEG_VOLUP|BUTTON_REPEAT: | 1191 | case MPEG_VOLUP|BUTTON_REPEAT: |
@@ -212,14 +1194,7 @@ static bool button_loop(void) | |||
212 | case MPEG_VOLUP2|BUTTON_REPEAT: | 1194 | case MPEG_VOLUP2|BUTTON_REPEAT: |
213 | #endif | 1195 | #endif |
214 | { | 1196 | { |
215 | int vol = rb->global_settings->volume; | 1197 | wvs_set_volume(+1); |
216 | int maxvol = rb->sound_max(SOUND_VOLUME); | ||
217 | |||
218 | if (vol < maxvol) { | ||
219 | vol++; | ||
220 | rb->sound_set(SOUND_VOLUME, vol); | ||
221 | rb->global_settings->volume = vol; | ||
222 | } | ||
223 | break; | 1198 | break; |
224 | } /* MPEG_VOLUP*: */ | 1199 | } /* MPEG_VOLUP*: */ |
225 | 1200 | ||
@@ -230,23 +1205,17 @@ static bool button_loop(void) | |||
230 | case MPEG_VOLDOWN2|BUTTON_REPEAT: | 1205 | case MPEG_VOLDOWN2|BUTTON_REPEAT: |
231 | #endif | 1206 | #endif |
232 | { | 1207 | { |
233 | int vol = rb->global_settings->volume; | 1208 | wvs_set_volume(-1); |
234 | int minvol = rb->sound_min(SOUND_VOLUME); | ||
235 | |||
236 | if (vol > minvol) { | ||
237 | vol--; | ||
238 | rb->sound_set(SOUND_VOLUME, vol); | ||
239 | rb->global_settings->volume = vol; | ||
240 | } | ||
241 | break; | 1209 | break; |
242 | } /* MPEG_VOLDOWN*: */ | 1210 | } /* MPEG_VOLDOWN*: */ |
243 | 1211 | ||
244 | case MPEG_MENU: | 1212 | case MPEG_MENU: |
245 | { | 1213 | { |
246 | int state = stream_pause(); /* save previous state */ | 1214 | int state = wvs_halt(); /* save previous state */ |
247 | int result; | 1215 | int result; |
248 | 1216 | ||
249 | /* Hide video output */ | 1217 | /* Hide video output */ |
1218 | wvs_show(WVS_HIDE | WVS_NODRAW); | ||
250 | stream_show_vo(false); | 1219 | stream_show_vo(false); |
251 | backlight_use_settings(rb); | 1220 | backlight_use_settings(rb); |
252 | 1221 | ||
@@ -258,17 +1227,19 @@ static bool button_loop(void) | |||
258 | switch (result) | 1227 | switch (result) |
259 | { | 1228 | { |
260 | case MPEG_MENU_QUIT: | 1229 | case MPEG_MENU_QUIT: |
261 | stream_stop(); | 1230 | wvs_stop(); |
262 | break; | 1231 | break; |
263 | default: | 1232 | default: |
264 | /* If not stopped, show video again */ | 1233 | /* If not stopped, show video again */ |
265 | if (state != STREAM_STOPPED) | 1234 | if (state != STREAM_STOPPED) { |
1235 | wvs_show(WVS_SHOW); | ||
266 | stream_show_vo(true); | 1236 | stream_show_vo(true); |
1237 | } | ||
267 | 1238 | ||
268 | /* If stream was playing, restart it */ | 1239 | /* If stream was playing, restart it */ |
269 | if (state == STREAM_PLAYING) { | 1240 | if (state == STREAM_PLAYING) { |
270 | backlight_force_on(rb); | 1241 | backlight_force_on(rb); |
271 | stream_resume(); | 1242 | wvs_resume(); |
272 | } | 1243 | } |
273 | break; | 1244 | break; |
274 | } | 1245 | } |
@@ -277,7 +1248,7 @@ static bool button_loop(void) | |||
277 | 1248 | ||
278 | case MPEG_STOP: | 1249 | case MPEG_STOP: |
279 | { | 1250 | { |
280 | stream_stop(); | 1251 | wvs_stop(); |
281 | break; | 1252 | break; |
282 | } /* MPEG_STOP: */ | 1253 | } /* MPEG_STOP: */ |
283 | 1254 | ||
@@ -286,27 +1257,34 @@ static bool button_loop(void) | |||
286 | case MPEG_PAUSE2: | 1257 | case MPEG_PAUSE2: |
287 | #endif | 1258 | #endif |
288 | { | 1259 | { |
289 | if (stream_status() == STREAM_PLAYING) { | 1260 | int status = wvs_status(); |
1261 | |||
1262 | if (status == STREAM_PLAYING) { | ||
290 | /* Playing => Paused */ | 1263 | /* Playing => Paused */ |
291 | stream_pause(); | 1264 | wvs_pause(); |
292 | backlight_use_settings(rb); | 1265 | backlight_use_settings(rb); |
293 | } | 1266 | } |
294 | else if (stream_status() == STREAM_PAUSED) { | 1267 | else if (status == STREAM_PAUSED) { |
295 | /* Paused => Playing */ | 1268 | /* Paused => Playing */ |
296 | backlight_force_on(rb); | 1269 | backlight_force_on(rb); |
297 | stream_resume(); | 1270 | wvs_resume(); |
298 | } | 1271 | } |
299 | 1272 | ||
300 | break; | 1273 | break; |
301 | } /* MPEG_PAUSE*: */ | 1274 | } /* MPEG_PAUSE*: */ |
302 | 1275 | ||
1276 | case MPEG_RW: | ||
1277 | case MPEG_FF: | ||
1278 | { | ||
1279 | wvs_seek(button); | ||
1280 | break; | ||
1281 | } /* MPEG_RW: MPEG_FF: */ | ||
1282 | |||
303 | case SYS_POWEROFF: | 1283 | case SYS_POWEROFF: |
304 | case SYS_USB_CONNECTED: | 1284 | case SYS_USB_CONNECTED: |
305 | /* Stop and get the resume time before closing the file early */ | 1285 | /* Stop and get the resume time before closing the file early */ |
306 | stream_stop(); | 1286 | wvs_stop(); |
307 | settings.resume_time = stream_get_resume_time(); | ||
308 | stream_close(); | 1287 | stream_close(); |
309 | ret = false; | ||
310 | /* Fall-through */ | 1288 | /* Fall-through */ |
311 | default: | 1289 | default: |
312 | rb->default_event_handler(button); | 1290 | rb->default_event_handler(button); |
@@ -316,9 +1294,12 @@ static bool button_loop(void) | |||
316 | rb->yield(); | 1294 | rb->yield(); |
317 | } /* end while */ | 1295 | } /* end while */ |
318 | 1296 | ||
1297 | wvs_stop(); | ||
1298 | |||
319 | rb->lcd_setfont(FONT_UI); | 1299 | rb->lcd_setfont(FONT_UI); |
320 | 1300 | ||
321 | return ret; | 1301 | /* Turn on backlight timeout (revert to settings) */ |
1302 | backlight_use_settings(rb); | ||
322 | } | 1303 | } |
323 | 1304 | ||
324 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | 1305 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) |
@@ -367,17 +1348,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | |||
367 | result = mpeg_start_menu(stream_get_duration()); | 1348 | result = mpeg_start_menu(stream_get_duration()); |
368 | 1349 | ||
369 | if (result != MPEG_START_QUIT) { | 1350 | if (result != MPEG_START_QUIT) { |
370 | /* Turn off backlight timeout */ | ||
371 | /* backlight control in lib/helper.c */ | ||
372 | backlight_force_on(rb); | ||
373 | |||
374 | /* Enter button loop and process UI */ | 1351 | /* Enter button loop and process UI */ |
375 | if (button_loop()) { | 1352 | button_loop(); |
376 | settings.resume_time = stream_get_resume_time(); | ||
377 | } | ||
378 | |||
379 | /* Turn on backlight timeout (revert to settings) */ | ||
380 | backlight_use_settings(rb); | ||
381 | } | 1353 | } |
382 | 1354 | ||
383 | stream_close(); | 1355 | stream_close(); |
diff --git a/apps/plugins/mpegplayer/stream_mgr.c b/apps/plugins/mpegplayer/stream_mgr.c index 06f269ca31..1baa2032ec 100644 --- a/apps/plugins/mpegplayer/stream_mgr.c +++ b/apps/plugins/mpegplayer/stream_mgr.c | |||
@@ -251,6 +251,7 @@ static void set_stream_clock(uint32_t time) | |||
251 | static uint32_t time_from_whence(uint32_t time, int whence) | 251 | static uint32_t time_from_whence(uint32_t time, int whence) |
252 | { | 252 | { |
253 | int64_t currtime; | 253 | int64_t currtime; |
254 | uint32_t start; | ||
254 | 255 | ||
255 | switch (whence) | 256 | switch (whence) |
256 | { | 257 | { |
@@ -262,12 +263,8 @@ static uint32_t time_from_whence(uint32_t time, int whence) | |||
262 | case SEEK_CUR: | 263 | case SEEK_CUR: |
263 | /* Seek forward or backward from the current time | 264 | /* Seek forward or backward from the current time |
264 | * (time = signed offset from current) */ | 265 | * (time = signed offset from current) */ |
265 | if (stream_mgr.seeked) | 266 | currtime = stream_get_seek_time(&start); |
266 | currtime = str_parser.last_seek_time; | 267 | currtime -= start; |
267 | else | ||
268 | currtime = TICKS_TO_TS(pcm_output_get_clock()); | ||
269 | |||
270 | currtime -= str_parser.start_pts; | ||
271 | currtime += (int32_t)time; | 268 | currtime += (int32_t)time; |
272 | 269 | ||
273 | if (currtime < 0) | 270 | if (currtime < 0) |
@@ -525,27 +522,28 @@ static void stream_on_stop(bool reply) | |||
525 | 522 | ||
526 | if (status != STREAM_STOPPED) | 523 | if (status != STREAM_STOPPED) |
527 | { | 524 | { |
528 | /* Not stopped = paused or playing */ | ||
529 | stream_mgr.seeked = false; | ||
530 | |||
531 | /* Pause the clock */ | 525 | /* Pause the clock */ |
532 | pcm_output_play_pause(false); | 526 | pcm_output_play_pause(false); |
533 | 527 | ||
528 | /* Assume invalidity */ | ||
529 | stream_mgr.resume_time = 0; | ||
530 | |||
534 | if (stream_can_seek()) | 531 | if (stream_can_seek()) |
535 | { | 532 | { |
536 | /* Read the current stream time */ | 533 | /* Read the current stream time or the last seeked position */ |
537 | uint32_t time = TICKS_TO_TS(pcm_output_get_clock()); | 534 | uint32_t start; |
538 | 535 | uint32_t time = stream_get_seek_time(&start); | |
539 | /* Assume invalidity */ | ||
540 | stream_mgr.resume_time = 0; | ||
541 | 536 | ||
542 | if (time >= str_parser.start_pts && time < str_parser.end_pts) | 537 | if (time >= str_parser.start_pts && time < str_parser.end_pts) |
543 | { | 538 | { |
544 | /* Save the current stream time */ | 539 | /* Save the current stream time */ |
545 | stream_mgr.resume_time = time - str_parser.start_pts; | 540 | stream_mgr.resume_time = time - start; |
546 | } | 541 | } |
547 | } | 542 | } |
548 | 543 | ||
544 | /* Not stopped = paused or playing */ | ||
545 | stream_mgr.seeked = false; | ||
546 | |||
549 | /* Stop buffering */ | 547 | /* Stop buffering */ |
550 | disk_buf_send_msg(STREAM_STOP, 0); | 548 | disk_buf_send_msg(STREAM_STOP, 0); |
551 | 549 | ||
@@ -578,10 +576,10 @@ static void stream_on_seek(struct stream_seek_data *skd) | |||
578 | if (stream_mgr.filename == NULL) | 576 | if (stream_mgr.filename == NULL) |
579 | break; | 577 | break; |
580 | 578 | ||
581 | stream_mgr_reply_msg(STREAM_OK); | ||
582 | |||
583 | stream_keep_disk_active(); | 579 | stream_keep_disk_active(); |
584 | 580 | ||
581 | stream_mgr_reply_msg(STREAM_OK); | ||
582 | |||
585 | stream_mgr_lock(); | 583 | stream_mgr_lock(); |
586 | 584 | ||
587 | if (!stream_can_seek()) | 585 | if (!stream_can_seek()) |
@@ -705,9 +703,11 @@ bool stream_show_vo(bool show) | |||
705 | 703 | ||
706 | vis = parser_send_video_msg(VIDEO_DISPLAY_SHOW, show); | 704 | vis = parser_send_video_msg(VIDEO_DISPLAY_SHOW, show); |
707 | #ifndef HAVE_LCD_COLOR | 705 | #ifndef HAVE_LCD_COLOR |
708 | GRAY_VIDEO_FLUSH_ICACHE(); | 706 | GRAY_VIDEO_INVALIDATE_ICACHE(); |
709 | GRAY_INVALIDATE_ICACHE(); | 707 | GRAY_INVALIDATE_ICACHE(); |
708 | |||
710 | gray_show(show); | 709 | gray_show(show); |
710 | |||
711 | GRAY_FLUSH_ICACHE(); | 711 | GRAY_FLUSH_ICACHE(); |
712 | #endif | 712 | #endif |
713 | stream_mgr_unlock(); | 713 | stream_mgr_unlock(); |
@@ -743,6 +743,32 @@ bool stream_vo_get_size(struct vo_ext *sz) | |||
743 | return retval; | 743 | return retval; |
744 | } | 744 | } |
745 | 745 | ||
746 | void stream_vo_set_clip(const struct vo_rect *rc) | ||
747 | { | ||
748 | stream_mgr_lock(); | ||
749 | |||
750 | if (rc) | ||
751 | { | ||
752 | stream_mgr.parms.rc = *rc; | ||
753 | rc = &stream_mgr.parms.rc; | ||
754 | } | ||
755 | #ifndef HAVE_LCD_COLOR | ||
756 | else | ||
757 | { | ||
758 | vo_rect_set_ext(&stream_mgr.parms.rc, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); | ||
759 | rc = &stream_mgr.parms.rc; | ||
760 | } | ||
761 | #endif | ||
762 | |||
763 | parser_send_video_msg(VIDEO_SET_CLIP_RECT, (intptr_t)rc); | ||
764 | |||
765 | #ifndef HAVE_LCD_COLOR | ||
766 | stream_set_gray_rect(rc); | ||
767 | #endif | ||
768 | |||
769 | stream_mgr_unlock(); | ||
770 | } | ||
771 | |||
746 | #ifndef HAVE_LCD_COLOR | 772 | #ifndef HAVE_LCD_COLOR |
747 | /* Set the rectangle for the gray video overlay - clipped to screen */ | 773 | /* Set the rectangle for the gray video overlay - clipped to screen */ |
748 | bool stream_set_gray_rect(const struct vo_rect *rc) | 774 | bool stream_set_gray_rect(const struct vo_rect *rc) |
@@ -756,21 +782,38 @@ bool stream_set_gray_rect(const struct vo_rect *rc) | |||
756 | 782 | ||
757 | if (vo_rect_intersect(&rc_gray, &rc_gray, rc)) | 783 | if (vo_rect_intersect(&rc_gray, &rc_gray, rc)) |
758 | { | 784 | { |
759 | bool vo_vis = stream_show_vo(false); | 785 | bool vis = parser_send_video_msg(VIDEO_DISPLAY_SHOW, false); |
760 | 786 | ||
761 | GRAY_VIDEO_FLUSH_ICACHE(); | 787 | /* The impudence! Keeps the image from disappearing anyway. */ |
788 | #ifdef SIMULATOR | ||
789 | rb->sim_lcd_ex_init(0, NULL); | ||
790 | #else | ||
791 | rb->timer_unregister(); | ||
792 | #endif | ||
793 | GRAY_VIDEO_INVALIDATE_ICACHE(); | ||
762 | GRAY_INVALIDATE_ICACHE(); | 794 | GRAY_INVALIDATE_ICACHE(); |
763 | 795 | ||
796 | vo_lock(); | ||
797 | |||
764 | gray_init(rb, stream_mgr.graymem, stream_mgr.graysize, | 798 | gray_init(rb, stream_mgr.graymem, stream_mgr.graysize, |
765 | false, rc_gray.r - rc_gray.l, rc_gray.b - rc_gray.t, | 799 | false, rc_gray.r - rc_gray.l, rc_gray.b - rc_gray.t, |
766 | 32, 2<<8, NULL); | 800 | 32, 2<<8, NULL); |
767 | 801 | ||
768 | gray_set_position(rc_gray.l, rc_gray.t); | 802 | gray_set_position(rc_gray.l, rc_gray.t); |
769 | GRAY_FLUSH_ICACHE(); | ||
770 | 803 | ||
771 | if (vo_vis) | 804 | vo_unlock(); |
805 | |||
806 | GRAY_INVALIDATE_ICACHE(); | ||
807 | |||
808 | if (stream_mgr.status != STREAM_PLAYING) | ||
809 | parser_send_video_msg(VIDEO_PRINT_FRAME, true); | ||
810 | |||
811 | GRAY_VIDEO_FLUSH_ICACHE(); | ||
812 | |||
813 | if (vis) | ||
772 | { | 814 | { |
773 | stream_show_vo(true); | 815 | gray_show(true); |
816 | parser_send_video_msg(VIDEO_DISPLAY_SHOW, true); | ||
774 | } | 817 | } |
775 | } | 818 | } |
776 | 819 | ||
@@ -784,9 +827,11 @@ void stream_gray_show(bool show) | |||
784 | { | 827 | { |
785 | stream_mgr_lock(); | 828 | stream_mgr_lock(); |
786 | 829 | ||
787 | GRAY_VIDEO_FLUSH_ICACHE(); | 830 | GRAY_VIDEO_INVALIDATE_ICACHE(); |
788 | GRAY_INVALIDATE_ICACHE(); | 831 | GRAY_INVALIDATE_ICACHE(); |
832 | |||
789 | gray_show(show); | 833 | gray_show(show); |
834 | |||
790 | GRAY_FLUSH_ICACHE(); | 835 | GRAY_FLUSH_ICACHE(); |
791 | 836 | ||
792 | stream_mgr_unlock(); | 837 | stream_mgr_unlock(); |
@@ -803,11 +848,32 @@ bool stream_display_thumb(const struct vo_rect *rc) | |||
803 | 848 | ||
804 | stream_mgr_lock(); | 849 | stream_mgr_lock(); |
805 | 850 | ||
851 | GRAY_INVALIDATE_ICACHE(); | ||
852 | |||
806 | stream_mgr.parms.rc = *rc; | 853 | stream_mgr.parms.rc = *rc; |
807 | retval = parser_send_video_msg(VIDEO_PRINT_THUMBNAIL, | 854 | retval = parser_send_video_msg(VIDEO_PRINT_THUMBNAIL, |
808 | (intptr_t)&stream_mgr.parms.rc); | 855 | (intptr_t)&stream_mgr.parms.rc); |
809 | 856 | ||
857 | GRAY_VIDEO_FLUSH_ICACHE(); | ||
858 | |||
810 | stream_mgr_unlock(); | 859 | stream_mgr_unlock(); |
860 | |||
861 | return retval; | ||
862 | } | ||
863 | |||
864 | bool stream_draw_frame(bool no_prepare) | ||
865 | { | ||
866 | bool retval; | ||
867 | stream_mgr_lock(); | ||
868 | |||
869 | GRAY_INVALIDATE_ICACHE(); | ||
870 | |||
871 | retval = parser_send_video_msg(VIDEO_PRINT_FRAME, no_prepare); | ||
872 | |||
873 | GRAY_VIDEO_FLUSH_ICACHE(); | ||
874 | |||
875 | stream_mgr_unlock(); | ||
876 | |||
811 | return retval; | 877 | return retval; |
812 | } | 878 | } |
813 | 879 | ||
@@ -826,6 +892,25 @@ uint32_t stream_get_resume_time(void) | |||
826 | return resume_time; | 892 | return resume_time; |
827 | } | 893 | } |
828 | 894 | ||
895 | uint32_t stream_get_seek_time(uint32_t *start) | ||
896 | { | ||
897 | uint32_t time; | ||
898 | |||
899 | stream_mgr_lock(); | ||
900 | |||
901 | if (stream_mgr.seeked) | ||
902 | time = str_parser.last_seek_time; | ||
903 | else | ||
904 | time = TICKS_TO_TS(pcm_output_get_clock()); | ||
905 | |||
906 | if (start != NULL) | ||
907 | *start = str_parser.start_pts; | ||
908 | |||
909 | stream_mgr_unlock(); | ||
910 | |||
911 | return time; | ||
912 | } | ||
913 | |||
829 | /* Returns the smallest file window that includes all active streams' | 914 | /* Returns the smallest file window that includes all active streams' |
830 | * windows */ | 915 | * windows */ |
831 | static bool stream_get_window_callback(struct list_item *item, | 916 | static bool stream_get_window_callback(struct list_item *item, |
diff --git a/apps/plugins/mpegplayer/stream_mgr.h b/apps/plugins/mpegplayer/stream_mgr.h index 63452ecbc0..dd5d8cabec 100644 --- a/apps/plugins/mpegplayer/stream_mgr.h +++ b/apps/plugins/mpegplayer/stream_mgr.h | |||
@@ -105,6 +105,9 @@ int stream_seek(uint32_t time, int whence); | |||
105 | /* Show/Hide the video image at the current seekpoint */ | 105 | /* Show/Hide the video image at the current seekpoint */ |
106 | bool stream_show_vo(bool show); | 106 | bool stream_show_vo(bool show); |
107 | 107 | ||
108 | /* Set the visible section of video */ | ||
109 | void stream_vo_set_clip(const struct vo_rect *rc); | ||
110 | |||
108 | #ifndef HAVE_LCD_COLOR | 111 | #ifndef HAVE_LCD_COLOR |
109 | /* Set the gray overlay rectangle */ | 112 | /* Set the gray overlay rectangle */ |
110 | bool stream_set_gray_rect(const struct vo_rect *rc); | 113 | bool stream_set_gray_rect(const struct vo_rect *rc); |
@@ -114,12 +117,19 @@ void stream_gray_show(bool show); | |||
114 | /* Display thumbnail of the current seekpoint */ | 117 | /* Display thumbnail of the current seekpoint */ |
115 | bool stream_display_thumb(const struct vo_rect *rc); | 118 | bool stream_display_thumb(const struct vo_rect *rc); |
116 | 119 | ||
120 | /* Draw the frame at the current position */ | ||
121 | bool stream_draw_frame(bool no_prepare); | ||
122 | |||
117 | /* Return video dimensions */ | 123 | /* Return video dimensions */ |
118 | bool stream_vo_get_size(struct vo_ext *sz); | 124 | bool stream_vo_get_size(struct vo_ext *sz); |
119 | 125 | ||
120 | /* Returns the resume time in timestamp ticks */ | 126 | /* Returns the resume time in timestamp ticks */ |
121 | uint32_t stream_get_resume_time(void); | 127 | uint32_t stream_get_resume_time(void); |
122 | 128 | ||
129 | /* Returns stream_get_time if no seek is pending or else the | ||
130 | last time give to seek */ | ||
131 | uint32_t stream_get_seek_time(uint32_t *start); | ||
132 | |||
123 | /* Return the absolute stream time in clock ticks - adjusted by | 133 | /* Return the absolute stream time in clock ticks - adjusted by |
124 | * master clock stream via audio timestamps */ | 134 | * master clock stream via audio timestamps */ |
125 | static inline uint32_t stream_get_time(void) | 135 | static inline uint32_t stream_get_time(void) |
diff --git a/apps/plugins/mpegplayer/stream_thread.h b/apps/plugins/mpegplayer/stream_thread.h index 1962a66878..58cb7b93e4 100644 --- a/apps/plugins/mpegplayer/stream_thread.h +++ b/apps/plugins/mpegplayer/stream_thread.h | |||
@@ -106,6 +106,7 @@ enum stream_message | |||
106 | VIDEO_GET_SIZE, /* Get the video dimensions */ | 106 | VIDEO_GET_SIZE, /* Get the video dimensions */ |
107 | VIDEO_PRINT_FRAME, /* Print the frame at the current position */ | 107 | VIDEO_PRINT_FRAME, /* Print the frame at the current position */ |
108 | VIDEO_PRINT_THUMBNAIL, /* Print a thumbnail of the current position */ | 108 | VIDEO_PRINT_THUMBNAIL, /* Print a thumbnail of the current position */ |
109 | VIDEO_SET_CLIP_RECT, /* Set the visible video area */ | ||
109 | #ifdef GRAY_CACHE_MAINT | 110 | #ifdef GRAY_CACHE_MAINT |
110 | VIDEO_GRAY_CACHEOP, | 111 | VIDEO_GRAY_CACHEOP, |
111 | #endif | 112 | #endif |
diff --git a/apps/plugins/mpegplayer/video_out.h b/apps/plugins/mpegplayer/video_out.h index 08cd7aa848..ed8c4c5907 100644 --- a/apps/plugins/mpegplayer/video_out.h +++ b/apps/plugins/mpegplayer/video_out.h | |||
@@ -24,6 +24,16 @@ | |||
24 | #ifndef VIDEO_OUT_H | 24 | #ifndef VIDEO_OUT_H |
25 | #define VIDEO_OUT_H | 25 | #define VIDEO_OUT_H |
26 | 26 | ||
27 | #if LCD_WIDTH >= LCD_HEIGHT | ||
28 | #define SCREEN_WIDTH LCD_WIDTH | ||
29 | #define SCREEN_HEIGHT LCD_HEIGHT | ||
30 | #define LCD_LANDSCAPE | ||
31 | #else /* Assume the screen is rotated on portrait LCDs */ | ||
32 | #define SCREEN_WIDTH LCD_HEIGHT | ||
33 | #define SCREEN_HEIGHT LCD_WIDTH | ||
34 | #define LCD_PORTRAIT | ||
35 | #endif | ||
36 | |||
27 | /* Structure to hold width and height values */ | 37 | /* Structure to hold width and height values */ |
28 | struct vo_ext | 38 | struct vo_ext |
29 | { | 39 | { |
@@ -43,9 +53,18 @@ bool vo_init (void); | |||
43 | bool vo_show (bool show); | 53 | bool vo_show (bool show); |
44 | bool vo_is_visible(void); | 54 | bool vo_is_visible(void); |
45 | void vo_setup (const mpeg2_sequence_t * sequence); | 55 | void vo_setup (const mpeg2_sequence_t * sequence); |
56 | void vo_set_clip_rect(const struct vo_rect *rc); | ||
46 | void vo_dimensions(struct vo_ext *sz); | 57 | void vo_dimensions(struct vo_ext *sz); |
47 | void vo_cleanup (void); | 58 | void vo_cleanup (void); |
48 | 59 | ||
60 | #if NUM_CORES > 1 || !defined (HAVE_LCD_COLOR) | ||
61 | void vo_lock(void); | ||
62 | void vo_unlock(void); | ||
63 | #else | ||
64 | static inline void vo_lock(void) {} | ||
65 | static inline void vo_unlock(void) {} | ||
66 | #endif | ||
67 | |||
49 | /* Sets all coordinates of a vo_rect to 0 */ | 68 | /* Sets all coordinates of a vo_rect to 0 */ |
50 | void vo_rect_clear(struct vo_rect *rc); | 69 | void vo_rect_clear(struct vo_rect *rc); |
51 | /* Returns true if left >= right or top >= bottom */ | 70 | /* Returns true if left >= right or top >= bottom */ |
@@ -68,4 +87,10 @@ bool vo_rect_intersect(struct vo_rect *rc_dst, | |||
68 | const struct vo_rect *rc1, | 87 | const struct vo_rect *rc1, |
69 | const struct vo_rect *rc2); | 88 | const struct vo_rect *rc2); |
70 | 89 | ||
90 | bool vo_rect_union(struct vo_rect *rc_dst, | ||
91 | const struct vo_rect *rc1, | ||
92 | const struct vo_rect *rc2); | ||
93 | |||
94 | void vo_rect_offset(struct vo_rect *rc, int dx, int dy); | ||
95 | |||
71 | #endif /* VIDEO_OUT_H */ | 96 | #endif /* VIDEO_OUT_H */ |
diff --git a/apps/plugins/mpegplayer/video_out_rockbox.c b/apps/plugins/mpegplayer/video_out_rockbox.c index ff0d39eba6..6efbaf0a01 100644 --- a/apps/plugins/mpegplayer/video_out_rockbox.c +++ b/apps/plugins/mpegplayer/video_out_rockbox.c | |||
@@ -21,6 +21,9 @@ | |||
21 | #include "plugin.h" | 21 | #include "plugin.h" |
22 | #include "mpegplayer.h" | 22 | #include "mpegplayer.h" |
23 | 23 | ||
24 | #define VO_NON_NULL_RECT 0x1 | ||
25 | #define VO_VISIBLE 0x2 | ||
26 | |||
24 | struct vo_data | 27 | struct vo_data |
25 | { | 28 | { |
26 | int image_width; | 29 | int image_width; |
@@ -34,8 +37,9 @@ struct vo_data | |||
34 | int output_width; | 37 | int output_width; |
35 | int output_height; | 38 | int output_height; |
36 | bool visible; | 39 | bool visible; |
37 | bool thumb_mode; | 40 | unsigned flags; |
38 | void *last; | 41 | struct vo_rect rc_vid; |
42 | struct vo_rect rc_clip; | ||
39 | }; | 43 | }; |
40 | 44 | ||
41 | #ifdef PROC_NEEDS_CACHEALIGN | 45 | #ifdef PROC_NEEDS_CACHEALIGN |
@@ -48,10 +52,40 @@ static uint8_t __vo_data[CACHEALIGN_UP(sizeof(struct vo_data))] | |||
48 | static struct vo_data vo; | 52 | static struct vo_data vo; |
49 | #endif | 53 | #endif |
50 | 54 | ||
55 | #if NUM_CORES > 1 | ||
56 | static struct mutex vo_mtx NOCACHEBSS_ATTR; | ||
57 | #endif | ||
58 | |||
59 | static inline void video_lock_init(void) | ||
60 | { | ||
61 | #if NUM_CORES > 1 | ||
62 | rb->mutex_init(&vo_mtx); | ||
63 | #endif | ||
64 | } | ||
65 | |||
66 | static inline void video_lock(void) | ||
67 | { | ||
68 | #if NUM_CORES > 1 | ||
69 | rb->mutex_lock(&vo_mtx); | ||
70 | #endif | ||
71 | } | ||
72 | |||
73 | static inline void video_unlock(void) | ||
74 | { | ||
75 | #if NUM_CORES > 1 | ||
76 | rb->mutex_unlock(&vo_mtx); | ||
77 | #endif | ||
78 | } | ||
79 | |||
80 | |||
51 | /* Draw a black rectangle if no video frame is available */ | 81 | /* Draw a black rectangle if no video frame is available */ |
52 | static void vo_draw_black(void) | 82 | static void vo_draw_black(void) |
53 | { | 83 | { |
54 | int foreground = lcd_(get_foreground)(); | 84 | int foreground; |
85 | |||
86 | video_lock(); | ||
87 | |||
88 | foreground = lcd_(get_foreground)(); | ||
55 | 89 | ||
56 | lcd_(set_foreground)(DRAW_BLACK); | 90 | lcd_(set_foreground)(DRAW_BLACK); |
57 | 91 | ||
@@ -61,21 +95,27 @@ static void vo_draw_black(void) | |||
61 | vo.output_height); | 95 | vo.output_height); |
62 | 96 | ||
63 | lcd_(set_foreground)(foreground); | 97 | lcd_(set_foreground)(foreground); |
98 | |||
99 | video_unlock(); | ||
64 | } | 100 | } |
65 | 101 | ||
66 | static inline void yuv_blit(uint8_t * const * buf, int src_x, int src_y, | 102 | static inline void yuv_blit(uint8_t * const * buf, int src_x, int src_y, |
67 | int stride, int x, int y, int width, int height) | 103 | int stride, int x, int y, int width, int height) |
68 | { | 104 | { |
105 | video_lock(); | ||
106 | |||
69 | #ifdef HAVE_LCD_COLOR | 107 | #ifdef HAVE_LCD_COLOR |
70 | rb->lcd_yuv_blit(buf, src_x, src_y, stride, x, y , width, height); | 108 | rb->lcd_yuv_blit(buf, src_x, src_y, stride, x, y , width, height); |
71 | #else | 109 | #else |
72 | gray_ub_gray_bitmap_part(buf[0], src_x, src_y, stride, x, y, width, height); | 110 | gray_ub_gray_bitmap_part(buf[0], src_x, src_y, stride, x, y, width, height); |
73 | #endif | 111 | #endif |
112 | |||
113 | video_unlock(); | ||
74 | } | 114 | } |
75 | 115 | ||
76 | void vo_draw_frame(uint8_t * const * buf) | 116 | void vo_draw_frame(uint8_t * const * buf) |
77 | { | 117 | { |
78 | if (!vo.visible) | 118 | if (vo.flags == 0) |
79 | { | 119 | { |
80 | /* Frame is hidden - copout */ | 120 | /* Frame is hidden - copout */ |
81 | DEBUGF("vo hidden\n"); | 121 | DEBUGF("vo hidden\n"); |
@@ -94,14 +134,6 @@ void vo_draw_frame(uint8_t * const * buf) | |||
94 | vo.output_height); | 134 | vo.output_height); |
95 | } | 135 | } |
96 | 136 | ||
97 | #if LCD_WIDTH >= LCD_HEIGHT | ||
98 | #define SCREEN_WIDTH LCD_WIDTH | ||
99 | #define SCREEN_HEIGHT LCD_HEIGHT | ||
100 | #else /* Assume the screen is rotated on portrait LCDs */ | ||
101 | #define SCREEN_WIDTH LCD_HEIGHT | ||
102 | #define SCREEN_HEIGHT LCD_WIDTH | ||
103 | #endif | ||
104 | |||
105 | static inline void vo_rect_clear_inl(struct vo_rect *rc) | 137 | static inline void vo_rect_clear_inl(struct vo_rect *rc) |
106 | { | 138 | { |
107 | rc->l = rc->t = rc->r = rc->b = 0; | 139 | rc->l = rc->t = rc->r = rc->b = 0; |
@@ -172,6 +204,48 @@ bool vo_rect_intersect(struct vo_rect *rc_dst, | |||
172 | return false; | 204 | return false; |
173 | } | 205 | } |
174 | 206 | ||
207 | bool vo_rect_union(struct vo_rect *rc_dst, | ||
208 | const struct vo_rect *rc1, | ||
209 | const struct vo_rect *rc2) | ||
210 | { | ||
211 | if (rc_dst != NULL) | ||
212 | { | ||
213 | if (!vo_rect_empty_inl(rc1)) | ||
214 | { | ||
215 | if (!vo_rect_empty_inl(rc2)) | ||
216 | { | ||
217 | rc_dst->l = MIN(rc1->l, rc2->l); | ||
218 | rc_dst->t = MIN(rc1->t, rc2->t); | ||
219 | rc_dst->r = MAX(rc1->r, rc2->r); | ||
220 | rc_dst->b = MAX(rc1->b, rc2->b); | ||
221 | } | ||
222 | else | ||
223 | { | ||
224 | *rc_dst = *rc1; | ||
225 | } | ||
226 | |||
227 | return true; | ||
228 | } | ||
229 | else if (!vo_rect_empty(rc2)) | ||
230 | { | ||
231 | *rc_dst = *rc2; | ||
232 | return true; | ||
233 | } | ||
234 | |||
235 | vo_rect_clear_inl(rc_dst); | ||
236 | } | ||
237 | |||
238 | return false; | ||
239 | } | ||
240 | |||
241 | void vo_rect_offset(struct vo_rect *rc, int dx, int dy) | ||
242 | { | ||
243 | rc->l += dx; | ||
244 | rc->t += dy; | ||
245 | rc->r += dx; | ||
246 | rc->b += dy; | ||
247 | } | ||
248 | |||
175 | /* Shink or stretch each axis - rotate counter-clockwise to retain upright | 249 | /* Shink or stretch each axis - rotate counter-clockwise to retain upright |
176 | * orientation on rotated displays (they rotate clockwise) */ | 250 | * orientation on rotated displays (they rotate clockwise) */ |
177 | void stretch_image_plane(const uint8_t * src, uint8_t *dst, int stride, | 251 | void stretch_image_plane(const uint8_t * src, uint8_t *dst, int stride, |
@@ -350,25 +424,27 @@ void vo_setup(const mpeg2_sequence_t * sequence) | |||
350 | 424 | ||
351 | if (sequence->display_width >= SCREEN_WIDTH) | 425 | if (sequence->display_width >= SCREEN_WIDTH) |
352 | { | 426 | { |
353 | vo.output_width = SCREEN_WIDTH; | 427 | vo.rc_vid.l = 0; |
354 | vo.output_x = 0; | 428 | vo.rc_vid.r = SCREEN_WIDTH; |
355 | } | 429 | } |
356 | else | 430 | else |
357 | { | 431 | { |
358 | vo.output_width = sequence->display_width; | 432 | vo.rc_vid.l = (SCREEN_WIDTH - sequence->display_width) / 2; |
359 | vo.output_x = (SCREEN_WIDTH - sequence->display_width) / 2; | 433 | vo.rc_vid.r = vo.rc_vid.l + sequence->display_width; |
360 | } | 434 | } |
361 | 435 | ||
362 | if (sequence->display_height >= SCREEN_HEIGHT) | 436 | if (sequence->display_height >= SCREEN_HEIGHT) |
363 | { | 437 | { |
364 | vo.output_height = SCREEN_HEIGHT; | 438 | vo.rc_vid.t = 0; |
365 | vo.output_y = 0; | 439 | vo.rc_vid.b = SCREEN_HEIGHT; |
366 | } | 440 | } |
367 | else | 441 | else |
368 | { | 442 | { |
369 | vo.output_height = sequence->display_height; | 443 | vo.rc_vid.t = (SCREEN_HEIGHT - sequence->display_height) / 2; |
370 | vo.output_y = (SCREEN_HEIGHT - sequence->display_height) / 2; | 444 | vo.rc_vid.b = vo.rc_vid.t + sequence->display_height; |
371 | } | 445 | } |
446 | |||
447 | vo_set_clip_rect(&vo.rc_clip); | ||
372 | } | 448 | } |
373 | 449 | ||
374 | void vo_dimensions(struct vo_ext *sz) | 450 | void vo_dimensions(struct vo_ext *sz) |
@@ -379,23 +455,68 @@ void vo_dimensions(struct vo_ext *sz) | |||
379 | 455 | ||
380 | bool vo_init(void) | 456 | bool vo_init(void) |
381 | { | 457 | { |
382 | vo.visible = false; | 458 | vo.flags = 0; |
459 | vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); | ||
460 | video_lock_init(); | ||
383 | return true; | 461 | return true; |
384 | } | 462 | } |
385 | 463 | ||
386 | bool vo_show(bool show) | 464 | bool vo_show(bool show) |
387 | { | 465 | { |
388 | bool vis = vo.visible; | 466 | bool vis = vo.flags & VO_VISIBLE; |
389 | vo.visible = show; | 467 | |
468 | if (show) | ||
469 | vo.flags |= VO_VISIBLE; | ||
470 | else | ||
471 | vo.flags &= ~VO_VISIBLE; | ||
472 | |||
390 | return vis; | 473 | return vis; |
391 | } | 474 | } |
392 | 475 | ||
393 | bool vo_is_visible(void) | 476 | bool vo_is_visible(void) |
394 | { | 477 | { |
395 | return vo.visible; | 478 | return vo.flags & VO_VISIBLE; |
396 | } | 479 | } |
397 | 480 | ||
398 | void vo_cleanup(void) | 481 | void vo_cleanup(void) |
399 | { | 482 | { |
400 | vo.visible = false; | 483 | vo.flags = 0; |
401 | } | 484 | } |
485 | |||
486 | void vo_set_clip_rect(const struct vo_rect *rc) | ||
487 | { | ||
488 | struct vo_rect rc_out; | ||
489 | |||
490 | if (rc == NULL) | ||
491 | vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); | ||
492 | else | ||
493 | vo.rc_clip = *rc; | ||
494 | |||
495 | if (!vo_rect_intersect(&rc_out, &vo.rc_vid, &vo.rc_clip)) | ||
496 | vo.flags &= ~VO_NON_NULL_RECT; | ||
497 | else | ||
498 | vo.flags |= VO_NON_NULL_RECT; | ||
499 | |||
500 | vo.output_x = rc_out.l; | ||
501 | vo.output_y = rc_out.t; | ||
502 | vo.output_width = rc_out.r - rc_out.l; | ||
503 | vo.output_height = rc_out.b - rc_out.t; | ||
504 | } | ||
505 | |||
506 | #if NUM_CORES > 1 || !defined (HAVE_LCD_COLOR) | ||
507 | void vo_lock(void) | ||
508 | { | ||
509 | #ifndef HAVE_LCD_COLOR | ||
510 | set_irq_level(HIGHEST_IRQ_LEVEL); | ||
511 | #endif | ||
512 | video_lock(); | ||
513 | } | ||
514 | |||
515 | void vo_unlock(void) | ||
516 | { | ||
517 | video_unlock(); | ||
518 | #ifndef HAVE_LCD_COLOR | ||
519 | set_irq_level(0); | ||
520 | #endif | ||
521 | } | ||
522 | #endif | ||
diff --git a/apps/plugins/mpegplayer/video_thread.c b/apps/plugins/mpegplayer/video_thread.c index aeaf942058..950d49a935 100644 --- a/apps/plugins/mpegplayer/video_thread.c +++ b/apps/plugins/mpegplayer/video_thread.c | |||
@@ -75,7 +75,10 @@ static void draw_fps(struct video_thread_data *td) | |||
75 | fps / 100, fps % 100, td->num_skipped, | 75 | fps / 100, fps % 100, td->num_skipped, |
76 | td->info->display_picture->temporal_reference); | 76 | td->info->display_picture->temporal_reference); |
77 | rb->lcd_putsxy(0, 0, str); | 77 | rb->lcd_putsxy(0, 0, str); |
78 | |||
79 | vo_lock(); | ||
78 | rb->lcd_update_rect(0, 0, LCD_WIDTH, 8); | 80 | rb->lcd_update_rect(0, 0, LCD_WIDTH, 8); |
81 | vo_unlock(); | ||
79 | 82 | ||
80 | td->last_showfps = *rb->current_tick; | 83 | td->last_showfps = *rb->current_tick; |
81 | } | 84 | } |
@@ -522,7 +525,9 @@ static void video_thread_msg(struct video_thread_data *td) | |||
522 | else | 525 | else |
523 | { | 526 | { |
524 | IF_COP(invalidate_icache()); | 527 | IF_COP(invalidate_icache()); |
528 | vo_lock(); | ||
525 | rb->lcd_update(); | 529 | rb->lcd_update(); |
530 | vo_unlock(); | ||
526 | } | 531 | } |
527 | #else | 532 | #else |
528 | GRAY_FLUSH_ICACHE(); | 533 | GRAY_FLUSH_ICACHE(); |
@@ -580,6 +585,10 @@ static void video_thread_msg(struct video_thread_data *td) | |||
580 | } | 585 | } |
581 | break; | 586 | break; |
582 | 587 | ||
588 | case VIDEO_SET_CLIP_RECT: | ||
589 | vo_set_clip_rect((const struct vo_rect *)td->ev.data); | ||
590 | break; | ||
591 | |||
583 | case VIDEO_PRINT_FRAME: | 592 | case VIDEO_PRINT_FRAME: |
584 | /* Print the last frame decoded */ | 593 | /* Print the last frame decoded */ |
585 | if (td->info != NULL && td->info->display_fbuf != NULL) | 594 | if (td->info != NULL && td->info->display_fbuf != NULL) |