FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_mcdeint.c
Go to the documentation of this file.
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
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);
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;
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;
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 ff_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=ff_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=ff_vf_get_image(vf->next,mpi->imgfmt,
264  mpi->width,mpi->height);
265  ff_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 ff_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 ff_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;
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  ff_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 
331  "motion compensating deinterlacer",
332  "mcdeint",
333  "Michael Niedermayer",
334  "",
335  vf_open,
336  NULL
337 };