1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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"
24 #include "mpegplayer.h"
26 #define VO_NON_NULL_RECT 0x1
27 #define VO_VISIBLE 0x2
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
49 static uint8_t __vo_data
[CACHEALIGN_UP(sizeof(struct vo_data
))]
51 #define vo (*((struct vo_data *)__vo_data))
53 static struct vo_data vo
;
57 static struct mutex vo_mtx SHAREDBSS_ATTR
;
60 static inline void video_lock_init(void)
63 rb
->mutex_init(&vo_mtx
);
67 static inline void video_lock(void)
70 rb
->mutex_lock(&vo_mtx
);
74 static inline void video_unlock(void)
77 rb
->mutex_unlock(&vo_mtx
);
82 /* Draw a black rectangle if no video frame is available */
83 static void vo_draw_black(void)
89 foreground
= lcd_(get_foreground
)();
91 lcd_(set_foreground
)(DRAW_BLACK
);
93 lcd_(fillrect
)(vo
.output_x
, vo
.output_y
, vo
.output_width
,
95 lcd_(update_rect
)(vo
.output_x
, vo
.output_y
, vo
.output_width
,
98 lcd_(set_foreground
)(foreground
);
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
)
108 #ifdef HAVE_LCD_COLOR
109 rb
->lcd_blit_yuv(buf
, src_x
, src_y
, stride
, x
, y
, width
, height
);
111 grey_ub_gray_bitmap_part(buf
[0], src_x
, src_y
, stride
, x
, y
, width
, height
);
117 void vo_draw_frame(uint8_t * const * buf
)
121 /* Frame is hidden - copout */
122 DEBUGF("vo hidden\n");
125 else if (buf
== NULL
)
127 /* No frame exists - draw black */
129 DEBUGF("vo no frame\n");
133 yuv_blit(buf
, 0, 0, vo
.image_width
,
134 vo
.output_x
, vo
.output_y
, vo
.output_width
,
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
)
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
)
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
);
202 vo_rect_clear_inl(rc_dst
);
208 bool vo_rect_union(struct vo_rect
*rc_dst
,
209 const struct vo_rect
*rc1
,
210 const struct vo_rect
*rc2
)
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
);
230 else if (!vo_rect_empty_inl(rc2
))
236 vo_rect_clear_inl(rc_dst
);
242 void vo_rect_offset(struct vo_rect
*rc
, int dx
, int 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 */
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
;
285 const uint8_t *s
= src
;
286 #if LCD_WIDTH >= LCD_HEIGHT
287 uint8_t * const dst_line_end
= dst
+ dst_w
;
289 uint8_t * const dst_line_end
= dst
+ dst_h
;
295 if (dst
>= dst_line_end
)
301 #if LCD_WIDTH >= LCD_HEIGHT
311 #if LCD_WIDTH >= LCD_HEIGHT
321 #if LCD_WIDTH >= LCD_HEIGHT
331 #if LCD_WIDTH >= LCD_HEIGHT
340 bool vo_draw_frame_thumb(uint8_t * const * buf
, const struct vo_rect
*rc
)
345 struct vo_rect thumb_rc
;
346 int thumb_width
, thumb_height
;
347 int thumb_uv_width
, thumb_uv_height
;
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
))
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
)
377 DEBUGF("thumb: insufficient buffer\n");
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
);
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
);
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 */
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
)
429 vo
.rc_vid
.r
= SCREEN_WIDTH
;
433 vo
.rc_vid
.l
= (SCREEN_WIDTH
- sequence
->display_width
) / 2;
434 #ifdef HAVE_LCD_COLOR
437 vo
.rc_vid
.r
= vo
.rc_vid
.l
+ sequence
->display_width
;
440 if (sequence
->display_height
>= SCREEN_HEIGHT
)
443 vo
.rc_vid
.b
= SCREEN_HEIGHT
;
447 vo
.rc_vid
.t
= (SCREEN_HEIGHT
- sequence
->display_height
) / 2;
448 #ifdef HAVE_LCD_COLOR
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
;
466 vo_rect_set_ext(&vo
.rc_clip
, 0, 0, SCREEN_WIDTH
, SCREEN_HEIGHT
);
471 bool vo_show(bool show
)
473 bool vis
= vo
.flags
& VO_VISIBLE
;
476 vo
.flags
|= VO_VISIBLE
;
478 vo
.flags
&= ~VO_VISIBLE
;
483 bool vo_is_visible(void)
485 return vo
.flags
& VO_VISIBLE
;
488 void vo_cleanup(void)
493 void vo_set_clip_rect(const struct vo_rect
*rc
)
495 struct vo_rect rc_out
;
498 vo_rect_set_ext(&vo
.rc_clip
, 0, 0, SCREEN_WIDTH
, SCREEN_HEIGHT
);
502 if (!vo_rect_intersect(&rc_out
, &vo
.rc_vid
, &vo
.rc_clip
))
503 vo
.flags
&= ~VO_NON_NULL_RECT
;
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
;