]> git.sesse.net Git - mlt/blob - src/modules/xine/filter_deinterlace.c
Refactor to use mlt_frame_set_image/_alpha.
[mlt] / src / modules / xine / filter_deinterlace.c
1 /*
2  * filter_deinterlace.c -- deinterlace filter
3  * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4  * Author: Charles Yates <charles.yates@pandora.be>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include <framework/mlt_filter.h>
22 #include <framework/mlt_log.h>
23 #include <framework/mlt_producer.h>
24 #include <framework/mlt_events.h>
25 #include "deinterlace.h"
26 #include "yadif.h"
27
28 #include <framework/mlt_frame.h>
29
30 #include <string.h>
31 #include <stdlib.h>
32
33 static yadif_filter *init_yadif( int width, int height )
34 {
35         yadif_filter *yadif = mlt_pool_alloc( sizeof( *yadif ) );
36
37         yadif->cpu = 0; // Pure C
38 #ifdef USE_SSE
39         yadif->cpu |= AVS_CPU_INTEGER_SSE;
40 #endif
41 #ifdef USE_SSE2
42         yadif->cpu |= AVS_CPU_SSE2;
43 #endif
44         // Create intermediate planar planes
45         yadif->yheight = height;
46         yadif->ywidth  = width;
47         yadif->uvwidth = yadif->ywidth / 2;
48         yadif->ypitch  = ( yadif->ywidth +  15 ) / 16 * 16;
49         yadif->uvpitch = ( yadif->uvwidth + 15 ) / 16 * 16;
50         yadif->ysrc  = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch );
51         yadif->usrc  = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch);
52         yadif->vsrc  = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch );
53         yadif->yprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch );
54         yadif->uprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch );
55         yadif->vprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch );
56         yadif->ynext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch );
57         yadif->unext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch );
58         yadif->vnext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch );
59         yadif->ydest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch );
60         yadif->udest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch );
61         yadif->vdest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch );
62
63         return yadif;
64 }
65
66 static void close_yadif(yadif_filter *yadif)
67 {
68         mlt_pool_release( yadif->ysrc );
69         mlt_pool_release( yadif->usrc );
70         mlt_pool_release( yadif->vsrc );
71         mlt_pool_release( yadif->yprev );
72         mlt_pool_release( yadif->uprev );
73         mlt_pool_release( yadif->vprev );
74         mlt_pool_release( yadif->ynext );
75         mlt_pool_release( yadif->unext );
76         mlt_pool_release( yadif->vnext );
77         mlt_pool_release( yadif->ydest );
78         mlt_pool_release( yadif->udest );
79         mlt_pool_release( yadif->vdest );
80         mlt_pool_release( yadif );
81
82 #if defined(__GNUC__) && !defined(PIC)
83         // Set SSSE3 bit to cpu
84         asm (\
85         "mov $1, %%eax \n\t"\
86         "push %%ebx \n\t"\
87         "cpuid \n\t"\
88         "pop %%ebx \n\t"\
89         "mov %%ecx, %%edx \n\t"\
90         "shr $9, %%edx \n\t"\
91         "and $1, %%edx \n\t"\
92         "shl $9, %%edx \n\t"\
93         "and $511, %%ebx \n\t"\
94         "or %%edx, %%ebx \n\t"\
95         : "=b"(yadif->cpu) : "p"(yadif->cpu) : "%eax", "%ecx", "%edx");
96 #endif
97 }
98
99 static int deinterlace_yadif( mlt_frame frame, mlt_filter filter, uint8_t **image, mlt_image_format *format, int *width, int *height, int mode )
100 {
101         mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
102         mlt_frame previous_frame = mlt_properties_get_data( properties, "previous frame", NULL );
103         uint8_t* previous_image = NULL;
104         int previous_width = *width;
105         int previous_height = *height;
106         mlt_frame next_frame = mlt_properties_get_data( properties, "next frame", NULL );
107         uint8_t* next_image = NULL;
108         int next_width = *width;
109         int next_height = *height;
110         
111         mlt_log_debug( MLT_FILTER_SERVICE(filter), "previous %d current %d next %d\n",
112                 previous_frame? mlt_frame_get_position(previous_frame) : -1,
113                 mlt_frame_get_position(frame),
114                 next_frame?  mlt_frame_get_position(next_frame) : -1);
115
116         if ( !previous_frame || !next_frame )
117                 return 1;
118
119         // Get the preceding frame's image
120         int error = mlt_frame_get_image( previous_frame, &previous_image, format, &previous_width, &previous_height, 0 );
121
122         // Check that we aren't already progressive
123         if ( !error && previous_image  && *format == mlt_image_yuv422 &&
124                  !mlt_properties_get_int( MLT_FRAME_PROPERTIES( previous_frame ), "progressive" ) )
125         {
126                 // Get the current frame's image
127                 error = mlt_frame_get_image( frame, image, format, width, height, 0 );
128
129                 if ( !error && *image && *format == mlt_image_yuv422 )
130                 {
131                         // Get the following frame's image
132                         error = mlt_frame_get_image( next_frame, &next_image, format, &next_width, &next_height, 0 );
133                 
134                         if ( !error && next_image && *format == mlt_image_yuv422 )
135                         {
136                                 yadif_filter *yadif = init_yadif( *width, *height );
137                                 if ( yadif )
138                                 {
139                                         const int order = mlt_properties_get_int( properties, "top_field_first" );
140                                         const int pitch = *width << 1;
141                                         const int parity = 0;
142
143                                         // Convert packed to planar
144                                         YUY2ToPlanes( *image, pitch, *width, *height, yadif->ysrc,
145                                                 yadif->ypitch, yadif->usrc, yadif->vsrc, yadif->uvpitch, yadif->cpu );
146                                         YUY2ToPlanes( previous_image, pitch, *width, *height, yadif->yprev,
147                                                 yadif->ypitch, yadif->uprev, yadif->vprev, yadif->uvpitch, yadif->cpu );
148                                         YUY2ToPlanes( next_image, pitch, *width, *height, yadif->ynext,
149                                                 yadif->ypitch, yadif->unext, yadif->vnext, yadif->uvpitch, yadif->cpu );
150
151                                         // Deinterlace each plane
152                                         filter_plane( mode, yadif->ydest, yadif->ypitch, yadif->yprev, yadif->ysrc,
153                                                 yadif->ynext, yadif->ypitch, *width, *height, parity, order, yadif->cpu);
154                                         filter_plane( mode, yadif->udest, yadif->uvpitch,yadif->uprev, yadif->usrc,
155                                                 yadif->unext, yadif->uvpitch, *width >> 1, *height, parity, order, yadif->cpu);
156                                         filter_plane( mode, yadif->vdest, yadif->uvpitch, yadif->vprev, yadif->vsrc,
157                                                 yadif->vnext, yadif->uvpitch, *width >> 1, *height, parity, order, yadif->cpu);
158
159                                         // Convert planar to packed
160                                         YUY2FromPlanes( *image, pitch, *width, *height, yadif->ydest,
161                                                 yadif->ypitch, yadif->udest, yadif->vdest, yadif->uvpitch, yadif->cpu);
162
163                                         close_yadif( yadif );
164                                 }
165                         }
166                 }
167         }
168         else
169         {
170                 // Get the current frame's image
171                 error = mlt_frame_get_image( frame, image, format, width, height, 0 );
172         }
173         return error;
174 }
175
176 /** Do it :-).
177 */
178
179 static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
180 {
181         int error = 0;
182         mlt_properties properties = MLT_FRAME_PROPERTIES( this );
183         int deinterlace = mlt_properties_get_int( properties, "consumer_deinterlace" );
184         int progressive = mlt_properties_get_int( properties, "progressive" );
185         
186         // Pop the service off the stack
187         mlt_filter filter = mlt_frame_pop_service( this );
188
189         // Get the input image
190         if ( deinterlace && !progressive )
191         {
192                 // Determine deinterlace method
193                 char *method_str = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "method" );
194                 int method = DEINTERLACE_NONE;
195                 char *frame_method_str = mlt_properties_get( properties, "deinterlace_method" );
196                 
197                 if ( frame_method_str )
198                         method_str = frame_method_str;
199                 
200                 if ( !method_str || strcmp( method_str, "yadif" ) == 0 )
201                         method = DEINTERLACE_YADIF;
202                 else if ( strcmp( method_str, "yadif-nospatial" ) == 0 )
203                         method = DEINTERLACE_YADIF_NOSPATIAL;
204                 else if ( strcmp( method_str, "onefield" ) == 0 )
205                         method = DEINTERLACE_ONEFIELD;
206                 else if ( strcmp( method_str, "linearblend" ) == 0 )
207                         method = DEINTERLACE_LINEARBLEND;
208                 else if ( strcmp( method_str, "bob" ) == 0 )
209                         method = DEINTERLACE_BOB;
210                 else if ( strcmp( method_str, "weave" ) == 0 )
211                         method = DEINTERLACE_BOB;
212                 else if ( strcmp( method_str, "greedy" ) == 0 )
213                         method = DEINTERLACE_GREEDY;
214
215                 *format = mlt_image_yuv422;
216
217                 if ( method == DEINTERLACE_YADIF )
218                 {
219                         int mode = 0;
220                         error = deinterlace_yadif( this, filter, image, format, width, height, mode );
221                         progressive = mlt_properties_get_int( properties, "progressive" );
222                 }
223                 else if ( method == DEINTERLACE_YADIF_NOSPATIAL )
224                 {
225                         int mode = 2;
226                         error = deinterlace_yadif( this, filter, image, format, width, height, mode );
227                         progressive = mlt_properties_get_int( properties, "progressive" );
228                 }
229                 if ( error || ( method > DEINTERLACE_NONE && method < DEINTERLACE_YADIF ) )
230                 {
231                         // Signal that we no longer need previous and next frames
232                         mlt_service service = mlt_properties_get_data( MLT_FILTER_PROPERTIES(filter), "service", NULL );
233                         mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_need_previous_next", 0 );
234                         
235                         if ( error )
236                                 method = DEINTERLACE_ONEFIELD;
237                         
238                         // Get the current frame's image
239                         error = mlt_frame_get_image( this, image, format, width, height, writable );
240                         progressive = mlt_properties_get_int( properties, "progressive" );
241
242                         // Check that we aren't already progressive
243                         if ( !progressive && !error && *image && *format == mlt_image_yuv422 )
244                         {
245                                 // Deinterlace the image using one of the Xine deinterlacers
246                                 int image_size = *width * *height * 2;
247                                 uint8_t *new_image = mlt_pool_alloc( image_size );
248
249                                 deinterlace_yuv( new_image, image, *width * 2, *height, method );
250                                 mlt_frame_set_image( this, new_image, image_size, mlt_pool_release );
251                                 *image = new_image;
252                         }
253                 }
254                 else if ( method == DEINTERLACE_NONE )
255                 {
256                         error = mlt_frame_get_image( this, image, format, width, height, writable );
257                 }
258                 
259                 mlt_log_debug( MLT_FILTER_SERVICE( filter ), "error %d deint %d prog %d fmt %s method %s\n",
260                         error, deinterlace, progressive, mlt_image_format_name( *format ), method_str ? method_str : "yadif" );
261                 
262                 if ( !error )
263                 {
264                         // Make sure that others know the frame is deinterlaced
265                         mlt_properties_set_int( properties, "progressive", 1 );
266                 }
267         }
268         else
269         {
270                 // Pass through
271                 error = mlt_frame_get_image( this, image, format, width, height, writable );
272         }
273
274         if ( !deinterlace || progressive )
275         {
276                 // Signal that we no longer need previous and next frames
277                 mlt_service service = mlt_properties_get_data( MLT_FILTER_PROPERTIES(filter), "service", NULL );
278                 if ( service )
279                         mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_need_previous_next", 0 );
280         }
281
282         return error;
283 }
284
285 /** Deinterlace filter processing - this should be lazy evaluation here...
286 */
287
288 static mlt_frame deinterlace_process( mlt_filter this, mlt_frame frame )
289 {
290         // Push this on to the service stack
291         mlt_frame_push_service( frame, this );
292
293         // Push the get_image method on to the stack
294         mlt_frame_push_get_image( frame, filter_get_image );
295         
296         return frame;
297 }
298
299 static void on_service_changed( mlt_service owner, mlt_service filter )
300 {
301         mlt_service service = mlt_properties_get_data( MLT_SERVICE_PROPERTIES(filter), "service", NULL );
302         mlt_properties_set_int( MLT_SERVICE_PROPERTIES(service), "_need_previous_next", 1 );
303 }
304
305 /** Constructor for the filter.
306 */
307
308 mlt_filter filter_deinterlace_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
309 {
310         mlt_filter this = mlt_filter_new( );
311         if ( this != NULL )
312         {
313                 this->process = deinterlace_process;
314                 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "method", arg );
315                 mlt_events_listen( MLT_FILTER_PROPERTIES( this ), this, "service-changed", (mlt_listener) on_service_changed ); 
316         }
317         return this;
318 }
319