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
28 #include <libavformat/avformat.h>
33 #define MAX_NEG_CROP 1024
34 static uint8_t ff_cropTbl[256 + 2 * MAX_NEG_CROP] = {0,};
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 /* filter parameters: [-1 4 2 4 -1] // 8 */
85 static inline void deinterlace_line(uint8_t *dst,
86 const uint8_t *lum_m4, const uint8_t *lum_m3,
87 const uint8_t *lum_m2, const uint8_t *lum_m1,
92 uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
95 for(;size > 0;size--) {
97 sum += lum_m3[0] << 2;
98 sum += lum_m2[0] << 1;
99 sum += lum_m1[0] << 2;
101 dst[0] = cm[(sum + 4) >> 3];
118 movq_m2r(rounder,mm6);
120 for (;size > 3; size-=4) {
131 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,
135 uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
138 for(;size > 0;size--) {
140 sum += lum_m3[0] << 2;
141 sum += lum_m2[0] << 1;
143 sum += lum_m1[0] << 2;
145 lum_m2[0] = cm[(sum + 4) >> 3];
161 movq_m2r(rounder,mm6);
163 for (;size > 3; size-=4) {
164 DEINT_INPLACE_LINE_LUM
174 /* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
175 top field is copied as is, but the bottom field is deinterlaced
176 against the top field. */
177 static inline void deinterlace_bottom_field(uint8_t *dst, int dst_wrap,
178 const uint8_t *src1, int src_wrap,
179 int width, int height)
181 const uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
186 src_0=&src_m1[src_wrap];
187 src_p1=&src_0[src_wrap];
188 src_p2=&src_p1[src_wrap];
189 for(y=0;y<(height-2);y+=2) {
190 memcpy(dst,src_m1,width);
192 deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width);
196 src_p1 += 2*src_wrap;
197 src_p2 += 2*src_wrap;
200 memcpy(dst,src_m1,width);
203 deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width);
206 static inline void deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap,
207 int width, int height)
209 uint8_t *src_m1, *src_0, *src_p1, *src_p2;
212 buf = (uint8_t*)av_malloc(width);
215 memcpy(buf,src_m1,width);
216 src_0=&src_m1[src_wrap];
217 src_p1=&src_0[src_wrap];
218 src_p2=&src_p1[src_wrap];
219 for(y=0;y<(height-2);y+=2) {
220 deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width);
223 src_p1 += 2*src_wrap;
224 src_p2 += 2*src_wrap;
227 deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width);
232 /* deinterlace - if not supported return -1 */
233 static int mlt_avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
234 int pix_fmt, int width, int height)
238 if (pix_fmt != PIX_FMT_YUV420P &&
239 pix_fmt != PIX_FMT_YUV422P &&
240 pix_fmt != PIX_FMT_YUYV422 &&
241 pix_fmt != PIX_FMT_YUV444P &&
242 pix_fmt != PIX_FMT_YUV411P)
244 if ((width & 3) != 0 || (height & 3) != 0)
247 if ( pix_fmt != PIX_FMT_YUYV422 )
252 case PIX_FMT_YUV420P:
256 case PIX_FMT_YUV422P:
259 case PIX_FMT_YUV411P:
267 deinterlace_bottom_field_inplace(dst->data[i], dst->linesize[i],
270 deinterlace_bottom_field(dst->data[i],dst->linesize[i],
271 src->data[i], src->linesize[i],
278 deinterlace_bottom_field_inplace(dst->data[0], dst->linesize[0],
281 deinterlace_bottom_field(dst->data[0],dst->linesize[0],
282 src->data[0], src->linesize[0],
296 static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
299 int deinterlace = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace" );
301 // Determine if we need a writable version or not
302 if ( deinterlace && !writable )
303 writable = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "progressive" );
305 // Get the input image
306 *format = mlt_image_yuv422;
307 error = mlt_frame_get_image( frame, image, format, width, height, 1 );
309 // Check that we want progressive and we aren't already progressive
310 if ( deinterlace && *format == mlt_image_yuv422 && *image != NULL && !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "progressive" ) )
313 AVPicture *output = mlt_pool_alloc( sizeof( AVPicture ) );
316 avpicture_fill( output, *image, PIX_FMT_YUYV422, *width, *height );
317 mlt_avpicture_deinterlace( output, output, PIX_FMT_YUYV422, *width, *height );
320 mlt_pool_release( output );
322 // Make sure that others know the frame is deinterlaced
323 mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "progressive", 1 );
329 /** Deinterlace filter processing - this should be lazy evaluation here...
332 static mlt_frame deinterlace_process( mlt_filter filter, mlt_frame frame )
334 // Push the get_image method on to the stack
335 mlt_frame_push_get_image( frame, filter_get_image );
340 /** Constructor for the filter.
343 mlt_filter filter_avdeinterlace_init( void *arg )
346 if ( ff_cropTbl[MAX_NEG_CROP + 1] == 0 )
349 for(i=0;i<256;i++) ff_cropTbl[i + MAX_NEG_CROP] = i;
350 for(i=0;i<MAX_NEG_CROP;i++) {
352 ff_cropTbl[i + MAX_NEG_CROP + 256] = 255;
356 mlt_filter filter = mlt_filter_new( );
357 if ( filter != NULL )
358 filter->process = deinterlace_process;