]> git.sesse.net Git - vlc/blobdiff - src/misc/filter_chain.c
Move last.fm password from PasswordShowOnEdit to Password.
[vlc] / src / misc / filter_chain.c
index 0d649f9942e9f8d44c89f553104bd7764a968319..5397b067a7d600e8a6393d3a00e4f2a52fe1e161 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include <vlc_filter.h>
 #include <vlc_arrays.h>
+#include <libvlc.h>
 
 struct filter_chain_t
 {
@@ -40,6 +45,16 @@ struct filter_chain_t
     void *p_buffer_allocation_data; /* Data for pf_buffer_allocation_init */
 };
 
+/**
+ * Local prototypes
+ */
+static filter_t *filter_chain_AppendFilterInternal( filter_chain_t *, const char *, config_chain_t *, const es_format_t *, const es_format_t * );
+static int filter_chain_AppendFromStringInternal( filter_chain_t *, const char * );
+static int filter_chain_DeleteFilterInternal( filter_chain_t *, filter_t * );
+
+static int UpdateBufferFunctions( filter_chain_t * );
+static picture_t *VideoBufferNew( filter_t * );
+
 /**
  * Filter chain initialisation
  */
@@ -78,7 +93,7 @@ filter_chain_t *__filter_chain_New( vlc_object_t *p_this,
 void filter_chain_Delete( filter_chain_t *p_chain )
 {
     while( p_chain->filters.i_count )
-        filter_chain_DeleteFilter( p_chain,
+        filter_chain_DeleteFilterInternal( p_chain,
                                    (filter_t*)p_chain->filters.pp_elems[0] );
     vlc_array_clear( &p_chain->filters );
     free( p_chain->psz_capability );
@@ -93,26 +108,34 @@ void filter_chain_Reset( filter_chain_t *p_chain, const es_format_t *p_fmt_in,
                          const es_format_t *p_fmt_out )
 {
     while( p_chain->filters.i_count )
-        filter_chain_DeleteFilter( p_chain,
+        filter_chain_DeleteFilterInternal( p_chain,
                                    (filter_t*)p_chain->filters.pp_elems[0] );
-    es_format_Clean( &p_chain->fmt_in );
-    es_format_Clean( &p_chain->fmt_out );
-    es_format_Copy( &p_chain->fmt_in, p_fmt_in );
-    es_format_Copy( &p_chain->fmt_out, p_fmt_out );
+    if( p_fmt_in )
+    {
+        es_format_Clean( &p_chain->fmt_in );
+        es_format_Copy( &p_chain->fmt_in, p_fmt_in );
+    }
+    if( p_fmt_out )
+    {
+        es_format_Clean( &p_chain->fmt_out );
+        es_format_Copy( &p_chain->fmt_out, p_fmt_out );
+    }
 }
 
 
 /**
  * Modifying the filter chain
  */
-filter_t *filter_chain_AppendFilter( filter_chain_t *p_chain,
-                                     const char *psz_name,
-                                     config_chain_t *p_cfg,
-                                     const es_format_t *p_fmt_in,
-                                     const es_format_t *p_fmt_out )
+static filter_t *filter_chain_AppendFilterInternal( filter_chain_t *p_chain,
+                                                    const char *psz_name,
+                                                    config_chain_t *p_cfg,
+                                                    const es_format_t *p_fmt_in,
+                                                    const es_format_t *p_fmt_out )
 {
+    static const char typename[] = "filter";
     filter_t *p_filter =
-        vlc_object_create( p_chain->p_this, VLC_OBJECT_FILTER );
+        vlc_custom_create( p_chain->p_this, sizeof(filter_t),
+                           VLC_OBJECT_GENERIC, typename );
     if( !p_filter ) return NULL;
     vlc_object_attach( p_filter, p_chain->p_this );
 
@@ -153,13 +176,16 @@ filter_t *filter_chain_AppendFilter( filter_chain_t *p_chain,
     vlc_array_append( &p_chain->filters, p_filter );
 
     msg_Dbg( p_chain->p_this, "Filter '%s' (%p) appended to chain",
-             psz_name, p_filter );
+             psz_name?:p_filter->psz_object_name, p_filter );
 
     return p_filter;
 
     error:
-        msg_Err( p_chain->p_this, "Failed to create video filter '%s'",
-                 psz_name );
+        if( psz_name )
+            msg_Err( p_chain->p_this, "Failed to create video filter '%s'",
+                     psz_name );
+        else
+            msg_Err( p_chain->p_this, "Failed to create video filter" );
         if( p_filter->p_module ) module_Unneed( p_filter,
                                                 p_filter->p_module );
         es_format_Clean( &p_filter->fmt_in );
@@ -169,8 +195,22 @@ filter_t *filter_chain_AppendFilter( filter_chain_t *p_chain,
         return NULL;
 }
 
-int filter_chain_AppendFromString( filter_chain_t *p_chain,
-                                         const char *psz_string )
+filter_t *filter_chain_AppendFilter( filter_chain_t *p_chain,
+                                     const char *psz_name,
+                                     config_chain_t *p_cfg,
+                                     const es_format_t *p_fmt_in,
+                                     const es_format_t *p_fmt_out )
+{
+    filter_t *p_filter = filter_chain_AppendFilterInternal( p_chain, psz_name,
+                                                            p_cfg, p_fmt_in,
+                                                            p_fmt_out );
+    if( UpdateBufferFunctions( p_chain ) < 0 )
+        msg_Err( p_filter, "Woah! This doesn't look good." );
+    return p_filter;
+}
+
+static int filter_chain_AppendFromStringInternal( filter_chain_t *p_chain,
+                                                  const char *psz_string )
 {
     config_chain_t *p_cfg = NULL;
     char *psz_name = NULL;
@@ -179,8 +219,8 @@ int filter_chain_AppendFromString( filter_chain_t *p_chain,
 
     psz_string = config_ChainCreate( &psz_name, &p_cfg, psz_string );
 
-    filter_t *p_filter = filter_chain_AppendFilter( p_chain, psz_name, p_cfg,
-                                                    NULL, NULL );
+    filter_t *p_filter = filter_chain_AppendFilterInternal( p_chain, psz_name,
+                                                            p_cfg, NULL, NULL );
     if( !p_filter )
     {
         msg_Err( p_chain->p_this, "Failed while trying to append '%s' "
@@ -191,16 +231,27 @@ int filter_chain_AppendFromString( filter_chain_t *p_chain,
     }
     free( psz_name );
 
-    int ret = filter_chain_AppendFromString( p_chain, psz_string );
+    int ret = filter_chain_AppendFromStringInternal( p_chain, psz_string );
     if( ret < 0 )
     {
-        filter_chain_DeleteFilter( p_chain, p_filter );
+        filter_chain_DeleteFilterInternal( p_chain, p_filter );
         return ret;
     }
     return 1 + ret;
 }
 
-int filter_chain_DeleteFilter( filter_chain_t *p_chain, filter_t *p_filter )
+int filter_chain_AppendFromString( filter_chain_t *p_chain,
+                                   const char *psz_string )
+{
+    int i_ret = filter_chain_AppendFromStringInternal( p_chain, psz_string );
+    if( i_ret < 0 ) return i_ret;
+    int i_ret2 = UpdateBufferFunctions( p_chain );
+    if( i_ret2 < 0 ) return i_ret2;
+    return i_ret;
+}
+
+static int filter_chain_DeleteFilterInternal( filter_chain_t *p_chain,
+                                              filter_t *p_filter )
 {
     int i;
     /* Find the filter in the chain */
@@ -231,10 +282,16 @@ int filter_chain_DeleteFilter( filter_chain_t *p_chain, filter_t *p_filter )
     vlc_object_release( p_filter );
 
     /* FIXME: check fmt_in/fmt_out consitency */
-
     return VLC_SUCCESS;
 }
 
+int filter_chain_DeleteFilter( filter_chain_t *p_chain, filter_t *p_filter )
+{
+    int i_ret = filter_chain_DeleteFilterInternal( p_chain, p_filter );
+    if( i_ret < 0 ) return i_ret;
+    return UpdateBufferFunctions( p_chain );
+}
+
 /**
  * Reading from the filter chain
  */
@@ -277,6 +334,10 @@ const es_format_t *filter_chain_GetFmtOut( filter_chain_t *p_chain )
 /**
  * Apply the filter chain
  */
+
+/* FIXME This include is needed by the Ugly hack */
+#include <vlc_vout.h>
+
 picture_t *filter_chain_VideoFilter( filter_chain_t *p_chain, picture_t *p_pic )
 {
     int i;
@@ -284,9 +345,33 @@ picture_t *filter_chain_VideoFilter( filter_chain_t *p_chain, picture_t *p_pic )
     for( i = 0; i < p_chain->filters.i_count; i++ )
     {
         filter_t *p_filter = pp_filter[i];
-        p_pic = p_filter->pf_video_filter( p_filter, p_pic );
-        if( !p_pic )
+        picture_t *p_newpic = p_filter->pf_video_filter( p_filter, p_pic );
+
+        /* FIXME Ugly hack to make it work in picture core.
+         * FIXME Remove this code when the picture release API has been
+         * FIXME cleaned up (a git revert of the commit should work) */
+        if( p_chain->p_this->i_object_type == VLC_OBJECT_VOUT )
+        {
+            vout_thread_t *p_vout = (vout_thread_t*)p_chain->p_this;
+            vlc_mutex_lock( &p_vout->picture_lock );
+            if( p_pic->i_refcount )
+            {
+                p_pic->i_status = DISPLAYED_PICTURE;
+            }
+            else
+            {
+                p_pic->i_status = DESTROYED_PICTURE;
+                p_vout->i_heap_size--;
+            }
+            vlc_mutex_unlock( &p_vout->picture_lock );
+
+            if( p_newpic )
+                p_newpic->i_status = READY_PICTURE;
+        }
+        if( !p_newpic )
             return NULL;
+
+        p_pic = p_newpic;
     }
     return p_pic;
 }
@@ -315,8 +400,69 @@ void filter_chain_SubFilter( filter_chain_t *p_chain,
     for( i = 0; i < p_chain->filters.i_count; i++ )
     {
         filter_t *p_filter = pp_filter[i];
-        subpicture_t *p_subpic = p_filter->pf_sub_filter( p_filter, display_date );
+        subpicture_t *p_subpic = p_filter->pf_sub_filter( p_filter,
+                                                          display_date );
         if( p_subpic )
             spu_DisplaySubpicture( (spu_t*)p_chain->p_this, p_subpic );
     }
 }
+
+/**
+ * Internal chain buffer handling
+ */
+
+/**
+ * This function should be called after every filter chain change
+ */
+static int UpdateBufferFunctions( filter_chain_t *p_chain )
+{
+    if( !strcmp( p_chain->psz_capability, "video filter2" ) )
+    {
+        /**
+         * Last filter uses the filter chain's parent buffer allocation
+         * functions. All the other filters use internal functions.
+         * This makes it possible to have format changes between each
+         * filter without having to worry about the parent's picture
+         * heap format.
+         */
+        int i;
+        filter_t **pp_filter = (filter_t **)p_chain->filters.pp_elems;
+        filter_t *p_filter;
+        for( i = 0; i < p_chain->filters.i_count - 1; i++ )
+        {
+            p_filter = pp_filter[i];
+            if( p_filter->pf_vout_buffer_new != VideoBufferNew )
+            {
+                if( p_chain->pf_buffer_allocation_clear )
+                    p_chain->pf_buffer_allocation_clear( p_filter );
+                p_filter->pf_vout_buffer_new = VideoBufferNew;
+                p_filter->pf_vout_buffer_del = NULL;
+            }
+        }
+        if( p_chain->filters.i_count >= 1 )
+        {
+            p_filter = pp_filter[i];
+            if( p_filter->pf_vout_buffer_new == VideoBufferNew )
+            {
+                p_filter->pf_vout_buffer_new = NULL;
+                if( p_chain->pf_buffer_allocation_init( p_filter,
+                        p_chain->p_buffer_allocation_data ) != VLC_SUCCESS )
+                    return VLC_EGENERIC;
+            }
+        }
+    }
+    return VLC_SUCCESS;
+}
+
+static picture_t *VideoBufferNew( filter_t *p_filter )
+{
+    const video_format_t *p_fmt = &p_filter->fmt_out.video;
+
+    picture_t *p_picture = picture_New( p_fmt->i_chroma,
+                                        p_fmt->i_width, p_fmt->i_height,
+                                        p_fmt->i_aspect );
+    if( !p_picture )
+        msg_Err( p_filter, "Failed to allocate picture\n" );
+    return p_picture;
+}
+