config mods; avformat static or shared build; corrections to sdl
[melted] / 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