packages/mplayer/mplayer_0.0+1.0rc1.bb : update the vo_pxa driver from Tim Chick
authorGraeme Gregory <dp@xora.org.uk>
Thu, 15 Mar 2007 12:44:17 +0000 (12:44 +0000)
committerGraeme Gregory <dp@xora.org.uk>
Thu, 15 Mar 2007 12:44:17 +0000 (12:44 +0000)
packages/mplayer/files/vo_pxa.c
packages/mplayer/files/vo_pxa.h
packages/mplayer/mplayer_0.0+1.0rc1.bb

index 2e9bb57..1488d14 100644 (file)
@@ -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" );
 }
index ee7825b..31cc1a7 100644 (file)
 
 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 );
index 5ade18b..b030be5 100644 (file)
@@ -33,7 +33,7 @@ PACKAGE_ARCH_mencoder_collie = "collie"
 
 RCONFLICTS_${PN} = "mplayer-atty"
 RREPLACES_${PN} = "mplayer-atty"
-PR = "r8"
+PR = "r9"
 
 PARALLEL_MAKE = ""