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