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