Rearange menu of mpegplayer. Add new menu with "settings" and "quit", and remove...
[kugel-rb.git] / apps / plugins / mpegplayer / video_out_rockbox.c
blob450a8bc7a17dbe6f720148ff7733592618468cbd
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * mpegplayer video output routines
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "mpeg2dec_config.h"
23 #include "plugin.h"
24 #include "mpegplayer.h"
26 #define VO_NON_NULL_RECT 0x1
27 #define VO_VISIBLE 0x2
29 struct vo_data
31 int image_width;
32 int image_height;
33 int image_chroma_x;
34 int image_chroma_y;
35 int display_width;
36 int display_height;
37 int output_x;
38 int output_y;
39 int output_width;
40 int output_height;
41 unsigned flags;
42 struct vo_rect rc_vid;
43 struct vo_rect rc_clip;
46 #ifdef PROC_NEEDS_CACHEALIGN
47 /* Cache aligned and padded to avoid clobbering other processors' cacheable
48 * data */
49 static uint8_t __vo_data[CACHEALIGN_UP(sizeof(struct vo_data))]
50 CACHEALIGN_ATTR;
51 #define vo (*((struct vo_data *)__vo_data))
52 #else
53 static struct vo_data vo;
54 #endif
56 #if NUM_CORES > 1
57 static struct mutex vo_mtx SHAREDBSS_ATTR;
58 #endif
60 static inline void video_lock_init(void)
62 #if NUM_CORES > 1
63 rb->mutex_init(&vo_mtx);
64 #endif
67 static inline void video_lock(void)
69 #if NUM_CORES > 1
70 rb->mutex_lock(&vo_mtx);
71 #endif
74 static inline void video_unlock(void)
76 #if NUM_CORES > 1
77 rb->mutex_unlock(&vo_mtx);
78 #endif
82 /* Draw a black rectangle if no video frame is available */
83 static void vo_draw_black(void)
85 int foreground;
87 video_lock();
89 foreground = lcd_(get_foreground)();
91 lcd_(set_foreground)(DRAW_BLACK);
93 lcd_(fillrect)(vo.output_x, vo.output_y, vo.output_width,
94 vo.output_height);
95 lcd_(update_rect)(vo.output_x, vo.output_y, vo.output_width,
96 vo.output_height);
98 lcd_(set_foreground)(foreground);
100 video_unlock();
103 static inline void yuv_blit(uint8_t * const * buf, int src_x, int src_y,
104 int stride, int x, int y, int width, int height)
106 video_lock();
108 #ifdef HAVE_LCD_COLOR
109 rb->lcd_blit_yuv(buf, src_x, src_y, stride, x, y , width, height);
110 #else
111 grey_ub_gray_bitmap_part(buf[0], src_x, src_y, stride, x, y, width, height);
112 #endif
114 video_unlock();
117 void vo_draw_frame(uint8_t * const * buf)
119 if (vo.flags == 0)
121 /* Frame is hidden - copout */
122 DEBUGF("vo hidden\n");
123 return;
125 else if (buf == NULL)
127 /* No frame exists - draw black */
128 vo_draw_black();
129 DEBUGF("vo no frame\n");
130 return;
133 yuv_blit(buf, 0, 0, vo.image_width,
134 vo.output_x, vo.output_y, vo.output_width,
135 vo.output_height);
138 static inline void vo_rect_clear_inl(struct vo_rect *rc)
140 rc->l = rc->t = rc->r = rc->b = 0;
143 static inline bool vo_rect_empty_inl(const struct vo_rect *rc)
145 return rc == NULL || rc->l >= rc->r || rc->t >= rc->b;
148 static inline bool vo_rects_intersect_inl(const struct vo_rect *rc1,
149 const struct vo_rect *rc2)
151 return !vo_rect_empty_inl(rc1) &&
152 !vo_rect_empty_inl(rc2) &&
153 rc1->l < rc2->r && rc1->r > rc2->l &&
154 rc1->t < rc2->b && rc1->b > rc2->t;
157 /* Sets all coordinates of a vo_rect to 0 */
158 void vo_rect_clear(struct vo_rect *rc)
160 vo_rect_clear_inl(rc);
163 /* Returns true if left >= right or top >= bottom */
164 bool vo_rect_empty(const struct vo_rect *rc)
166 return vo_rect_empty_inl(rc);
169 /* Initializes a vo_rect using upper-left corner and extents */
170 void vo_rect_set_ext(struct vo_rect *rc, int x, int y,
171 int width, int height)
173 rc->l = x;
174 rc->t = y;
175 rc->r = x + width;
176 rc->b = y + height;
179 /* Query if two rectangles intersect */
180 bool vo_rects_intersect(const struct vo_rect *rc1,
181 const struct vo_rect *rc2)
183 return vo_rects_intersect_inl(rc1, rc2);
186 /* Intersect two rectangles, placing the result in rc_dst */
187 bool vo_rect_intersect(struct vo_rect *rc_dst,
188 const struct vo_rect *rc1,
189 const struct vo_rect *rc2)
191 if (rc_dst != NULL)
193 if (vo_rects_intersect_inl(rc1, rc2))
195 rc_dst->l = MAX(rc1->l, rc2->l);
196 rc_dst->r = MIN(rc1->r, rc2->r);
197 rc_dst->t = MAX(rc1->t, rc2->t);
198 rc_dst->b = MIN(rc1->b, rc2->b);
199 return true;
202 vo_rect_clear_inl(rc_dst);
205 return false;
208 bool vo_rect_union(struct vo_rect *rc_dst,
209 const struct vo_rect *rc1,
210 const struct vo_rect *rc2)
212 if (rc_dst != NULL)
214 if (!vo_rect_empty_inl(rc1))
216 if (!vo_rect_empty_inl(rc2))
218 rc_dst->l = MIN(rc1->l, rc2->l);
219 rc_dst->t = MIN(rc1->t, rc2->t);
220 rc_dst->r = MAX(rc1->r, rc2->r);
221 rc_dst->b = MAX(rc1->b, rc2->b);
223 else
225 *rc_dst = *rc1;
228 return true;
230 else if (!vo_rect_empty_inl(rc2))
232 *rc_dst = *rc2;
233 return true;
236 vo_rect_clear_inl(rc_dst);
239 return false;
242 void vo_rect_offset(struct vo_rect *rc, int dx, int dy)
244 rc->l += dx;
245 rc->t += dy;
246 rc->r += dx;
247 rc->b += dy;
250 /* Shink or stretch each axis - rotate counter-clockwise to retain upright
251 * orientation on rotated displays (they rotate clockwise) */
252 void stretch_image_plane(const uint8_t * src, uint8_t *dst, int stride,
253 int src_w, int src_h, int dst_w, int dst_h)
255 uint8_t *dst_end = dst + dst_w*dst_h;
257 #if LCD_WIDTH >= LCD_HEIGHT
258 int src_w2 = src_w*2; /* 2x dimensions (for rounding before division) */
259 int dst_w2 = dst_w*2;
260 int src_h2 = src_h*2;
261 int dst_h2 = dst_h*2;
262 int qw = src_w2 / dst_w2; /* src-dst width ratio quotient */
263 int rw = src_w2 - qw*dst_w2; /* src-dst width ratio remainder */
264 int qh = src_h2 / dst_h2; /* src-dst height ratio quotient */
265 int rh = src_h2 - qh*dst_h2; /* src-dst height ratio remainder */
266 int dw = dst_w; /* Width error accumulator */
267 int dh = dst_h; /* Height error accumulator */
268 #else
269 int src_w2 = src_w*2;
270 int dst_w2 = dst_h*2;
271 int src_h2 = src_h*2;
272 int dst_h2 = dst_w*2;
273 int qw = src_h2 / dst_w2;
274 int rw = src_h2 - qw*dst_w2;
275 int qh = src_w2 / dst_h2;
276 int rh = src_w2 - qh*dst_h2;
277 int dw = dst_h;
278 int dh = dst_w;
280 src += src_w - 1;
281 #endif
283 while (1)
285 const uint8_t *s = src;
286 #if LCD_WIDTH >= LCD_HEIGHT
287 uint8_t * const dst_line_end = dst + dst_w;
288 #else
289 uint8_t * const dst_line_end = dst + dst_h;
290 #endif
291 while (1)
293 *dst++ = *s;
295 if (dst >= dst_line_end)
297 dw = dst_w;
298 break;
301 #if LCD_WIDTH >= LCD_HEIGHT
302 s += qw;
303 #else
304 s += qw*stride;
305 #endif
306 dw += rw;
308 if (dw >= dst_w2)
310 dw -= dst_w2;
311 #if LCD_WIDTH >= LCD_HEIGHT
312 s++;
313 #else
314 s += stride;
315 #endif
319 if (dst >= dst_end)
320 break;
321 #if LCD_WIDTH >= LCD_HEIGHT
322 src += qh*stride;
323 #else
324 src -= qh;
325 #endif
326 dh += rh;
328 if (dh >= dst_h2)
330 dh -= dst_h2;
331 #if LCD_WIDTH >= LCD_HEIGHT
332 src += stride;
333 #else
334 src--;
335 #endif
340 bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc)
342 void *mem;
343 size_t bufsize;
344 uint8_t *yuv[3];
345 struct vo_rect thumb_rc;
346 int thumb_width, thumb_height;
347 int thumb_uv_width, thumb_uv_height;
349 if (buf == NULL)
350 return false;
352 /* Obtain rectangle as clipped to the screen */
353 vo_rect_set_ext(&thumb_rc, 0, 0, LCD_WIDTH, LCD_HEIGHT);
354 if (!vo_rect_intersect(&thumb_rc, rc, &thumb_rc))
355 return true;
357 DEBUGF("thumb_rc: %d, %d, %d, %d\n", thumb_rc.l, thumb_rc.t,
358 thumb_rc.r, thumb_rc.b);
360 thumb_width = rc->r - rc->l;
361 thumb_height = rc->b - rc->t;
362 thumb_uv_width = thumb_width / 2;
363 thumb_uv_height = thumb_height / 2;
365 DEBUGF("thumb: w: %d h: %d uvw: %d uvh: %d\n", thumb_width,
366 thumb_height, thumb_uv_width, thumb_uv_height);
368 /* Use remaining mpeg2 buffer as temp space */
369 mem = mpeg2_get_buf(&bufsize);
371 if (bufsize < (size_t)(thumb_width*thumb_height)
372 #ifdef HAVE_LCD_COLOR
373 + 2u*(thumb_uv_width * thumb_uv_height)
374 #endif
377 DEBUGF("thumb: insufficient buffer\n");
378 return false;
381 yuv[0] = mem;
382 stretch_image_plane(buf[0], yuv[0], vo.image_width,
383 vo.display_width, vo.display_height,
384 thumb_width, thumb_height);
386 #ifdef HAVE_LCD_COLOR
387 yuv[1] = yuv[0] + thumb_width*thumb_height;
388 yuv[2] = yuv[1] + thumb_uv_width*thumb_uv_height;
390 stretch_image_plane(buf[1], yuv[1], vo.image_width / 2,
391 vo.display_width / 2, vo.display_height / 2,
392 thumb_uv_width, thumb_uv_height);
394 stretch_image_plane(buf[2], yuv[2], vo.image_width / 2,
395 vo.display_width / 2, vo.display_height / 2,
396 thumb_uv_width, thumb_uv_height);
397 #endif
399 #if LCD_WIDTH >= LCD_HEIGHT
400 yuv_blit(yuv, 0, 0, thumb_width,
401 thumb_rc.l, thumb_rc.t,
402 thumb_rc.r - thumb_rc.l,
403 thumb_rc.b - thumb_rc.t);
404 #else
405 yuv_blit(yuv, 0, 0, thumb_height,
406 thumb_rc.t, thumb_rc.l,
407 thumb_rc.b - thumb_rc.t,
408 thumb_rc.r - thumb_rc.l);
409 #endif /* LCD_WIDTH >= LCD_HEIGHT */
411 return true;
414 void vo_setup(const mpeg2_sequence_t * sequence)
416 vo.image_width = sequence->width;
417 vo.image_height = sequence->height;
418 vo.display_width = sequence->display_width;
419 vo.display_height = sequence->display_height;
421 DEBUGF("vo_setup - w:%d h:%d\n", vo.display_width, vo.display_height);
423 vo.image_chroma_x = vo.image_width / sequence->chroma_width;
424 vo.image_chroma_y = vo.image_height / sequence->chroma_height;
426 if (sequence->display_width >= SCREEN_WIDTH)
428 vo.rc_vid.l = 0;
429 vo.rc_vid.r = SCREEN_WIDTH;
431 else
433 vo.rc_vid.l = (SCREEN_WIDTH - sequence->display_width) / 2;
434 #ifdef HAVE_LCD_COLOR
435 vo.rc_vid.l &= ~1;
436 #endif
437 vo.rc_vid.r = vo.rc_vid.l + sequence->display_width;
440 if (sequence->display_height >= SCREEN_HEIGHT)
442 vo.rc_vid.t = 0;
443 vo.rc_vid.b = SCREEN_HEIGHT;
445 else
447 vo.rc_vid.t = (SCREEN_HEIGHT - sequence->display_height) / 2;
448 #ifdef HAVE_LCD_COLOR
449 vo.rc_vid.t &= ~1;
450 #endif
451 vo.rc_vid.b = vo.rc_vid.t + sequence->display_height;
454 vo_set_clip_rect(&vo.rc_clip);
457 void vo_dimensions(struct vo_ext *sz)
459 sz->w = vo.display_width;
460 sz->h = vo.display_height;
463 bool vo_init(void)
465 vo.flags = 0;
466 vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
467 video_lock_init();
468 return true;
471 bool vo_show(bool show)
473 bool vis = vo.flags & VO_VISIBLE;
475 if (show)
476 vo.flags |= VO_VISIBLE;
477 else
478 vo.flags &= ~VO_VISIBLE;
480 return vis;
483 bool vo_is_visible(void)
485 return vo.flags & VO_VISIBLE;
488 void vo_cleanup(void)
490 vo.flags = 0;
493 void vo_set_clip_rect(const struct vo_rect *rc)
495 struct vo_rect rc_out;
497 if (rc == NULL)
498 vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
499 else
500 vo.rc_clip = *rc;
502 if (!vo_rect_intersect(&rc_out, &vo.rc_vid, &vo.rc_clip))
503 vo.flags &= ~VO_NON_NULL_RECT;
504 else
505 vo.flags |= VO_NON_NULL_RECT;
507 vo.output_x = rc_out.l;
508 vo.output_y = rc_out.t;
509 vo.output_width = rc_out.r - rc_out.l;
510 vo.output_height = rc_out.b - rc_out.t;
513 #if NUM_CORES > 1
514 void vo_lock(void)
516 video_lock();
519 void vo_unlock(void)
521 video_unlock();
523 #endif