1 //
2 //
3 // Port to avidemux2 by mean
4 // Original filter by M Niedermayer
5 // See below
6 /*
7     Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
8 
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23 
24 #include "ADM_default.h"
25 #include "ADM_coreVideoFilterInternal.h"
26 #include "mcdeint.h"
27 #include "mcdeint_desc.cpp"
28 #include "DIA_factory.h"
29 
30 extern "C"
31 {
32     #include "libavcodec/avcodec.h"
33 }
34 
35 
36 struct vf_priv_s {
37     int mode;
38     int qp;
39     int parity;
40 #if 0
41     int temp_stride[3];
42     uint8_t *src[3];
43     int16_t *temp[3];
44 #endif
45     int outbuf_size;
46     uint8_t *outbuf;
47     AVCodecContext *avctx_enc;
48     AVFrame *frame;
49     AVFrame *frame_dec;
50 };
51 
52 
53 /**
54     \class horizontalFlipFilter
55 */
56 class AVDMVideoMCDeint : public  ADM_coreVideoFilterCached
57 {
58 protected:
59         mcdeint          _param;
60         uint8_t         init();
61         uint8_t         cleanup();
62         vf_priv_s        priv;
63 public:
64                     AVDMVideoMCDeint(ADM_coreVideoFilter *previous,CONFcouple *conf);
65                     ~AVDMVideoMCDeint();
66 
67         virtual const char   *getConfiguration(void);                   /// Return  current configuration as a human readable string
68         virtual bool         getNextFrame(uint32_t *fn,ADMImage *image);    /// Return the next image
69 	 //  virtual FilterInfo  *getInfo(void);                             /// Return picture parameters after this filter
70         virtual bool         getCoupledConf(CONFcouple **couples) ;   /// Return the current filter configuration
71 		virtual void setCoupledConf(CONFcouple *couples);
72         virtual bool         configure(void);           /// Start graphical user interface
73 };
74 
75 // Add the hook to make it valid plugin
76 DECLARE_VIDEO_FILTER(   AVDMVideoMCDeint,   // Class
77                         1,0,0,              // Version
78                         ADM_UI_ALL,         // UI
79                         VF_INTERLACING,            // Category
80                         "mcdeinterlace",            // internal name (must be uniq!)
81                        QT_TRANSLATE_NOOP("mcdeint", "MCDeint"),            // Display name
82                        QT_TRANSLATE_NOOP("mcdeint", "Motion compensation deinterlacer. Ported from MPlayer.") // Description
83                     );
84 
85 //********** Register chunk ************
86 
87 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);
88 
89 
90 /**
91     \fn getCoupledConf
92     \brief Return our current configuration as couple name=value
93 */
getCoupledConf(CONFcouple ** couples)94 bool         AVDMVideoMCDeint::getCoupledConf(CONFcouple **couples)
95 {
96       return ADM_paramSave(couples, mcdeint_param,&_param);
97 }
98 
setCoupledConf(CONFcouple * couples)99 void AVDMVideoMCDeint::setCoupledConf(CONFcouple *couples)
100 {
101     ADM_paramLoad(couples, mcdeint_param, &_param);
102 }
103 
104 /**
105     \fn getConfiguration
106     \brief Return current setting as a string
107 */
getConfiguration(void)108 const char *AVDMVideoMCDeint::getConfiguration(void)
109 {
110     static char conf[256];
111     snprintf(conf,255,"MC deinterlacer : Mode %d, qp %d, parity %d ",_param.mode,_param.qp,_param.initial_parity);
112     return conf;
113 }
114 /**
115      \fn configure
116 */
configure()117 bool AVDMVideoMCDeint::configure()
118 {
119 
120    diaMenuEntry menuMode[4]={{0,QT_TRANSLATE_NOOP("mcdeint","Fast"),NULL},
121                              {1,QT_TRANSLATE_NOOP("mcdeint","Medium"),NULL},
122                              {2,QT_TRANSLATE_NOOP("mcdeint","Slow iterative motion search"),NULL},
123                              {3,QT_TRANSLATE_NOOP("mcdeint","Extra slow (same as 3+multiple reference frames)"),NULL}
124                           };
125 
126     diaElemMenu     menu1(&(_param.mode),QT_TRANSLATE_NOOP("mcdeint","_Mode:"), 4,menuMode);
127     diaElemToggle     menu2(&(_param.initial_parity),QT_TRANSLATE_NOOP("mcdeint","Bottom :"));
128     diaElemUInteger qp(&(_param.qp),QT_TRANSLATE_NOOP("mcdeint","_Qp:"),1,60);
129 
130     diaElem *elems[3]={&menu1,&menu2,&qp};
131 
132     return  diaFactoryRun(QT_TRANSLATE_NOOP("mcdeint","mcDeinterlace"),3,elems);
133 
134 }
135 /**
136     \fn ctor
137 */
AVDMVideoMCDeint(ADM_coreVideoFilter * in,CONFcouple * setup)138 AVDMVideoMCDeint::AVDMVideoMCDeint( ADM_coreVideoFilter *in,CONFcouple *setup)
139 : ADM_coreVideoFilterCached(4,in,setup)
140 {
141 	 if(!setup || !ADM_paramLoad(setup,mcdeint_param,&_param))
142     {
143         // Default value
144          _param.mode=0;
145          _param.qp=1;
146          _param.initial_parity=0;
147 
148     }
149     init();
150 
151 }
152 /**
153     \fn dtor
154 */
~AVDMVideoMCDeint()155 AVDMVideoMCDeint::~AVDMVideoMCDeint()
156 {
157       cleanup();
158 }
159 
160 
161 /**
162     \fn getNextFrame
163 */
getNextFrame(uint32_t * fn,ADMImage * image)164 bool         AVDMVideoMCDeint::getNextFrame(uint32_t *fn,ADMImage *image)
165 {
166 
167 ADMImage *curImage;
168 char txt[256];
169 uint32_t frame=nextFrame++;
170             *fn=frame;
171             curImage=vidCache->getImage(frame);
172             if(!curImage)
173             {
174                     printf("MCDeint : error getting frame\n");
175                     return 0;
176             }
177 
178                   // Prepare to call filter...
179               uint8_t *dplanes[3],*splanes[3];
180               int dstride[3],sstride[3];
181               for(int i=0;i<3;i++)
182                 {
183                     ADM_PLANE plane=(ADM_PLANE)i;
184 
185                     splanes[i]=curImage->GetReadPtr(plane);
186                     sstride[i]=curImage->GetPitch(plane);
187 
188                     dplanes[i]=image->GetWritePtr(plane);
189                     dstride[i]=image->GetPitch(plane);
190 
191                 }
192 
193               filter(&priv, dplanes, splanes, dstride, sstride, info.width, info.height);
194               image->copyInfo(curImage);
195               vidCache->unlockAll();
196         return 1;
197 }
198 /**
199     \fn init
200 */
init(void)201 uint8_t AVDMVideoMCDeint::init( void )
202 {
203   memset(&priv,0,sizeof(priv));
204   int i;
205 
206   AVCodec *enc= avcodec_find_encoder(CODEC_ID_SNOW);
207   ADM_assert(enc);
208 
209         for(i=0; i<3; i++)
210         {
211             AVCodecContext *avctx_enc;
212             avctx_enc=     priv.avctx_enc= avcodec_alloc_context();
213             avctx_enc->width = info.width;
214             avctx_enc->height = info.height;
215             avctx_enc->time_base= (AVRational){1,25};  // meaningless
216             avctx_enc->gop_size = 300;
217             avctx_enc->max_b_frames= 0;
218             avctx_enc->pix_fmt = PIX_FMT_YUV420P;
219             avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
220             avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
221             avctx_enc->global_quality= 1;
222             avctx_enc->flags2= CODEC_FLAG2_MEMC_ONLY;
223             avctx_enc->me_cmp=
224             avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
225             avctx_enc->mb_cmp= FF_CMP_SSE;
226 
227             switch(_param.mode)
228             {
229             case 3:
230                 avctx_enc->refs= 3;
231             case 2:
232                 avctx_enc->me_method= ME_ITER;
233             case 1:
234                 avctx_enc->flags |= CODEC_FLAG_4MV;
235                 avctx_enc->dia_size=2;
236 //                avctx_enc->mb_decision = MB_DECISSION_RD;
237             case 0:
238                 avctx_enc->flags |= CODEC_FLAG_QPEL;
239             }
240 
241             avcodec_open(avctx_enc, enc);
242 
243         }
244         priv.frame= av_frame_alloc();
245 
246         priv.outbuf_size= info.width*info.height*10;
247         priv.outbuf= (uint8_t *)ADM_alloc(priv.outbuf_size);
248         priv.parity=_param.initial_parity;
249   return 1;
250 }
251 /**
252     \fn cleanup
253 */
cleanup(void)254 uint8_t AVDMVideoMCDeint::cleanup( void )
255 {
256   //
257    avcodec_close(priv.avctx_enc);
258    av_free(priv.avctx_enc);
259    ADM_dezalloc(priv.outbuf);
260    memset(&priv,0,sizeof(priv));
261   return 1;
262 }
263 
264 
265 /*
266 Known Issues:
267 * The motion estimation is somewhat at the mercy of the input, if the input
268   frames are created purely based on spatial interpolation then for example
269   a thin black line or another random and not interpolateable pattern
270   will cause problems
271   Note: completly ignoring the "unavailable" lines during motion estimation
272   didnt look any better, so the most obvious solution would be to improve
273   tfields or penalize problematic motion vectors ...
274 
275 * If non iterative ME is used then snow currently ignores the OBMC window
276   and as a result sometimes creates artifacts
277 
278 * only past frames are used, we should ideally use future frames too, something
279   like filtering the whole movie in forward and then backward direction seems
280   like a interresting idea but the current filter framework is FAR from
281   supporting such things
282 
283 * combining the motion compensated image with the input image also isnt
284   as trivial as it seems, simple blindly taking even lines from one and
285   odd ones from the other doesnt work at all as ME/MC sometimes simple
286   has nothing in the previous frames which matches the current, the current
287   algo has been found by trial and error and almost certainly can be
288   improved ...
289 */
290 
291 
292 
293 #define MIN(a,b) ((a) > (b) ? (b) : (a))
294 #define MAX(a,b) ((a) < (b) ? (b) : (a))
295 #define ABS(a) ((a) > 0 ? (a) : (-(a)))
296 
297 //===========================================================================//
298 
299 
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)300 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){
301     int x, y, i;
302     int out_size;
303 
304     for(i=0; i<3; i++){
305         p->frame->data[i]= src[i];
306         p->frame->linesize[i]= src_stride[i];
307     }
308 
309     p->avctx_enc->me_cmp=
310     p->avctx_enc->me_sub_cmp= FF_CMP_SAD /*| (p->parity ? FF_CMP_ODD : FF_CMP_EVEN)*/;
311     p->frame->quality= p->qp*FF_QP2LAMBDA;
312     out_size = avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->frame);
313     p->frame_dec = p->avctx_enc->coded_frame;
314 
315     for(i=0; i<3; i++){
316         int is_chroma= !!i;
317         int w= width >>is_chroma;
318         int h= height>>is_chroma;
319         int fils= p->frame_dec->linesize[i];
320         int srcs= src_stride[i];
321 
322         for(y=0; y<h; y++){
323             if((y ^ p->parity) & 1){
324                 for(x=0; x<w; x++){
325                     if((x-2)+(y-1)*w>=0 && (x+2)+(y+1)*w<w*h){ //FIXME either alloc larger images or optimize this
326                         uint8_t *filp= &p->frame_dec->data[i][x + y*fils];
327                         uint8_t *srcp= &src[i][x + y*srcs];
328                         int diff0= filp[-fils] - srcp[-srcs];
329                         int diff1= filp[+fils] - srcp[+srcs];
330                         int spatial_score= ABS(srcp[-srcs-1] - srcp[+srcs-1])
331                                           +ABS(srcp[-srcs  ] - srcp[+srcs  ])
332                                           +ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1;
333                         int temp= filp[0];
334 
335 #define CHECK(j)\
336     {   int score= ABS(srcp[-srcs-1+j] - srcp[+srcs-1-j])\
337                  + ABS(srcp[-srcs  +j] - srcp[+srcs  -j])\
338                  + ABS(srcp[-srcs+1+j] - srcp[+srcs+1-j]);\
339         if(score < spatial_score){\
340             spatial_score= score;\
341             diff0= filp[-fils+j] - srcp[-srcs+j];\
342             diff1= filp[+fils-j] - srcp[+srcs-j];
343 
344                         CHECK(-1) CHECK(-2) }} }}
345                         CHECK( 1) CHECK( 2) }} }}
346 #if 0
347                         if((diff0 ^ diff1) > 0){
348                             int mindiff= ABS(diff0) > ABS(diff1) ? diff1 : diff0;
349                             temp-= mindiff;
350                         }
351 #elif 1
352                         if(diff0 + diff1 > 0)
353                             temp-= (diff0 + diff1 - ABS( ABS(diff0) - ABS(diff1) )/2)/2;
354                         else
355                             temp-= (diff0 + diff1 + ABS( ABS(diff0) - ABS(diff1) )/2)/2;
356 #else
357                         temp-= (diff0 + diff1)/2;
358 #endif
359 #if 1
360                         filp[0]=
361                         dst[i][x + y*dst_stride[i]]= temp > 255U ? ~(temp>>31) : temp;
362 #else
363                         dst[i][x + y*dst_stride[i]]= filp[0];
364                         filp[0]= temp > 255U ? ~(temp>>31) : temp;
365 #endif
366                     }else
367                         dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
368                 }
369             }
370         }
371         for(y=0; y<h; y++){
372             if(!((y ^ p->parity) & 1)){
373                 for(x=0; x<w; x++){
374 #if 1
375                     p->frame_dec->data[i][x + y*fils]=
376                     dst[i][x + y*dst_stride[i]]= src[i][x + y*srcs];
377 #else
378                     dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
379                     p->frame_dec->data[i][x + y*fils]= src[i][x + y*srcs];
380 #endif
381                 }
382             }
383         }
384     }
385     p->parity ^= 1;
386 
387 }
388 
389 //EOF
390