summaryrefslogtreecommitdiff
path: root/apps/plugins/mpegplayer/video_out_rockbox.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-12-29 19:46:35 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-12-29 19:46:35 +0000
commita222f27c4a17ed8f9809cda7861fe5f23d4cc0c1 (patch)
treed393a23d83549f99772bb156e59ffb88725148b6 /apps/plugins/mpegplayer/video_out_rockbox.c
parent1d0f6b90ff43776e55b4b9f062c9bea3f99aa768 (diff)
downloadrockbox-a222f27c4a17ed8f9809cda7861fe5f23d4cc0c1.tar.gz
rockbox-a222f27c4a17ed8f9809cda7861fe5f23d4cc0c1.zip
mpegplayer: Make playback engine fully seekable and frame-accurate and split into logical parts. Be sure to have all current features work. Actual UI for seeking will be added soon. Recommended GOP size is about 15-30 frames depending on target or seeking can be slow with really long GOPs (nature of MPEG video). More refined encoding recommendations for a particular player should be posted soon.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15977 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/mpegplayer/video_out_rockbox.c')
-rw-r--r--apps/plugins/mpegplayer/video_out_rockbox.c479
1 files changed, 347 insertions, 132 deletions
diff --git a/apps/plugins/mpegplayer/video_out_rockbox.c b/apps/plugins/mpegplayer/video_out_rockbox.c
index 9dd8d6a467..d5e927e9f1 100644
--- a/apps/plugins/mpegplayer/video_out_rockbox.c
+++ b/apps/plugins/mpegplayer/video_out_rockbox.c
@@ -1,189 +1,404 @@
1/* 1/***************************************************************************
2 * video_out_null.c 2 * __________ __ ___.
3 * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
5 * 9 *
6 * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. 10 * mpegplayer video output routines
7 * See http://libmpeg2.sourceforge.net/ for updates.
8 * 11 *
9 * mpeg2dec is free software; you can redistribute it and/or modify 12 * All files in this archive are subject to the GNU General Public License.
10 * it under the terms of the GNU General Public License as published by 13 * See the file COPYING in the source tree root for full license agreement.
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 * 14 *
14 * mpeg2dec is distributed in the hope that it will be useful, 15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * KIND, either express or implied.
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 * 17 *
19 * You should have received a copy of the GNU General Public License 18 ****************************************************************************/
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include "mpeg2dec_config.h" 19#include "mpeg2dec_config.h"
25 20
26#include "plugin.h" 21#include "plugin.h"
27#include "gray.h" 22#include "mpegplayer.h"
23
24struct vo_data
25{
26 int image_width;
27 int image_height;
28 int image_chroma_x;
29 int image_chroma_y;
30 int display_width;
31 int display_height;
32 int output_x;
33 int output_y;
34 int output_width;
35 int output_height;
36 bool visible;
37 bool thumb_mode;
38 void *last;
39};
40
41#ifdef PROC_NEEDS_CACHEALIGN
42/* Cache aligned and padded to avoid clobbering other processors' cacheable
43 * data */
44static uint8_t __vo_data[CACHEALIGN_UP(sizeof(struct vo_data))]
45 CACHEALIGN_ATTR;
46#define vo (*((struct vo_data *)__vo_data))
47#else
48static struct vo_data vo;
49#endif
50
51/* Draw a black rectangle if no video frame is available */
52static void vo_draw_black(void)
53{
54 int foreground = lcd_(get_foreground)();
28 55
29extern struct plugin_api* rb; 56 lcd_(set_foreground)(DRAW_BLACK);
30 57
31#include "mpeg2.h" 58 lcd_(fillrect)(vo.output_x, vo.output_y, vo.output_width,
32#include "video_out.h" 59 vo.output_height);
60 lcd_(update_rect)(vo.output_x, vo.output_y, vo.output_width,
61 vo.output_height);
33 62
34static int image_width; 63 lcd_(set_foreground)(foreground);
35static int image_height; 64}
36static int image_chroma_x;
37static int image_chroma_y;
38static int output_x;
39static int output_y;
40static int output_width;
41static int output_height;
42 65
43void vo_draw_frame (uint8_t * const * buf) 66static 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)
44{ 68{
45#ifdef HAVE_LCD_COLOR 69#ifdef HAVE_LCD_COLOR
46 rb->lcd_yuv_blit(buf, 0,0,image_width, 70 rb->lcd_yuv_blit(buf, src_x, src_y, stride, x, y , width, height);
47 output_x,output_y,output_width,output_height);
48#else 71#else
49 gray_ub_gray_bitmap_part(buf[0],0,0,image_width, 72 gray_ub_gray_bitmap_part(buf[0], src_x, src_y, stride, x, y, width, height);
50 output_x,output_y,output_width,output_height);
51#endif 73#endif
52} 74}
53 75
76void vo_draw_frame(uint8_t * const * buf)
77{
78 if (!vo.visible)
79 {
80 /* Frame is hidden - copout */
81 DEBUGF("vo hidden\n");
82 return;
83 }
84 else if (buf == NULL)
85 {
86 /* No frame exists - draw black */
87 vo_draw_black();
88 DEBUGF("vo no frame\n");
89 return;
90 }
91
92 yuv_blit(buf, 0, 0, vo.image_width,
93 vo.output_x, vo.output_y, vo.output_width,
94 vo.output_height);
95}
96
54#if LCD_WIDTH >= LCD_HEIGHT 97#if LCD_WIDTH >= LCD_HEIGHT
55#define SCREEN_WIDTH LCD_WIDTH 98#define SCREEN_WIDTH LCD_WIDTH
56#define SCREEN_HEIGHT LCD_HEIGHT 99#define SCREEN_HEIGHT LCD_HEIGHT
57#else /* Assume the screen is rotates on portraid LCDs */ 100#else /* Assume the screen is rotated on portrait LCDs */
58#define SCREEN_WIDTH LCD_HEIGHT 101#define SCREEN_WIDTH LCD_HEIGHT
59#define SCREEN_HEIGHT LCD_WIDTH 102#define SCREEN_HEIGHT LCD_WIDTH
60#endif 103#endif
61 104
62uint8_t* tmpbufa = 0; 105static inline void vo_rect_clear_inl(struct vo_rect *rc)
63uint8_t* tmpbufb = 0; 106{
64uint8_t* tmpbufc = 0; 107 rc->l = rc->t = rc->r = rc->b = 0;
65uint8_t* tmpbuf[3]; 108}
66 109
67void vo_draw_frame_thumb (uint8_t * const * buf) 110static inline bool vo_rect_empty_inl(const struct vo_rect *rc)
68{ 111{
69 int r,c; 112 return rc == NULL || rc->l >= rc->r || rc->t >= rc->b;
113}
70 114
71#if LCD_WIDTH >= LCD_HEIGHT 115static inline bool vo_rects_intersect_inl(const struct vo_rect *rc1,
72 for (r=0;r<image_width/2;r++) 116 const struct vo_rect *rc2)
73 for (c=0;c<image_height/2;c++) 117{
74 *(tmpbuf[0]+c*image_width/2+r) = 118 return !vo_rect_empty_inl(rc1) &&
75 *(buf[0]+2*c*image_width+2*r); 119 !vo_rect_empty_inl(rc2) &&
76 120 rc1->l < rc2->r && rc1->r > rc2->l &&
77 for (r=0;r<image_width/4;r++) 121 rc1->t < rc2->b && rc1->b > rc2->t;
78 for (c=0;c<image_height/4;c++) 122}
123
124/* Sets all coordinates of a vo_rect to 0 */
125void vo_rect_clear(struct vo_rect *rc)
126{
127 vo_rect_clear_inl(rc);
128}
129
130/* Returns true if left >= right or top >= bottom */
131bool vo_rect_empty(const struct vo_rect *rc)
132{
133 return vo_rect_empty_inl(rc);
134}
135
136/* Initializes a vo_rect using upper-left corner and extents */
137void vo_rect_set_ext(struct vo_rect *rc, int x, int y,
138 int width, int height)
139{
140 rc->l = x;
141 rc->t = y;
142 rc->r = x + width;
143 rc->b = y + height;
144}
145
146/* Query if two rectangles intersect */
147bool vo_rects_intersect(const struct vo_rect *rc1,
148 const struct vo_rect *rc2)
149{
150 return vo_rects_intersect_inl(rc1, rc2);
151}
152
153/* Intersect two rectangles, placing the result in rc_dst */
154bool vo_rect_intersect(struct vo_rect *rc_dst,
155 const struct vo_rect *rc1,
156 const struct vo_rect *rc2)
157{
158 if (rc_dst != NULL)
79 { 159 {
80 *(tmpbuf[1]+c*image_width/4+r) = 160 if (vo_rects_intersect_inl(rc1, rc2))
81 *(buf[1]+c*image_width+2*r); 161 {
82 *(tmpbuf[2]+c*image_width/4+r) = 162 rc_dst->l = MAX(rc1->l, rc2->l);
83 *(buf[2]+c*image_width+2*r); 163 rc_dst->r = MIN(rc1->r, rc2->r);
164 rc_dst->t = MAX(rc1->t, rc2->t);
165 rc_dst->b = MIN(rc1->b, rc2->b);
166 return true;
167 }
168
169 vo_rect_clear_inl(rc_dst);
84 } 170 }
171
172 return false;
173}
174
175/* Shink or stretch each axis - rotate counter-clockwise to retain upright
176 * orientation on rotated displays (they rotate clockwise) */
177void stretch_image_plane(const uint8_t * src, uint8_t *dst, int stride,
178 int src_w, int src_h, int dst_w, int dst_h)
179{
180 uint8_t *dst_end = dst + dst_w*dst_h;
181
182#if LCD_WIDTH >= LCD_HEIGHT
183 int src_w2 = src_w*2; /* 2x dimensions (for rounding before division) */
184 int dst_w2 = dst_w*2;
185 int src_h2 = src_h*2;
186 int dst_h2 = dst_h*2;
187 int qw = src_w2 / dst_w2; /* src-dst width ratio quotient */
188 int rw = src_w2 - qw*dst_w2; /* src-dst width ratio remainder */
189 int qh = src_h2 / dst_h2; /* src-dst height ratio quotient */
190 int rh = src_h2 - qh*dst_h2; /* src-dst height ratio remainder */
191 int dw = dst_w; /* Width error accumulator */
192 int dh = dst_h; /* Height error accumulator */
85#else 193#else
86 for (r=0;r<image_width/2;r++) 194 int src_w2 = src_w*2;
87 for (c=0;c<image_height/2;c++) 195 int dst_w2 = dst_h*2;
88 *(tmpbuf[0]+(image_width/2-1-r)*image_height/2+c) = 196 int src_h2 = src_h*2;
89 *(buf[0]+2*c*image_width+2*r); 197 int dst_h2 = dst_w*2;
90 198 int qw = src_h2 / dst_w2;
91 for (r=0;r<image_width/4;r++) 199 int rw = src_h2 - qw*dst_w2;
92 for (c=0;c<image_height/4;c++) 200 int qh = src_w2 / dst_h2;
201 int rh = src_w2 - qh*dst_h2;
202 int dw = dst_h;
203 int dh = dst_w;
204
205 src += src_w - 1;
206#endif
207
208 while (1)
93 { 209 {
94 *(tmpbuf[1]+(image_width/4-1-r)*image_height/4+c) = 210 const uint8_t *s = src;
95 *(buf[1]+c*image_width+2*r); 211#if LCD_WIDTH >= LCD_HEIGHT
96 *(tmpbuf[2]+(image_width/4-1-r)*image_height/4+c) = 212 uint8_t * const dst_line_end = dst + dst_w;
97 *(buf[2]+c*image_width+2*r); 213#else
98 } 214 uint8_t * const dst_line_end = dst + dst_h;
99#endif 215#endif
216 while (1)
217 {
218 *dst++ = *s;
100 219
101rb->lcd_clear_display(); 220 if (dst >= dst_line_end)
102rb->lcd_update(); 221 {
222 dw = dst_w;
223 break;
224 }
103 225
104#ifdef HAVE_LCD_COLOR
105#ifdef SIMULATOR
106#if LCD_WIDTH >= LCD_HEIGHT 226#if LCD_WIDTH >= LCD_HEIGHT
107 rb->lcd_yuv_blit(tmpbuf,0,0,image_width/2, 227 s += qw;
108 (LCD_WIDTH-1-image_width/2)/2,
109 LCD_HEIGHT-50-(image_height/2),
110 output_width/2,output_height/2);
111
112#else 228#else
113 rb->lcd_yuv_blit(tmpbuf,0,0,image_height/2, 229 s += qw*stride;
114 LCD_HEIGHT-50-(image_height/2),
115 (LCD_WIDTH-1-image_width/2)/2,
116 output_height/2,output_width/2);
117#endif 230#endif
118#else 231 dw += rw;
232
233 if (dw >= dst_w2)
234 {
235 dw -= dst_w2;
119#if LCD_WIDTH >= LCD_HEIGHT 236#if LCD_WIDTH >= LCD_HEIGHT
120 rb->lcd_yuv_blit(tmpbuf,0,0,image_width/2, 237 s++;
121 (LCD_WIDTH-1-image_width/2)/2,
122 LCD_HEIGHT-50-(image_height/2),
123 output_width/2,output_height/2);
124#else 238#else
125 rb->lcd_yuv_blit(tmpbuf,0,0,image_height/2, 239 s += stride;
126 LCD_HEIGHT-50-(image_height/2),
127 (LCD_WIDTH-1-image_width/2)/2,
128 output_height/2,output_width/2);
129#endif
130#endif 240#endif
241 }
242 }
243
244 if (dst >= dst_end)
245 break;
246#if LCD_WIDTH >= LCD_HEIGHT
247 src += qh*stride;
131#else 248#else
249 src -= qh;
250#endif
251 dh += rh;
252
253 if (dh >= dst_h2)
254 {
255 dh -= dst_h2;
132#if LCD_WIDTH >= LCD_HEIGHT 256#if LCD_WIDTH >= LCD_HEIGHT
133 gray_ub_gray_bitmap_part(tmpbuf[0],0,0,image_width/2, 257 src += stride;
134 (LCD_WIDTH-1-image_width/2)/2,
135 LCD_HEIGHT-50-(image_height/2),
136 output_width/2,output_height/2);
137#else 258#else
138 gray_ub_gray_bitmap_part(tmpbuf[0],0,0,image_height/2, 259 src--;
139 LCD_HEIGHT-50-(image_height/2), 260#endif
140 (LCD_WIDTH-1-image_width/2)/2, 261 }
141 output_height/2,output_width/2); 262 }
263}
264
265bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc)
266{
267 void *mem;
268 size_t bufsize;
269 uint8_t *yuv[3];
270 struct vo_rect thumb_rc;
271 int thumb_width, thumb_height;
272 int thumb_uv_width, thumb_uv_height;
273
274 if (buf == NULL)
275 return false;
276
277 /* Obtain rectangle as clipped to the screen */
278 vo_rect_set_ext(&thumb_rc, 0, 0, LCD_WIDTH, LCD_HEIGHT);
279 if (!vo_rect_intersect(&thumb_rc, rc, &thumb_rc))
280 return true;
281
282 DEBUGF("thumb_rc: %d, %d, %d, %d\n", thumb_rc.l, thumb_rc.t,
283 thumb_rc.r, thumb_rc.b);
284
285 thumb_width = rc->r - rc->l;
286 thumb_height = rc->b - rc->t;
287 thumb_uv_width = thumb_width / 2;
288 thumb_uv_height = thumb_height / 2;
289
290 DEBUGF("thumb: w: %d h: %d uvw: %d uvh: %d\n", thumb_width,
291 thumb_height, thumb_uv_width, thumb_uv_height);
292
293 /* Use remaining mpeg2 buffer as temp space */
294 mem = mpeg2_get_buf(&bufsize);
295
296 if (bufsize < (size_t)(thumb_width*thumb_height)
297#ifdef HAVE_LCD_COLOR
298 + 2u*(thumb_uv_width * thumb_uv_height)
142#endif 299#endif
300 )
301 {
302 DEBUGF("thumb: insufficient buffer\n");
303 return false;
304 }
305
306 yuv[0] = mem;
307 stretch_image_plane(buf[0], yuv[0], vo.image_width,
308 vo.display_width, vo.display_height,
309 thumb_width, thumb_height);
310
311#ifdef HAVE_LCD_COLOR
312 yuv[1] = yuv[0] + thumb_width*thumb_height;
313 yuv[2] = yuv[1] + thumb_uv_width*thumb_uv_height;
314
315 stretch_image_plane(buf[1], yuv[1], vo.image_width / 2,
316 vo.display_width / 2, vo.display_height / 2,
317 thumb_uv_width, thumb_uv_height);
318
319 stretch_image_plane(buf[2], yuv[2], vo.image_width / 2,
320 vo.display_width / 2, vo.display_height / 2,
321 thumb_uv_width, thumb_uv_height);
143#endif 322#endif
323
324#if LCD_WIDTH >= LCD_HEIGHT
325 yuv_blit(yuv, 0, 0, thumb_width,
326 thumb_rc.l, thumb_rc.t,
327 thumb_rc.r - thumb_rc.l,
328 thumb_rc.b - thumb_rc.t);
329#else
330 yuv_blit(yuv, 0, 0, thumb_height,
331 thumb_rc.t, thumb_rc.l,
332 thumb_rc.b - thumb_rc.t,
333 thumb_rc.r - thumb_rc.l);
334#endif /* LCD_WIDTH >= LCD_HEIGHT */
335
336 return true;
144} 337}
145 338
146void vo_setup(const mpeg2_sequence_t * sequence) 339void vo_setup(const mpeg2_sequence_t * sequence)
147{ 340{
148 image_width=sequence->width; 341 vo.image_width = sequence->width;
149 image_height=sequence->height; 342 vo.image_height = sequence->height;
150 343 vo.display_width = sequence->display_width;
151 tmpbufa = (uint8_t*)mpeg2_malloc(sizeof(uint8_t)*image_width* 344 vo.display_height = sequence->display_height;
152 image_height/4, -2); 345
153 tmpbufb = (uint8_t*)mpeg2_malloc(sizeof(uint8_t)*image_width* 346 DEBUGF("vo_setup - w:%d h:%d\n", vo.display_width, vo.display_height);
154 image_height/16, -2); 347
155 tmpbufc = (uint8_t*)mpeg2_malloc(sizeof(uint8_t)*image_width* 348 vo.image_chroma_x = vo.image_width / sequence->chroma_width;
156 image_height/16, -2); 349 vo.image_chroma_y = vo.image_height / sequence->chroma_height;
157 tmpbuf[0] = tmpbufa; 350
158 tmpbuf[1] = tmpbufb; 351 if (sequence->display_width >= SCREEN_WIDTH)
159 tmpbuf[2] = tmpbufc; 352 {
160 353 vo.output_width = SCREEN_WIDTH;
161 image_chroma_x=image_width/sequence->chroma_width; 354 vo.output_x = 0;
162 image_chroma_y=image_height/sequence->chroma_height; 355 }
163 356 else
164 if (sequence->display_width >= SCREEN_WIDTH) { 357 {
165 output_width = SCREEN_WIDTH; 358 vo.output_width = sequence->display_width;
166 output_x = 0; 359 vo.output_x = (SCREEN_WIDTH - sequence->display_width) / 2;
167 } else {
168 output_width = sequence->display_width;
169 output_x = (SCREEN_WIDTH-sequence->display_width)/2;
170 } 360 }
171 361
172 if (sequence->display_height >= SCREEN_HEIGHT) { 362 if (sequence->display_height >= SCREEN_HEIGHT)
173 output_height = SCREEN_HEIGHT; 363 {
174 output_y = 0; 364 vo.output_height = SCREEN_HEIGHT;
175 } else { 365 vo.output_y = 0;
176 output_height = sequence->display_height; 366 }
177 output_y = (SCREEN_HEIGHT-sequence->display_height)/2; 367 else
368 {
369 vo.output_height = sequence->display_height;
370 vo.output_y = (SCREEN_HEIGHT - sequence->display_height) / 2;
178 } 371 }
179} 372}
180 373
374void vo_dimensions(struct vo_ext *sz)
375{
376 sz->w = vo.display_width;
377 sz->h = vo.display_height;
378}
379
380bool vo_init(void)
381{
382 vo.visible = false;
383 return true;
384}
385
386bool vo_show(bool show)
387{
388 bool vis = vo.visible;
389 vo.visible = show;
390 return vis;
391}
392
393bool vo_is_visible(void)
394{
395 return vo.visible;
396}
397
181void vo_cleanup(void) 398void vo_cleanup(void)
182{ 399{
183 if (tmpbufc) 400 vo.visible = false;
184 mpeg2_free(tmpbufc); 401#ifndef HAVE_LCD_COLOR
185 if (tmpbufb) 402 gray_release();
186 mpeg2_free(tmpbufb); 403#endif
187 if (tmpbufa)
188 mpeg2_free(tmpbufa);
189} 404}