1 /*****************************************************************************
2 * chain.c : chain multiple video filter modules as a last resort solution
3 *****************************************************************************
4 * Copyright (C) 2007-2008 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea at videolan dot org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_filter.h>
37 /*****************************************************************************
38 * Local and extern prototypes.
39 *****************************************************************************/
40 static int Activate ( vlc_object_t * );
41 static void Destroy ( vlc_object_t * );
42 static picture_t *Chain( filter_t *, picture_t * );
44 /*****************************************************************************
46 *****************************************************************************/
48 set_description( N_("Video filtering using a chain of video filter modules") );
49 set_capability( "video filter2", 1 );
50 set_callbacks( Activate, Destroy );
57 filter_t *p_filter1; /* conversion from fmt_in to fmr_mid */
58 filter_t *p_filter2; /* conversion from fmt_mid to fmt_out */
59 picture_t *p_tmp; /* temporary picture buffer */
60 video_format_t fmt_mid;
63 static const vlc_fourcc_t pi_allowed_chromas[] = {
64 VLC_FOURCC('I','4','2','0'),
65 VLC_FOURCC('I','4','2','2'),
66 VLC_FOURCC('R','V','3','2'),
67 VLC_FOURCC('R','V','2','4'),
71 static picture_t *get_pic( filter_t *p_filter )
73 picture_t *p_pic = (picture_t *)p_filter->p_owner;
74 p_filter->p_owner = NULL;
78 /* FIXME: this is almost like DeleteFilter in src/misc/image.c */
79 static void DeleteFilter( filter_t *p_filter )
81 vlc_object_detach( p_filter );
82 if( p_filter->p_module ) module_Unneed( p_filter, p_filter->p_module );
83 vlc_object_release( p_filter );
86 /* FIXME: this is almost like CreateFilter in src/misc/image.c */
87 static filter_t *CreateFilter( vlc_object_t *p_this, video_format_t *fmt_in,
88 video_format_t *fmt_out )
90 filter_t *p_filter = vlc_object_create( p_this, sizeof(filter_t) );
91 vlc_object_attach( p_filter, p_this );
93 p_filter->pf_vout_buffer_new = get_pic;
95 p_filter->fmt_in = *fmt_in;
96 p_filter->fmt_out = *fmt_out;
98 p_filter->p_module = module_Need( p_filter, "video filter2", NULL, 0 );
100 if( !p_filter->p_module )
102 DeleteFilter( p_filter );
109 static int CreateChain( vlc_object_t *p_this, filter_sys_t *p_sys )
111 p_sys->p_filter1 = CreateFilter( p_this, &p_filter->fmt_in.video,
113 if( p_sys->p_filter1 )
115 p_sys->p_filter2 = CreateFilter( p_this, &p_sys->fmt_mid,
116 &p_filter->fmt_out.video );
117 if( p_sys->p_filter2 )
119 DeleteFilter( p_sys->p_filter1 );
124 /*****************************************************************************
125 * Activate: allocate a chroma function
126 *****************************************************************************
127 * This function allocates and initializes a chroma function
128 *****************************************************************************/
129 static int Activate( vlc_object_t *p_this )
131 filter_t *p_filter = (filter_t *)p_this;
132 static int hack = 0; /* FIXME */
134 if( p_filter->fmt_in.video.i_chroma == p_filter->fmt_out.video.i_chroma )
138 if( hack >= MAX_FILTERS )
140 msg_Err( p_this, "Preventing chain filter reccursion (already %d long)",
145 filter_sys_t *p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
151 memset( p_sys, 0, sizeof( filter_sys_t ) );
152 p_filter->p_sys = p_sys;
154 if( p_filter->fmt_in.i_width != p_filter->fmt_out.i_width ||
155 p_filter->fmt_in.i_height != p_filter->fmt_out.i_height ||
156 p_filter->fmt_in.i_visible_width != p_filter->fmt_out.i_visible_width ||
157 p_filter->fmt_in.i_visible_height != p_filter->fmt_out.i_visible_height )
159 /* Lets try resizing and then doing the chroma conversion */
160 p_sys->fmt_mid = p_filter->fmt_out.video;
161 p_sys->fmt_mid.i_chroma = p_filter->fmt_in.video.i_chroma;
162 if( CreateChain( p_this, p_sys ) == VLC_SUCCESS )
165 /* Lets try it the other way arround (chroma and then resize) */
166 p_sys->fmt_mid = p_filter->fmt_in.video;
167 p_sys->fmt_mid.i_chroma = p_filter->fmt_out.video.i_chroma;
168 if( CreateChain( p_this, p_sys ) == VLC_SUCCESS )
173 /* Lets try doing a chroma chain */
175 p_sys->fmt_mid = p_filter->fmt_in.video;
176 for( i = 0; pi_allowed_chomas[i]; i++ )
178 p_sys->fmt_mid.i_chroma = pi_allowed_chromas[i];
179 if( CreateChain( p_this, p_sys ) == VLC_SUCCESS )
184 /* Hum ... looks like this really isn't going to work. Too bad. */
190 static void Destroy( vlc_object_t *p_this )
192 filter_t *p_filter = (filter_t *)p_this;
194 DeleteFilter( p_filter->p_sys->filter1 );
195 DeleteFilter( p_filter->p_sys->filter2 );
197 if( p_filter->p_sys->p_tmp )
199 free( p_filter->p_sys->p_tmp->p_data_orig );
200 free( p_filter->p_sys->p_tmp );
203 free( p_filter->p_sys );
206 /*****************************************************************************
208 *****************************************************************************/
209 static picture_t *Chain( filter_t *p_filter, picture_t *p_pic )
211 picture_t *p_outpic = p_filter->pf_vout_buffer_new( p_filter );
214 msg_Warn( p_filter, "can't get output picture" );
215 if( p_pic->pf_release )
216 p_pic->pf_release( p_pic );
223 picture_t *p_tmp = malloc( sizeof( picture_t ) );
226 vout_AllocatePicture( VLC_OBJECT( p_vout ), p_tmp,
227 p_sys->fmt_mid.i_chroma,
228 p_sys->fmt_mid.i_width,
229 p_sys->fmt_mid.i_height,
230 p_sys->fmt_mid.i_aspect );
231 p_sys->p_tmp = p_tmp;
232 p_tmp->pf_release = NULL;
233 p_tmp->i_status = RESERVED_PICTURE;
237 p_sys->p_filter1->p_owner = (filter_owner_sys_t*)p_sys->p_tmp;
238 if( !p_sys->p_filter1->pf_video_filter( p_sys->p_filter1, p_pic ) )
240 if( p_pic->pf_release )
241 p_pic->pf_release( p_pic );
244 if( p_pic->pf_release )
245 p_pic->pf_release( p_pic );
246 p_sys->p_filter2->p_owner = (filter_owner_sys_t*)p_outpic;
247 return p_sys->p_filter2->pf_video_filter( p_sys->p_filter2, p_sys->p_tmp );