]> git.sesse.net Git - ffmpeg/blob - libavfilter/libmpcodecs/vf_mcdeint.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / 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     int out_size;
96
97     for(i=0; i<3; i++){
98         p->frame->data[i]= src[i];
99         p->frame->linesize[i]= src_stride[i];
100     }
101
102     p->avctx_enc->me_cmp=
103     p->avctx_enc->me_sub_cmp= FF_CMP_SAD /*| (p->parity ? FF_CMP_ODD : FF_CMP_EVEN)*/;
104     p->frame->quality= p->qp*FF_QP2LAMBDA;
105     out_size = avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->frame);
106     p->frame_dec = p->avctx_enc->coded_frame;
107
108     for(i=0; i<3; i++){
109         int is_chroma= !!i;
110         int w= width >>is_chroma;
111         int h= height>>is_chroma;
112         int fils= p->frame_dec->linesize[i];
113         int srcs= src_stride[i];
114
115         for(y=0; y<h; y++){
116             if((y ^ p->parity) & 1){
117                 for(x=0; x<w; x++){
118                     if((x-2)+(y-1)*w>=0 && (x+2)+(y+1)*w<w*h){ //FIXME either alloc larger images or optimize this
119                         uint8_t *filp= &p->frame_dec->data[i][x + y*fils];
120                         uint8_t *srcp= &src[i][x + y*srcs];
121                         int diff0= filp[-fils] - srcp[-srcs];
122                         int diff1= filp[+fils] - srcp[+srcs];
123                         int spatial_score= ABS(srcp[-srcs-1] - srcp[+srcs-1])
124                                           +ABS(srcp[-srcs  ] - srcp[+srcs  ])
125                                           +ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1;
126                         int temp= filp[0];
127
128 #define CHECK(j)\
129     {   int score= ABS(srcp[-srcs-1+j] - srcp[+srcs-1-j])\
130                  + ABS(srcp[-srcs  +j] - srcp[+srcs  -j])\
131                  + ABS(srcp[-srcs+1+j] - srcp[+srcs+1-j]);\
132         if(score < spatial_score){\
133             spatial_score= score;\
134             diff0= filp[-fils+j] - srcp[-srcs+j];\
135             diff1= filp[+fils-j] - srcp[+srcs-j];
136
137                         CHECK(-1) CHECK(-2) }} }}
138                         CHECK( 1) CHECK( 2) }} }}
139 #if 0
140                         if((diff0 ^ diff1) > 0){
141                             int mindiff= ABS(diff0) > ABS(diff1) ? diff1 : diff0;
142                             temp-= mindiff;
143                         }
144 #elif 1
145                         if(diff0 + diff1 > 0)
146                             temp-= (diff0 + diff1 - ABS( ABS(diff0) - ABS(diff1) )/2)/2;
147                         else
148                             temp-= (diff0 + diff1 + ABS( ABS(diff0) - ABS(diff1) )/2)/2;
149 #else
150                         temp-= (diff0 + diff1)/2;
151 #endif
152 #if 1
153                         filp[0]=
154                         dst[i][x + y*dst_stride[i]]= temp > 255U ? ~(temp>>31) : temp;
155 #else
156                         dst[i][x + y*dst_stride[i]]= filp[0];
157                         filp[0]= temp > 255U ? ~(temp>>31) : temp;
158 #endif
159                     }else
160                         dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
161                 }
162             }
163         }
164         for(y=0; y<h; y++){
165             if(!((y ^ p->parity) & 1)){
166                 for(x=0; x<w; x++){
167 #if 1
168                     p->frame_dec->data[i][x + y*fils]=
169                     dst[i][x + y*dst_stride[i]]= src[i][x + y*srcs];
170 #else
171                     dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
172                     p->frame_dec->data[i][x + y*fils]= src[i][x + y*srcs];
173 #endif
174                 }
175             }
176         }
177     }
178     p->parity ^= 1;
179
180 }
181
182 static int config(struct vf_instance *vf,
183         int width, int height, int d_width, int d_height,
184         unsigned int flags, unsigned int outfmt){
185         int i;
186         AVCodec *enc= avcodec_find_encoder(CODEC_ID_SNOW);
187
188         for(i=0; i<3; i++){
189             AVCodecContext *avctx_enc;
190 #if 0
191             int is_chroma= !!i;
192             int w= ((width  + 31) & (~31))>>is_chroma;
193             int h= ((height + 31) & (~31))>>is_chroma;
194
195             vf->priv->temp_stride[i]= w;
196             vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t));
197             vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t));
198 #endif
199             avctx_enc=
200             vf->priv->avctx_enc= avcodec_alloc_context();
201             avctx_enc->width = width;
202             avctx_enc->height = height;
203             avctx_enc->time_base= (AVRational){1,25};  // meaningless
204             avctx_enc->gop_size = 300;
205             avctx_enc->max_b_frames= 0;
206             avctx_enc->pix_fmt = PIX_FMT_YUV420P;
207             avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
208             avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
209             avctx_enc->global_quality= 1;
210             avctx_enc->flags2= CODEC_FLAG2_MEMC_ONLY;
211             avctx_enc->me_cmp=
212             avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
213             avctx_enc->mb_cmp= FF_CMP_SSE;
214
215             switch(vf->priv->mode){
216             case 3:
217                 avctx_enc->refs= 3;
218             case 2:
219                 avctx_enc->me_method= ME_ITER;
220             case 1:
221                 avctx_enc->flags |= CODEC_FLAG_4MV;
222                 avctx_enc->dia_size=2;
223 //                avctx_enc->mb_decision = MB_DECISION_RD;
224             case 0:
225                 avctx_enc->flags |= CODEC_FLAG_QPEL;
226             }
227
228             avcodec_open(avctx_enc, enc);
229
230         }
231         vf->priv->frame= avcodec_alloc_frame();
232
233         vf->priv->outbuf_size= width*height*10;
234         vf->priv->outbuf= malloc(vf->priv->outbuf_size);
235
236         return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
237 }
238
239 static void get_image(struct vf_instance *vf, mp_image_t *mpi){
240     if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
241 return; //caused problems, dunno why
242     // ok, we can do pp in-place (or pp disabled):
243     vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
244         mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height);
245     mpi->planes[0]=vf->dmpi->planes[0];
246     mpi->stride[0]=vf->dmpi->stride[0];
247     mpi->width=vf->dmpi->width;
248     if(mpi->flags&MP_IMGFLAG_PLANAR){
249         mpi->planes[1]=vf->dmpi->planes[1];
250         mpi->planes[2]=vf->dmpi->planes[2];
251         mpi->stride[1]=vf->dmpi->stride[1];
252         mpi->stride[2]=vf->dmpi->stride[2];
253     }
254     mpi->flags|=MP_IMGFLAG_DIRECT;
255 }
256
257 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
258     mp_image_t *dmpi;
259
260     if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
261         // no DR, so get a new image! hope we'll get DR buffer:
262         dmpi=vf_get_image(vf->next,mpi->imgfmt,
263             MP_IMGTYPE_TEMP,
264             MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
265             mpi->width,mpi->height);
266         vf_clone_mpi_attributes(dmpi, mpi);
267     }else{
268         dmpi=vf->dmpi;
269     }
270
271     filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h);
272
273     return vf_next_put_image(vf,dmpi, pts);
274 }
275
276 static void uninit(struct vf_instance *vf){
277     if(!vf->priv) return;
278
279 #if 0
280     for(i=0; i<3; i++){
281         free(vf->priv->temp[i]);
282         vf->priv->temp[i]= NULL;
283         free(vf->priv->src[i]);
284         vf->priv->src[i]= NULL;
285     }
286 #endif
287     if (vf->priv->avctx_enc) {
288     avcodec_close(vf->priv->avctx_enc);
289     av_freep(&vf->priv->avctx_enc);
290     }
291
292     free(vf->priv->outbuf);
293     free(vf->priv);
294     vf->priv=NULL;
295 }
296
297 //===========================================================================//
298 static int query_format(struct vf_instance *vf, unsigned int fmt){
299     switch(fmt){
300         case IMGFMT_YV12:
301         case IMGFMT_I420:
302         case IMGFMT_IYUV:
303         case IMGFMT_Y800:
304         case IMGFMT_Y8:
305             return vf_next_query_format(vf,fmt);
306     }
307     return 0;
308 }
309
310 static int vf_open(vf_instance_t *vf, char *args){
311
312     vf->config=config;
313     vf->put_image=put_image;
314     vf->get_image=get_image;
315     vf->query_format=query_format;
316     vf->uninit=uninit;
317     vf->priv=malloc(sizeof(struct vf_priv_s));
318     memset(vf->priv, 0, sizeof(struct vf_priv_s));
319
320     init_avcodec();
321
322     vf->priv->mode=0;
323     vf->priv->parity= -1;
324     vf->priv->qp=1;
325
326     if (args) sscanf(args, "%d:%d:%d", &vf->priv->mode, &vf->priv->parity, &vf->priv->qp);
327
328     return 1;
329 }
330
331 const vf_info_t vf_info_mcdeint = {
332     "motion compensating deinterlacer",
333     "mcdeint",
334     "Michael Niedermayer",
335     "",
336     vf_open,
337     NULL
338 };