]> git.sesse.net Git - mlt/blob - src/modules/avformat/filter_avdeinterlace.c
config mods; avformat static or shared build; corrections to sdl
[mlt] / src / modules / avformat / filter_avdeinterlace.c
1 /*
2  * filter_avdeinterlace.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 "filter_avdeinterlace.h"
22
23 #include <framework/mlt_frame.h>
24
25 #include <string.h>
26 #include <stdlib.h>
27
28 // ffmpeg Header files
29 #include <avformat.h>
30
31 #ifdef USE_MMX
32 #include "mmx.h"
33 #endif
34
35 #ifdef USE_MMX
36 #define DEINT_INPLACE_LINE_LUM \
37                     movd_m2r(lum_m4[0],mm0);\
38                     movd_m2r(lum_m3[0],mm1);\
39                     movd_m2r(lum_m2[0],mm2);\
40                     movd_m2r(lum_m1[0],mm3);\
41                     movd_m2r(lum[0],mm4);\
42                     punpcklbw_r2r(mm7,mm0);\
43                     movd_r2m(mm2,lum_m4[0]);\
44                     punpcklbw_r2r(mm7,mm1);\
45                     punpcklbw_r2r(mm7,mm2);\
46                     punpcklbw_r2r(mm7,mm3);\
47                     punpcklbw_r2r(mm7,mm4);\
48                     paddw_r2r(mm3,mm1);\
49                     psllw_i2r(1,mm2);\
50                     paddw_r2r(mm4,mm0);\
51                     psllw_i2r(2,mm1);\
52                     paddw_r2r(mm6,mm2);\
53                     paddw_r2r(mm2,mm1);\
54                     psubusw_r2r(mm0,mm1);\
55                     psrlw_i2r(3,mm1);\
56                     packuswb_r2r(mm7,mm1);\
57                     movd_r2m(mm1,lum_m2[0]);
58
59 #define DEINT_LINE_LUM \
60                     movd_m2r(lum_m4[0],mm0);\
61                     movd_m2r(lum_m3[0],mm1);\
62                     movd_m2r(lum_m2[0],mm2);\
63                     movd_m2r(lum_m1[0],mm3);\
64                     movd_m2r(lum[0],mm4);\
65                     punpcklbw_r2r(mm7,mm0);\
66                     punpcklbw_r2r(mm7,mm1);\
67                     punpcklbw_r2r(mm7,mm2);\
68                     punpcklbw_r2r(mm7,mm3);\
69                     punpcklbw_r2r(mm7,mm4);\
70                     paddw_r2r(mm3,mm1);\
71                     psllw_i2r(1,mm2);\
72                     paddw_r2r(mm4,mm0);\
73                     psllw_i2r(2,mm1);\
74                     paddw_r2r(mm6,mm2);\
75                     paddw_r2r(mm2,mm1);\
76                     psubusw_r2r(mm0,mm1);\
77                     psrlw_i2r(3,mm1);\
78                     packuswb_r2r(mm7,mm1);\
79                     movd_r2m(mm1,dst[0]);
80 #endif
81
82 /* filter parameters: [-1 4 2 4 -1] // 8 */
83 static void deinterlace_line(uint8_t *dst, 
84                              const uint8_t *lum_m4, const uint8_t *lum_m3, 
85                              const uint8_t *lum_m2, const uint8_t *lum_m1, 
86                              const uint8_t *lum,
87                              int size)
88 {
89 #ifndef USE_MMX
90     uint8_t *cm = cropTbl + MAX_NEG_CROP;
91     int sum;
92
93     for(;size > 0;size--) {
94         sum = -lum_m4[0];
95         sum += lum_m3[0] << 2;
96         sum += lum_m2[0] << 1;
97         sum += lum_m1[0] << 2;
98         sum += -lum[0];
99         dst[0] = cm[(sum + 4) >> 3];
100         lum_m4++;
101         lum_m3++;
102         lum_m2++;
103         lum_m1++;
104         lum++;
105         dst++;
106     }
107 #else
108
109     {
110         mmx_t rounder;
111         rounder.uw[0]=4;
112         rounder.uw[1]=4;
113         rounder.uw[2]=4;
114         rounder.uw[3]=4;
115         pxor_r2r(mm7,mm7);
116         movq_m2r(rounder,mm6);
117     }
118     for (;size > 3; size-=4) {
119         DEINT_LINE_LUM
120         lum_m4+=4;
121         lum_m3+=4;
122         lum_m2+=4;
123         lum_m1+=4;
124         lum+=4;
125         dst+=4;
126     }
127 #endif
128 }
129 static void deinterlace_line_inplace(uint8_t *lum_m4, uint8_t *lum_m3, uint8_t *lum_m2, uint8_t *lum_m1, uint8_t *lum,
130                              int size)
131 {
132 #ifndef USE_MMX
133     uint8_t *cm = cropTbl + MAX_NEG_CROP;
134     int sum;
135
136     for(;size > 0;size--) {
137         sum = -lum_m4[0];
138         sum += lum_m3[0] << 2;
139         sum += lum_m2[0] << 1;
140         lum_m4[0]=lum_m2[0];
141         sum += lum_m1[0] << 2;
142         sum += -lum[0];
143         lum_m2[0] = cm[(sum + 4) >> 3];
144         lum_m4++;
145         lum_m3++;
146         lum_m2++;
147         lum_m1++;
148         lum++;
149     }
150 #else
151
152     {
153         mmx_t rounder;
154         rounder.uw[0]=4;
155         rounder.uw[1]=4;
156         rounder.uw[2]=4;
157         rounder.uw[3]=4;
158         pxor_r2r(mm7,mm7);
159         movq_m2r(rounder,mm6);
160     }
161     for (;size > 3; size-=4) {
162         DEINT_INPLACE_LINE_LUM
163         lum_m4+=4;
164         lum_m3+=4;
165         lum_m2+=4;
166         lum_m1+=4;
167         lum+=4;
168     }
169 #endif
170 }
171
172 /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
173    top field is copied as is, but the bottom field is deinterlaced
174    against the top field. */
175 static void deinterlace_bottom_field(uint8_t *dst, int dst_wrap,
176                                     const uint8_t *src1, int src_wrap,
177                                     int width, int height)
178 {
179     const uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
180     int y;
181
182     src_m2 = src1;
183     src_m1 = src1;
184     src_0=&src_m1[src_wrap];
185     src_p1=&src_0[src_wrap];
186     src_p2=&src_p1[src_wrap];
187     for(y=0;y<(height-2);y+=2) {
188         memcpy(dst,src_m1,width);
189         dst += dst_wrap;
190         deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width);
191         src_m2 = src_0;
192         src_m1 = src_p1;
193         src_0 = src_p2;
194         src_p1 += 2*src_wrap;
195         src_p2 += 2*src_wrap;
196         dst += dst_wrap;
197     }
198     memcpy(dst,src_m1,width);
199     dst += dst_wrap;
200     /* do last line */
201     deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width);
202 }
203
204 static void deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap,
205                                              int width, int height)
206 {
207     uint8_t *src_m1, *src_0, *src_p1, *src_p2;
208     int y;
209     uint8_t *buf;
210     buf = (uint8_t*)av_malloc(width);
211
212     src_m1 = src1;
213     memcpy(buf,src_m1,width);
214     src_0=&src_m1[src_wrap];
215     src_p1=&src_0[src_wrap];
216     src_p2=&src_p1[src_wrap];
217     for(y=0;y<(height-2);y+=2) {
218         deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width);
219         src_m1 = src_p1;
220         src_0 = src_p2;
221         src_p1 += 2*src_wrap;
222         src_p2 += 2*src_wrap;
223     }
224     /* do last line */
225     deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width);
226     av_free(buf);
227 }
228
229
230 /* deinterlace - if not supported return -1 */
231 static int mlt_avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
232                           int pix_fmt, int width, int height)
233 {
234     int i;
235
236     if (pix_fmt != PIX_FMT_YUV420P &&
237         pix_fmt != PIX_FMT_YUV422P &&
238         pix_fmt != PIX_FMT_YUV422 &&
239         pix_fmt != PIX_FMT_YUV444P &&
240         pix_fmt != PIX_FMT_YUV411P)
241         return -1;
242     if ((width & 3) != 0 || (height & 3) != 0)
243         return -1;
244
245         if ( pix_fmt != PIX_FMT_YUV422 )
246         {
247       for(i=0;i<3;i++) {
248           if (i == 1) {
249               switch(pix_fmt) {
250               case PIX_FMT_YUV420P:
251                   width >>= 1;
252                   height >>= 1;
253                   break;
254               case PIX_FMT_YUV422P:
255                   width >>= 1;
256                   break;
257               case PIX_FMT_YUV411P:
258                   width >>= 2;
259                   break;
260               default:
261                   break;
262               }
263           }
264           if (src == dst) {
265               deinterlace_bottom_field_inplace(dst->data[i], dst->linesize[i],
266                                    width, height);
267           } else {
268               deinterlace_bottom_field(dst->data[i],dst->linesize[i],
269                                           src->data[i], src->linesize[i],
270                                           width, height);
271           }
272           }
273     }
274         else {
275       if (src == dst) {
276           deinterlace_bottom_field_inplace(dst->data[0], dst->linesize[0],
277                                width, height);
278       } else {
279           deinterlace_bottom_field(dst->data[0],dst->linesize[0],
280                                       src->data[0], src->linesize[0],
281                                       width, height);
282       }
283         }
284
285 #ifdef USE_MMX
286     emms();
287 #endif
288     return 0;
289 }
290
291 /** Do it :-).
292 */
293
294 static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
295 {
296         int error = 0;
297         
298         // Check that we want progressive and we aren't already progressive
299         if ( *format == mlt_image_yuv422 &&
300                  !mlt_properties_get_int( mlt_frame_properties( this ), "progressive" ) &&
301                  mlt_properties_get_int( mlt_frame_properties( this ), "consumer_deinterlace" ) )
302         {
303                 // Create a picture
304                 AVPicture *output = mlt_pool_alloc( sizeof( AVPicture ) );
305
306                 // Get the input image
307                 error = mlt_frame_get_image( this, image, format, width, height, 1 );
308
309                 // Fill the picture
310                 if ( *format == mlt_image_yuv422 )
311                 {
312                         avpicture_fill( output, *image, PIX_FMT_YUV422, *width, *height );
313                         mlt_avpicture_deinterlace( output, output, PIX_FMT_YUV422, *width, *height );
314                 }
315
316                 // Free the picture
317                 mlt_pool_release( output );
318
319                 // Make sure that others know the frame is deinterlaced
320                 mlt_properties_set_int( mlt_frame_properties( this ), "progressive", 1 );
321         }
322         else
323         {
324                 // Get the input image
325                 error = mlt_frame_get_image( this, image, format, width, height, writable );
326         }
327
328         return error;
329 }
330
331 /** Deinterlace filter processing - this should be lazy evaluation here...
332 */
333
334 static mlt_frame deinterlace_process( mlt_filter this, mlt_frame frame )
335 {
336         // Push the get_image method on to the stack
337         mlt_frame_push_get_image( frame, filter_get_image );
338         
339         return frame;
340 }
341
342 /** Constructor for the filter.
343 */
344
345 mlt_filter filter_avdeinterlace_init( void *arg )
346 {
347         mlt_filter this = mlt_filter_new( );
348         if ( this != NULL )
349                 this->process = deinterlace_process;
350         return this;
351 }
352