diff options
Diffstat (limited to 'packages/mplayer/files')
-rw-r--r-- | packages/mplayer/files/vo_pxa.c | 746 | ||||
-rw-r--r-- | packages/mplayer/files/vo_pxa.h | 20 |
2 files changed, 649 insertions, 117 deletions
diff --git a/packages/mplayer/files/vo_pxa.c b/packages/mplayer/files/vo_pxa.c index 2e9bb57b9c..1488d14064 100644 --- a/packages/mplayer/files/vo_pxa.c +++ b/packages/mplayer/files/vo_pxa.c @@ -7,6 +7,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include "config.h" #include "video_out.h" @@ -62,7 +63,8 @@ static int preinit(const char *vo_subdevice) if( rc == -1 ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: FBIOGET_VSCREENINFO line %d failed\n", __LINE__ ); + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: FBIOGET_VSCREENINFO preinit base_fd failed %d\n", + errno ); /* If this failed, close down the FD so we don't try to set this again */ close( priv->base_fd ); @@ -94,9 +96,9 @@ static int config(uint32_t src_width, uint32_t src_height, { pxa_priv_t *priv = &st_pxa_priv; int rc; + int i; - mp_msg(MSGT_VO, MSGL_V, "vo_pxa: config() was called\n"); - mp_msg(MSGT_VO, MSGL_V, "vo_pxa: src_width:%d, src_height:%d, dst_width:%d, dst_height:%d\n", + mp_msg(MSGT_VO, MSGL_V, "vo_pxa: config() src_width:%d, src_height:%d, dst_width:%d, dst_height:%d\n", src_width, src_height, dst_width, dst_height); /* Check format */ @@ -129,21 +131,23 @@ static int config(uint32_t src_width, uint32_t src_height, if( rc == -1 ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: Set of base fb failed\n"); + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: config() Set FBIOPUT_VSCREENINFO on base_fd failed %d\n", + errno ); priv->vm = 0; goto err_out; } + + /* We need this sleep, to make the change in resolution actually happen, before we open the overlay */ + sleep(1); } - /* We need these sleeps, to make the change in resolution actually happen, before we open the overlay */ - sleep(2); /* Open up the overlay fbdev */ priv->fd = open( "/dev/fb2", O_RDWR ); if( priv->fd < 0 ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: Could not open framebuffer device\n"); + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: Could not open /dev/fb2: %d\n", errno ); goto err_out; } @@ -152,13 +156,40 @@ static int config(uint32_t src_width, uint32_t src_height, if( rc == -1 ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: FBIOGET_VSCREENINFO line %d failed\n", __LINE__ ); + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: config() FBIOGET_VSCREENINFO from fd failed %d\n", + errno ); goto err_out; } + /* Store away the source dimensions, so we can place in centre of screen later in vm mode */ + priv->src_width = src_width; + priv->src_height = src_height; + /* Set up the buffer */ - priv->my_fb_var.xres = src_width; - priv->my_fb_var.yres = src_height; + if( priv->vm ) + { + /* Ignore size, as the rest of the screen is toast. Use max size */ + priv->my_fb_var.xres = 240; + priv->my_fb_var.yres = 320; + + /* Do we need to rotate? */ + if( priv->src_width > priv->src_height ) + { + /* Yes */ + priv->rotate = 1; + } + + priv->width = 240; + priv->height = 320; + } + else + { + priv->my_fb_var.xres = src_width; + priv->my_fb_var.yres = src_height; + priv->width = src_width; + priv->height = src_height; + } + priv->my_fb_var.nonstd = ( 4 << 20) /* Format YV12 */ | ( 0 << 0) /* x position */ | ( 0 << 10); /* y position */ @@ -171,7 +202,8 @@ static int config(uint32_t src_width, uint32_t src_height, if( rc == -1 ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: FBIOPUT_VSCREENINFO line %d failed\n", __LINE__ ); + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: config() FBIOPUT_VSCREENINFO to fd failed: %d\n", + errno ); goto err_out; } @@ -180,7 +212,8 @@ static int config(uint32_t src_width, uint32_t src_height, if( rc == -1 ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: FBIOGET_FSCREENINFO line %d failed\n", __LINE__ ); + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: config() FBIOGET_FSCREENINFO from fd failed: %d\n", + errno ); goto err_out; } @@ -191,7 +224,7 @@ static int config(uint32_t src_width, uint32_t src_height, if( priv->fb_mem_base == MAP_FAILED ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: mmap buffer failed\n" ); + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: mmap fd buffer failed: %d\n", errno ); goto err_out; } @@ -200,12 +233,79 @@ static int config(uint32_t src_width, uint32_t src_height, if( rc == -1 ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: FBIOGET_VSCREENINFO line %d failed\n", __LINE__ ); + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: config() FBIOGET_VSCREENINFO from fd (2) failed %d\n", + errno ); goto err_out; } + /* Fill the overlay with black */ + memset( priv->fb_mem_base + priv->my_fb_var.red.offset, 16, priv->my_fb_var.red.length ); + memset( priv->fb_mem_base + priv->my_fb_var.green.offset, 128, priv->my_fb_var.green.length ); + memset( priv->fb_mem_base + priv->my_fb_var.blue.offset, 128, priv->my_fb_var.blue.length ); + + /* Now open the OSD overlay - overlay 1, and fill with transparent */ + sleep( 1 ); + + priv->overlay_fd = open( "/dev/fb1", O_RDWR ); + + if( priv->overlay_fd < 0 ) + { + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: Could not open /dev/fb1: %d\n", errno ); + goto err_out; + } + + /* Read in fb var data */ + rc = ioctl( priv->overlay_fd, FBIOGET_VSCREENINFO, &(priv->osd_fb_var) ); + + if( rc == -1 ) + { + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: config() FBIOGET_VSCREENINFO from overlay_fd failed; %d\n", + errno ); + goto err_out; + } + + priv->osd_fb_var.xres = priv->width; + priv->osd_fb_var.yres = priv->height; + priv->osd_fb_var.nonstd = ( 0 << 0) /* x position */ + | ( 0 << 10); /* y position */ + /* Use 15 bit mode, with top bit transparency */ + priv->osd_fb_var.bits_per_pixel = 16; + + rc = ioctl( priv->overlay_fd, FBIOPUT_VSCREENINFO, &(priv->osd_fb_var) ); + + if( rc == -1 ) + { + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: config() FBIOPUT_VSCREENINFO to overlay_fd failed: %d\n", + errno ); + goto err_out; + } + + /* Next get the fixed fbvars, so we can mmap the data */ + rc = ioctl( priv->overlay_fd, FBIOGET_FSCREENINFO, &(priv->osd_fb_fix) ); + + if( rc == -1 ) + { + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: config() FBIOGET_FSCREENINFO from overlay_fd failed %d\n", + errno ); + goto err_out; + } + + priv->osd_mem_base = mmap( NULL, priv->osd_fb_fix.smem_len, (PROT_READ | PROT_WRITE ), + MAP_SHARED, + priv->overlay_fd, + 0 ); + + if( priv->osd_mem_base == MAP_FAILED ) + { + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: mmap osd_mem_base failed: %d\n", errno ); + goto err_out; + } + + /* Fill the overlay with transparent */ + vo_pxa_clear_osd( priv->osd_mem_base, priv->osd_fb_fix.smem_len ); + /* We are good to go! */ - mp_msg( MSGT_VO, MSGL_V, "vo_pxa: FOpened screen %d x %d fourcc %s\n", + mp_msg( MSGT_VO, MSGL_V, "vo_pxa: Opened video overlay %d x %d fourcc %s\n", priv->my_fb_var.xres, priv->my_fb_var.yres, vo_format_name(format) ); @@ -213,18 +313,8 @@ static int config(uint32_t src_width, uint32_t src_height, return 0; err_out: - - if( priv->fb_mem_base != MAP_FAILED ) - { - munmap( priv->fb_mem_base, priv->my_fb_fix.smem_len ); - priv->fb_mem_base = MAP_FAILED; - } - - if( priv->fd >= 0 ) - { - close( priv->fd ); - priv->fd = -1; - } + + /* Don't do anything here for the moment */ return -1; } @@ -238,6 +328,8 @@ static int config(uint32_t src_width, uint32_t src_height, ****************************************************************************/ static int control(uint32_t request, void *data, ...) { + mp_msg(MSGT_VO, MSGL_V, "vo_pxa: control %08x\n", request ); + switch( request ) { case VOCTRL_QUERY_FORMAT: @@ -261,7 +353,7 @@ static int control(uint32_t request, void *data, ...) int draw_frame(uint8_t *src[]) { /* This is not implimented */ - mp_msg(MSGT_VO, MSGL_V, "vo_pxa: dummy draw_frame() was called\n"); + mp_msg(MSGT_VO, MSGL_ERR, "vo_pxa: dummy draw_frame() was called\n"); return -1; } @@ -281,79 +373,291 @@ int draw_frame(uint8_t *src[]) int draw_slice(uint8_t *src[], int stride[], int w,int h, int x,int y) { pxa_priv_t *priv = &st_pxa_priv; - uint8_t *my_src; - uint8_t *dest; - size_t length; - int i; /* This routine is only display routine actually implimented */ - mp_msg(MSGT_VO, MSGL_V, "vo_pxa: draw_slice() was called\n"); + mp_msg(MSGT_VO, MSGL_V, "vo_pxa: draw_slice() w %d h %d x %d y %d stride %d %d %d\n", + w, h, x, y, stride[0], stride[1], stride[2] ); /* It would be faster to check if source and dest have same geometry and copy * whole block * For the moment we just copy a line at a time */ - /* Limit area written to */ - if( x >= priv->my_fb_fix.line_length ) + /* In vm mode rotate if wider than long */ + if( priv->vm ) { - return 0; - } + /* Do we nee to rotate? */ + if( priv->rotate ) + { + /* Yes, rotated version */ + int dst_x_offset = 0; + int dst_y_offset = 0; + int src_x_offset = 0; + int src_y_offset = 0; + + /* Figure out dst offset */ + if( priv->src_width < 320 ) + { + dst_x_offset = ( ( 320 - priv->src_width ) / 2 ); + /* Make it a multiple of 16 */ + dst_x_offset &= ~(0xf); + } + + if( priv->src_height < 240 ) + { + dst_y_offset = ( ( 240 - priv->src_height ) / 2 ); + /* Make it a multiple of 16 */ + dst_y_offset &= ~(0xf); + } + + dst_x_offset += x; + dst_y_offset += y; + + if( ( dst_x_offset >= 320 ) || ( dst_y_offset >= 240 ) ) + { + /* Nothing to do - drawing off the screen! */ + return( 0 ); + } + + /* Limit to drawable area */ + if( ( w + dst_x_offset ) > 320 ) + { + w = ( 320 - dst_x_offset ); + } + + if( ( h + dst_y_offset ) > 240 ) + { + h = ( 240 - dst_y_offset ); + } + + /* And source offset */ + if( priv->src_width > 320 ) + { + src_x_offset = ( ( priv->src_width - 320 ) / 2 ); + /* Make it a multiple of 16 */ + src_x_offset &= ~(0xf); + } + + if( priv->src_height > 240 ) + { + src_y_offset = ( ( priv->src_height - 240 ) / 2 ); + /* Make it a multiple of 16 */ + src_y_offset &= ~(0xf); + } + + + /* Y first */ + vo_pxa_copy_and_rotate( src[0] + src_x_offset + (src_y_offset * stride[0]), stride[0], + priv->fb_mem_base + priv->my_fb_var.red.offset + (240 * dst_x_offset) + (240 - dst_y_offset - h), + w, h, 240 ); + /* Now U */ + vo_pxa_copy_and_rotate( src[1] + src_x_offset/2 + (src_y_offset/2 * stride[1]), stride[1], + priv->fb_mem_base + priv->my_fb_var.green.offset + (120 * dst_x_offset/2) + (120 - dst_y_offset/2 - h/2), + w/2, h/2, 120 ); + vo_pxa_copy_and_rotate( src[2] + src_x_offset/2 + (src_y_offset/2 * stride[2]), stride[2], + priv->fb_mem_base + priv->my_fb_var.blue.offset + (120 * dst_x_offset/2) + (120 - dst_y_offset/2 - h/2), + w/2, h/2, 120 ); + } + else + { + /* Don't rotate */ + int i; + uint8_t *my_src; + uint8_t *dest; + int dst_x_offset = 0; + int dst_y_offset = 0; + int src_x_offset = 0; + int src_y_offset = 0; + + /* Figure out dst offset */ + if( priv->src_width < 240 ) + { + dst_x_offset = ( ( 240 - priv->src_width ) / 2 ); + /* Make it a multiple of 16 */ + dst_x_offset &= ~(0xf); + } + + if( priv->src_height < 320 ) + { + dst_y_offset = ( ( 320 - priv->src_height ) / 2 ); + /* Make it a multiple of 16 */ + dst_y_offset &= ~(0xf); + } + + dst_x_offset += x; + dst_y_offset += y; + + if( ( dst_x_offset >= 240 ) || ( dst_y_offset >= 320 ) ) + { + /* Nothing to do - drawing off the screen! */ + return( 0 ); + } + + /* Limit to drawable area */ + if( ( w + dst_x_offset ) > 240 ) + { + w = ( 240 - dst_x_offset ); + } + + if( ( h + dst_y_offset ) > 320 ) + { + h = ( 320 - dst_y_offset ); + } + + /* And source offset */ + if( priv->src_width > 240 ) + { + src_x_offset = ( ( priv->src_width - 240 ) / 2 ); + /* Make it a multiple of 16 */ + src_x_offset &= ~(0xf); + } + + if( priv->src_height > 320 ) + { + src_y_offset = ( ( priv->src_height - 320 ) / 2 ); + /* Make it a multiple of 16 */ + src_y_offset &= ~(0xf); + } + + /* First Y */ + for( i = 0; i<h; i++ ) + { + dest = priv->fb_mem_base + + priv->my_fb_var.red.offset + + ( (dst_y_offset+i) * priv->my_fb_fix.line_length ) + + dst_x_offset; + my_src = src[0] + src_x_offset + (stride[0] * (i+src_y_offset)); + memcpy( dest, my_src, w ); + } + + /* Now U */ + for( i = 0; i<(h/2); i++ ) + { + dest = priv->fb_mem_base + + priv->my_fb_var.green.offset + + ( ((dst_y_offset/2)+i) * (priv->my_fb_fix.line_length/2) ) + + dst_x_offset/2; + my_src = src[1] + src_x_offset/2 + (stride[1] * (i+(src_y_offset/2))); + memcpy( dest, my_src, w/2 ); + } - if( w + x > priv->my_fb_fix.line_length ) - { - w = priv->my_fb_fix.line_length - x; + /* Finaly V */ + for( i = 0; i<(h/2); i++ ) + { + dest = priv->fb_mem_base + + priv->my_fb_var.blue.offset + + ( ((dst_y_offset/2)+i) * (priv->my_fb_fix.line_length/2) ) + + dst_x_offset/2; + my_src = src[2] + src_x_offset/2 + (stride[2] * (i+(src_y_offset/2))); + memcpy( dest, my_src, w/2 ); + } + + } } - - if( y>= priv->my_fb_var.yres ) + else { - return 0; - } + /* Not full screen mode */ + uint8_t *my_src; + uint8_t *dest; + size_t length; + int i; + + /* It would be faster to check if source and dest have same geometry and copy + * whole block + * For the moment we just copy a line at a time + */ + + /* Limit area written to */ + if( x >= priv->my_fb_fix.line_length ) + { + return 0; + } - if( h + y > priv->my_fb_var.yres ) - { - h = priv->my_fb_var.yres - y; - } + if( w + x > priv->my_fb_fix.line_length ) + { + w = priv->my_fb_fix.line_length - x; + } - /* First Y */ - for( i = 0; i<h; i++ ) - { - dest = priv->fb_mem_base + - priv->my_fb_var.red.offset + - ( (y+i) * priv->my_fb_fix.line_length ) + - x; - my_src = src[0] + stride[0] * i; - memcpy( dest, my_src, w ); - } + if( y>= priv->my_fb_var.yres ) + { + return 0; + } + + if( h + y > priv->my_fb_var.yres ) + { + h = priv->my_fb_var.yres - y; + } + + /* First Y */ + for( i = 0; i<h; i++ ) + { + dest = priv->fb_mem_base + + priv->my_fb_var.red.offset + + ( (y+i) * priv->my_fb_fix.line_length ) + + x; + my_src = src[0] + stride[0] * i; + memcpy( dest, my_src, w ); + } - /* Now U */ - for( i = 0; i<(h/2); i++ ) - { - dest = priv->fb_mem_base + - priv->my_fb_var.green.offset + - ( ((y/2)+i) * (priv->my_fb_fix.line_length/2) ) + - x; - my_src = src[1] + stride[1] * i; - memcpy( dest, my_src, w/2 ); - } + /* Now U */ + for( i = 0; i<(h/2); i++ ) + { + dest = priv->fb_mem_base + + priv->my_fb_var.green.offset + + ( ((y/2)+i) * (priv->my_fb_fix.line_length/2) ) + + x; + my_src = src[1] + stride[1] * i; + memcpy( dest, my_src, w/2 ); + } - /* Finaly V */ - for( i = 0; i<(h/2); i++ ) - { - dest = priv->fb_mem_base + - priv->my_fb_var.blue.offset + - ( ((y/2)+i) * (priv->my_fb_fix.line_length/2) ) + - x; - my_src = src[2] + stride[2] * i; - memcpy( dest, my_src, w/2 ); + /* Finaly V */ + for( i = 0; i<(h/2); i++ ) + { + dest = priv->fb_mem_base + + priv->my_fb_var.blue.offset + + ( ((y/2)+i) * (priv->my_fb_fix.line_length/2) ) + + x; + my_src = src[2] + stride[2] * i; + memcpy( dest, my_src, w/2 ); + } } - return 0; } static void draw_osd(void) { + pxa_priv_t *priv = &st_pxa_priv; + int osd_has_changed; + + /* This gets called every frame, so systems which do the OSD without a + * seperate overlay can mix in the image. We need to find out if the osd + * has actually been updated! + */ mp_msg(MSGT_VO, MSGL_V, "vo_pxa: draw_osd() was called\n"); + + osd_has_changed = vo_update_osd( priv->width, priv->height); + + if(osd_has_changed) + { + int i; + + mp_msg(MSGT_VO, MSGL_V, "vo_pxa: Clear and update OSD\n"); + + /* Fill with transparent */ + vo_pxa_clear_osd( priv->osd_mem_base, priv->osd_fb_fix.smem_len ); + + priv->osd_cleared = 1; + + /* now update */ + if( priv->rotate ) + { + vo_draw_text( priv->width, priv->height, vo_pxa_draw_alpha_with_rotate ); + } + else + { + vo_draw_text( priv->width, priv->height, vo_pxa_draw_alpha ); + } + } } /***************************************************************************** @@ -377,6 +681,7 @@ static void flip_page(void) ****************************************************************************/ static void check_events(void) { + mp_msg(MSGT_VO, MSGL_V, "vo_pxa: check_events() was called\n"); } /***************************************************************************** @@ -390,41 +695,74 @@ static void uninit(void) pxa_priv_t *priv = &st_pxa_priv; int rc; - if( priv->fb_mem_base != MAP_FAILED ) - { - munmap( priv->fb_mem_base, priv->my_fb_fix.smem_len ); - priv->fb_mem_base = MAP_FAILED; - } - - if( priv->fd >= 0 ) - { - close( priv->fd ); - priv->fd = -1; - } - - /* We need these sleeps, to make the change in resolution actually happen */ - sleep(1); - + mp_msg(MSGT_VO, MSGL_V, "vo_pxa: uninit() was called\n"); + if( priv->vm ) { + /* We need these sleeps, to make the change in resolution actually happen */ + sleep(1); + /* Restore original resolution */ if( priv->base_fd >= 0 ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: Try to restore original video mode\n", __LINE__ ); - rc = ioctl( priv->base_fd, FBIOPUT_VSCREENINFO, &(priv->base_orig_fb_var) ); if( rc == -1 ) { - mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: FBIOPUT_VSCREENINFO line %d failed\n", __LINE__ ); + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: uninit() FBIOPUT_VSCREENINFO to base_fd failed %d\n", + errno ); } } - + /* We need these sleeps, to make the change in resolution actually happen */ + /* For some reason, if we change the reolution the overlay buffer never gets deleted? */ + sleep(1); } - /* We need these sleeps, to make the change in resolution actually happen */ - /* For some reason, if we change the reolution the overlay buffer never gets deleted? */ - sleep(1); + + /* We need to force the overlays to be really disabled, otherwise they + * will come back as zombies after suspend, resume + * This trick seems to work, but will not be needed once kernel driver + * is fixed + */ + if( priv->fd >= 0 ) + { + rc = ioctl( priv->fd, FBIOGET_VSCREENINFO, &(priv->my_fb_var) ); + + if( rc == -1 ) + { + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: uninit() FBIOGET_VSCREENINFO from fd failed %d\n", + errno ); + } + priv->my_fb_var.bits_per_pixel = 0; + + rc = ioctl( priv->fd, FBIOPUT_VSCREENINFO, &(priv->my_fb_var) ); + + if( rc == -1 ) + { + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: uninit() FBIOPUT_VSCREENINFO from fd failed %d\n", + errno ); + } + } + + if( priv->overlay_fd >= 0 ) + { + rc = ioctl( priv->overlay_fd, FBIOGET_VSCREENINFO, &(priv->my_fb_var) ); + + if( rc == -1 ) + { + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: uninit() FBIOGET_VSCREENINFO from overlay_fd failed %d\n", + errno ); + } + priv->my_fb_var.bits_per_pixel = 0; + + rc = ioctl( priv->overlay_fd, FBIOPUT_VSCREENINFO, &(priv->my_fb_var) ); + + if( rc == -1 ) + { + mp_msg( MSGT_VO, MSGL_ERR, "vo_pxa: uninit() FBIOPUT_VSCREENINFO from overlay_fd failed %d\n", + errno ); + } + } if( priv->base_fd >= 0 ) { @@ -444,25 +782,199 @@ static int vo_pxa_query_format( uint32_t format ) mp_msg(MSGT_VO, MSGL_V, "vo_pxa: vo_pxa_query_format was called: %x (%s)\n", format, vo_format_name(format)); - if( IMGFMT_IS_RGB(format) ) + switch (format) + { + /* Planar YUV Formats */ + /* Warning! dropthrough */ + case IMGFMT_YV12: + case IMGFMT_IYUV: + case IMGFMT_I420: + return( VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW + | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD + | VFCAP_ACCEPT_STRIDE ); + break; + } + + return 0; +} + +static void vo_pxa_copy_and_rotate( uint8_t *src, int stride, uint8_t *dst, int w, int h, int dst_stride ) +{ + int i,j; + uint8_t *my_src, *my_dst; + Vo_Pxa_Pixel_Data8 *img_dst_pixel_data8; + + /* Loop so writing consectuive data in rotated image */ + /* This produces some pretty good assembler - better than the handcoded stuff in w100 */ + for( j=0; j<w; j++ ) + { + my_src = src + j + ( stride * (h - 1) ); + + img_dst_pixel_data8 = (Vo_Pxa_Pixel_Data8 *)dst; + + /* Allow for src not multiple of 8 by running off the end a little. Should not matter */ + for( i=0; i<((h+7)/8); i++ ) + { + register Vo_Pxa_Pixel_Data8 build_pixels; + + build_pixels.a = *my_src; + my_src -= stride; + build_pixels.a |= (*my_src<<8); + my_src -= stride; + build_pixels.a |= (*my_src<<16); + my_src -= stride; + build_pixels.a |= (*my_src<<24); + my_src -= stride; + + build_pixels.b = *my_src; + my_src -= stride; + build_pixels.b |= (*my_src<<8); + my_src -= stride; + build_pixels.b |= (*my_src<<16); + my_src -= stride; + build_pixels.b |= (*my_src<<24); + my_src -= stride; + + *img_dst_pixel_data8++ = build_pixels; + } + + /* Allow source not as big as dest */ + dst += dst_stride; + } +} + +static void vo_pxa_draw_alpha( int x, int y, int w, int h, unsigned char *src, + unsigned char *srca, int stride ) +{ + /* Dump data into our 15bit buffer with transparency */ + pxa_priv_t *priv = &st_pxa_priv; + int i,j; + unsigned char *src_ptr = src; + unsigned char *a_ptr = srca; + unsigned short *out_ptr; + + mp_msg(MSGT_VO, MSGL_V, "vo_pxa: vo_pxa_draw_alpha() w %d y %d w %d h %d\n", x, y, w, h ); + + /* We ignore the alpha channel, other than off or on */ + for( i=0; i<h; i++ ) + { + out_ptr = priv->osd_mem_base + x + ( priv->width * ( y + i ) ); + src_ptr = src + ( i * stride ); + a_ptr = srca + ( i * stride ); + + for( j=0; j<w; j++ ) + { + /* The srca is a 0-255 transpaency level, where 0 is transparent. + * We only support transparent on or off + */ + if( *a_ptr++ ) + { + unsigned int grey; + /* The src is a greylevel from 0 - 255 */ + /* We may as well use this value */ + grey = *src_ptr++ >> 3; + *out_ptr++ = grey | (grey << 5) | (grey<<10); + } + else + { + *out_ptr++ = 0x8000; + src_ptr++; + } + + } + } +} + +static void vo_pxa_draw_alpha_with_rotate( int x, int y, int w, int h, unsigned char *src, + unsigned char *srca, int stride ) +{ + /* Dump data into our 15bit buffer with transparency */ + pxa_priv_t *priv = &st_pxa_priv; + int i,j; + unsigned char *src_ptr = src; + unsigned char *a_ptr = srca; + unsigned short *out_ptr; + + mp_msg(MSGT_VO, MSGL_V, "vo_pxa: vo_pxa_draw_alpha_with_rotate() x %d y %d w %d h %d\n", x, y, w, h ); + + if( x >= 320 ) + { + /* Off the screen */ + return; + } + + /* Limit to size of screen/memory */ + if( ( w + x ) > 320 ) + { + w = 320 - x; + } + + if( y >= 240 ) { - /* RGB/BGR Formats not supported yet */ - return 0; - } - else + /* Off the screen */ + return; + } + + /* Limit to size of screen/memory */ + if( ( y + h ) > 240 ) + { + h = 240 - y; + } + + + /* We ignore the alpha channel, other than off or on */ + for( i=0; i<w; i++ ) { - /* Planar YUV Formats */ - switch (format) { - /* Warning! dropthrough */ - case IMGFMT_YV12: - case IMGFMT_IYUV: - case IMGFMT_I420: - return( VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW - | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD - | VFCAP_ACCEPT_STRIDE ); - break; - } + out_ptr = priv->osd_mem_base + y + ( priv->width * ( x + i ) ); + src_ptr = src + i + ( stride * (h - 1)); + a_ptr = srca + i + ( stride * (h - 1)); + + for( j=0; j<h; j++ ) + { + /* The srca is a 0-255 transpaency level, where 0 is transparent. + * We only support transparent on or off + */ + if( *a_ptr ) + { + unsigned int grey; + /* The src is a greylevel from 0 - 255 */ + /* We may as well use this value */ + grey = *src_ptr >> 3; + *out_ptr++ = grey | (grey << 5) | (grey<<10); + } + else + { + *out_ptr++ = 0x8000; + src_ptr; + } + a_ptr -= stride; + src_ptr -= stride; + } } +} - return 0; +static void vo_pxa_clear_osd( uint16_t *mem_base, int len ) +{ + /* fill whole area with 0x8000 -> trsnaparent. + * assume area is word aligned, and a mulitple of 16 bytes in length + * However I tried I could not get the compiler to generate this. + * It always wanted to to do ldmia 4 words from stack followed by + * stmia 4 words. This seems odd! + */ + __asm__ __volatile__ ( + "mov r4, %0 \n\t" + "mov r5, %1, lsr #4 \n\t" + "subs r5, r5, #1\n\t" + "mov r0, #0x80000000 \n\t" + "orr r0, r0, #0x00008000 \n\t" + "mov r1, r0 \n\t" + "mov r2, r0 \n\t" + "mov r3, r0 \n\t" + "1: \n\t" + "subs r5, r5, #1\n\t" + "stmia r4!, {r0, r1, r2, r3} \n\t" + "bne 1b \n\t" + : + : "r"(mem_base), "r"(len) + : "memory", "r0", "r1", "r2", "r3", "r4", "r5", "cc" ); } diff --git a/packages/mplayer/files/vo_pxa.h b/packages/mplayer/files/vo_pxa.h index ee7825b76e..31cc1a7862 100644 --- a/packages/mplayer/files/vo_pxa.h +++ b/packages/mplayer/files/vo_pxa.h @@ -14,18 +14,38 @@ typedef struct pxa_priv_s { uint8_t *fb_mem_base; + uint16_t *osd_mem_base; + int fd; int base_fd; + int overlay_fd; struct fb_var_screeninfo my_fb_var; struct fb_fix_screeninfo my_fb_fix; struct fb_var_screeninfo base_orig_fb_var; + struct fb_var_screeninfo osd_fb_var; + struct fb_fix_screeninfo osd_fb_fix; int vm; uint32_t format; int src_width; int src_height; + int width; + int height; + int rotate; + int osd_cleared; } pxa_priv_t; +typedef struct vo_pxa_pixel_data8 { + unsigned int a,b; +} Vo_Pxa_Pixel_Data8; + #define UNUSED(v) ((void)(v)) /* Internal API */ static int vo_pxa_query_format( uint32_t format ); +static void vo_pxa_copy_and_rotate( uint8_t *src, int stride, uint8_t *dst, int w, int h, int dst_stride ); +static void vo_pxa_draw_alpha( int x, int y, int w, int h, unsigned char *src, + unsigned char *srca, int stride ); +static void vo_pxa_draw_alpha_with_rotate( int x, int y, int w, int h, unsigned char *src, + unsigned char *srca, int stride ); + +static void vo_pxa_clear_osd( uint16_t *mem_base, int len ); |