]> git.sesse.net Git - vlc/blob - modules/video_filter/chain.c
dd65f08c141dec4f21242c5d2d5ae928e072cfad
[vlc] / modules / video_filter / chain.c
1 /*****************************************************************************
2  * chain.c : chain multiple video filter modules as a last resort solution
3  *****************************************************************************
4  * Copyright (C) 2007-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea at videolan dot org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_filter.h>
35 #include <vlc_vout.h>
36
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 * );
43
44 /*****************************************************************************
45  * Module descriptor
46  *****************************************************************************/
47 vlc_module_begin();
48     set_description( N_("Video filtering using a chain of video filter modules") );
49     set_capability( "video filter2", 1 );
50     set_callbacks( Activate, Destroy );
51 vlc_module_end();
52
53 #define MAX_FILTERS 4
54
55 struct filter_sys_t
56 {
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;
61 };
62
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'),
68     0
69 };
70
71 static picture_t *get_pic( filter_t *p_filter )
72 {
73     picture_t *p_pic = (picture_t *)p_filter->p_owner;
74     p_filter->p_owner = NULL;
75     return p_pic;
76 }
77
78 /* FIXME: this is almost like DeleteFilter in src/misc/image.c */
79 static void DeleteFilter( filter_t *p_filter )
80 {
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 );
84 }
85
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 )
89 {
90     filter_t *p_filter = vlc_object_create( p_this, VLC_OBJECT_FILTER );
91     vlc_object_attach( p_filter, p_this );
92
93     p_filter->pf_vout_buffer_new = get_pic;
94
95     p_filter->fmt_in = *fmt_in;
96     p_filter->fmt_out = *fmt_out;
97
98     p_filter->p_module = module_Need( p_filter, "video filter2", NULL, 0 );
99
100     if( !p_filter->p_module )
101     {
102         DeleteFilter( p_filter );
103         return NULL;
104     }
105
106     return p_filter;
107 }
108
109 static int CreateChain( vlc_object_t *p_this, filter_sys_t *p_sys )
110 {
111     p_sys->p_filter1 = CreateFilter( p_this, &p_filter->fmt_in.video,
112                                      &p_sys->fmt_mid );
113     if( p_sys->p_filter1 )
114     {
115         p_sys->p_filter2 = CreateFilter( p_this, &p_sys->fmt_mid,
116                                          &p_filter->fmt_out.video );
117         if( p_sys->p_filter2 )
118             return VLC_SUCCESS;
119         DeleteFilter( p_sys->p_filter1 );
120     }
121     return VLC_EGENERIC;
122 }
123
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 )
130 {
131     filter_t *p_filter = (filter_t *)p_this;
132     static int hack = 0; /* FIXME */
133
134     if( p_filter->fmt_in.video.i_chroma == p_filter->fmt_out.video.i_chroma )
135         return VLC_EGENERIC;
136
137     hack++;
138     if( hack >= MAX_FILTERS )
139     {
140         msg_Err( p_this, "Preventing chain filter reccursion (already %d long)",
141                  hack );
142         return VLC_EGENERIC;
143     }
144
145     filter_sys_t *p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
146     if( !p_sys )
147     {
148         hack--;
149         return VLC_ENOMEM;
150     }
151     memset( p_sys, 0, sizeof( filter_sys_t ) );
152     p_filter->p_sys = p_sys;
153
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 )
158     {
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 )
163             return VLC_SUCCESS;
164
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 )
169             return VLC_SUCCESS;
170     }
171     else
172     {
173         /* Lets try doing a chroma chain */
174         int i;
175         p_sys->fmt_mid = p_filter->fmt_in.video;
176         for( i = 0; pi_allowed_chomas[i]; i++ )
177         {
178             p_sys->fmt_mid.i_chroma = pi_allowed_chromas[i];
179             if( CreateChain( p_this, p_sys ) == VLC_SUCCESS )
180                 return VLC_SUCCESS;
181         }
182     }
183
184     /* Hum ... looks like this really isn't going to work. Too bad. */
185     free( p_sys );
186     hack--;
187     return VLC_EGENERIC;
188 }
189
190 static void Destroy( vlc_object_t *p_this )
191 {
192     filter_t *p_filter = (filter_t *)p_this;
193
194     DeleteFilter( p_filter->p_sys->filter1 );
195     DeleteFilter( p_filter->p_sys->filter2 );
196
197     if( p_filter->p_sys->p_tmp )
198     {
199         free( p_filter->p_sys->p_tmp->p_data_orig );
200         free( p_filter->p_sys->p_tmp );
201     }
202
203     free( p_filter->p_sys );
204 }
205
206 /*****************************************************************************
207  * Chain
208  *****************************************************************************/
209 static picture_t *Chain( filter_t *p_filter, picture_t *p_pic )
210 {
211     picture_t *p_outpic = p_filter->pf_vout_buffer_new( p_filter );
212     if( !p_outpic )
213     {
214         msg_Warn( p_filter, "can't get output picture" );
215         if( p_pic->pf_release )
216             p_pic->pf_release( p_pic );
217         return NULL;
218     }
219
220
221     if( !p_sys->p_tmp )
222     {
223         picture_t *p_tmp = malloc( sizeof( picture_t ) );
224         if( !p_tmp )
225             return NULL;
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;
234         p_tmp->p_sys = NULL;
235     }
236
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 ) )
239     {
240         if( p_pic->pf_release )
241             p_pic->pf_release( p_pic );
242         return NULL;
243     }
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 );
248 }