]> git.sesse.net Git - vlc/commitdiff
Nouvelle interface, effacement des zones modifi�es d'une image sur 2,
authorVincent Seguin <seguin@videolan.org>
Sun, 30 Jan 2000 15:08:59 +0000 (15:08 +0000)
committerVincent Seguin <seguin@videolan.org>
Sun, 30 Jan 2000 15:08:59 +0000 (15:08 +0000)
calcul de la taille optimale d'une image, scaling.

-Le scaling donne de bonnes tailles, mais les conversions YUV ne peuvent
pas suivre pour le moment.
-J'ai peut etre un peu cass� le fb et ggi (trop long � compiler pour tester).
En cas de probl�me, je corrige de suite.
-Les idle screens ("no stream") sont temporairement hors service.

14 files changed:
Makefile
include/config.h
include/video.h
include/video_output.h
include/video_sys.h
include/video_text.h
src/interface/interface.c
src/interface/main.c
src/video_output/video_fb.c
src/video_output/video_ggi.c
src/video_output/video_output.c
src/video_output/video_text.c
src/video_output/video_x11.c
src/video_output/video_yuv.c

index e0d4759f766529819269c4b4e7387fcd3bf50c64..0d2e34fc2c218a9fbabe353986f883081fd0809c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -89,7 +89,7 @@ endif
 # Libraries
 #
 LIB += -lpthread
-LIB += -lm
+LIN += -lm
 
 ifeq ($(VIDEO),X11)
 LIB += -L/usr/X11R6/lib
index e66a769956f5b7a657e0ae7bc1b06b96984f227f..8ecfb85dc02c9f9f3202e2d2dea06e131f6a6dca 100644 (file)
 #define VOUT_WIDTH_DEFAULT              640
 #define VOUT_HEIGHT_DEFAULT             480
 
-/* Default video heap size - remember that a decompressed picture is big 
+/* Video heap size - remember that a decompressed picture is big 
  * (~1 Mbyte) before using huge values */
 #define VOUT_MAX_PICTURES               10
 
+/* Maximum number of active areas in a rendering buffer. Active areas are areas
+ * of the picture which need to be cleared before re-using the buffer. If a 
+ * picture, including its many additions such as subtitles, additionnal user
+ * informations and interface, has too many active areas, some of them are 
+ * joined. */
+#define VOUT_MAX_AREAS                  5
+
 /* Environment variable for grayscale output mode, and default value */
 #define VOUT_GRAYSCALE_VAR              "vlc_grayscale"
 #define VOUT_GRAYSCALE_DEFAULT          0
index 19b7198e11226819651d12209fccedd4d65e45f5..85cc7e44ff9426d5a909a4154428c5f9b0d3bf32 100644 (file)
@@ -117,6 +117,5 @@ typedef struct subtitle_s
 #define FREE_SUBTITLE           0        /* subtitle is free and not allocated */
 #define RESERVED_SUBTITLE       1        /* subtitle is allocated and reserved */
 #define READY_SUBTITLE          2             /* subtitle is ready for display */
-#define DISPLAYED_SUBTITLE      3 /* subtitle has been displayed but is linked */
-#define DESTROYED_SUBTITLE      4    /* subtitle is allocated but no more used */
+#define DESTROYED_SUBTITLE      3    /* subtitle is allocated but no more used */
 
index cbc3e82a5cc637296b8adaa451c9e7a54ba7b5c2..2dd2fb24677dfc18eb8fa54755fd266d43ba4af0 100644 (file)
@@ -24,6 +24,27 @@ typedef struct vout_tables_s
     } yuv;    
 } vout_tables_t;
 
+/*******************************************************************************
+ * vout_buffer_t: rendering buffer
+ *******************************************************************************
+ * This structure store informations about a buffer. Buffers are not completely
+ * cleared between displays, and modified areas needs to be stored.
+ *******************************************************************************/
+typedef struct vout_buffer_s
+{     
+    /* Picture area */
+    int         i_pic_x, i_pic_y;                         /* picture position  */
+    int         i_pic_width, i_pic_height;                /* picture extension */
+    
+    /* Other areas - only vertical extensions of areas are stored */
+    int         i_areas;                                    /* number of areas */    
+    int         pi_area_begin[VOUT_MAX_AREAS];            /* beginning of area */ 
+    int         pi_area_end[VOUT_MAX_AREAS];                    /* end of area */
+    
+    /* Picture data */
+    byte_t *    p_data;                                      /* memory address */
+} vout_buffer_t;
+
 /*******************************************************************************
  * vout_convert_t: convertion function
  *******************************************************************************
@@ -70,7 +91,6 @@ typedef struct vout_thread_s
     p_vout_sys_t        p_sys;                         /* system output method */
 
     /* Current display properties */    
-    boolean_t           b_grayscale;             /* color or grayscale display */   
     int                 i_width;                /* current output method width */
     int                 i_height;              /* current output method height */
     int                 i_bytes_per_line;/* bytes per line (including virtual) */
@@ -79,14 +99,17 @@ typedef struct vout_thread_s
     float               f_gamma;                                      /* gamma */
 
     /* Pictures and rendering properties */
+    boolean_t           b_grayscale;             /* color or grayscale display */   
     boolean_t           b_info;              /* print additionnal informations */
+    boolean_t           b_interface;                       /* render interface */    
+    boolean_t           b_scale;                      /* allow picture scaling */    
 
 #ifdef STATS    
     /* Statistics - these numbers are not supposed to be accurate, but are a
      * good indication of the thread status */
     mtime_t             render_time;               /* last picture render time */
     count_t             c_fps_samples;                       /* picture counts */    
-    mtime_t             fps_sample[ VOUT_FPS_SAMPLES ];   /* FPS samples dates */
+    mtime_t             p_fps_sample[ VOUT_FPS_SAMPLES ]; /* FPS samples dates */
 #endif
 
     /* Running properties */
@@ -94,6 +117,10 @@ typedef struct vout_thread_s
     mtime_t             last_picture_date;        /* last picture display date */
     mtime_t             last_display_date;         /* last screen display date */    
 
+    /* Rendering buffers */
+    int                 i_buffer_index;                        /* buffer index */
+    vout_buffer_t       p_buffer[2];                     /* buffers properties */
+
     /* Videos heap and translation tables */
     picture_t           p_picture[VOUT_MAX_PICTURES];              /* pictures */
     subtitle_t          p_subtitle[VOUT_MAX_PICTURES];            /* subtitles */    
@@ -111,10 +138,12 @@ typedef struct vout_thread_s
  * thread changed a variable */
 #define VOUT_INFO_CHANGE        0x0001                       /* b_info changed */
 #define VOUT_GRAYSCALE_CHANGE   0x0002                  /* b_grayscale changed */
-#define VOUT_SIZE_CHANGE        0x0008                         /* size changed */
-#define VOUT_DEPTH_CHANGE       0x0010                        /* depth changed */
-#define VOUT_GAMMA_CHANGE       0x0080                        /* gamma changed */
-#define VOUT_NODISPLAY_CHANGE   0xffff      /* changes which forbidden display */
+#define VOUT_INTF_CHANGE        0x0004                  /* b_interface changed */
+#define VOUT_SCALE_CHANGE       0x0008                      /* b_scale changed */
+#define VOUT_SIZE_CHANGE        0x0200                         /* size changed */
+#define VOUT_DEPTH_CHANGE       0x0400                        /* depth changed */
+#define VOUT_GAMMA_CHANGE       0x0010                        /* gamma changed */
+#define VOUT_NODISPLAY_CHANGE   0xff00      /* changes which forbidden display */
 
 /*******************************************************************************
  * Prototypes
@@ -132,7 +161,7 @@ void            vout_UnlinkPicture      ( vout_thread_t *p_vout, picture_t *p_pi
 subtitle_t *    vout_CreateSubtitle     ( vout_thread_t *p_vout, int i_type, int i_size );
 void            vout_DestroySubtitle    ( vout_thread_t *p_vout, subtitle_t *p_sub );
 void            vout_DisplaySubtitle    ( vout_thread_t *p_vout, subtitle_t *p_sub );
-
+void            vout_ClearBuffer        ( vout_thread_t *p_vout, vout_buffer_t *p_buffer );
 
 
 
index 9be4617ba8bf1da25e80ea85554df1808343738a..ec983a86f0ce547d93b06f5c7f69c431e2f27ce0 100644 (file)
@@ -12,7 +12,6 @@ void         vout_SysEnd        ( p_vout_thread_t p_vout );
 void         vout_SysDestroy    ( p_vout_thread_t p_vout );
 int          vout_SysManage     ( p_vout_thread_t p_vout );
 void         vout_SysDisplay    ( p_vout_thread_t p_vout );
-void *       vout_SysGetPicture ( p_vout_thread_t p_vout );
 
 
 
index e3da8231d9835167ab9732d7a7e9461d90ca340f..eadd714e159174486bf794fe4ddf330f5d60222f 100644 (file)
 /*******************************************************************************
  * Prototypes
  *******************************************************************************/
-p_vout_font_t   vout_LoadFont   ( char *psz_name );
+p_vout_font_t   vout_LoadFont   ( const char *psz_name );
 void            vout_UnloadFont ( p_vout_font_t p_font );
-void            vout_TextSize   ( p_vout_font_t p_font, int i_style, char *psz_text,
+void            vout_TextSize   ( p_vout_font_t p_font, int i_style, 
+                                  const char *psz_text,
                                   int *pi_width, int *pi_height );
-void            vout_Print      ( p_vout_font_t p_font, byte_t *p_pic, int i_depth, 
-                                  int i_bytes_per_pixel, u32 i_char_color, 
-                                  u32 i_border_color, u32 i_bg_color,
-                                  int i_style, char *psz_text );
+void            vout_Print      ( p_vout_font_t p_font, byte_t *p_pic, 
+                                  int i_bytes_per_pixel, int i_bytes_per_line,
+                                  u32 i_char_color, u32 i_border_color, u32 i_bg_color,
+                                  int i_style, const char *psz_text );
 
 
 
index 6397511546c953ce5b740a56b1d1d86f73168847..9e22ba2d024ccc6b51f056cc599962961ee94241 100644 (file)
@@ -228,7 +228,16 @@ int intf_ProcessKey( intf_thread_t *p_intf, int i_key )
             vlc_mutex_unlock( &p_intf->p_vout->change_lock );      
         }
         break;  
-    case ' ':                                                   /* toggle info */
+    case ' ':                                              /* toggle interface */
+        if( p_intf->p_vout != NULL )
+        {
+            vlc_mutex_lock( &p_intf->p_vout->change_lock );                        
+            p_intf->p_vout->b_interface     = !p_intf->p_vout->b_interface;                    
+            p_intf->p_vout->i_changes |= VOUT_INTF_CHANGE;                        
+            vlc_mutex_unlock( &p_intf->p_vout->change_lock );      
+        }
+        break;                                
+    case 'i':                                                   /* toggle info */
         if( p_intf->p_vout != NULL )
         {
             vlc_mutex_lock( &p_intf->p_vout->change_lock );                        
@@ -237,7 +246,16 @@ int intf_ProcessKey( intf_thread_t *p_intf, int i_key )
             vlc_mutex_unlock( &p_intf->p_vout->change_lock );      
         }
         break;                                
-    default:                                                    /* unknown key */
+    case 's':                                                 /* toggle scaling */
+        if( p_intf->p_vout != NULL )
+        {
+            vlc_mutex_lock( &p_intf->p_vout->change_lock );                        
+            p_intf->p_vout->b_scale     = !p_intf->p_vout->b_scale;                    
+            p_intf->p_vout->i_changes |= VOUT_SCALE_CHANGE;                        
+            vlc_mutex_unlock( &p_intf->p_vout->change_lock );      
+        }
+        break;                                
+   default:                                                    /* unknown key */
         return( 1 );        
     }
 
index 8c9ed8542b374fb0b68a79802877f10058ca6317..b13c868a71dcc2ed659ae1dcc6d8beb6dbb5c5a8 100644 (file)
@@ -443,11 +443,13 @@ static void Usage( void )
 
     /* Interfaces keys */
     intf_Msg("Interface keys: most interfaces accept the following commands:\n" \
+             "  [space]                           \ttoggle interface\n"
              "  [esc], q                          \tquit\n" \
+             "  0 - 9                             \tselect channel\n" \
              "  +, -, m                           \tchange volume, mute\n" \
              "  g, G, c                           \tchange gamma, toggle grayscale\n" \
-             "  0 - 9                             \tselect channel\n" \
-             "  [space]                           \ttoggle info printing\n" \
+             "  i                                 \ttoggle info printing\n" \
+             "  s                                 \ttoggle picture scaling\n" \
              );    
 }
 
index f8c5a0271585f80aed82788e359a154c813c76d1..9fbc418af14f4a7dfefb6aad69881311299a2d6b 100644 (file)
@@ -41,25 +41,11 @@ typedef struct vout_sys_s
 {
     /* System informations */
     int                         i_fb_dev;        /* framebuffer device handle */
-    size_t                      i_page_size;                     /* page size */
     struct fb_var_screeninfo    var_info;    /* framebuffer mode informations */
 
     /* Video memory */
-    byte_t *                    p_video;
-
-    /* User settings */
-    boolean_t           b_shm;                /* shared memory extension flag */
-
-    /* Font information */
-    int                 i_char_bytes_per_line;     /* character width (bytes) */
-    int                 i_char_height;            /* character height (lines) */
-    int                 i_char_interspacing;/* space between centers (pixels) */
-    byte_t *            pi_font;                      /* pointer to font data */
-
-    /* Display buffers information */
-    int                 i_buffer_index;                       /* buffer index */
-    void *              p_image[2];                                  /* image */
-
+    byte_t *                    p_video;                       /* base adress */    
+    size_t                      i_page_size;                     /* page size */
 } vout_sys_t;
 
 /******************************************************************************
@@ -98,32 +84,18 @@ int vout_SysCreate( vout_thread_t *p_vout, char *psz_display, int i_root_window
 
 /******************************************************************************
  * vout_SysInit: initialize framebuffer video thread output method
- ******************************************************************************
- * This function creates the images needed by the output thread. It is called
- * at the beginning of the thread, but also each time the display is resized.
  ******************************************************************************/
 int vout_SysInit( vout_thread_t *p_vout )
 {
-    // Blank both screens
-    memset( p_vout->p_sys->p_video, 0x00, 2*p_vout->p_sys->i_page_size );
-    //memset( p_vout->p_sys->p_image[0], 0xf0, p_vout->p_sys->i_page_size );
-    //memset( p_vout->p_sys->p_image[1], 0x0f, p_vout->p_sys->i_page_size );
-
-    /* Set buffer index to 0 */
-    p_vout->p_sys->i_buffer_index = 0;
-
     return( 0 );
 }
 
 /******************************************************************************
  * vout_SysEnd: terminate FB video thread output method
- ******************************************************************************
- * Destroy the FB images created by vout_SysInit. It is called at the end of 
- * the thread, but also each time the window is resized.
  ******************************************************************************/
 void vout_SysEnd( vout_thread_t *p_vout )
-{
-    intf_DbgMsg("%p\n", p_vout );
+{       
+    ;    
 }
 
 /******************************************************************************
@@ -141,19 +113,10 @@ void vout_SysDestroy( vout_thread_t *p_vout )
  * vout_SysManage: handle FB events
  ******************************************************************************
  * This function should be called regularly by video output thread. It manages
- * console events and allows screen resizing. It returns a non null value on 
- * error.
+ * console events. It returns a non null value on error.
  ******************************************************************************/
 int vout_SysManage( vout_thread_t *p_vout )
 {
-    /* XXX */
-    if( p_vout->i_changes & VOUT_SIZE_CHANGE )
-    {
-        intf_DbgMsg("resizing window\n");
-        p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
-       FBBlankDisplay( p_vout );
-    }
-                                       
     return 0;
 }
 
@@ -165,10 +128,6 @@ int vout_SysManage( vout_thread_t *p_vout )
  ******************************************************************************/
 void vout_SysDisplay( vout_thread_t *p_vout )
 {
-    /* Swap buffers */
-    //p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
-    p_vout->p_sys->i_buffer_index = 0;
-
     /* tout est bien affiché, on peut échanger les 2 écrans */
     p_vout->p_sys->var_info.xoffset = 0;
     p_vout->p_sys->var_info.yoffset =
@@ -179,16 +138,6 @@ void vout_SysDisplay( vout_thread_t *p_vout )
     ioctl( p_vout->p_sys->i_fb_dev, FBIOPAN_DISPLAY, &p_vout->p_sys->var_info );       
 }
 
-/******************************************************************************
- * vout_SysGetPicture: get current display buffer informations
- ******************************************************************************
- * This function returns the address of the current display buffer.
- ******************************************************************************/
-void * vout_SysGetPicture( vout_thread_t *p_vout )
-{
-    return( p_vout->p_sys->p_image[ p_vout->p_sys->i_buffer_index ] );
-}
-
 /* following functions are local */
 
 /******************************************************************************
@@ -291,8 +240,12 @@ static int FBOpenDisplay( vout_thread_t *p_vout )
         close( p_vout->p_sys->i_fb_dev );
         return( 1 );
     }
-    p_vout->p_sys->p_image[ 0 ] = p_vout->p_sys->p_video;
-    p_vout->p_sys->p_image[ 1 ] = p_vout->p_sys->p_video + p_vout->p_sys->i_page_size;
+
+    /* Set and initialize buffers */
+    p_vout->p_buffer[0].p_data = p_vout->p_sys->p_video;
+    p_vout->p_buffer[1].p_data = p_vout->p_sys->p_video + p_vout->p_sys->i_page_size;    
+    vout_ClearBuffer( p_vout, &p_vout->p_buffer[0] );
+    vout_ClearBuffer( p_vout, &p_vout->p_buffer[1] );    
 
     intf_DbgMsg("framebuffer type=%d, visual=%d, ypanstep=%d, ywrap=%d, accel=%d\n",
                 fix_info.type, fix_info.visual, fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
@@ -310,20 +263,6 @@ static int FBOpenDisplay( vout_thread_t *p_vout )
  ******************************************************************************/
 static void FBCloseDisplay( vout_thread_t *p_vout )
 {
-    // Free font info
-    free( p_vout->p_sys->pi_font );    
-
     // Destroy window and close display
     close( p_vout->p_sys->i_fb_dev );    
 }
-
-/******************************************************************************
- * FBBlankDisplay: render a blank screen
- ******************************************************************************
- * This function is called by all other rendering functions when they arrive on
- * a non blanked screen.
- ******************************************************************************/
-static void FBBlankDisplay( vout_thread_t *p_vout )
-{
-    memset( p_vout->p_sys->p_video, 0x00, 2*p_vout->p_sys->i_page_size );
-}
index 45f2f56d97667895866d7c0119586b6b73277035..d9f0024390bac9318555cf58cc8bf213a82a90de 100644 (file)
@@ -33,13 +33,8 @@ typedef struct vout_sys_s
     ggi_visual_t        p_display;                           /* display device */
 
     /* Buffers informations */
-    int                 i_buffer_index;                        /* buffer index */
     ggi_directbuffer *  p_buffer[2];                                /* buffers */
     boolean_t           b_must_acquire;     /* must be acquired before writing */    
-
-    /* Characters size */
-    int                 i_char_width;
-    int                 i_char_height;    
 } vout_sys_t;
 
 /*******************************************************************************
@@ -72,7 +67,6 @@ int vout_SysCreate( vout_thread_t *p_vout, char *psz_display, int i_root_window
         free( p_vout->p_sys );
         return( 1 );        
     }
-    
     return( 0 );
 }
 
@@ -84,10 +78,9 @@ int vout_SysCreate( vout_thread_t *p_vout, char *psz_display, int i_root_window
 int vout_SysInit( vout_thread_t *p_vout )
 {
     /* Acquire first buffer */
-    p_vout->p_sys->i_buffer_index = 0;
     if( p_vout->p_sys->b_must_acquire )
     {
-        ggiResourceAcquire( p_vout->p_sys->p_buffer[ 0 ]->resource, GGI_ACTYPE_WRITE );        
+        ggiResourceAcquire( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource, GGI_ACTYPE_WRITE );        
     }    
 
     return( 0 );
@@ -103,7 +96,7 @@ void vout_SysEnd( vout_thread_t *p_vout )
     /* Release buffer */
     if( p_vout->p_sys->b_must_acquire )
     {
-        ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->resource );
+        ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
     }
 }
 
@@ -140,64 +133,20 @@ void vout_SysDisplay( vout_thread_t *p_vout )
     /* Change display frame */
     if( p_vout->p_sys->b_must_acquire )
     {            
-        ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->resource );
+        ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
     }    
     ggiFlush( p_vout->p_sys->p_display ); // ??    
     ggiSetDisplayFrame( p_vout->p_sys->p_display, 
-                        p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->frame );      
+                        p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->frame );      
         
     /* Swap buffers and change write frame */
-    p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
     if( p_vout->p_sys->b_must_acquire )
     {            
-        ggiResourceAcquire( p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->resource, 
+        ggiResourceAcquire( p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->resource, 
                             GGI_ACTYPE_WRITE );
     } 
     ggiSetWriteFrame( p_vout->p_sys->p_display,
-                      p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->frame );    
- }
-
-/*******************************************************************************
- * vout_SysGetPicture: get current display buffer informations
- *******************************************************************************
- * This function returns the address of the current display buffer.
- *******************************************************************************/
-void * vout_SysGetPicture( vout_thread_t *p_vout )
-{    
-    return( p_vout->p_sys->p_buffer[ p_vout->p_sys->i_buffer_index ]->write );        
-}
-
-/*******************************************************************************
- * vout_SysPrint: print simple text on a picture
- *******************************************************************************
- * This function will print a simple text on the picture. It is designed to
- * print debugging or general informations, not to render subtitles. 
- *******************************************************************************/
-void vout_SysPrint( vout_thread_t *p_vout, int i_x, int i_y, int i_halign, 
-                    int i_valign, unsigned char *psz_text )
-{
-    /* Update upper left coordinates according to alignment */
-    switch( i_halign )
-    {
-    case 0:                                                        /* centered */
-        i_x -= p_vout->p_sys->i_char_width * strlen( psz_text ) / 2;
-        break;        
-    case 1:                                                   /* right aligned */
-        i_x -= p_vout->p_sys->i_char_width * strlen( psz_text );
-        break;                
-    }
-    switch( i_valign )
-    {
-    case 0:                                                        /* centered */
-        i_y -= p_vout->p_sys->i_char_height / 2;
-        break;        
-    case 1:                                                   /* bottom aligned */
-        i_y -= p_vout->p_sys->i_char_height;
-        break;                
-    }
-
-    /* Print text */
-    ggiPuts( p_vout->p_sys->p_display, i_x, i_y, psz_text );
+                      p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->frame );    
 }
 
 /*******************************************************************************
@@ -373,6 +322,12 @@ static int GGIOpenDisplay( vout_thread_t *p_vout, char *psz_display )
         break;        
     }
 
+    /* Set and initialize buffers */
+    p_vout->p_buffer[0].p_data = p_vout->p_sys->p_buffer[ 0 ]->write;
+    p_vout->p_buffer[1].p_data = p_vout->p_sys->p_buffer[ 1 ]->write;
+    vout_ClearBuffer( p_vout, &p_vout->p_buffer[0] );
+    vout_ClearBuffer( p_vout, &p_vout->p_buffer[1] );    
+
     return( 0 );    
 }
 
index dc0dea7449cb6b0fcdeaf9447affe54ca4e3b58d..3f9792332599fd9cf095d818f16f4a8abcfd5759 100644 (file)
@@ -34,12 +34,17 @@ static int      InitThread              ( vout_thread_t *p_vout );
 static void     RunThread               ( vout_thread_t *p_vout );
 static void     ErrorThread             ( vout_thread_t *p_vout );
 static void     EndThread               ( vout_thread_t *p_vout );
+static void     DestroyThread           ( vout_thread_t *p_vout, int i_status );
 static void     Print                   ( vout_thread_t *p_vout, int i_x, int i_y, int i_halign, int i_valign, unsigned char *psz_text );
-static void     RenderBlank             ( vout_thread_t *p_vout );
-static int      RenderPicture           ( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank );
-static int      RenderPictureInfo       ( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank );
-static int      RenderIdle              ( vout_thread_t *p_vout, boolean_t b_blank );
-static int      RenderInfo              ( vout_thread_t *p_vout, boolean_t b_balnk );
+
+static void     SetBufferArea           ( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int i_h );
+static void     SetBufferPicture        ( vout_thread_t *p_vout, picture_t *p_pic );
+static void     RenderPicture           ( vout_thread_t *p_vout, picture_t *p_pic );
+static void     RenderPictureInfo       ( vout_thread_t *p_vout, picture_t *p_pic );
+static void     RenderSubtitle          ( vout_thread_t *p_vout, subtitle_t *p_sub );
+static void     RenderInterface         ( vout_thread_t *p_vout );
+static void     RenderIdle              ( vout_thread_t *p_vout );
+static void     RenderInfo              ( vout_thread_t *p_vout );
 static int      Manage                  ( vout_thread_t *p_vout );
 
 /******************************************************************************
@@ -55,6 +60,7 @@ vout_thread_t * vout_CreateThread               ( char *psz_display, int i_root_
 {
     vout_thread_t * p_vout;                              /* thread descriptor */
     int             i_status;                                /* thread status */
+    int             i_index;                /* index for array initialization */    
 
     /* Allocate descriptor */
     intf_DbgMsg("\n");    
@@ -65,7 +71,8 @@ vout_thread_t * vout_CreateThread               ( char *psz_display, int i_root_
         return( NULL );
     }
 
-    /* Initialize thread properties */
+    /* Initialize thread properties - thread id and locks will be initialized 
+     * later */
     p_vout->b_die               = 0;
     p_vout->b_error             = 0;    
     p_vout->b_active            = 0;
@@ -74,22 +81,46 @@ vout_thread_t * vout_CreateThread               ( char *psz_display, int i_root_
 
     /* Initialize some fields used by the system-dependant method - these fields will
      * probably be modified by the method, and are only preferences */
-    p_vout->b_grayscale         = main_GetIntVariable( VOUT_GRAYSCALE_VAR, 
-                                                       VOUT_GRAYSCALE_DEFAULT );
     p_vout->i_width             = i_width;
     p_vout->i_height            = i_height;
     p_vout->i_bytes_per_line    = i_width * 2;    
     p_vout->i_screen_depth      = 15;
     p_vout->i_bytes_per_pixel   = 2;
     p_vout->f_gamma             = VOUT_GAMMA;    
-#ifdef DEBUG
-    p_vout->b_info              = 1;    
-#else
+
+    p_vout->b_grayscale         = main_GetIntVariable( VOUT_GRAYSCALE_VAR, 
+                                                       VOUT_GRAYSCALE_DEFAULT );
     p_vout->b_info              = 0;    
-#endif
+    p_vout->b_interface         = 0;
+    p_vout->b_scale             = 0;
+    
     intf_DbgMsg("wished configuration: %dx%d,%d (%d bytes/pixel, %d bytes/line)\n",
                 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
                 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
+
+#ifdef STATS
+    /* Initialize statistics fields */
+    p_vout->render_time         = 0;    
+    p_vout->c_fps_samples       = 0;    
+#endif      
+
+    /* Initialize running properties */
+    p_vout->i_changes           = 0;
+    p_vout->last_picture_date   = 0;
+    p_vout->last_display_date   = 0;
+
+    /* Initialize buffer index */
+    p_vout->i_buffer_index      = 0;
+
+    /* Initialize pictures and subtitles - translation tables and functions
+     * will be initialized later in InitThread */    
+    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
+    {
+        p_vout->p_picture[i_index].i_type   = EMPTY_PICTURE;
+        p_vout->p_picture[i_index].i_status = FREE_PICTURE;
+        p_vout->p_subtitle[i_index].i_type  = EMPTY_SUBTITLE;
+        p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
+    }
    
     /* Create and initialize system-dependant method - this function issues its
      * own error messages */
@@ -102,7 +133,8 @@ vout_thread_t * vout_CreateThread               ( char *psz_display, int i_root_
                 p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth,
                 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
 
-    /* Load fonts */
+    /* Load fonts - fonts must be initialized after the systme method since
+     * they may be dependant of screen depth and other thread properties */
     p_vout->p_default_font      = vout_LoadFont( VOUT_DEFAULT_FONT );    
     if( p_vout->p_default_font == NULL )
     {
@@ -117,18 +149,7 @@ vout_thread_t * vout_CreateThread               ( char *psz_display, int i_root_
         vout_SysDestroy( p_vout );        
         free( p_vout );        
         return( NULL );        
-    }    
-#ifdef STATS
-    /* Initialize statistics fields */
-    p_vout->render_time           = 0;    
-    p_vout->c_fps_samples       = 0;    
-#endif      
-
-    /* Initialize running properties */
-    p_vout->i_changes           = 0;
-    p_vout->last_picture_date   = 0;
-    p_vout->last_display_date   = 0;
+    }     
 
     /* Create thread and set locks */
     vlc_mutex_init( &p_vout->picture_lock );
@@ -239,7 +260,7 @@ void  vout_DisplaySubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
 subtitle_t *vout_CreateSubtitle( vout_thread_t *p_vout, int i_type, 
                                  int i_size )
 {
-    //???
+    //??
 }
 
 /******************************************************************************
@@ -553,6 +574,26 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
     vlc_mutex_unlock( &p_vout->picture_lock );
 }
 
+/******************************************************************************
+ * vout_ClearBuffer: clear a whole buffer
+ ******************************************************************************
+ * This function is called when a buffer is initialized. It clears the whole
+ * buffer.
+ ******************************************************************************/
+void vout_ClearBuffer( vout_thread_t *p_vout, vout_buffer_t *p_buffer )
+{
+    /* No picture previously */
+    p_buffer->i_pic_x =         0;
+    p_buffer->i_pic_y =         0;
+    p_buffer->i_pic_width =     0;
+    p_buffer->i_pic_height =    0;
+
+    /* The first area covers all the screen */
+    p_buffer->i_areas =                 1;
+    p_buffer->pi_area_begin[0] =        0;
+    p_buffer->pi_area_end[0] =          p_vout->i_height - 1;
+}
+
 /* following functions are local */
 
 /******************************************************************************
@@ -564,8 +605,6 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
  ******************************************************************************/
 static int InitThread( vout_thread_t *p_vout )
 {
-    int     i_index;                                         /* generic index */    
-
     /* Update status */
     intf_DbgMsg("\n");
     *p_vout->pi_status = THREAD_START;    
@@ -573,19 +612,9 @@ static int InitThread( vout_thread_t *p_vout )
     /* Initialize output method - this function issues its own error messages */
     if( vout_SysInit( p_vout ) )
     {
-        *p_vout->pi_status = THREAD_ERROR;        
         return( 1 );
     } 
 
-    /* Initialize pictures and subtitles */    
-    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++)
-    {
-        p_vout->p_picture[i_index].i_type   = EMPTY_PICTURE;
-        p_vout->p_picture[i_index].i_status = FREE_PICTURE;
-        p_vout->p_subtitle[i_index].i_type  = EMPTY_SUBTITLE;
-        p_vout->p_subtitle[i_index].i_status= FREE_SUBTITLE;
-    }
-
     /* Initialize convertion tables and functions */
     if( vout_InitTables( p_vout ) )
     {
@@ -609,20 +638,20 @@ static int InitThread( vout_thread_t *p_vout )
  ******************************************************************************/
 static void RunThread( vout_thread_t *p_vout)
 {
-    int             i_picture;                               /* picture index */
+    int             i_index;                                 /* index in heap */
     mtime_t         current_date;                             /* current date */
-    mtime_t         pic_date = 0;                             /* picture date */    
+    mtime_t         display_date;                             /* display date */    
     boolean_t       b_display;                                /* display flag */    
     picture_t *     p_pic;                                 /* picture pointer */
+    subtitle_t *    p_sub;                                /* subtitle pointer */    
      
     /* 
-     * Initialize thread and free configuration 
+     * Initialize thread
      */
     p_vout->b_error = InitThread( p_vout );
     if( p_vout->b_error )
     {
-        //??
-        free( p_vout );                                 /* destroy descriptor */
+        DestroyThread( p_vout, THREAD_ERROR );
         return;        
     }    
     intf_DbgMsg("\n");
@@ -632,115 +661,171 @@ static void RunThread( vout_thread_t *p_vout)
      * initialization
      */
     while( (!p_vout->b_die) && (!p_vout->b_error) )
-    {            
+    {
+        /* Initialize loop variables */
+        p_pic =         NULL;
+        p_sub =         NULL;
+        display_date =  0;        
+        current_date =  mdate();
+
         /* 
         * Find the picture to display - this operation does not need lock,
-         * since only READY_PICTURES are handled 
+         * since only READY_PICTUREs are handled 
          */
-        p_pic = NULL;         
-        current_date = mdate();
-        for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
+        for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
        {
-           if( (p_vout->p_picture[i_picture].i_status == READY_PICTURE) &&
+           if( (p_vout->p_picture[i_index].i_status == READY_PICTURE) &&
                ( (p_pic == NULL) || 
-                 (p_vout->p_picture[i_picture].date < pic_date) ) )
+                 (p_vout->p_picture[i_index].date < display_date) ) )
            {
-                p_pic = &p_vout->p_picture[i_picture];
-                pic_date = p_pic->date;                
+                p_pic = &p_vout->p_picture[i_index];
+                display_date = p_pic->date;                
            }
        }
  
-        /* 
-        * Render picture if any
-        */
         if( p_pic )
         {
 #ifdef STATS
             /* Computes FPS rate */
-            p_vout->fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = pic_date;
+            p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date;
 #endif     
-           if( pic_date < current_date )
+           if( display_date < current_date )
            {
                /* Picture is late: it will be destroyed and the thread will sleep and
                  * go to next picture */
                 vlc_mutex_lock( &p_vout->picture_lock );
                 p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
-#ifdef DEBUG_VIDEO
                intf_DbgMsg( "warning: late picture %p skipped refcount=%d\n", p_pic, p_pic->i_refcount );
-#endif
                 vlc_mutex_unlock( &p_vout->picture_lock );
                 p_pic =         NULL;                
+                display_date =  0;                
            }
-           else if( pic_date > current_date + VOUT_DISPLAY_DELAY )
+           else if( display_date > current_date + VOUT_DISPLAY_DELAY )
            {
                /* A picture is ready to be rendered, but its rendering date is
                 * far from the current one so the thread will perform an empty loop
                 * as if no picture were found. The picture state is unchanged */
                 p_pic =         NULL;                
+                display_date =  0;                
            }
         }
-              
+
+        /*
+         * Find the subtitle to display - this operation does not need lock, since
+         * only READY_SUBTITLEs are handled. If no picture has been selected,
+         * display_date will depend on the subtitle
+         */
+        //??
+
         /*
          * Perform rendering, sleep and display rendered picture
          */
-        if( p_pic )
+        if( p_pic )                            /* picture and perhaps subtitle */
         {
-            /* A picture is ready to be displayed : render it */
-            if( p_vout->b_active )
-            {                    
-                b_display = RenderPicture( p_vout, p_pic, 1 );
+            b_display = p_vout->b_active;            
+
+            if( b_display )
+            {                
+                /* Set picture dimensions and clear buffer */
+                SetBufferPicture( p_vout, p_pic );
+
+                /* Render picture and informations */
+                RenderPicture( p_vout, p_pic );             
                 if( p_vout->b_info )
                 {
-                    b_display |= RenderPictureInfo( p_vout, p_pic, b_display );
-                    b_display |= RenderInfo( p_vout, b_display );                    
-                }                    
+                    RenderPictureInfo( p_vout, p_pic );
+                    RenderInfo( p_vout );                
+                }
             }
-            else
-            {
-                b_display = 0;                
-            } 
-
+            
             /* Remove picture from heap */
             vlc_mutex_lock( &p_vout->picture_lock );
             p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
             vlc_mutex_unlock( &p_vout->picture_lock );                          
-        }            
-        else
+
+            /* Render interface and subtitles */
+            if( b_display && p_vout->b_interface )
+            {
+                RenderInterface( p_vout );                
+            }
+            if( p_sub )
+            {
+                if( b_display )
+                {                    
+                    RenderSubtitle( p_vout, p_sub );
+                }                
+
+                /* Remove subtitle from heap */
+                vlc_mutex_lock( &p_vout->subtitle_lock );
+                p_sub->i_status = DESTROYED_SUBTITLE;
+                vlc_mutex_unlock( &p_vout->subtitle_lock );                          
+            }
+
+        }
+        else if( p_sub )                                     /* subtitle alone */
         {
-            /* No picture. However, an idle screen may be ready to display */
-            if( p_vout->b_active )
+            b_display = p_vout->b_active;
+
+            if( b_display )
             {                
-                b_display = RenderIdle( p_vout, 1 );
+                /* Clear buffer */
+                SetBufferPicture( p_vout, NULL );
+
+                /* Render informations, interface and subtitle */
                 if( p_vout->b_info )
-                {                    
-                    b_display |= RenderInfo( p_vout, b_display );
-                }        
-            }
-            else
-            {
-                b_display = 0;                
+                {
+                    RenderInfo( p_vout );
+                }
+                if( p_vout->b_interface )
+                {
+                    RenderInterface( p_vout );
+                }
+                RenderSubtitle( p_vout, p_sub );            
             }            
+
+            /* Remove subtitle from heap */
+            vlc_mutex_lock( &p_vout->subtitle_lock );
+            p_sub->i_status = DESTROYED_SUBTITLE;
+            vlc_mutex_unlock( &p_vout->subtitle_lock );                          
+        }
+        else                                              /* idle screen alone */
+        {            
+            //??? render on idle screen or interface change
+            b_display = 0;             //???
         }
 
+        /*
+         * Sleep, wake up and display rendered picture
+         */
+
+#ifdef STATS
+        /* Store render time */
+        p_vout->render_time = mdate() - current_date;
+#endif
+
         /* Give back change lock */
         vlc_mutex_unlock( &p_vout->change_lock );        
 
         /* Sleep a while or until a given date */
-        if( p_pic )
+        if( display_date != 0 )
         {
-            mwait( pic_date );
+            mwait( display_date );
         }
         else
         {
             msleep( VOUT_IDLE_SLEEP );                
         }            
 
-        /* On awakening, take back lock and send immediately picture to display */
+        /* On awakening, take back lock and send immediately picture to display, 
+         * then swap buffers */
         vlc_mutex_lock( &p_vout->change_lock );        
-        if( b_display && p_vout->b_active && 
-            !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
+#ifdef DEBUG_VIDEO
+        intf_DbgMsg( "picture %p, subtitle %p\n", p_pic, p_sub );        
+#endif            
+        if( b_display && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
         {
             vout_SysDisplay( p_vout );
+            p_vout->i_buffer_index = ++p_vout->i_buffer_index & 1;
         }
 
         /*
@@ -756,7 +841,7 @@ static void RunThread( vout_thread_t *p_vout)
     } 
 
     /*
-     * Error loop
+     * Error loop - wait until the thread destruction is requested
      */
     if( p_vout->b_error )
     {
@@ -765,6 +850,7 @@ static void RunThread( vout_thread_t *p_vout)
 
     /* End of thread */
     EndThread( p_vout );
+    DestroyThread( p_vout, THREAD_OVER ); 
     intf_DbgMsg( "thread end\n" );
 }
 
@@ -786,43 +872,58 @@ static void ErrorThread( vout_thread_t *p_vout )
     }
 }
 
-/******************************************************************************
+/*******************************************************************************
  * EndThread: thread destruction
- ******************************************************************************
+ *******************************************************************************
  * This function is called when the thread ends after a sucessfull 
- * initialization.
- ******************************************************************************/
+ * initialization. It frees all ressources allocated by InitThread.
+ *******************************************************************************/
 static void EndThread( vout_thread_t *p_vout )
 {
-    int *   pi_status;                                       /* thread status */
-    int     i_picture;
-        
+    int     i_index;                                          /* index in heap */
+            
     /* Store status */
     intf_DbgMsg("\n");
-    pi_status = p_vout->pi_status;    
-    *pi_status = THREAD_END;    
+    *p_vout->pi_status = THREAD_END;    
 
-    /* Destroy all remaining pictures */
-    for( i_picture = 0; i_picture < VOUT_MAX_PICTURES; i_picture++ )
+    /* Destroy all remaining pictures and subtitles */
+    for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
     {
-       if( p_vout->p_picture[i_picture].i_status != FREE_PICTURE )
+       if( p_vout->p_picture[i_index].i_status != FREE_PICTURE )
        {
-            free( p_vout->p_picture[i_picture].p_data );
+            free( p_vout->p_picture[i_index].p_data );
         }
+        if( p_vout->p_subtitle[i_index].i_status != FREE_SUBTITLE )
+        {
+            free( p_vout->p_subtitle[i_index].p_data );            
+        }        
     }
 
     /* Destroy translation tables */
-    vout_EndTables( p_vout );
+    vout_EndTables( p_vout );  
+    vout_SysEnd( p_vout );    
+}
+
+/*******************************************************************************
+ * DestroyThread: thread destruction
+ *******************************************************************************
+ * This function is called when the thread ends. It frees all ressources
+ * allocated by CreateThread. Status is available at this stage.
+ *******************************************************************************/
+static void DestroyThread( vout_thread_t *p_vout, int i_status )
+{  
+    int *pi_status;                                           /* status adress */
+    
+    /* Store status adress */
+    intf_DbgMsg("\n");
+    pi_status = p_vout->pi_status;    
     
     /* Destroy thread structures allocated by Create and InitThread */
-    vout_SysEnd( p_vout );
     vout_UnloadFont( p_vout->p_default_font );
     vout_UnloadFont( p_vout->p_large_font ); 
     vout_SysDestroy( p_vout );
     free( p_vout );
-
-    /* Update status */
-    *pi_status = THREAD_OVER;    
+    *pi_status = i_status;    
 }
 
 /*******************************************************************************
@@ -865,55 +966,308 @@ void Print( vout_thread_t *p_vout, int i_x, int i_y, int i_halign, int i_valign,
         return;        
     }    
 
-    /* Print text */
-    vout_Print( p_vout->p_default_font, vout_SysGetPicture( p_vout ) + 
+    /* Set area and print text */
+    SetBufferArea( p_vout, i_x, i_y, i_text_width, i_text_height );    
+    vout_Print( p_vout->p_default_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data + 
                 i_y * p_vout->i_bytes_per_line + i_x * p_vout->i_bytes_per_pixel,
                 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, 
-                0xffffffff, 0x00000000, 0x00000000, 0, psz_text );
+                0xffffffff, 0x00000000, 0x00000000, TRANSPARENT_TEXT, psz_text );
 }
 
-/******************************************************************************
- * RenderBlank: render a blank screen
- ******************************************************************************
- * This function is called by all other rendering functions when they arrive on
- * a non blanked screen.
- ******************************************************************************/
-static void RenderBlank( vout_thread_t *p_vout )
+/*******************************************************************************
+ * SetBufferArea: activate an area in current buffer
+ *******************************************************************************
+ * This function is called when something is rendered on the current buffer.
+ * It set the area as active and prepare it to be cleared on next rendering.
+ * Pay attention to the fact that in this functions, i_h is in fact the end y
+ * coordinate of the new area.
+ *******************************************************************************/
+static void SetBufferArea( vout_thread_t *p_vout, int i_x, int i_y, int i_w, int i_h )
 {
-    //?? toooooo slow
-    int  i_index;                                   /* current 64 bits sample */    
-    int  i_width;                                /* number of 64 bits samples */    
-    u64 *p_pic;                                 /* pointer to 64 bits samples */
+    vout_buffer_t *     p_buffer;                            /* current buffer */
+    int                 i_area_begin, i_area_end;   /* area vertical extension */
+    int                 i_area, i_area_copy;                     /* area index */    
+    int                 i_area_shift;              /* shift distance for areas */    
     
-    /* Initialize variables */
-    p_pic =     vout_SysGetPicture( p_vout );
-    i_width =   p_vout->i_bytes_per_line * p_vout->i_height / 256;
+    /* Choose buffer and modify h to end of area position */
+    p_buffer =  &p_vout->p_buffer[ p_vout->i_buffer_index ];    
+    i_h +=      i_y - 1;
+    /* 
+     * Remove part of the area which is inside the picture - this is done
+     * by calling again SetBufferArea with the correct areas dimensions.
+     */
+    if( (i_x >= p_buffer->i_pic_x) && (i_x + i_w <= p_buffer->i_pic_x + p_buffer->i_pic_width) )
+    {
+        i_area_begin =  p_buffer->i_pic_y;
+        i_area_end =    i_area_begin + p_buffer->i_pic_height - 1;
+
+        if( ((i_y >= i_area_begin) && (i_y <= i_area_end)) ||
+            ((i_h >= i_area_begin) && (i_h <= i_area_end)) ||
+            ((i_y <  i_area_begin) && (i_h > i_area_end)) )
+        {                    
+            /* Keep the stripe above the picture, if any */
+            if( i_y < i_area_begin )
+            {
+                SetBufferArea( p_vout, i_x, i_y, i_w, i_area_begin - i_y );            
+            }
+            /* Keep the stripe below the picture, if any */
+            if( i_h > i_area_end )
+            {
+                SetBufferArea( p_vout, i_x, i_area_end, i_w, i_h - i_area_end );
+            }        
+            return;
+        }        
+    }   
 
-    /* Clear beginning of screen by 256 bytes blocks */
-    for( i_index = 0; i_index < i_width; i_index++ )
+    /* Skip some extensions until interesting areas */
+    for( i_area = 0; 
+         (i_area < p_buffer->i_areas) &&
+             (p_buffer->pi_area_end[i_area] + 1 <= i_y); 
+         i_area++ )
     {
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
-        *p_pic++ = 0;   *p_pic++ = 0;
+        ;        
+    }
+    
+    if( i_area == p_buffer->i_areas )
+    {
+        /* New area is below all existing ones: just add it at the end of the 
+         * array, if possible - else, append it to the last one */
+        if( i_area < VOUT_MAX_AREAS )
+        {
+            p_buffer->pi_area_begin[i_area] = i_y;
+            p_buffer->pi_area_end[i_area] = i_h;            
+            p_buffer->i_areas++;            
+        }
+        else
+        {
+#ifdef DEBUG_VIDEO
+            intf_DbgMsg("areas overflow\n");            
+#endif
+            p_buffer->pi_area_end[VOUT_MAX_AREAS - 1] = i_h;  
+        }        
     }
+    else 
+    {
+        i_area_begin =  p_buffer->pi_area_begin[i_area];
+        i_area_end =    p_buffer->pi_area_end[i_area];
+        
+        if( i_y < i_area_begin ) 
+        {
+            if( i_h >= i_area_begin - 1 )
+            {                
+                /* Extend area above */
+                p_buffer->pi_area_begin[i_area] = i_y;
+            }
+            else
+            {
+                /* Create a new area above : merge last area if overflow, then 
+                 * move all old areas down */
+                if( p_buffer->i_areas == VOUT_MAX_AREAS )
+                {                    
+#ifdef DEBUG_VIDEO
+                    intf_DbgMsg("areas overflow\n");       
+#endif
+                    p_buffer->pi_area_end[VOUT_MAX_AREAS - 2] = p_buffer->pi_area_end[VOUT_MAX_AREAS - 1];                    
+                }
+                else
+                {
+                    p_buffer->i_areas++;                    
+                }
+                for( i_area_copy = p_buffer->i_areas - 1; i_area_copy > i_area; i_area_copy++ )
+                {
+                    p_buffer->pi_area_begin[i_area_copy] = p_buffer->pi_area_begin[i_area_copy - 1];
+                    p_buffer->pi_area_end[i_area_copy] =   p_buffer->pi_area_end[i_area_copy - 1];
+                }
+                p_buffer->pi_area_begin[i_area] = i_y;
+                p_buffer->pi_area_end[i_area] = i_h;
+                return;
+            }              
+        }
+        if( i_h > i_area_end )
+        {
+            /* Find further areas which can be merged with the new one */
+            for( i_area_copy = i_area + 1; 
+                 (i_area_copy < p_buffer->i_areas) &&
+                     (p_buffer->pi_area_begin[i_area] <= i_h);
+                 i_area_copy++ )
+            {
+                ;                
+            }
+            i_area_copy--;            
 
-    /* Clear last pixels */
-    //??
+            if( i_area_copy != i_area )
+            {
+                /* Merge with last possible areas */
+                p_buffer->pi_area_end[i_area] = MAX( i_h, p_buffer->pi_area_end[i_area_copy] );
+
+                /* Shift lower areas upward */
+                i_area_shift = i_area_copy - i_area;                
+                p_buffer->i_areas -= i_area_shift;
+                for( i_area_copy = i_area + 1; i_area_copy < p_buffer->i_areas; i_area_copy++ )
+                {
+                    p_buffer->pi_area_begin[i_area_copy] = p_buffer->pi_area_begin[i_area_copy + i_area_shift];
+                    p_buffer->pi_area_end[i_area_copy] =   p_buffer->pi_area_end[i_area_copy + i_area_shift];
+                }
+            }
+            else
+            {
+                /* Extend area below */
+                p_buffer->pi_area_end[i_area] = i_h;
+            }            
+        }
+    }
 }
 
+/*******************************************************************************
+ * SetBufferPicture: clear buffer and set picture area
+ *******************************************************************************
+ * This function is called before any rendering. It clears the current 
+ * rendering buffer and set the new picture area. If the picture pointer is
+ * NULL, then no picture area is defined. Floating operations are avoided since
+ * some MMX calculations may follow.
+ *******************************************************************************/
+static void SetBufferPicture( vout_thread_t *p_vout, picture_t *p_pic )
+{
+    vout_buffer_t *     p_buffer;                            /* current buffer */
+    int                 i_pic_x, i_pic_y;                  /* picture position */
+    int                 i_pic_width, i_pic_height;       /* picture dimensions */    
+    int                 i_old_pic_y, i_old_pic_height;     /* old picture area */    
+    int                 i_vout_width, i_vout_height;     /* display dimensions */
+    int                 i_area;                                  /* area index */    
+    int                 i_data_index;                       /* area data index */    
+    int                 i_data_size;     /* area data size, in 256 bytes blocs */
+    u64 *               p_data;                                   /* area data */    
+    
+    /* Choose buffer and set display dimensions */
+    p_buffer =          &p_vout->p_buffer[ p_vout->i_buffer_index ];    
+    i_vout_width =      p_vout->i_width;
+    i_vout_height =     p_vout->i_height;    
+
+    /*
+     * Computes new picture size 
+     */
+    if( p_pic != NULL )
+    {
+        /* Try horizontal scaling first */
+        i_pic_width = ( p_vout->b_scale || (p_pic->i_width > i_vout_width)) ? 
+            i_vout_width : p_pic->i_width;
+        i_pic_width = i_pic_width / 16 * 16; //?? currently, width must be multiple of 16        
+        switch( p_pic->i_aspect_ratio )
+        {
+        case AR_3_4_PICTURE:
+            i_pic_height = i_pic_width * 3 / 4;
+            break;                
+        case AR_16_9_PICTURE:
+            i_pic_height = i_pic_width * 9 / 16;
+            break;
+        case AR_221_1_PICTURE:        
+            i_pic_height = i_pic_width * 100 / 221;
+            break;               
+        case AR_SQUARE_PICTURE:
+        default:
+            i_pic_height = p_pic->i_height * i_pic_width / p_pic->i_width;            
+            break;
+        }
+
+        /* If picture dimensions using horizontal scaling are too large, use 
+         * vertical scaling */
+        if( i_pic_height > i_vout_height )
+        {
+            i_pic_height = ( p_vout->b_scale || (p_pic->i_height > i_vout_height)) ? 
+                i_vout_height : p_pic->i_height;
+            switch( p_pic->i_aspect_ratio )
+            {
+            case AR_3_4_PICTURE:
+                i_pic_width = i_pic_height * 4 / 3;
+                break;                
+            case AR_16_9_PICTURE:
+                i_pic_width = i_pic_height * 16 / 9;
+                break;
+            case AR_221_1_PICTURE:        
+                i_pic_width = i_pic_height * 221 / 100;
+                break;               
+            case AR_SQUARE_PICTURE:
+            default:
+                i_pic_width = p_pic->i_width * i_pic_height / p_pic->i_height;
+                break;
+            }        
+            i_pic_width = i_pic_width / 16 * 16; //?? currently, width must be multiple of 16        
+        }        
+
+        /* Set picture position */
+        i_pic_x = (p_vout->i_width - i_pic_width) / 2;
+        i_pic_y = (p_vout->i_height - i_pic_height) / 2;                
+    }    
+    else
+    {
+        /* No picture: size is 0 */
+        i_pic_x =       0;
+        i_pic_y =       0;
+        i_pic_width =   0;
+        i_pic_height =  0;
+    }
+
+    /*
+     * Set new picture size - if is is smaller than the previous one, clear 
+     * around it. Since picture are centered, only their size is tested.
+     */                                          
+    if( (p_buffer->i_pic_width > i_pic_width) || (p_buffer->i_pic_height > i_pic_height) )
+    {
+        i_old_pic_y =            p_buffer->i_pic_y;
+        i_old_pic_height =       p_buffer->i_pic_height;
+        p_buffer->i_pic_x =      i_pic_x;
+        p_buffer->i_pic_y =      i_pic_y;
+        p_buffer->i_pic_width =  i_pic_width;
+        p_buffer->i_pic_height = i_pic_height;                        
+        SetBufferArea( p_vout, 0, i_old_pic_y, p_vout->i_width, i_old_pic_height );
+    }
+    else
+    {
+        p_buffer->i_pic_x =      i_pic_x;
+        p_buffer->i_pic_y =      i_pic_y;
+        p_buffer->i_pic_width =  i_pic_width;
+        p_buffer->i_pic_height = i_pic_height;    
+    }
+
+    /*
+     * Clear areas
+     */
+    for( i_area = 0; i_area < p_buffer->i_areas; i_area++ )
+    {
+#ifdef DEBUG_VIDEO    
+        intf_DbgMsg("clearing picture %p area: %d-%d\n", p_pic, 
+                    p_buffer->pi_area_begin[i_area], p_buffer->pi_area_end[i_area]);    
+#endif
+        p_data = (u64*) (p_buffer->p_data + p_vout->i_bytes_per_line * p_buffer->pi_area_begin[i_area]);
+        i_data_size = (p_buffer->pi_area_end[i_area] - p_buffer->pi_area_begin[i_area] + 1) * 
+            p_vout->i_bytes_per_line / 256;
+        for( i_data_index = 0; i_data_index < i_data_size; i_data_index++ )
+        {
+            /* Clear 256 bytes block */
+            *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
+            *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
+            *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
+            *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
+            *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
+            *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
+            *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
+            *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;  *p_data++ = 0;
+        }
+        i_data_size = (p_buffer->pi_area_end[i_area] - p_buffer->pi_area_begin[i_area] + 1) *
+            p_vout->i_bytes_per_line % 256 / 4;
+        for( i_data_index = 0; i_data_index < i_data_size; i_data_index++ )
+        {
+            /* Clear remaining 4 bytes blocks */
+            *p_data++ = 0;
+        }
+    }    
+
+    /*
+     * Clear areas array
+     */
+    p_buffer->i_areas = 0;
+}
 
 /******************************************************************************
  * RenderPicture: render a picture
@@ -923,66 +1277,35 @@ static void RenderBlank( vout_thread_t *p_vout )
  * rendered picture has been determined as existant, and will only be destroyed
  * by the vout thread later.
  ******************************************************************************/
-static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
+static void RenderPicture( vout_thread_t *p_vout, picture_t *p_pic )
 {
-    int         i_display_height, i_display_width;      /* display dimensions */
-    int         i_height, i_width;               /* source picture dimensions */
-    int         i_scaled_height;              /* scaled height of the picture */   
-    int         i_aspect_scale;                /* aspect ratio vertical scale */
-    int         i_eol;                       /* end of line offset for source */    
-    byte_t *    p_convert_dst;                      /* convertion destination */        
+    vout_buffer_t *     p_buffer;                         /* rendering buffer */    
+    byte_t *            p_convert_dst;              /* convertion destination */
+    int                 i_width, i_height, i_eol, i_pic_eol, i_scale;        /* ?? tmp variables*/
     
-#ifdef STATS
-    /* Start recording render time */
-    p_vout->render_time = mdate();
-#endif
-
-    /* Mark last picture date */
+    /* Get and set rendering informations */
+    p_buffer = &p_vout->p_buffer[ p_vout->i_buffer_index ];    
     p_vout->last_picture_date = p_pic->date;
-    i_width =                   p_pic->i_width;    
-    i_height =                  p_pic->i_height;
-    i_display_width =           p_vout->i_width;    
-    i_display_height =          p_vout->i_height;    
-
-    /* Select scaling depending of aspect ratio */
-    switch( p_pic->i_aspect_ratio )
-    {
-    case AR_3_4_PICTURE:
-        i_aspect_scale = (4 * i_height - 3 * i_width) ? 
-            1 + 3 * i_width / ( 4 * i_height - 3 * i_width ) : 0;
-        break;
-    case AR_16_9_PICTURE:
-        i_aspect_scale = ( 16 * i_height - 9 * i_width ) ? 
-            1 + 9 * i_width / ( 16 * i_height - 9 * i_width ) : 0;
-        break;
-    case AR_221_1_PICTURE:        
-        i_aspect_scale = ( 221 * i_height - 100 * i_width ) ?
-            1 + 100 * i_width / ( 221 * i_height - 100 * i_width ) : 0;
-        break;               
-    case AR_SQUARE_PICTURE:
-    default:
-        i_aspect_scale = 0;        
-    }
-    i_scaled_height = (i_aspect_scale ? i_height * (i_aspect_scale - 1) / i_aspect_scale : i_height);
-    
-    /* Crop picture if too large for the screen */
-    if( i_width > i_display_width )
-    {
-        i_eol = i_width - i_display_width / 16 * 16;
-        i_width = i_display_width / 16 * 16;        
-    }
+    p_convert_dst = p_buffer->p_data + p_buffer->i_pic_x * p_vout->i_bytes_per_pixel +
+        p_buffer->i_pic_y * p_vout->i_bytes_per_line;
+
+    // ?? temporary section: rebuild aspect scale from size informations.
+    // ?? when definitive convertion prototype will be used, those info will
+    // ?? no longer be required
+    i_width = MIN( p_pic->i_width, p_buffer->i_pic_width );
+    i_eol = p_pic->i_width - i_width / 16 * 16;
+    i_pic_eol = p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width;    
+    if( p_pic->i_height == p_buffer->i_pic_height )
+    {        
+        i_scale = 0;    
+    }    
     else
     {
-        i_eol = 0;        
-    }
-    if( i_scaled_height > i_display_height )
-    {
-        i_height = (i_aspect_scale * i_display_height / (i_aspect_scale - 1)) / 2 * 2;
-        i_scaled_height = i_display_height;        
+        i_scale = p_pic->i_height / (p_pic->i_height - p_buffer->i_pic_height);        
     }    
-    p_convert_dst = vout_SysGetPicture( p_vout ) + 
-        ( i_display_width - i_width ) / 2 * p_vout->i_bytes_per_pixel +
-        ( i_display_height - i_scaled_height ) / 2 * p_vout->i_bytes_per_line;
+    i_eol = p_pic->i_width - p_buffer->i_pic_width;    
+    i_height = p_pic->i_height * i_width / p_pic->i_width;
+    // ?? end of temporary code
 
     /*
      * Choose appropriate rendering function and render picture
@@ -992,23 +1315,20 @@ static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_b
     case YUV_420_PICTURE:
         p_vout->p_ConvertYUV420( p_vout, p_convert_dst, 
                                  p_pic->p_y, p_pic->p_u, p_pic->p_v,
-                                 i_width, i_height, i_eol, 
-                                 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
-                                 i_aspect_scale, p_pic->i_matrix_coefficients );
+                                 i_width, i_height, i_eol, i_pic_eol, i_scale, 
+                                 p_pic->i_matrix_coefficients );
         break;        
     case YUV_422_PICTURE:
         p_vout->p_ConvertYUV422( p_vout, p_convert_dst, 
                                  p_pic->p_y, p_pic->p_u, p_pic->p_v,
-                                 i_width, i_height, i_eol, 
-                                 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
-                                 i_aspect_scale, p_pic->i_matrix_coefficients );
+                                 i_width, i_height, i_eol, i_pic_eol, i_scale, 
+                                 p_pic->i_matrix_coefficients );
         break;        
     case YUV_444_PICTURE:
         p_vout->p_ConvertYUV444( p_vout, p_convert_dst, 
                                  p_pic->p_y, p_pic->p_u, p_pic->p_v,
-                                 i_width, i_height, i_eol, 
-                                 p_vout->i_bytes_per_line / p_vout->i_bytes_per_pixel - i_width,
-                                 i_aspect_scale, p_pic->i_matrix_coefficients );
+                                 i_width, i_height, i_eol, i_pic_eol, i_scale, 
+                                 p_pic->i_matrix_coefficients );
         break;                
 #ifdef DEBUG
     default:        
@@ -1016,12 +1336,6 @@ static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_b
         break;        
 #endif
     }
-
-#ifdef STATS
-    /* End recording render time */
-    p_vout->render_time = mdate() - p_vout->render_time;
-#endif
-    return( 1 );    
 }
 
 /******************************************************************************
@@ -1030,9 +1344,11 @@ static int RenderPicture( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_b
  * This function will print informations such as fps and other picture
  * dependant informations.
  ******************************************************************************/
-static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t b_blank )
+static void RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic )
 {
+#if defined(STATS) || defined(DEBUG)
     char        psz_buffer[256];                             /* string buffer */
+#endif
 
 #ifdef STATS
     /* 
@@ -1041,24 +1357,24 @@ static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t
     if( p_vout->c_fps_samples > VOUT_FPS_SAMPLES )
     {        
         sprintf( psz_buffer, "%.2f fps", (double) VOUT_FPS_SAMPLES * 1000000 /
-                 ( p_vout->fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
-                   p_vout->fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );        
+                 ( p_vout->p_fps_sample[ (p_vout->c_fps_samples - 1) % VOUT_FPS_SAMPLES ] -
+                   p_vout->p_fps_sample[ p_vout->c_fps_samples % VOUT_FPS_SAMPLES ] ) );        
         Print( p_vout, p_vout->i_width, 0, 1, -1, psz_buffer );
     }
 
     /* 
      * Print frames count and loop time in upper left corner 
      */
-    sprintf( psz_buffer, "%ld frames   render time: %lu us", 
-             p_vout->c_fps_samples, (long unsigned) p_vout->render_time );
-    Print( p_vout, 0, 0, -1, -1, psz_buffer );    
+    sprintf( psz_buffer, "%ld frames   rendering: %ld us", 
+             (long) p_vout->c_fps_samples, (long) p_vout->render_time );
+    Print( p_vout, 0, 0, -1, -1, psz_buffer );
 #endif
 
 #ifdef DEBUG
     /*
      * Print picture information in lower right corner
      */
-    sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s)",
+    sprintf( psz_buffer, "%s picture %dx%d (%dx%d%+d%+d %s) -> %dx%d+%d+%d",
              (p_pic->i_type == YUV_420_PICTURE) ? "4:2:0" :
              ((p_pic->i_type == YUV_422_PICTURE) ? "4:2:2" :
               ((p_pic->i_type == YUV_444_PICTURE) ? "4:4:4" : "ukn-type")),
@@ -1068,33 +1384,25 @@ static int RenderPictureInfo( vout_thread_t *p_vout, picture_t *p_pic, boolean_t
              (p_pic->i_aspect_ratio == AR_SQUARE_PICTURE) ? "sq" :
              ((p_pic->i_aspect_ratio == AR_3_4_PICTURE) ? "4:3" :
               ((p_pic->i_aspect_ratio == AR_16_9_PICTURE) ? "16:9" :
-               ((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))));    
+               ((p_pic->i_aspect_ratio == AR_221_1_PICTURE) ? "2.21:1" : "ukn-ar" ))),
+             p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_width,
+             p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_height,
+             p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_x,
+             p_vout->p_buffer[ p_vout->i_buffer_index ].i_pic_y );    
     Print( p_vout, p_vout->i_width, p_vout->i_height, 1, 1, psz_buffer );
 #endif
-    
-    return( 0 );    
 }
 
 /******************************************************************************
  * RenderIdle: render idle picture
  ******************************************************************************
- * This function will clear the display or print a logo.
+ * This function will print something on the screen.
  ******************************************************************************/
-static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
+static void RenderIdle( vout_thread_t *p_vout )
 {
-    /* Blank screen if required */
-    if( (mdate() - p_vout->last_picture_date > VOUT_IDLE_DELAY) &&
-        (p_vout->last_picture_date > p_vout->last_display_date) &&
-        b_blank )
-    {        
-        RenderBlank( p_vout );
-        p_vout->last_display_date = mdate();        
-        Print( p_vout, p_vout->i_width / 2, p_vout->i_height / 2, 0, 0, 
-               "no stream" );        //??
-        return( 1 );        
-    }
-
-    return( 0 );    
+    //??
+    Print( p_vout, p_vout->i_width / 2, p_vout->i_height / 2, 0, 0, 
+           "no stream" );        //??
 }
 
 /******************************************************************************
@@ -1103,10 +1411,10 @@ static int RenderIdle( vout_thread_t *p_vout, boolean_t b_blank )
  * This function render informations which do not depend of the current picture
  * rendered.
  ******************************************************************************/
-static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
+static void RenderInfo( vout_thread_t *p_vout )
 {
-    char        psz_buffer[256];                             /* string buffer */
 #ifdef DEBUG
+    char        psz_buffer[256];                             /* string buffer */
     int         i_ready_pic = 0;                            /* ready pictures */
     int         i_reserved_pic = 0;                      /* reserved pictures */
     int         i_picture;                                   /* picture index */
@@ -1130,14 +1438,70 @@ static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
             break;            
         }        
     }
-    sprintf( psz_buffer, "%dx%d:%d g%+.2f   pic: %d/%d/%d", 
-             p_vout->i_width, p_vout->i_height, p_vout->i_screen_depth, 
-             p_vout->f_gamma, i_reserved_pic, i_ready_pic,
-             VOUT_MAX_PICTURES );
+    sprintf( psz_buffer, "pic: %d/%d/%d", 
+             i_reserved_pic, i_ready_pic, VOUT_MAX_PICTURES );
     Print( p_vout, 0, p_vout->i_height, -1, 1, psz_buffer );    
 #endif
+}
+
+/*******************************************************************************
+ * RenderSubtitle: render a subtitle
+ *******************************************************************************
+ * This function render a subtitle.
+ *******************************************************************************/
+static void RenderSubtitle( vout_thread_t *p_vout, subtitle_t *p_sub )
+{
+    //??
+}
+
+/*******************************************************************************
+ * RenderInterface: render the interface
+ *******************************************************************************
+ * This function render the interface, if any.
+ * ?? this is obviously only a temporary interface !
+ *******************************************************************************/
+static void RenderInterface( vout_thread_t *p_vout )
+{
+    int         i_height, i_text_height;              /* total and text height */
+    int         i_width_1, i_width_2;                            /* text width */
+    int         i_byte;                                          /* byte index */    
+    const char *psz_text_1 = "[1-9] Channel   [i]nfo   [c]olor     [g/G]amma";
+    const char *psz_text_2 = "[+/-] Volume    [m]ute   [s]caling   [Q]uit";    
+
+    /* Get text size */
+    vout_TextSize( p_vout->p_large_font, OUTLINED_TEXT | TRANSPARENT_TEXT, psz_text_1, &i_width_1, &i_height );
+    vout_TextSize( p_vout->p_large_font, OUTLINED_TEXT | TRANSPARENT_TEXT, psz_text_2, &i_width_2, &i_text_height );
+    i_height += i_text_height;
+
+    /* Render background - effective background color will depend of the screen
+     * depth */
+    for( i_byte = (p_vout->i_height - i_height) * p_vout->i_bytes_per_line;
+         i_byte < p_vout->i_height * p_vout->i_bytes_per_line;
+         i_byte++ )
+    {
+        p_vout->p_buffer[ p_vout->i_buffer_index ].p_data[ i_byte ] = 0x33;        
+    }    
 
-   return( 0 );    
+    /* Render text, if not larger than screen */
+    if( i_width_1 < p_vout->i_width )
+    {        
+        vout_Print( p_vout->p_large_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
+                    (p_vout->i_height - i_height) * p_vout->i_bytes_per_line,
+                    p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
+                    0xffffffff, 0x00000000, 0x00000000,
+                    OUTLINED_TEXT | TRANSPARENT_TEXT, psz_text_1 );
+    }
+    if( i_width_2 < p_vout->i_width )
+    {        
+        vout_Print( p_vout->p_large_font, p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
+                    (p_vout->i_height - i_height + i_text_height) * p_vout->i_bytes_per_line,
+                    p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line,
+                    0xffffffff, 0x00000000, 0x00000000,
+                    OUTLINED_TEXT | TRANSPARENT_TEXT, psz_text_2 );
+    }    
+
+    /* Activate modified area */
+    SetBufferArea( p_vout, 0, p_vout->i_height - i_height, p_vout->i_width, i_height );
 }
 
 /******************************************************************************
@@ -1147,6 +1511,14 @@ static int RenderInfo( vout_thread_t *p_vout, boolean_t b_blank )
  ******************************************************************************/
 static int Manage( vout_thread_t *p_vout )
 {
+#ifdef DEBUG_VIDEO
+    if( p_vout->i_changes )
+    {
+        intf_DbgMsg("changes: 0x%x (no display: 0x%x)\n", p_vout->i_changes, 
+                    p_vout->i_changes & VOUT_NODISPLAY_CHANGE );        
+    }    
+#endif
+
     /* On gamma or grayscale change, rebuild tables */
     if( p_vout->i_changes & (VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE) )
     {
@@ -1155,7 +1527,7 @@ static int Manage( vout_thread_t *p_vout )
 
     /* Clear changes flags which does not need management or have been handled */
     p_vout->i_changes &= ~(VOUT_GAMMA_CHANGE | VOUT_GRAYSCALE_CHANGE |
-                           VOUT_INFO_CHANGE );
+                           VOUT_INFO_CHANGE | VOUT_INTF_CHANGE | VOUT_SCALE_CHANGE );
 
     /* Detect unauthorized changes */
     if( p_vout->i_changes )
index f8fc977408d8fda6250631a06d0830a863cd7e01..0da75bcb22a7eb5e704e30230b11cfd1bf20b3cc 100644 (file)
@@ -175,7 +175,7 @@ static void PutByte32( u32 *p_pic, int i_byte, byte_t i_char, byte_t i_border, b
  * This function will try to open a .psf font and load it. It will return
  * NULL on error.
  *******************************************************************************/
-vout_font_t *vout_LoadFont( char *psz_name )
+vout_font_t *vout_LoadFont( const char *psz_name )
 {
     int                 i_char, i_line;          /* character and line indexes */    
     int                 i_file;                                 /* source file */
@@ -305,7 +305,7 @@ void vout_UnloadFont( vout_font_t *p_font )
  * This function is used to align text. It returns the width and height of a
  * given text. 
  *******************************************************************************/
-void vout_TextSize( vout_font_t *p_font, int i_style, char *psz_text, int *pi_width, int *pi_height )
+void vout_TextSize( vout_font_t *p_font, int i_style, const char *psz_text, int *pi_width, int *pi_height )
 {
     switch( p_font->i_type )
     {
@@ -333,7 +333,7 @@ void vout_TextSize( vout_font_t *p_font, int i_style, char *psz_text, int *pi_wi
  * loaded bitmap font.
  *******************************************************************************/
 void vout_Print( vout_font_t *p_font, byte_t *p_pic, int i_bytes_per_pixel, int i_bytes_per_line, 
-                 u32 i_char_color, u32 i_border_color, u32 i_bg_color, int i_style, char *psz_text )
+                 u32 i_char_color, u32 i_border_color, u32 i_bg_color, int i_style, const char *psz_text )
 {
     byte_t      *p_char, *p_border;          /* character and border mask data */    
     int         i_char_mask, i_border_mask, i_bg_mask;                /* masks */    
index 72e7dc8d2746ea3aea79e56d935177241f434ebd..3cde09ec07d361e5c00ad9802ac157cbbcc29fda 100644 (file)
@@ -48,7 +48,6 @@ typedef struct vout_sys_s
     GC                  gc;                /* graphic context instance handler */    
 
     /* Display buffers and shared memory information */
-    int                 i_buffer_index;                        /* buffer index */
     XImage *            p_ximage[2];                         /* XImage pointer */   
     XShmSegmentInfo     shm_info[2];         /* shared memory zone information */
 } vout_sys_t;
@@ -157,8 +156,11 @@ int vout_SysInit( vout_thread_t *p_vout )
     /* Set bytes per line */
     p_vout->i_bytes_per_line = p_vout->p_sys->p_ximage[0]->bytes_per_line;    
 
-    /* Set buffer index to 0 */
-    p_vout->p_sys->i_buffer_index = 0;
+    /* Set and initialize buffers */
+    p_vout->p_buffer[0].p_data = p_vout->p_sys->p_ximage[ 0 ]->data;    
+    p_vout->p_buffer[1].p_data = p_vout->p_sys->p_ximage[ 1 ]->data;
+    vout_ClearBuffer( p_vout, &p_vout->p_buffer[0] );
+    vout_ClearBuffer( p_vout, &p_vout->p_buffer[1] );    
     return( 0 );
 }
 
@@ -222,7 +224,7 @@ int vout_SysManage( vout_thread_t *p_vout )
             intf_ErrMsg("error: can't resize display\n");
             return( 1 );            
         }
-        intf_Msg("Video display resized to %dx%d\n", p_vout->i_width, p_vout->i_height);            
+        intf_Msg("Video display resized (%dx%d)\n", p_vout->i_width, p_vout->i_height);
     }
     
     return 0;
@@ -240,10 +242,10 @@ void vout_SysDisplay( vout_thread_t *p_vout )
     {
         /* Display rendered image using shared memory extension */
         XShmPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc, 
-                     p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ], 
+                     p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ], 
                      0, 0, 0, 0,  
-                     p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,  
-                     p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height, True);
+                     p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->width,  
+                     p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->height, True);
 
         /* Send the order to the X server */
         XFlush(p_vout->p_sys->p_display);
@@ -251,27 +253,14 @@ void vout_SysDisplay( vout_thread_t *p_vout )
     else                                  /* regular X11 capabilities are used */
     {
         XPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc, 
-                  p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ], 
+                  p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ], 
                   0, 0, 0, 0,  
-                  p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,  
-                  p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height);
+                  p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->width,  
+                  p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->height);
 
         /* Send the order to the X server */
         XFlush(p_vout->p_sys->p_display);
     }
-
-    /* Swap buffers */
-    p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
-}
-
-/*******************************************************************************
- * vout_SysGetPicture: get current display buffer informations
- *******************************************************************************
- * This function returns the address of the current display buffer.
- *******************************************************************************/
-void * vout_SysGetPicture( vout_thread_t *p_vout )
-{
-    return( p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data );        
 }
 
 /* following functions are local */
index 0abe7c516a013a62c5d532783966067a856cea30..f14502c67d795838bf69cddf4f188eec2e809489 100644 (file)
@@ -10,8 +10,8 @@
 /*******************************************************************************
  * Preamble
  *******************************************************************************/
-#include <errno.h>
 #include <math.h>
+#include <errno.h>
 #include <string.h>
 #include <stdlib.h>
 
@@ -46,6 +46,7 @@ const int MATRIX_COEFFICIENTS_TABLE[8][4] =
  *******************************************************************************/
 static int      BinaryLog         ( u32 i );
 static void     MaskToShift       ( int *pi_right, int *pi_left, u32 i_mask );
+static void     SetGammaTable     ( int *pi_table, double f_gamma );
 static void     SetTables         ( vout_thread_t *p_vout );
 
 static void     ConvertY4Gray16   ( p_vout_thread_t p_vout, u16 *p_pic, yuv_data_t *p_y, yuv_data_t *p_u, yuv_data_t *p_v,
@@ -387,24 +388,38 @@ static void MaskToShift (int *pi_right, int *pi_left, u32 i_mask)
 }
 
 /*******************************************************************************
- * SetTables: compute tables and set function pointers
+ * SetGammaTable: return intensity table transformed by gamma curve.
+ *******************************************************************************
+ * pi_table is a table of 256 entries from 0 to 255.
  *******************************************************************************/
+static void SetGammaTable( int *pi_table, double f_gamma )
+{
+    int         i_y;                                         /* base intensity */
+
+    /* Use exp(gamma) instead of gamma */
+    f_gamma = exp(f_gamma );
+
+    /* Build gamma table */
+    for( i_y = 0; i_y < 256; i_y++ )
+    {
+        pi_table[ i_y ] = pow( (double)i_y / 256, f_gamma ) * 256;
+    }
+ }
+
+/*******************************************************************************
+ * SetTables: compute tables and set function pointers
++ *******************************************************************************/
 static void SetTables( vout_thread_t *p_vout )
 {
-    u8          i_gamma[256];                                   /* gamma table */    
+    int         pi_gamma[256];                                  /* gamma table */    
     int         i_index;                                    /* index in tables */
     int         i_red_right, i_red_left;                         /* red shifts */
     int         i_green_right, i_green_left;                   /* green shifts */
     int         i_blue_right, i_blue_left;                      /* blue shifts */
 
-    /*
-     * Build gamma table 
-     */     
-    for( i_index = 0; i_index < 256; i_index++ )
-    {
-        i_gamma[i_index] = 255. * pow( (double)i_index / 255., exp(p_vout->f_gamma) );        
-    }
-
+    /* Build gamma table */    
+    SetGammaTable( pi_gamma, p_vout->f_gamma );
+    
     /*          
      * Set color masks and shifts
      */
@@ -447,9 +462,9 @@ static void SetTables( vout_thread_t *p_vout )
             for( i_index = -384; i_index < 640; i_index++) 
             {
                 p_vout->tables.yuv.gray16.p_gray[ i_index ] = 
-                    ((i_gamma[CLIP_BYTE( i_index )] >> i_red_right)   << i_red_left)   |
-                    ((i_gamma[CLIP_BYTE( i_index )] >> i_green_right) << i_green_left) |
-                    ((i_gamma[CLIP_BYTE( i_index )] >> i_blue_right)  << i_blue_left);                
+                    ((pi_gamma[CLIP_BYTE( i_index )] >> i_red_right)   << i_red_left)   |
+                    ((pi_gamma[CLIP_BYTE( i_index )] >> i_green_right) << i_green_left) |
+                    ((pi_gamma[CLIP_BYTE( i_index )] >> i_blue_right)  << i_blue_left);                
             }
             break;        
         case 24:
@@ -458,9 +473,9 @@ static void SetTables( vout_thread_t *p_vout )
             for( i_index = -384; i_index < 640; i_index++) 
             {
                 p_vout->tables.yuv.gray32.p_gray[ i_index ] = 
-                    ((i_gamma[CLIP_BYTE( i_index )] >> i_red_right)   << i_red_left)   |
-                    ((i_gamma[CLIP_BYTE( i_index )] >> i_green_right) << i_green_left) |
-                    ((i_gamma[CLIP_BYTE( i_index )] >> i_blue_right)  << i_blue_left);                
+                    ((pi_gamma[CLIP_BYTE( i_index )] >> i_red_right)   << i_red_left)   |
+                    ((pi_gamma[CLIP_BYTE( i_index )] >> i_green_right) << i_green_left) |
+                    ((pi_gamma[CLIP_BYTE( i_index )] >> i_blue_right)  << i_blue_left);                
             }        
             break;        
         }
@@ -477,9 +492,9 @@ static void SetTables( vout_thread_t *p_vout )
             p_vout->tables.yuv.rgb16.p_blue =   (u16 *)p_vout->tables.p_base + 2*1024 + 384;
             for( i_index = -384; i_index < 640; i_index++) 
             {
-                p_vout->tables.yuv.rgb16.p_red[i_index] =   (i_gamma[CLIP_BYTE(i_index)]>>i_red_right)<<i_red_left;
-                p_vout->tables.yuv.rgb16.p_green[i_index] = (i_gamma[CLIP_BYTE(i_index)]>>i_green_right)<<i_green_left;
-                p_vout->tables.yuv.rgb16.p_blue[i_index] =  (i_gamma[CLIP_BYTE(i_index)]>>i_blue_right)<<i_blue_left;
+                p_vout->tables.yuv.rgb16.p_red[i_index] =   (pi_gamma[CLIP_BYTE(i_index)]>>i_red_right)<<i_red_left;
+                p_vout->tables.yuv.rgb16.p_green[i_index] = (pi_gamma[CLIP_BYTE(i_index)]>>i_green_right)<<i_green_left;
+                p_vout->tables.yuv.rgb16.p_blue[i_index] =  (pi_gamma[CLIP_BYTE(i_index)]>>i_blue_right)<<i_blue_left;
             }
             break;        
         case 24:
@@ -489,9 +504,9 @@ static void SetTables( vout_thread_t *p_vout )
             p_vout->tables.yuv.rgb32.p_blue =   (u32 *)p_vout->tables.p_base + 2*1024 + 384;
             for( i_index = -384; i_index < 640; i_index++) 
             {
-                p_vout->tables.yuv.rgb32.p_red[i_index] =   (i_gamma[CLIP_BYTE(i_index)]>>i_red_right)<<i_red_left;
-                p_vout->tables.yuv.rgb32.p_green[i_index] = (i_gamma[CLIP_BYTE(i_index)]>>i_green_right)<<i_green_left;
-                p_vout->tables.yuv.rgb32.p_blue[i_index] =  (i_gamma[CLIP_BYTE(i_index)]>>i_blue_right)<<i_blue_left;
+                p_vout->tables.yuv.rgb32.p_red[i_index] =   (pi_gamma[CLIP_BYTE(i_index)]>>i_red_right)<<i_red_left;
+                p_vout->tables.yuv.rgb32.p_green[i_index] = (pi_gamma[CLIP_BYTE(i_index)]>>i_green_right)<<i_green_left;
+                p_vout->tables.yuv.rgb32.p_blue[i_index] =  (pi_gamma[CLIP_BYTE(i_index)]>>i_blue_right)<<i_blue_left;
             }
             break;        
         }