libavfilter/libmpcodecs/vf_mcdeint.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
00003  *
00004  * This file is part of MPlayer.
00005  *
00006  * MPlayer is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * MPlayer is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License along
00017  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
00018  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00019  */
00020 
00021 
00022 /*
00023 Known Issues:
00024 * The motion estimation is somewhat at the mercy of the input, if the input
00025   frames are created purely based on spatial interpolation then for example
00026   a thin black line or another random and not interpolateable pattern
00027   will cause problems
00028   Note: completly ignoring the "unavailable" lines during motion estimation
00029   didnt look any better, so the most obvious solution would be to improve
00030   tfields or penalize problematic motion vectors ...
00031 
00032 * If non iterative ME is used then snow currently ignores the OBMC window
00033   and as a result sometimes creates artifacts
00034 
00035 * only past frames are used, we should ideally use future frames too, something
00036   like filtering the whole movie in forward and then backward direction seems
00037   like a interresting idea but the current filter framework is FAR from
00038   supporting such things
00039 
00040 * combining the motion compensated image with the input image also isnt
00041   as trivial as it seems, simple blindly taking even lines from one and
00042   odd ones from the other doesnt work at all as ME/MC sometimes simple
00043   has nothing in the previous frames which matches the current, the current
00044   algo has been found by trial and error and almost certainly can be
00045   improved ...
00046 */
00047 
00048 #include <stdio.h>
00049 #include <stdlib.h>
00050 #include <string.h>
00051 #include <inttypes.h>
00052 #include <math.h>
00053 
00054 #include "mp_msg.h"
00055 #include "cpudetect.h"
00056 
00057 #include "libavutil/internal.h"
00058 #include "libavutil/intreadwrite.h"
00059 #include "libavcodec/avcodec.h"
00060 #include "libavcodec/dsputil.h"
00061 
00062 #undef fprintf
00063 #undef free
00064 #undef malloc
00065 
00066 #include "img_format.h"
00067 #include "mp_image.h"
00068 #include "vf.h"
00069 #include "vd_ffmpeg.h"
00070 
00071 #define MIN(a,b) ((a) > (b) ? (b) : (a))
00072 #define MAX(a,b) ((a) < (b) ? (b) : (a))
00073 #define ABS(a) ((a) > 0 ? (a) : (-(a)))
00074 
00075 //===========================================================================//
00076 
00077 struct vf_priv_s {
00078     int mode;
00079     int qp;
00080     int parity;
00081 #if 0
00082     int temp_stride[3];
00083     uint8_t *src[3];
00084     int16_t *temp[3];
00085 #endif
00086     int outbuf_size;
00087     uint8_t *outbuf;
00088     AVCodecContext *avctx_enc;
00089     AVFrame *frame;
00090     AVFrame *frame_dec;
00091 };
00092 
00093 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){
00094     int x, y, i;
00095 
00096     for(i=0; i<3; i++){
00097         p->frame->data[i]= src[i];
00098         p->frame->linesize[i]= src_stride[i];
00099     }
00100 
00101     p->avctx_enc->me_cmp=
00102     p->avctx_enc->me_sub_cmp= FF_CMP_SAD /*| (p->parity ? FF_CMP_ODD : FF_CMP_EVEN)*/;
00103     p->frame->quality= p->qp*FF_QP2LAMBDA;
00104     avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->frame);
00105     p->frame_dec = p->avctx_enc->coded_frame;
00106 
00107     for(i=0; i<3; i++){
00108         int is_chroma= !!i;
00109         int w= width >>is_chroma;
00110         int h= height>>is_chroma;
00111         int fils= p->frame_dec->linesize[i];
00112         int srcs= src_stride[i];
00113 
00114         for(y=0; y<h; y++){
00115             if((y ^ p->parity) & 1){
00116                 for(x=0; x<w; x++){
00117                     if((x-2)+(y-1)*w>=0 && (x+2)+(y+1)*w<w*h){ //FIXME either alloc larger images or optimize this
00118                         uint8_t *filp= &p->frame_dec->data[i][x + y*fils];
00119                         uint8_t *srcp= &src[i][x + y*srcs];
00120                         int diff0= filp[-fils] - srcp[-srcs];
00121                         int diff1= filp[+fils] - srcp[+srcs];
00122                         int spatial_score= ABS(srcp[-srcs-1] - srcp[+srcs-1])
00123                                           +ABS(srcp[-srcs  ] - srcp[+srcs  ])
00124                                           +ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1;
00125                         int temp= filp[0];
00126 
00127 #define CHECK(j)\
00128     {   int score= ABS(srcp[-srcs-1+j] - srcp[+srcs-1-j])\
00129                  + ABS(srcp[-srcs  +j] - srcp[+srcs  -j])\
00130                  + ABS(srcp[-srcs+1+j] - srcp[+srcs+1-j]);\
00131         if(score < spatial_score){\
00132             spatial_score= score;\
00133             diff0= filp[-fils+j] - srcp[-srcs+j];\
00134             diff1= filp[+fils-j] - srcp[+srcs-j];
00135 
00136                         CHECK(-1) CHECK(-2) }} }}
00137                         CHECK( 1) CHECK( 2) }} }}
00138 #if 0
00139                         if((diff0 ^ diff1) > 0){
00140                             int mindiff= ABS(diff0) > ABS(diff1) ? diff1 : diff0;
00141                             temp-= mindiff;
00142                         }
00143 #elif 1
00144                         if(diff0 + diff1 > 0)
00145                             temp-= (diff0 + diff1 - ABS( ABS(diff0) - ABS(diff1) )/2)/2;
00146                         else
00147                             temp-= (diff0 + diff1 + ABS( ABS(diff0) - ABS(diff1) )/2)/2;
00148 #else
00149                         temp-= (diff0 + diff1)/2;
00150 #endif
00151 #if 1
00152                         filp[0]=
00153                         dst[i][x + y*dst_stride[i]]= temp > 255U ? ~(temp>>31) : temp;
00154 #else
00155                         dst[i][x + y*dst_stride[i]]= filp[0];
00156                         filp[0]= temp > 255U ? ~(temp>>31) : temp;
00157 #endif
00158                     }else
00159                         dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
00160                 }
00161             }
00162         }
00163         for(y=0; y<h; y++){
00164             if(!((y ^ p->parity) & 1)){
00165                 for(x=0; x<w; x++){
00166 #if 1
00167                     p->frame_dec->data[i][x + y*fils]=
00168                     dst[i][x + y*dst_stride[i]]= src[i][x + y*srcs];
00169 #else
00170                     dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
00171                     p->frame_dec->data[i][x + y*fils]= src[i][x + y*srcs];
00172 #endif
00173                 }
00174             }
00175         }
00176     }
00177     p->parity ^= 1;
00178 
00179 }
00180 
00181 static int config(struct vf_instance *vf,
00182         int width, int height, int d_width, int d_height,
00183         unsigned int flags, unsigned int outfmt){
00184         int i;
00185         AVCodec *enc= avcodec_find_encoder(CODEC_ID_SNOW);
00186 
00187         for(i=0; i<3; i++){
00188             AVCodecContext *avctx_enc;
00189 #if 0
00190             int is_chroma= !!i;
00191             int w= ((width  + 31) & (~31))>>is_chroma;
00192             int h= ((height + 31) & (~31))>>is_chroma;
00193 
00194             vf->priv->temp_stride[i]= w;
00195             vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t));
00196             vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t));
00197 #endif
00198             avctx_enc=
00199             vf->priv->avctx_enc= avcodec_alloc_context();
00200             avctx_enc->width = width;
00201             avctx_enc->height = height;
00202             avctx_enc->time_base= (AVRational){1,25};  // meaningless
00203             avctx_enc->gop_size = 300;
00204             avctx_enc->max_b_frames= 0;
00205             avctx_enc->pix_fmt = PIX_FMT_YUV420P;
00206             avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
00207             avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
00208             avctx_enc->global_quality= 1;
00209             avctx_enc->flags2= CODEC_FLAG2_MEMC_ONLY;
00210             avctx_enc->me_cmp=
00211             avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
00212             avctx_enc->mb_cmp= FF_CMP_SSE;
00213 
00214             switch(vf->priv->mode){
00215             case 3:
00216                 avctx_enc->refs= 3;
00217             case 2:
00218                 avctx_enc->me_method= ME_ITER;
00219             case 1:
00220                 avctx_enc->flags |= CODEC_FLAG_4MV;
00221                 avctx_enc->dia_size=2;
00222 //                avctx_enc->mb_decision = MB_DECISION_RD;
00223             case 0:
00224                 avctx_enc->flags |= CODEC_FLAG_QPEL;
00225             }
00226 
00227             avcodec_open(avctx_enc, enc);
00228 
00229         }
00230         vf->priv->frame= avcodec_alloc_frame();
00231 
00232         vf->priv->outbuf_size= width*height*10;
00233         vf->priv->outbuf= malloc(vf->priv->outbuf_size);
00234 
00235         return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
00236 }
00237 
00238 static void get_image(struct vf_instance *vf, mp_image_t *mpi){
00239     if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
00240 return; //caused problems, dunno why
00241     // ok, we can do pp in-place (or pp disabled):
00242     vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
00243         mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height);
00244     mpi->planes[0]=vf->dmpi->planes[0];
00245     mpi->stride[0]=vf->dmpi->stride[0];
00246     mpi->width=vf->dmpi->width;
00247     if(mpi->flags&MP_IMGFLAG_PLANAR){
00248         mpi->planes[1]=vf->dmpi->planes[1];
00249         mpi->planes[2]=vf->dmpi->planes[2];
00250         mpi->stride[1]=vf->dmpi->stride[1];
00251         mpi->stride[2]=vf->dmpi->stride[2];
00252     }
00253     mpi->flags|=MP_IMGFLAG_DIRECT;
00254 }
00255 
00256 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
00257     mp_image_t *dmpi;
00258 
00259     if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
00260         // no DR, so get a new image! hope we'll get DR buffer:
00261         dmpi=vf_get_image(vf->next,mpi->imgfmt,
00262             MP_IMGTYPE_TEMP,
00263             MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
00264             mpi->width,mpi->height);
00265         vf_clone_mpi_attributes(dmpi, mpi);
00266     }else{
00267         dmpi=vf->dmpi;
00268     }
00269 
00270     filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h);
00271 
00272     return vf_next_put_image(vf,dmpi, pts);
00273 }
00274 
00275 static void uninit(struct vf_instance *vf){
00276     if(!vf->priv) return;
00277 
00278 #if 0
00279     for(i=0; i<3; i++){
00280         free(vf->priv->temp[i]);
00281         vf->priv->temp[i]= NULL;
00282         free(vf->priv->src[i]);
00283         vf->priv->src[i]= NULL;
00284     }
00285 #endif
00286     if (vf->priv->avctx_enc) {
00287     avcodec_close(vf->priv->avctx_enc);
00288     av_freep(&vf->priv->avctx_enc);
00289     }
00290 
00291     free(vf->priv->outbuf);
00292     free(vf->priv);
00293     vf->priv=NULL;
00294 }
00295 
00296 //===========================================================================//
00297 static int query_format(struct vf_instance *vf, unsigned int fmt){
00298     switch(fmt){
00299         case IMGFMT_YV12:
00300         case IMGFMT_I420:
00301         case IMGFMT_IYUV:
00302         case IMGFMT_Y800:
00303         case IMGFMT_Y8:
00304             return vf_next_query_format(vf,fmt);
00305     }
00306     return 0;
00307 }
00308 
00309 static int vf_open(vf_instance_t *vf, char *args){
00310 
00311     vf->config=config;
00312     vf->put_image=put_image;
00313     vf->get_image=get_image;
00314     vf->query_format=query_format;
00315     vf->uninit=uninit;
00316     vf->priv=malloc(sizeof(struct vf_priv_s));
00317     memset(vf->priv, 0, sizeof(struct vf_priv_s));
00318 
00319     init_avcodec();
00320 
00321     vf->priv->mode=0;
00322     vf->priv->parity= -1;
00323     vf->priv->qp=1;
00324 
00325     if (args) sscanf(args, "%d:%d:%d", &vf->priv->mode, &vf->priv->parity, &vf->priv->qp);
00326 
00327     return 1;
00328 }
00329 
00330 const vf_info_t vf_info_mcdeint = {
00331     "motion compensating deinterlacer",
00332     "mcdeint",
00333     "Michael Niedermayer",
00334     "",
00335     vf_open,
00336     NULL
00337 };