25b513593835e23ae5240828802b96d4576c78cd
[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 #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