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/common.h"
58 #include "libavutil/internal.h"
59 #include "libavutil/intreadwrite.h"
60 #include "libavcodec/avcodec.h"
61 #include "libavcodec/dsputil.h"
62 
63 #undef fprintf
64 #undef free
65 #undef malloc
66 
67 #include "img_format.h"
68 #include "mp_image.h"
69 #include "vf.h"
70 #include "av_helpers.h"
71 
72 #define MIN(a,b) ((a) > (b) ? (b) : (a))
73 #define MAX(a,b) ((a) < (b) ? (b) : (a))
74 #define ABS(a) ((a) > 0 ? (a) : (-(a)))
75 
76 //===========================================================================//
77 
78 struct vf_priv_s {
79  int mode;
80  int qp;
81  int parity;
82 #if 0
83  int temp_stride[3];
84  uint8_t *src[3];
85  int16_t *temp[3];
86 #endif
92 };
93 
94 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){
95  int x, y, i;
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  avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->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;
187 
188  for(i=0; i<3; i++){
189  AVCodecContext *avctx_enc;
190  AVDictionary *opts = NULL;
191 #if 0
192  int is_chroma= !!i;
193  int w= ((width + 31) & (~31))>>is_chroma;
194  int h= ((height + 31) & (~31))>>is_chroma;
195 
196  vf->priv->temp_stride[i]= w;
197  vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t));
198  vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t));
199 #endif
200  avctx_enc=
201  vf->priv->avctx_enc= avcodec_alloc_context3(enc);
202  avctx_enc->width = width;
203  avctx_enc->height = height;
204  avctx_enc->time_base= (AVRational){1,25}; // meaningless
205  avctx_enc->gop_size = 300;
206  avctx_enc->max_b_frames= 0;
207  avctx_enc->pix_fmt = AV_PIX_FMT_YUV420P;
210  avctx_enc->global_quality= 1;
211  av_dict_set(&opts, "memc_only", "1", 0);
212  avctx_enc->me_cmp=
213  avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
214  avctx_enc->mb_cmp= FF_CMP_SSE;
215 
216  switch(vf->priv->mode){
217  case 3:
218  avctx_enc->refs= 3;
219  case 2:
220  avctx_enc->me_method= ME_ITER;
221  case 1:
222  avctx_enc->flags |= CODEC_FLAG_4MV;
223  avctx_enc->dia_size=2;
224 // avctx_enc->mb_decision = MB_DECISION_RD;
225  case 0:
226  avctx_enc->flags |= CODEC_FLAG_QPEL;
227  }
228 
229  avcodec_open2(avctx_enc, enc, &opts);
230  av_dict_free(&opts);
231 
232  }
233  vf->priv->frame= avcodec_alloc_frame();
234 
235  vf->priv->outbuf_size= width*height*10;
236  vf->priv->outbuf= malloc(vf->priv->outbuf_size);
237 
238  return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
239 }
240 
241 static void get_image(struct vf_instance *vf, mp_image_t *mpi){
242  if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
243 return; //caused problems, dunno why
244  // ok, we can do pp in-place (or pp disabled):
245  vf->dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
246  mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height);
247  mpi->planes[0]=vf->dmpi->planes[0];
248  mpi->stride[0]=vf->dmpi->stride[0];
249  mpi->width=vf->dmpi->width;
250  if(mpi->flags&MP_IMGFLAG_PLANAR){
251  mpi->planes[1]=vf->dmpi->planes[1];
252  mpi->planes[2]=vf->dmpi->planes[2];
253  mpi->stride[1]=vf->dmpi->stride[1];
254  mpi->stride[2]=vf->dmpi->stride[2];
255  }
256  mpi->flags|=MP_IMGFLAG_DIRECT;
257 }
258 
259 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
260  mp_image_t *dmpi;
261 
262  if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
263  // no DR, so get a new image! hope we'll get DR buffer:
264  dmpi=ff_vf_get_image(vf->next,mpi->imgfmt,
267  mpi->width,mpi->height);
268  ff_vf_clone_mpi_attributes(dmpi, mpi);
269  }else{
270  dmpi=vf->dmpi;
271  }
272 
273  filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h);
274 
275  return ff_vf_next_put_image(vf,dmpi, pts);
276 }
277 
278 static void uninit(struct vf_instance *vf){
279  if(!vf->priv) return;
280 
281 #if 0
282  for(i=0; i<3; i++){
283  free(vf->priv->temp[i]);
284  vf->priv->temp[i]= NULL;
285  free(vf->priv->src[i]);
286  vf->priv->src[i]= NULL;
287  }
288 #endif
289  if (vf->priv->avctx_enc) {
290  avcodec_close(vf->priv->avctx_enc);
291  av_freep(&vf->priv->avctx_enc);
292  }
293 
294  free(vf->priv->outbuf);
295  free(vf->priv);
296  vf->priv=NULL;
297 }
298 
299 //===========================================================================//
300 static int query_format(struct vf_instance *vf, unsigned int fmt){
301  switch(fmt){
302  case IMGFMT_YV12:
303  case IMGFMT_I420:
304  case IMGFMT_IYUV:
305  case IMGFMT_Y800:
306  case IMGFMT_Y8:
307  return ff_vf_next_query_format(vf,fmt);
308  }
309  return 0;
310 }
311 
312 static int vf_open(vf_instance_t *vf, char *args){
313 
314  vf->config=config;
315  vf->put_image=put_image;
316  vf->get_image=get_image;
318  vf->uninit=uninit;
319  vf->priv=malloc(sizeof(struct vf_priv_s));
320  memset(vf->priv, 0, sizeof(struct vf_priv_s));
321 
322  ff_init_avcodec();
323 
324  vf->priv->mode=0;
325  vf->priv->parity= -1;
326  vf->priv->qp=1;
327 
328  if (args) sscanf(args, "%d:%d:%d", &vf->priv->mode, &vf->priv->parity, &vf->priv->qp);
329 
330  return 1;
331 }
332 
334  "motion compensating deinterlacer",
335  "mcdeint",
336  "Michael Niedermayer",
337  "",
338  vf_open,
339  NULL
340 };