Merge commit '716d413c13981da15323c7a3821860536eefdbbb'
[ffmpeg.git] / libavfilter / libmpcodecs / vf_mcdeint.c
1 /*
2  * Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
3  *
4  * This file is part of MPlayer.
5  *
6  * MPlayer 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  * MPlayer 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 along
17  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21
22 /*
23 Known Issues:
24 * The motion estimation is somewhat at the mercy of the input, if the input
25   frames are created purely based on spatial interpolation then for example
26   a thin black line or another random and not interpolateable pattern
27   will cause problems
28   Note: completly ignoring the "unavailable" lines during motion estimation
29   didnt look any better, so the most obvious solution would be to improve
30   tfields or penalize problematic motion vectors ...
31
32 * If non iterative ME is used then snow currently ignores the OBMC window
33   and as a result sometimes creates artifacts
34
35 * only past frames are used, we should ideally use future frames too, something
36   like filtering the whole movie in forward and then backward direction seems
37   like a interresting idea but the current filter framework is FAR from
38   supporting such things
39
40 * combining the motion compensated image with the input image also isnt
41   as trivial as it seems, simple blindly taking even lines from one and
42   odd ones from the other doesnt work at all as ME/MC sometimes simple
43   has nothing in the previous frames which matches the current, the current
44   algo has been found by trial and error and almost certainly can be
45   improved ...
46 */
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <inttypes.h>
52 #include <math.h>
53
54 #include "mp_msg.h"
55 #include "cpudetect.h"
56
57 #include "libavutil/internal.h"
58 #include "libavutil/intreadwrite.h"
59 #include "libavcodec/avcodec.h"
60 #include "libavcodec/dsputil.h"
61
62 #undef fprintf
63 #undef free
64 #undef malloc
65
66 #include "img_format.h"
67 #include "mp_image.h"
68 #include "vf.h"
69 #include "vd_ffmpeg.h"
70
71 #define MIN(a,b) ((a) > (b) ? (b) : (a))
72 #define MAX(a,b) ((a) < (b) ? (b) : (a))
73 #define ABS(a) ((a) > 0 ? (a) : (-(a)))
74
75 //===========================================================================//
76
77 struct vf_priv_s {
78     int mode;
79     int qp;
80     int parity;
81 #if 0
82     int temp_stride[3];
83     uint8_t *src[3];
84     int16_t *temp[3];
85 #endif
86     int outbuf_size;
87     uint8_t *outbuf;
88     AVCodecContext *avctx_enc;
89     AVFrame *frame;
90     AVFrame *frame_dec;
91 };
92
93 static void filter(struct vf_priv_s *p, uint8_t *dst[3], uint8_t *src[3], int dst_stride[3], int src_stride[3], int width, int height){
94     int x, y, i;
95
96     for(i=0; i<3; i++){
97         p->frame->data[i]= src[i];
98         p->frame->linesize[i]= src_stride[i];
99     }
100
101     p->avctx_enc->me_cmp=
102     p->avctx_enc->me_sub_cmp= FF_CMP_SAD /*| (p->parity ? FF_CMP_ODD : FF_CMP_EVEN)*/;
103     p->frame->quality= p->qp*FF_QP2LAMBDA;
104     avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->frame);
105     p->frame_dec = p->avctx_enc->coded_frame;
106
107     for(i=0; i<3; i++){
108         int is_chroma= !!i;
109         int w= width >>is_chroma;
110         int h= height>>is_chroma;
111         int fils= p->frame_dec->linesize[i];
112         int srcs= src_stride[i];
113
114         for(y=0; y<h; y++){
115             if((y ^ p->parity) & 1){
116                 for(x=0; x<w; x++){
117                     if((x-2)+(y-1)*w>=0 && (x+2)+(y+1)*w<w*h){ //FIXME either alloc larger images or optimize this
118                         uint8_t *filp= &p->frame_dec->data[i][x + y*fils];
119                         uint8_t *srcp= &src[i][x + y*srcs];
120                         int diff0= filp[-fils] - srcp[-srcs];
121                         int diff1= filp[+fils] - srcp[+srcs];
122                         int spatial_score= ABS(srcp[-srcs-1] - srcp[+srcs-1])
123                                           +ABS(srcp[-srcs  ] - srcp[+srcs  ])
124                                           +ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1;
125                         int temp= filp[0];
126
127 #define CHECK(j)\
128     {   int score= ABS(srcp[-srcs-1+(j)] - srcp[+srcs-1-(j)])\
129                  + ABS(srcp[-srcs  +(j)] - srcp[+srcs  -(j)])\
130                  + ABS(srcp[-srcs+1+(j)] - srcp[+srcs+1-(j)]);\
131         if(score < spatial_score){\
132             spatial_score= score;\
133             diff0= filp[-fils+(j)] - srcp[-srcs+(j)];\
134             diff1= filp[+fils-(j)] - srcp[+srcs-(j)];
135
136                         CHECK(-1) CHECK(-2) }} }}
137                         CHECK( 1) CHECK( 2) }} }}
138 #if 0
139                         if((diff0 ^ diff1) > 0){
140                             int mindiff= ABS(diff0) > ABS(diff1) ? diff1 : diff0;
141                             temp-= mindiff;
142                         }
143 #elif 1
144                         if(diff0 + diff1 > 0)
145                             temp-= (diff0 + diff1 - ABS( ABS(diff0) - ABS(diff1) )/2)/2;
146                         else
147                             temp-= (diff0 + diff1 + ABS( ABS(diff0) - ABS(diff1) )/2)/2;
148 #else
149                         temp-= (diff0 + diff1)/2;
150 #endif
151 #if 1
152                         filp[0]=
153                         dst[i][x + y*dst_stride[i]]= temp > 255U ? ~(temp>>31) : temp;
154 #else
155                         dst[i][x + y*dst_stride[i]]= filp[0];
156                         filp[0]= temp > 255U ? ~(temp>>31) : temp;
157 #endif
158                     }else
159                         dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
160                 }
161             }
162         }
163         for(y=0; y<h; y++){
164             if(!((y ^ p->parity) & 1)){
165                 for(x=0; x<w; x++){
166 #if 1
167                     p->frame_dec->data[i][x + y*fils]=
168                     dst[i][x + y*dst_stride[i]]= src[i][x + y*srcs];
169 #else
170                     dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
171                     p->frame_dec->data[i][x + y*fils]= src[i][x + y*srcs];
172 #endif
173                 }
174             }
175         }
176     }
177     p->parity ^= 1;
178
179 }
180
181 static int config(struct vf_instance *vf,
182         int width, int height, int d_width, int d_height,
183         unsigned int flags, unsigned int outfmt){
184         int i;
185         AVCodec *enc= avcodec_find_encoder(AV_CODEC_ID_SNOW);
186
187         for(i=0; i<3; i++){
188             AVCodecContext *avctx_enc;
189 #if 0
190             int is_chroma= !!i;
191             int w= ((width  + 31) & (~31))>>is_chroma;
192             int h= ((height + 31) & (~31))>>is_chroma;
193
194             vf->priv->temp_stride[i]= w;
195             vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t));
196             vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t));
197 #endif
198             avctx_enc=
199             vf->priv->avctx_enc= avcodec_alloc_context();
200             avctx_enc->width = width;
201             avctx_enc->height = height;
202             avctx_enc->time_base= (AVRational){1,25};  // meaningless
203             avctx_enc->gop_size = 300;
204             avctx_enc->max_b_frames= 0;
205             avctx_enc->pix_fmt = AV_PIX_FMT_YUV420P;
206             avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
207             avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
208             avctx_enc->global_quality= 1;
209             avctx_enc->flags2= CODEC_FLAG2_MEMC_ONLY;
210             avctx_enc->me_cmp=
211             avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
212             avctx_enc->mb_cmp= FF_CMP_SSE;
213
214             switch(vf->priv->mode){
215             case 3:
216                 avctx_enc->refs= 3;
217             case 2:
218                 avctx_enc->me_method= ME_ITER;
219             case 1:
220                 avctx_enc->flags |= CODEC_FLAG_4MV;
221                 avctx_enc->dia_size=2;
222 //                avctx_enc->mb_decision = MB_DECISION_RD;
223             case 0:
224                 avctx_enc->flags |= CODEC_FLAG_QPEL;
225             }
226
227             avcodec_open(avctx_enc, enc);
228
229         }
230         vf->priv->frame= avcodec_alloc_frame();
231
232         vf->priv->outbuf_size= width*height*10;
233         vf->priv->outbuf= malloc(vf->priv->outbuf_size);
234
235         return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
236 }
237
238 static void get_image(struct vf_instance *vf, mp_image_t *mpi){
239     if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
240 return; //caused problems, dunno why
241     // ok, we can do pp in-place (or pp disabled):
242     vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
243         mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height);
244     mpi->planes[0]=vf->dmpi->planes[0];
245     mpi->stride[0]=vf->dmpi->stride[0];
246     mpi->width=vf->dmpi->width;
247     if(mpi->flags&MP_IMGFLAG_PLANAR){
248         mpi->planes[1]=vf->dmpi->planes[1];
249         mpi->planes[2]=vf->dmpi->planes[2];
250         mpi->stride[1]=vf->dmpi->stride[1];
251         mpi->stride[2]=vf->dmpi->stride[2];
252     }
253     mpi->flags|=MP_IMGFLAG_DIRECT;
254 }
255
256 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
257     mp_image_t *dmpi;
258
259     if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
260         // no DR, so get a new image! hope we'll get DR buffer:
261         dmpi=vf_get_image(vf->next,mpi->imgfmt,
262             MP_IMGTYPE_TEMP,
263             MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
264             mpi->width,mpi->height);
265         vf_clone_mpi_attributes(dmpi, mpi);
266     }else{
267         dmpi=vf->dmpi;
268     }
269
270     filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h);
271
272     return vf_next_put_image(vf,dmpi, pts);
273 }
274
275 static void uninit(struct vf_instance *vf){
276     if(!vf->priv) return;
277
278 #if 0
279     for(i=0; i<3; i++){
280         free(vf->priv->temp[i]);
281         vf->priv->temp[i]= NULL;
282         free(vf->priv->src[i]);
283         vf->priv->src[i]= NULL;
284     }
285 #endif
286     if (vf->priv->avctx_enc) {
287     avcodec_close(vf->priv->avctx_enc);
288     av_freep(&vf->priv->avctx_enc);
289     }
290
291     free(vf->priv->outbuf);
292     free(vf->priv);
293     vf->priv=NULL;
294 }
295
296 //===========================================================================//
297 static int query_format(struct vf_instance *vf, unsigned int fmt){
298     switch(fmt){
299         case IMGFMT_YV12:
300         case IMGFMT_I420:
301         case IMGFMT_IYUV:
302         case IMGFMT_Y800:
303         case IMGFMT_Y8:
304             return vf_next_query_format(vf,fmt);
305     }
306     return 0;
307 }
308
309 static int vf_open(vf_instance_t *vf, char *args){
310
311     vf->config=config;
312     vf->put_image=put_image;
313     vf->get_image=get_image;
314     vf->query_format=query_format;
315     vf->uninit=uninit;
316     vf->priv=malloc(sizeof(struct vf_priv_s));
317     memset(vf->priv, 0, sizeof(struct vf_priv_s));
318
319     init_avcodec();
320
321     vf->priv->mode=0;
322     vf->priv->parity= -1;
323     vf->priv->qp=1;
324
325     if (args) sscanf(args, "%d:%d:%d", &vf->priv->mode, &vf->priv->parity, &vf->priv->qp);
326
327     return 1;
328 }
329
330 const vf_info_t vf_info_mcdeint = {
331     "motion compensating deinterlacer",
332     "mcdeint",
333     "Michael Niedermayer",
334     "",
335     vf_open,
336     NULL
337 };