Improve SDL port 'configure --prefix' error message
[kugel-rb.git] / apps / plugins / mpegplayer / video_out_rockbox.c
blob214bdf3b5ce030d8a93d375524b4f11ce071536f
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;
44 void (*post_draw_callback)(void);
47 #if NUM_CORES > 1
48 /* Cache aligned and padded to avoid clobbering other processors' cacheable
49 * data */
50 static uint8_t __vo_data[CACHEALIGN_UP(sizeof(struct vo_data))]
51 CACHEALIGN_ATTR;
52 #define vo (*((struct vo_data *)__vo_data))
53 #else
54 static struct vo_data vo;
55 #endif
57 #if NUM_CORES > 1
58 static struct mutex vo_mtx SHAREDBSS_ATTR;
59 #endif
61 static inline void video_lock_init(void)
63 #if NUM_CORES > 1
64 rb->mutex_init(&vo_mtx);
65 #endif
68 static inline void video_lock(void)
70 #if NUM_CORES > 1
71 rb->mutex_lock(&vo_mtx);
72 #endif
75 static inline void video_unlock(void)
77 #if NUM_CORES > 1
78 rb->mutex_unlock(&vo_mtx);
79 #endif
83 /* Draw a black rectangle if no video frame is available */
84 static void vo_draw_black(struct vo_rect *rc)
86 int foreground;
87 int x, y, w, h;
89 video_lock();
91 foreground = mylcd_get_foreground();
93 mylcd_set_foreground(MYLCD_BLACK);
95 if (rc)
97 x = rc->l;
98 y = rc->t;
99 w = rc->r - rc->l;
100 h = rc->b - rc->t;
102 else
104 #if LCD_WIDTH >= LCD_HEIGHT
105 x = vo.output_x;
106 y = vo.output_y;
107 w = vo.output_width;
108 h = vo.output_height;
109 #else
110 x = LCD_WIDTH - vo.output_height - vo.output_y;
111 y = vo.output_x;
112 w = vo.output_height;
113 h = vo.output_width;
114 #endif
117 mylcd_fillrect(x, y, w, h);
118 mylcd_update_rect(x, y, w, h);
120 mylcd_set_foreground(foreground);
122 video_unlock();
125 static inline void yuv_blit(uint8_t * const * buf, int src_x, int src_y,
126 int stride, int x, int y, int width, int height)
128 video_lock();
130 #ifdef HAVE_LCD_COLOR
131 rb->lcd_blit_yuv(buf, src_x, src_y, stride, x, y , width, height);
132 #else
133 grey_ub_gray_bitmap_part(buf[0], src_x, src_y, stride, x, y, width, height);
134 #endif
136 video_unlock();
139 void vo_draw_frame(uint8_t * const * buf)
141 if ((vo.flags & (VO_NON_NULL_RECT | VO_VISIBLE)) !=
142 (VO_NON_NULL_RECT | VO_VISIBLE))
144 /* Frame is hidden - either by being set invisible or is clipped
145 * away - copout */
146 DEBUGF("vo hidden\n");
148 else if (buf == NULL)
150 /* No frame exists - draw black */
151 vo_draw_black(NULL);
152 DEBUGF("vo no frame\n");
154 else
156 yuv_blit(buf, 0, 0, vo.image_width,
157 vo.output_x, vo.output_y, vo.output_width,
158 vo.output_height);
161 if (vo.post_draw_callback)
162 vo.post_draw_callback();
165 static inline void vo_rect_clear_inl(struct vo_rect *rc)
167 rc->l = rc->t = rc->r = rc->b = 0;
170 static inline bool vo_rect_empty_inl(const struct vo_rect *rc)
172 return rc == NULL || rc->l >= rc->r || rc->t >= rc->b;
175 static inline bool vo_rects_intersect_inl(const struct vo_rect *rc1,
176 const struct vo_rect *rc2)
178 return !vo_rect_empty_inl(rc1) &&
179 !vo_rect_empty_inl(rc2) &&
180 rc1->l < rc2->r && rc1->r > rc2->l &&
181 rc1->t < rc2->b && rc1->b > rc2->t;
184 /* Sets all coordinates of a vo_rect to 0 */
185 void vo_rect_clear(struct vo_rect *rc)
187 vo_rect_clear_inl(rc);
190 /* Returns true if left >= right or top >= bottom */
191 bool vo_rect_empty(const struct vo_rect *rc)
193 return vo_rect_empty_inl(rc);
196 /* Initializes a vo_rect using upper-left corner and extents */
197 void vo_rect_set_ext(struct vo_rect *rc, int x, int y,
198 int width, int height)
200 rc->l = x;
201 rc->t = y;
202 rc->r = x + width;
203 rc->b = y + height;
206 /* Query if two rectangles intersect */
207 bool vo_rects_intersect(const struct vo_rect *rc1,
208 const struct vo_rect *rc2)
210 return vo_rects_intersect_inl(rc1, rc2);
213 /* Intersect two rectangles, placing the result in rc_dst */
214 bool vo_rect_intersect(struct vo_rect *rc_dst,
215 const struct vo_rect *rc1,
216 const struct vo_rect *rc2)
218 if (rc_dst != NULL)
220 if (vo_rects_intersect_inl(rc1, rc2))
222 rc_dst->l = MAX(rc1->l, rc2->l);
223 rc_dst->r = MIN(rc1->r, rc2->r);
224 rc_dst->t = MAX(rc1->t, rc2->t);
225 rc_dst->b = MIN(rc1->b, rc2->b);
226 return true;
229 vo_rect_clear_inl(rc_dst);
232 return false;
235 bool vo_rect_union(struct vo_rect *rc_dst,
236 const struct vo_rect *rc1,
237 const struct vo_rect *rc2)
239 if (rc_dst != NULL)
241 if (!vo_rect_empty_inl(rc1))
243 if (!vo_rect_empty_inl(rc2))
245 rc_dst->l = MIN(rc1->l, rc2->l);
246 rc_dst->t = MIN(rc1->t, rc2->t);
247 rc_dst->r = MAX(rc1->r, rc2->r);
248 rc_dst->b = MAX(rc1->b, rc2->b);
250 else
252 *rc_dst = *rc1;
255 return true;
257 else if (!vo_rect_empty_inl(rc2))
259 *rc_dst = *rc2;
260 return true;
263 vo_rect_clear_inl(rc_dst);
266 return false;
269 void vo_rect_offset(struct vo_rect *rc, int dx, int dy)
271 rc->l += dx;
272 rc->t += dy;
273 rc->r += dx;
274 rc->b += dy;
277 /* Shink or stretch each axis - rotate counter-clockwise to retain upright
278 * orientation on rotated displays (they rotate clockwise) */
279 void stretch_image_plane(const uint8_t * src, uint8_t *dst, int stride,
280 int src_w, int src_h, int dst_w, int dst_h)
282 uint8_t *dst_end = dst + dst_w*dst_h;
284 #if LCD_WIDTH >= LCD_HEIGHT
285 int src_w2 = src_w*2; /* 2x dimensions (for rounding before division) */
286 int dst_w2 = dst_w*2;
287 int src_h2 = src_h*2;
288 int dst_h2 = dst_h*2;
289 int qw = src_w2 / dst_w2; /* src-dst width ratio quotient */
290 int rw = src_w2 - qw*dst_w2; /* src-dst width ratio remainder */
291 int qh = src_h2 / dst_h2; /* src-dst height ratio quotient */
292 int rh = src_h2 - qh*dst_h2; /* src-dst height ratio remainder */
293 int dw = dst_w; /* Width error accumulator */
294 int dh = dst_h; /* Height error accumulator */
295 #else
296 int src_w2 = src_w*2;
297 int dst_w2 = dst_h*2;
298 int src_h2 = src_h*2;
299 int dst_h2 = dst_w*2;
300 int qw = src_h2 / dst_w2;
301 int rw = src_h2 - qw*dst_w2;
302 int qh = src_w2 / dst_h2;
303 int rh = src_w2 - qh*dst_h2;
304 int dw = dst_h;
305 int dh = dst_w;
307 src += src_w - 1;
308 #endif
310 while (1)
312 const uint8_t *s = src;
313 #if LCD_WIDTH >= LCD_HEIGHT
314 uint8_t * const dst_line_end = dst + dst_w;
315 #else
316 uint8_t * const dst_line_end = dst + dst_h;
317 #endif
318 while (1)
320 *dst++ = *s;
322 if (dst >= dst_line_end)
324 dw = dst_w;
325 break;
328 #if LCD_WIDTH >= LCD_HEIGHT
329 s += qw;
330 #else
331 s += qw*stride;
332 #endif
333 dw += rw;
335 if (dw >= dst_w2)
337 dw -= dst_w2;
338 #if LCD_WIDTH >= LCD_HEIGHT
339 s++;
340 #else
341 s += stride;
342 #endif
346 if (dst >= dst_end)
347 break;
348 #if LCD_WIDTH >= LCD_HEIGHT
349 src += qh*stride;
350 #else
351 src -= qh;
352 #endif
353 dh += rh;
355 if (dh >= dst_h2)
357 dh -= dst_h2;
358 #if LCD_WIDTH >= LCD_HEIGHT
359 src += stride;
360 #else
361 src--;
362 #endif
367 bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc)
369 void *mem;
370 size_t bufsize;
371 uint8_t *yuv[3];
372 struct vo_rect thumb_rc;
373 int thumb_width, thumb_height;
374 int thumb_uv_width, thumb_uv_height;
376 /* Obtain rectangle as clipped to the screen */
377 vo_rect_set_ext(&thumb_rc, 0, 0, LCD_WIDTH, LCD_HEIGHT);
378 if (!vo_rect_intersect(&thumb_rc, rc, &thumb_rc))
379 return true;
381 if (buf == NULL)
382 goto no_thumb_exit;
384 DEBUGF("thumb_rc: %d, %d, %d, %d\n", thumb_rc.l, thumb_rc.t,
385 thumb_rc.r, thumb_rc.b);
387 thumb_width = rc->r - rc->l;
388 thumb_height = rc->b - rc->t;
389 thumb_uv_width = thumb_width / 2;
390 thumb_uv_height = thumb_height / 2;
392 DEBUGF("thumb: w: %d h: %d uvw: %d uvh: %d\n", thumb_width,
393 thumb_height, thumb_uv_width, thumb_uv_height);
395 /* Use remaining mpeg2 buffer as temp space */
396 mem = mpeg2_get_buf(&bufsize);
398 if (bufsize < (size_t)(thumb_width*thumb_height)
399 #ifdef HAVE_LCD_COLOR
400 + 2u*(thumb_uv_width * thumb_uv_height)
401 #endif
404 DEBUGF("thumb: insufficient buffer\n");
405 goto no_thumb_exit;
408 yuv[0] = mem;
409 stretch_image_plane(buf[0], yuv[0], vo.image_width,
410 vo.display_width, vo.display_height,
411 thumb_width, thumb_height);
413 #ifdef HAVE_LCD_COLOR
414 yuv[1] = yuv[0] + thumb_width*thumb_height;
415 yuv[2] = yuv[1] + thumb_uv_width*thumb_uv_height;
417 stretch_image_plane(buf[1], yuv[1], vo.image_width / 2,
418 vo.display_width / 2, vo.display_height / 2,
419 thumb_uv_width, thumb_uv_height);
421 stretch_image_plane(buf[2], yuv[2], vo.image_width / 2,
422 vo.display_width / 2, vo.display_height / 2,
423 thumb_uv_width, thumb_uv_height);
424 #endif
426 #if LCD_WIDTH >= LCD_HEIGHT
427 yuv_blit(yuv, 0, 0, thumb_width,
428 thumb_rc.l, thumb_rc.t,
429 thumb_rc.r - thumb_rc.l,
430 thumb_rc.b - thumb_rc.t);
431 #else
432 yuv_blit(yuv, 0, 0, thumb_height,
433 thumb_rc.t, thumb_rc.l,
434 thumb_rc.b - thumb_rc.t,
435 thumb_rc.r - thumb_rc.l);
436 #endif /* LCD_WIDTH >= LCD_HEIGHT */
438 return true;
440 no_thumb_exit:
441 vo_draw_black(&thumb_rc);
442 return false;
445 void vo_setup(const mpeg2_sequence_t * sequence)
447 vo.image_width = sequence->width;
448 vo.image_height = sequence->height;
449 vo.display_width = sequence->display_width;
450 vo.display_height = sequence->display_height;
452 DEBUGF("vo_setup - w:%d h:%d\n", vo.display_width, vo.display_height);
454 vo.image_chroma_x = vo.image_width / sequence->chroma_width;
455 vo.image_chroma_y = vo.image_height / sequence->chroma_height;
457 if (sequence->display_width >= SCREEN_WIDTH)
459 vo.rc_vid.l = 0;
460 vo.rc_vid.r = SCREEN_WIDTH;
462 else
464 vo.rc_vid.l = (SCREEN_WIDTH - sequence->display_width) / 2;
465 #ifdef HAVE_LCD_COLOR
466 vo.rc_vid.l &= ~1;
467 #endif
468 vo.rc_vid.r = vo.rc_vid.l + sequence->display_width;
471 if (sequence->display_height >= SCREEN_HEIGHT)
473 vo.rc_vid.t = 0;
474 vo.rc_vid.b = SCREEN_HEIGHT;
476 else
478 vo.rc_vid.t = (SCREEN_HEIGHT - sequence->display_height) / 2;
479 #ifdef HAVE_LCD_COLOR
480 vo.rc_vid.t &= ~1;
481 #endif
482 vo.rc_vid.b = vo.rc_vid.t + sequence->display_height;
485 vo_set_clip_rect(&vo.rc_clip);
488 void vo_dimensions(struct vo_ext *sz)
490 sz->w = vo.display_width;
491 sz->h = vo.display_height;
494 bool vo_init(void)
496 vo.flags = 0;
497 vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
498 video_lock_init();
499 return true;
502 bool vo_show(bool show)
504 bool vis = vo.flags & VO_VISIBLE;
506 if (show)
507 vo.flags |= VO_VISIBLE;
508 else
509 vo.flags &= ~VO_VISIBLE;
511 return vis;
514 bool vo_is_visible(void)
516 return vo.flags & VO_VISIBLE;
519 void vo_cleanup(void)
521 vo.flags = 0;
524 void vo_set_clip_rect(const struct vo_rect *rc)
526 struct vo_rect rc_out;
528 if (rc == NULL)
529 vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
530 else
531 vo.rc_clip = *rc;
533 if (!vo_rect_intersect(&rc_out, &vo.rc_vid, &vo.rc_clip))
534 vo.flags &= ~VO_NON_NULL_RECT;
535 else
536 vo.flags |= VO_NON_NULL_RECT;
538 vo.output_x = rc_out.l;
539 vo.output_y = rc_out.t;
540 vo.output_width = rc_out.r - rc_out.l;
541 vo.output_height = rc_out.b - rc_out.t;
544 bool vo_get_clip_rect(struct vo_rect *rc)
546 rc->l = vo.output_x;
547 rc->t = vo.output_y;
548 rc->r = rc->l + vo.output_width;
549 rc->b = rc->t + vo.output_height;
550 return (vo.flags & VO_NON_NULL_RECT) != 0;
553 void vo_set_post_draw_callback(void (*cb)(void))
555 vo.post_draw_callback = cb;
558 #if NUM_CORES > 1
559 void vo_lock(void)
561 video_lock();
564 void vo_unlock(void)
566 video_unlock();
568 #endif