]> git.sesse.net Git - vlc/blobdiff - plugins/filter/wall.c
* ./BUGS: added a list of known bugs. Please add your findings!
[vlc] / plugins / filter / wall.c
index 95f8a4f351ba65f3af8c2c8a43fb0bead5f2635b..8860b9a4a7aa85894d02430de259b3f06d879f82 100644 (file)
@@ -2,7 +2,7 @@
  * wall.c : Wall video plugin for vlc
  *****************************************************************************
  * Copyright (C) 2000, 2001 VideoLAN
- * $Id: wall.c,v 1.1 2001/12/17 03:38:21 sam Exp $
+ * $Id: wall.c,v 1.6 2002/01/04 14:01:34 sam Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
-#define MODULE_NAME filter_wall
-#include "modules_inner.h"
-
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
-#include "defs.h"
-
 #include <errno.h>
 #include <stdlib.h>                                      /* malloc(), free() */
 #include <string.h>
 
-#include "common.h"                                     /* boolean_t, byte_t */
-#include "intf_msg.h"
-#include "threads.h"
-#include "mtime.h"
-#include "tests.h"
+#include <videolan/vlc.h>
 
 #include "video.h"
 #include "video_output.h"
 
-#include "modules.h"
-#include "modules_export.h"
-
-#define WALL_MAX_DIRECTBUFFERS 8
+#include "filter_common.h"
 
 /*****************************************************************************
  * Capabilities defined in the other files.
@@ -56,14 +44,14 @@ static void vout_getfunctions( function_list_t * p_function_list );
  * Build configuration tree.
  *****************************************************************************/
 MODULE_CONFIG_START
-ADD_WINDOW( "Configuration for Wall module" )
-    ADD_COMMENT( "Ha, ha -- nothing to configure yet" )
 MODULE_CONFIG_STOP
 
 MODULE_INIT_START
-    p_module->i_capabilities = MODULE_CAPABILITY_NULL
-                                | MODULE_CAPABILITY_VOUT;
-    p_module->psz_longname = "image wall video module";
+    SET_DESCRIPTION( "image wall video module" )
+    /* Capability score set to 0 because we don't want to be spawned
+     * as a video output unless explicitly requested to */
+    ADD_CAPABILITY( VOUT, 0 )
+    ADD_SHORTCUT( "wall" )
 MODULE_INIT_STOP
 
 MODULE_ACTIVATE_START
@@ -81,8 +69,15 @@ MODULE_DEACTIVATE_STOP
  *****************************************************************************/
 typedef struct vout_sys_s
 {
-    struct vout_thread_s *p_vout_top;
-    struct vout_thread_s *p_vout_bottom;
+    int    i_col;
+    int    i_row;
+    int    i_vout;
+    struct vout_list_s
+    {
+        int i_width;
+        int i_height;
+        struct vout_thread_s *p_vout;
+    } *pp_vout;
 
 } vout_sys_t;
 
@@ -90,14 +85,15 @@ typedef struct vout_sys_s
  * Local prototypes
  *****************************************************************************/
 static int  vout_Probe     ( probedata_t *p_data );
-static int  vout_Create    ( struct vout_thread_s * );
-static int  vout_Init      ( struct vout_thread_s * );
-static void vout_End       ( struct vout_thread_s * );
-static void vout_Destroy   ( struct vout_thread_s * );
-static int  vout_Manage    ( struct vout_thread_s * );
-static void vout_Display   ( struct vout_thread_s *, struct picture_s * );
+static int  vout_Create    ( vout_thread_t * );
+static int  vout_Init      ( vout_thread_t * );
+static void vout_End       ( vout_thread_t * );
+static void vout_Destroy   ( vout_thread_t * );
+static int  vout_Manage    ( vout_thread_t * );
+static void vout_Render    ( vout_thread_t *, struct picture_s * );
+static void vout_Display   ( vout_thread_t *, struct picture_s * );
 
-static int  WallNewPicture ( struct vout_thread_s *, struct picture_s * );
+static void RemoveAllVout  ( vout_thread_t *p_vout );
 
 /*****************************************************************************
  * Functions exported as capabilities. They are declared as static so that
@@ -111,6 +107,7 @@ static void vout_getfunctions( function_list_t * p_function_list )
     p_function_list->functions.vout.pf_end        = vout_End;
     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
     p_function_list->functions.vout.pf_manage     = vout_Manage;
+    p_function_list->functions.vout.pf_render     = vout_Render;
     p_function_list->functions.vout.pf_display    = vout_Display;
     p_function_list->functions.vout.pf_setpalette = NULL;
 }
@@ -120,12 +117,6 @@ static void vout_getfunctions( function_list_t * p_function_list )
  *****************************************************************************/
 static int vout_Probe( probedata_t *p_data )
 {
-    if( TestMethod( VOUT_FILTER_VAR, "wall" ) )
-    {
-        return( 999 );
-    }
-
-    /* If we weren't asked to filter, don't filter. */
     return( 0 );
 }
 
@@ -144,6 +135,20 @@ static int vout_Create( vout_thread_t *p_vout )
         return( 1 );
     }
 
+    p_vout->p_sys->i_col = 3;
+    p_vout->p_sys->i_row = 3;
+
+    p_vout->p_sys->pp_vout = malloc( p_vout->p_sys->i_row *
+                                     p_vout->p_sys->i_col *
+                                     sizeof(struct vout_list_s) );
+    if( p_vout->p_sys->pp_vout == NULL )
+    {
+        intf_ErrMsg("error: %s", strerror(ENOMEM) );
+        free( p_vout->p_sys );
+        return( 1 );
+    }
+
+
     return( 0 );
 }
 
@@ -152,95 +157,76 @@ static int vout_Create( vout_thread_t *p_vout )
  *****************************************************************************/
 static int vout_Init( vout_thread_t *p_vout )
 {
-    int i_index;
+    int i_index, i_row, i_col, i_width, i_height;
     char *psz_filter;
     picture_t *p_pic;
     
     I_OUTPUTPICTURES = 0;
 
+    /* Initialize the output structure */
+    p_vout->output.i_chroma = p_vout->render.i_chroma;
+    p_vout->output.i_width  = p_vout->render.i_width;
+    p_vout->output.i_height = p_vout->render.i_height;
+    p_vout->output.i_aspect = p_vout->render.i_aspect;
+
     /* Try to open the real video output */
-    psz_filter = main_GetPszVariable( VOUT_FILTER_VAR, "" );
+    psz_filter = main_GetPszVariable( VOUT_FILTER_VAR, NULL );
     main_PutPszVariable( VOUT_FILTER_VAR, "" );
 
     intf_WarnMsg( 1, "filter: spawning the real video outputs" );
 
-    p_vout->p_sys->p_vout_top =
-        vout_CreateThread( NULL,
-                           p_vout->render.i_width, p_vout->render.i_height / 2,
-                           p_vout->render.i_chroma, p_vout->render.i_aspect * 2);
-
-    /* Everything failed */
-    if( p_vout->p_sys->p_vout_top == NULL )
-    {
-        intf_ErrMsg( "filter error: can't open top vout, aborting" );
-
-        return( 0 );
-    }
-
-    p_vout->p_sys->p_vout_bottom =
-        vout_CreateThread( NULL,
-                           p_vout->render.i_width, p_vout->render.i_height / 2,
-                           p_vout->render.i_chroma, p_vout->render.i_aspect * 2 );
+    p_vout->p_sys->i_vout = 0;
 
-    /* Everything failed */
-    if( p_vout->p_sys->p_vout_bottom == NULL )
+    /* FIXME: use bresenham instead of those ugly divisions */
+    for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
     {
-        intf_ErrMsg( "filter error: can't open bottom vout, aborting" );
-        vout_DestroyThread( p_vout->p_sys->p_vout_top, NULL );
-
-        return( 0 );
-    }
-    main_PutPszVariable( VOUT_FILTER_VAR, psz_filter );
-
-    /* Initialize the output structure */
-    switch( p_vout->render.i_chroma )
-    {
-        case YUV_420_PICTURE:
-            p_vout->output.i_chroma = p_vout->render.i_chroma;
-            p_vout->output.i_width  = p_vout->render.i_width;
-            p_vout->output.i_height = p_vout->render.i_height;
-            p_vout->output.i_aspect = p_vout->render.i_aspect;
-            break;
-
-        default:
-            p_vout->output.i_chroma = EMPTY_PICTURE; /* unknown chroma */
-            break;
-    }
-
-    /* Try to initialize WALL_MAX_DIRECTBUFFERS direct buffers */
-    while( I_OUTPUTPICTURES < WALL_MAX_DIRECTBUFFERS )
-    {
-        p_pic = NULL;
-
-        /* Find an empty picture slot */
-        for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
+        for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
         {
-            if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
+            if( i_col + 1 < p_vout->p_sys->i_col )
             {
-                p_pic = p_vout->p_picture + i_index;
-                break;
+                i_width = ( p_vout->render.i_width
+                             / p_vout->p_sys->i_col ) & ~0x1;
+            }
+            else
+            {
+                i_width = p_vout->render.i_width
+                           - ( ( p_vout->render.i_width
+                                  / p_vout->p_sys->i_col ) & ~0x1 ) * i_col;
             }
-        }
 
-        /* Allocate the picture */
-        if( WallNewPicture( p_vout, p_pic ) )
-        {
-            break;
-        }
+            if( i_row + 1 < p_vout->p_sys->i_row )
+            {
+                i_height = ( p_vout->render.i_height
+                              / p_vout->p_sys->i_row ) & ~0x3;
+            }
+            else
+            {
+                i_height = p_vout->render.i_height
+                            - ( ( p_vout->render.i_height
+                                   / p_vout->p_sys->i_row ) & ~0x3 ) * i_row;
+            }
 
-        p_pic->i_status        = DESTROYED_PICTURE;
-        p_pic->i_type          = DIRECT_PICTURE;
+            p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout =
+                vout_CreateThread( NULL, i_width, i_height,
+                                   p_vout->render.i_chroma,
+                                   p_vout->render.i_aspect
+                                    * p_vout->render.i_height / i_height
+                                    * i_width / p_vout->render.i_width );
+            if( p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout == NULL )
+            {
+                intf_ErrMsg( "vout error: failed to get %ix%i vout threads",
+                             p_vout->p_sys->i_col, p_vout->p_sys->i_row );
+                RemoveAllVout( p_vout );
+                return 0;
+            }
 
-        p_pic->i_left_margin   =
-        p_pic->i_right_margin  =
-        p_pic->i_top_margin    =
-        p_pic->i_bottom_margin = 0;
+            p_vout->p_sys->i_vout++;
+        }
+    }
 
-        PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
+    main_PutPszVariable( VOUT_FILTER_VAR, psz_filter );
 
-        I_OUTPUTPICTURES++;
-    }
+    ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
 
     return( 0 );
 }
@@ -256,7 +242,7 @@ static void vout_End( vout_thread_t *p_vout )
     for( i_index = I_OUTPUTPICTURES ; i_index ; )
     {
         i_index--;
-        free( PP_OUTPUTPICTURE[ i_index ]->planes[ 0 ].p_data );
+        free( PP_OUTPUTPICTURE[ i_index ]->p_data );
     }
 }
 
@@ -267,9 +253,9 @@ static void vout_End( vout_thread_t *p_vout )
  *****************************************************************************/
 static void vout_Destroy( vout_thread_t *p_vout )
 {
-    vout_DestroyThread( p_vout->p_sys->p_vout_top, NULL );
-    vout_DestroyThread( p_vout->p_sys->p_vout_bottom, NULL );
+    RemoveAllVout( p_vout );
 
+    free( p_vout->p_sys->pp_vout );
     free( p_vout->p_sys );
 }
 
@@ -285,120 +271,113 @@ static int vout_Manage( vout_thread_t *p_vout )
 }
 
 /*****************************************************************************
- * vout_Display: displays previously rendered output
+ * vout_Render: displays previously rendered output
  *****************************************************************************
  * This function send the currently rendered image to Wall image, waits
  * until it is displayed and switch the two rendering buffers, preparing next
  * frame.
  *****************************************************************************/
-static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
+static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
 {
-    picture_t *p_outpic_top, *p_outpic_bottom;
-    int i_index;
-    mtime_t i_date = mdate() + 50000;
+    picture_t *p_outpic = NULL;
+    int i_col, i_row, i_vout, i_plane;
+    int pi_left_skip[VOUT_MAX_PLANES], pi_top_skip[VOUT_MAX_PLANES];
 
-    while( ( p_outpic_top
-              = vout_CreatePicture( p_vout->p_sys->p_vout_top, 0, 0, 0 ) )
-            == NULL )
+    i_vout = 0;
+
+    for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
     {
-        if( p_vout->b_die || p_vout->b_error )
-        {
-            return;
-        }
-        msleep( VOUT_OUTMEM_SLEEP );
-    }   
+        pi_top_skip[i_plane] = 0;
+    }
 
-    while( ( p_outpic_bottom
-              = vout_CreatePicture( p_vout->p_sys->p_vout_bottom, 0, 0, 0 ) )
-            == NULL )
+    for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
     {
-        if( p_vout->b_die || p_vout->b_error )
+        for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
         {
-            vout_DestroyPicture( p_vout->p_sys->p_vout_top, p_outpic_top );
-            return;
+            pi_left_skip[i_plane] = 0;
         }
-        msleep( VOUT_OUTMEM_SLEEP );
-    }   
-
-    vout_DatePicture( p_vout->p_sys->p_vout_top, p_outpic_top, i_date );
-    vout_DatePicture( p_vout->p_sys->p_vout_bottom, p_outpic_bottom, i_date );
-
-    vout_LinkPicture( p_vout->p_sys->p_vout_top, p_outpic_top );
-    vout_LinkPicture( p_vout->p_sys->p_vout_bottom, p_outpic_bottom );
-
-    for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
-    {
-        p_main->fast_memcpy( p_outpic_top->planes[ i_index ].p_data,
-                             p_pic->planes[ i_index ].p_data,
-                             p_pic->planes[ i_index ].i_bytes / 2 );
-
-        p_main->fast_memcpy( p_outpic_bottom->planes[ i_index ].p_data,
-                             p_pic->planes[ i_index ].p_data
-                              + p_pic->planes[ i_index ].i_bytes / 2,
-                             p_pic->planes[ i_index ].i_bytes / 2 );
-    }
-
-    vout_UnlinkPicture( p_vout->p_sys->p_vout_top, p_outpic_top );
-    vout_UnlinkPicture( p_vout->p_sys->p_vout_bottom, p_outpic_bottom );
-
-    vout_DisplayPicture( p_vout->p_sys->p_vout_top, p_outpic_top );
-    vout_DisplayPicture( p_vout->p_sys->p_vout_bottom, p_outpic_bottom );
-}
 
+        for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
+        {
+            while( ( p_outpic =
+                vout_CreatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
+                                    0, 0, 0 )
+                   ) == NULL )
+            {
+                if( p_vout->b_die || p_vout->b_error )
+                {
+                    vout_DestroyPicture(
+                        p_vout->p_sys->pp_vout[ i_vout ].p_vout, p_outpic );
+                    return;
+                }
+
+                msleep( VOUT_OUTMEM_SLEEP );
+            }
 
-/*****************************************************************************
- * WallNewPicture: allocate a picture
- *****************************************************************************
- * Returns 0 on success, -1 otherwise
- *****************************************************************************/
-static int WallNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
-{
-    int i_luma_bytes, i_chroma_bytes;
+            vout_DatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
+                              p_outpic, p_pic->date );
+            vout_LinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
+                              p_outpic );
 
-    int i_width  = p_vout->output.i_width;
-    int i_height = p_vout->output.i_height;
+            for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
+            {
+                u8 *p_in, *p_in_end, *p_out;
+                int i_in_pitch = p_pic->p[i_plane].i_pitch;
+                int i_out_pitch = p_outpic->p[i_plane].i_pitch;
 
-    switch( p_vout->output.i_chroma )
-    {
-    /* We know this chroma, allocate a buffer which will be used
-     * directly by the decoder */
-    case YUV_420_PICTURE:
+                p_in = p_pic->p[i_plane].p_pixels
+                        + pi_top_skip[i_plane] + pi_left_skip[i_plane];
 
-        /* Precalculate some values */
-        p_pic->i_size         = i_width * i_height;
-        p_pic->i_chroma_width = i_width / 2;
-        p_pic->i_chroma_size  = i_height * ( i_width / 2 );
+                p_in_end = p_in + p_outpic->p[i_plane].i_lines
+                                   * p_pic->p[i_plane].i_pitch;
 
-        /* Allocate the memory buffer */
-        i_luma_bytes = p_pic->i_size * sizeof(pixel_data_t);
-        i_chroma_bytes = p_pic->i_chroma_size * sizeof(pixel_data_t);
+                p_out = p_outpic->p[i_plane].p_pixels;
 
-        /* Y buffer */
-        p_pic->planes[ Y_PLANE ].p_data = malloc( i_luma_bytes + 2 * i_chroma_bytes );
-        p_pic->planes[ Y_PLANE ].i_bytes = i_luma_bytes;
-        p_pic->planes[ Y_PLANE ].i_line_bytes = i_width * sizeof(pixel_data_t);
+                while( p_in < p_in_end )
+                {
+                    FAST_MEMCPY( p_out, p_in, i_out_pitch );
+                    p_in += i_in_pitch;
+                    p_out += i_out_pitch;
+                }
 
-        /* U buffer */
-        p_pic->planes[ U_PLANE ].p_data = p_pic->planes[ Y_PLANE ].p_data + i_height * i_width;
-        p_pic->planes[ U_PLANE ].i_bytes = i_chroma_bytes / 2;
-        p_pic->planes[ U_PLANE ].i_line_bytes = p_pic->i_chroma_width * sizeof(pixel_data_t);
+                pi_left_skip[i_plane] += p_outpic->p[i_plane].i_pitch;
+            }
 
-        /* V buffer */
-        p_pic->planes[ V_PLANE ].p_data = p_pic->planes[ U_PLANE ].p_data + i_height * p_pic->i_chroma_width;
-        p_pic->planes[ V_PLANE ].i_bytes = i_chroma_bytes / 2;
-        p_pic->planes[ V_PLANE ].i_line_bytes = p_pic->i_chroma_width * sizeof(pixel_data_t);
+            vout_UnlinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
+                                p_outpic );
+            vout_DisplayPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
+                                 p_outpic );
 
-        /* We allocated 3 planes */
-        p_pic->i_planes = 3;
+            i_vout++;
+        }
 
-        return( 0 );
-        break;
+        for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
+        {
+            pi_top_skip[i_plane] += p_outpic->p[i_plane].i_lines
+                                     * p_pic->p[i_plane].i_pitch;
+        }
+    }
+}
 
-    /* Unknown chroma, do nothing */
-    default:
+/*****************************************************************************
+ * vout_Display: displays previously rendered output
+ *****************************************************************************
+ * This function send the currently rendered image to Invert image, waits
+ * until it is displayed and switch the two rendering buffers, preparing next
+ * frame.
+ *****************************************************************************/
+static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
+{
+    ;
+}
 
-        return( 0 );
-        break;
+static void RemoveAllVout( vout_thread_t *p_vout )
+{
+    while( p_vout->p_sys->i_vout )
+    {
+         --p_vout->p_sys->i_vout;
+         vout_DestroyThread(
+             p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout, NULL );
     }
 }