2 * filter_avdeinterlace.c -- deinterlace filter
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
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.
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.
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
21 #include <framework/mlt_filter.h>
22 #include <framework/mlt_frame.h>
27 // ffmpeg Header files
33 #define MAX_NEG_CROP 1024
34 extern uint8_t ff_cropTbl
[256 + 2 * MAX_NEG_CROP
];
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);\
56 psubusw_r2r(mm0,mm1);\
58 packuswb_r2r(mm7,mm1);\
59 movd_r2m(mm1,lum_m2[0]);
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);\
78 psubusw_r2r(mm0,mm1);\
80 packuswb_r2r(mm7,mm1);\
84 #if LIBAVUTIL_VERSION_INT < (50<<16)
85 #define PIX_FMT_YUYV422 PIX_FMT_YUV422
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
,
96 uint8_t *cm
= ff_cropTbl
+ MAX_NEG_CROP
;
99 for(;size
> 0;size
--) {
101 sum
+= lum_m3
[0] << 2;
102 sum
+= lum_m2
[0] << 1;
103 sum
+= lum_m1
[0] << 2;
105 dst
[0] = cm
[(sum
+ 4) >> 3];
122 movq_m2r(rounder
,mm6
);
124 for (;size
> 3; size
-=4) {
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
,
139 uint8_t *cm
= ff_cropTbl
+ MAX_NEG_CROP
;
142 for(;size
> 0;size
--) {
144 sum
+= lum_m3
[0] << 2;
145 sum
+= lum_m2
[0] << 1;
147 sum
+= lum_m1
[0] << 2;
149 lum_m2
[0] = cm
[(sum
+ 4) >> 3];
165 movq_m2r(rounder
,mm6
);
167 for (;size
> 3; size
-=4) {
168 DEINT_INPLACE_LINE_LUM
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
)
185 const uint8_t *src_m2
, *src_m1
, *src_0
, *src_p1
, *src_p2
;
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
);
196 deinterlace_line(dst
,src_m2
,src_m1
,src_0
,src_p1
,src_p2
,width
);
200 src_p1
+= 2*src_wrap
;
201 src_p2
+= 2*src_wrap
;
204 memcpy(dst
,src_m1
,width
);
207 deinterlace_line(dst
,src_m2
,src_m1
,src_0
,src_0
,src_0
,width
);
210 static inline void deinterlace_bottom_field_inplace(uint8_t *src1
, int src_wrap
,
211 int width
, int height
)
213 uint8_t *src_m1
, *src_0
, *src_p1
, *src_p2
;
216 buf
= (uint8_t*)av_malloc(width
);
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
);
227 src_p1
+= 2*src_wrap
;
228 src_p2
+= 2*src_wrap
;
231 deinterlace_line_inplace(buf
,src_m1
,src_0
,src_0
,src_0
,width
);
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
)
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
)
248 if ((width
& 3) != 0 || (height
& 3) != 0)
251 if ( pix_fmt
!= PIX_FMT_YUYV422
)
256 case PIX_FMT_YUV420P
:
260 case PIX_FMT_YUV422P
:
263 case PIX_FMT_YUV411P
:
271 deinterlace_bottom_field_inplace(dst
->data
[i
], dst
->linesize
[i
],
274 deinterlace_bottom_field(dst
->data
[i
],dst
->linesize
[i
],
275 src
->data
[i
], src
->linesize
[i
],
282 deinterlace_bottom_field_inplace(dst
->data
[0], dst
->linesize
[0],
285 deinterlace_bottom_field(dst
->data
[0],dst
->linesize
[0],
286 src
->data
[0], src
->linesize
[0],
300 static int filter_get_image( mlt_frame
this, uint8_t **image
, mlt_image_format
*format
, int *width
, int *height
, int writable
)
303 int deinterlace
= mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "consumer_deinterlace" );
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" );
309 // Get the input image
310 error
= mlt_frame_get_image( this, image
, format
, width
, height
, writable
);
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" ) )
316 AVPicture
*output
= mlt_pool_alloc( sizeof( AVPicture
) );
319 if ( *format
== mlt_image_yuv422
)
321 avpicture_fill( output
, *image
, PIX_FMT_YUYV422
, *width
, *height
);
322 mlt_avpicture_deinterlace( output
, output
, PIX_FMT_YUYV422
, *width
, *height
);
326 mlt_pool_release( output
);
328 // Make sure that others know the frame is deinterlaced
329 mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "progressive", 1 );
335 /** Deinterlace filter processing - this should be lazy evaluation here...
338 static mlt_frame
deinterlace_process( mlt_filter
this, mlt_frame frame
)
340 // Push the get_image method on to the stack
341 mlt_frame_push_get_image( frame
, filter_get_image
);
346 /** Constructor for the filter.
349 mlt_filter
filter_avdeinterlace_init( void *arg
)
351 mlt_filter
this = mlt_filter_new( );
353 this->process
= deinterlace_process
;