~ubuntu-branches/ubuntu/hardy/avidemux/hardy

« back to all changes in this revision

Viewing changes to avidemux/ADM_video/ADM_vidMcDeint.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel T Chen
  • Date: 2006-12-15 17:13:20 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20061215171320-w79pvpehxx2fr217
Tags: 1:2.3.0-0.0ubuntu1
* Merge from debian-multimedia.org, remaining Ubuntu change:
  - desktop file,
  - no support for ccache and make -j.
* Closes Ubuntu: #69614.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <string.h>
 
27
#include <ADM_assert.h>
 
28
#include "ADM_lavcodec.h"
 
29
 
 
30
#include "config.h"
 
31
#include "fourcc.h"
 
32
#include "avio.hxx"
 
33
#include "config.h"
 
34
#include "avi_vars.h"
 
35
 
 
36
 
 
37
 
 
38
#include "ADM_toolkit/toolkit.hxx"
 
39
#include "ADM_editor/ADM_edit.hxx"
 
40
#include "ADM_video/ADM_genvideo.hxx"
 
41
 
 
42
#include "ADM_filter/video_filters.h"
 
43
#include "ADM_video/ADM_cache.h"
 
44
 
 
45
#include "ADM_video/ADM_vidMcDeint_param.h"
 
46
 
 
47
static FILTER_PARAM mcDeintParam={3,{"mode","qp","initial_parity"}};
 
48
 
 
49
struct vf_priv_s {
 
50
    int mode;
 
51
    int qp;
 
52
    int parity;
 
53
#if 0
 
54
    int temp_stride[3];
 
55
    uint8_t *src[3];
 
56
    int16_t *temp[3];
 
57
#endif
 
58
    int outbuf_size;
 
59
    uint8_t *outbuf;
 
60
    AVCodecContext *avctx_enc;
 
61
    AVFrame *frame;
 
62
    AVFrame *frame_dec;
 
63
};
 
64
 
 
65
 
 
66
class  AVDMVideoMCDeint:public AVDMGenericVideoStream
 
67
 {
 
68
 
 
69
 protected:
 
70
                MCDEINT_PARAM *_param;
 
71
                VideoCache      *vidCache;
 
72
                uint8_t         init();
 
73
                uint8_t         cleanup();
 
74
                vf_priv_s       priv;
 
75
 public:
 
76
    virtual char          *printConf(void) ;
 
77
                  AVDMVideoMCDeint(  AVDMGenericVideoStream *in,CONFcouple *setup);
 
78
                 ~AVDMVideoMCDeint();
 
79
 virtual uint8_t getFrameNumberNoAlloc(uint32_t frame, uint32_t *len,
 
80
                            ADMImage *data,uint32_t *flags);
 
81
 
 
82
  virtual uint8_t configure( AVDMGenericVideoStream *instream);
 
83
  virtual uint8_t getCoupledConf( CONFcouple **couples);
 
84
 }     ;
 
85
 
 
86
SCRIPT_CREATE(mcdeint_script,AVDMVideoMCDeint,mcDeintParam);
 
87
BUILD_CREATE(mcdeint_create,AVDMVideoMCDeint);
 
88
 
 
89
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);
 
90
uint8_t DIA_mcDeint(MCDEINT_PARAM *param);
 
91
 
 
92
 
 
93
char *AVDMVideoMCDeint::printConf( void )
 
94
{
 
95
static char buf[50];
 
96
 
 
97
        sprintf((char *)buf," MC deinterlacer : Mode %d, qp %d, parity %d ",_param->mode,_param->qp,_param->initial_parity);
 
98
        return buf;
 
99
}
 
100
uint8_t AVDMVideoMCDeint::configure(AVDMGenericVideoStream * instream)
 
101
{
 
102
    if( DIA_mcDeint(_param))
 
103
    {
 
104
      cleanup();
 
105
      init();
 
106
      return 1;
 
107
    }
 
108
    return 0;
 
109
}
 
110
uint8_t AVDMVideoMCDeint::getCoupledConf( CONFcouple **couples)
 
111
{
 
112
 
 
113
                        ADM_assert(_param);
 
114
                        *couples=new CONFcouple(3);
 
115
 
 
116
#define CSET(x)  (*couples)->setCouple((char *)#x,(_param->x))
 
117
                CSET(mode);
 
118
                CSET(qp);
 
119
                CSET(initial_parity);
 
120
                return 1;
 
121
 
 
122
}
 
123
 
 
124
//_______________________________________________________________
 
125
AVDMVideoMCDeint::AVDMVideoMCDeint(AVDMGenericVideoStream *in,CONFcouple *couples)
 
126
{
 
127
 
 
128
        _in=in;
 
129
        memcpy(&_info,_in->getInfo(),sizeof(_info));
 
130
        _param=NEW(MCDEINT_PARAM);
 
131
        vidCache=new VideoCache(4,_in);
 
132
        if(couples)
 
133
        {
 
134
                GET(mode);
 
135
                GET(qp);
 
136
                GET(initial_parity);
 
137
        }
 
138
        else
 
139
        {
 
140
                _param->mode=0;
 
141
                _param->qp=1;
 
142
                _param->initial_parity=0;
 
143
                
 
144
        }
 
145
        _info.encoding=1;
 
146
        init();
 
147
}
 
148
 
 
149
 
 
150
 
 
151
// ___ destructor_____________
 
152
AVDMVideoMCDeint::~AVDMVideoMCDeint()
 
153
{
 
154
      cleanup();
 
155
      delete  vidCache;
 
156
      delete _param;
 
157
      _param=NULL;
 
158
      vidCache=NULL;
 
159
}
 
160
uint8_t AVDMVideoMCDeint::getFrameNumberNoAlloc(uint32_t frame,
 
161
                                uint32_t *len,
 
162
                                ADMImage *data,
 
163
                                uint32_t *flags)
 
164
{
 
165
                        if(frame>=_info.nb_frames) 
 
166
                        {
 
167
                                printf("MPdelogo : Filter : out of bound!\n");
 
168
                                return 0;
 
169
                        }
 
170
        
 
171
                        ADM_assert(_param);
 
172
 
 
173
ADMImage *curImage;
 
174
char txt[256];
 
175
                        curImage=vidCache->getImage(frame);
 
176
                        if(!curImage)
 
177
                        {
 
178
                                printf("MCDeint : error getting frame\n");
 
179
                                return 0;
 
180
                        }
 
181
              
 
182
                      // Prepare to call filter...
 
183
                  uint8_t *dplanes[3],*splanes[3];
 
184
                  int dstride[3],sstride[3];
 
185
 
 
186
                  dstride[0]=sstride[0]=_info.width;
 
187
                  dstride[2]=sstride[2]=dstride[1]=sstride[1]=_info.width>>1;
 
188
 
 
189
                  splanes[0]=YPLANE(curImage);
 
190
                  splanes[1]=UPLANE(curImage);
 
191
                  splanes[2]=VPLANE(curImage);
 
192
 
 
193
                  dplanes[0]=YPLANE(data);
 
194
                  dplanes[1]=UPLANE(data);
 
195
                  dplanes[2]=VPLANE(data);
 
196
 
 
197
 
 
198
                  filter(&priv, dplanes, splanes, dstride, sstride, _info.width, _info.height);
 
199
                  vidCache->unlockAll();
 
200
        return 1;
 
201
}
 
202
uint8_t AVDMVideoMCDeint::init( void )
 
203
{
 
204
  memset(&priv,0,sizeof(priv));
 
205
  int i;
 
206
  
 
207
  AVCodec *enc= avcodec_find_encoder(CODEC_ID_SNOW);
 
208
  ADM_assert(enc);
 
209
 
 
210
        for(i=0; i<3; i++)
 
211
        {
 
212
            AVCodecContext *avctx_enc;
 
213
            avctx_enc=     priv.avctx_enc= avcodec_alloc_context();
 
214
            avctx_enc->width = _info.width;
 
215
            avctx_enc->height = _info.height;
 
216
            avctx_enc->time_base= (AVRational){1,25};  // meaningless
 
217
            avctx_enc->gop_size = 300;
 
218
            avctx_enc->max_b_frames= 0;
 
219
            avctx_enc->pix_fmt = PIX_FMT_YUV420P;
 
220
            avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
 
221
            avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
 
222
            avctx_enc->global_quality= 1;
 
223
            avctx_enc->flags2= CODEC_FLAG2_MEMC_ONLY;
 
224
            avctx_enc->me_cmp=
 
225
            avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
 
226
            avctx_enc->mb_cmp= FF_CMP_SSE;
 
227
 
 
228
            switch(_param->mode)
 
229
            {
 
230
            case 3:
 
231
                avctx_enc->refs= 3;
 
232
            case 2:
 
233
                avctx_enc->me_method= ME_ITER;
 
234
            case 1:
 
235
                avctx_enc->flags |= CODEC_FLAG_4MV;
 
236
                avctx_enc->dia_size=2;
 
237
//                avctx_enc->mb_decision = MB_DECISSION_RD;
 
238
            case 0:
 
239
                avctx_enc->flags |= CODEC_FLAG_QPEL;
 
240
            }
 
241
 
 
242
            avcodec_open(avctx_enc, enc);
 
243
 
 
244
        }
 
245
        priv.frame= avcodec_alloc_frame();
 
246
 
 
247
        priv.outbuf_size= _info.width*_info.height*10;
 
248
        priv.outbuf= (uint8_t *)ADM_alloc(priv.outbuf_size);
 
249
        priv.parity=_param->initial_parity;
 
250
  return 1;
 
251
}
 
252
uint8_t AVDMVideoMCDeint::cleanup( void )
 
253
{
 
254
  //
 
255
   avcodec_close(priv.avctx_enc);
 
256
   av_free(priv.avctx_enc);
 
257
   ADM_dezalloc(priv.outbuf);
 
258
   memset(&priv,0,sizeof(priv));
 
259
  return 1;
 
260
}
 
261
 
 
262
 
 
263
/*
 
264
Known Issues:
 
265
* The motion estimation is somewhat at the mercy of the input, if the input
 
266
  frames are created purely based on spatial interpolation then for example
 
267
  a thin black line or another random and not interpolateable pattern
 
268
  will cause problems
 
269
  Note: completly ignoring the "unavailable" lines during motion estimation 
 
270
  didnt look any better, so the most obvious solution would be to improve
 
271
  tfields or penalize problematic motion vectors ...
 
272
 
 
273
* If non iterative ME is used then snow currently ignores the OBMC window
 
274
  and as a result sometimes creates artifacts
 
275
 
 
276
* only past frames are used, we should ideally use future frames too, something
 
277
  like filtering the whole movie in forward and then backward direction seems 
 
278
  like a interresting idea but the current filter framework is FAR from
 
279
  supporting such things
 
280
 
 
281
* combining the motion compensated image with the input image also isnt
 
282
  as trivial as it seems, simple blindly taking even lines from one and
 
283
  odd ones from the other doesnt work at all as ME/MC sometimes simple
 
284
  has nothing in the previous frames which matches the current, the current
 
285
  algo has been found by trial and error and almost certainly can be
 
286
  improved ...
 
287
*/
 
288
 
 
289
 
 
290
 
 
291
#define MIN(a,b) ((a) > (b) ? (b) : (a))
 
292
#define MAX(a,b) ((a) < (b) ? (b) : (a))
 
293
#define ABS(a) ((a) > 0 ? (a) : (-(a)))
 
294
 
 
295
//===========================================================================//
 
296
 
 
297
 
 
298
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){
 
299
    int x, y, i;
 
300
    int out_size;
 
301
 
 
302
    for(i=0; i<3; i++){
 
303
        p->frame->data[i]= src[i];
 
304
        p->frame->linesize[i]= src_stride[i];
 
305
    }
 
306
 
 
307
    p->avctx_enc->me_cmp=
 
308
    p->avctx_enc->me_sub_cmp= FF_CMP_SAD /*| (p->parity ? FF_CMP_ODD : FF_CMP_EVEN)*/;
 
309
    p->frame->quality= p->qp*FF_QP2LAMBDA;
 
310
    out_size = avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->frame);
 
311
    p->frame_dec = p->avctx_enc->coded_frame;
 
312
 
 
313
    for(i=0; i<3; i++){
 
314
        int is_chroma= !!i;
 
315
        int w= width >>is_chroma;
 
316
        int h= height>>is_chroma;
 
317
        int fils= p->frame_dec->linesize[i];
 
318
        int srcs= src_stride[i];
 
319
 
 
320
        for(y=0; y<h; y++){
 
321
            if((y ^ p->parity) & 1){
 
322
                for(x=0; x<w; x++){
 
323
                    if((x-2)+(y-1)*w>=0 && (x+2)+(y+1)*w<w*h){ //FIXME either alloc larger images or optimize this
 
324
                        uint8_t *filp= &p->frame_dec->data[i][x + y*fils];
 
325
                        uint8_t *srcp= &src[i][x + y*srcs];
 
326
                        int diff0= filp[-fils] - srcp[-srcs];
 
327
                        int diff1= filp[+fils] - srcp[+srcs];
 
328
                        int spatial_score= ABS(srcp[-srcs-1] - srcp[+srcs-1])
 
329
                                          +ABS(srcp[-srcs  ] - srcp[+srcs  ])
 
330
                                          +ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1;
 
331
                        int temp= filp[0];
 
332
 
 
333
#define CHECK(j)\
 
334
    {   int score= ABS(srcp[-srcs-1+j] - srcp[+srcs-1-j])\
 
335
                 + ABS(srcp[-srcs  +j] - srcp[+srcs  -j])\
 
336
                 + ABS(srcp[-srcs+1+j] - srcp[+srcs+1-j]);\
 
337
        if(score < spatial_score){\
 
338
            spatial_score= score;\
 
339
            diff0= filp[-fils+j] - srcp[-srcs+j];\
 
340
            diff1= filp[+fils-j] - srcp[+srcs-j];
 
341
 
 
342
                        CHECK(-1) CHECK(-2) }} }}
 
343
                        CHECK( 1) CHECK( 2) }} }}
 
344
#if 0
 
345
                        if((diff0 ^ diff1) > 0){
 
346
                            int mindiff= ABS(diff0) > ABS(diff1) ? diff1 : diff0;
 
347
                            temp-= mindiff;
 
348
                        }
 
349
#elif 1
 
350
                        if(diff0 + diff1 > 0)
 
351
                            temp-= (diff0 + diff1 - ABS( ABS(diff0) - ABS(diff1) )/2)/2;
 
352
                        else
 
353
                            temp-= (diff0 + diff1 + ABS( ABS(diff0) - ABS(diff1) )/2)/2;
 
354
#else
 
355
                        temp-= (diff0 + diff1)/2;
 
356
#endif
 
357
#if 1
 
358
                        filp[0]=
 
359
                        dst[i][x + y*dst_stride[i]]= temp > 255U ? ~(temp>>31) : temp;
 
360
#else
 
361
                        dst[i][x + y*dst_stride[i]]= filp[0];
 
362
                        filp[0]= temp > 255U ? ~(temp>>31) : temp;
 
363
#endif
 
364
                    }else
 
365
                        dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
 
366
                }
 
367
            }
 
368
        }
 
369
        for(y=0; y<h; y++){
 
370
            if(!((y ^ p->parity) & 1)){
 
371
                for(x=0; x<w; x++){
 
372
#if 1
 
373
                    p->frame_dec->data[i][x + y*fils]=
 
374
                    dst[i][x + y*dst_stride[i]]= src[i][x + y*srcs];
 
375
#else
 
376
                    dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
 
377
                    p->frame_dec->data[i][x + y*fils]= src[i][x + y*srcs];
 
378
#endif
 
379
                }
 
380
            }
 
381
        }
 
382
    }
 
383
    p->parity ^= 1;
 
384
 
 
385
}
 
386
#ifdef titititititi_II
 
387
static int config(struct vf_instance_s* vf,
 
388
        int width, int height, int d_width, int d_height,
 
389
        unsigned int flags, unsigned int outfmt){
 
390
        int i;
 
391
        AVCodec *enc= avcodec_find_encoder(CODEC_ID_SNOW);
 
392
 
 
393
        for(i=0; i<3; i++){
 
394
            AVCodecContext *avctx_enc;
 
395
#if 0
 
396
            int is_chroma= !!i;
 
397
            int w= ((width  + 31) & (~31))>>is_chroma;
 
398
            int h= ((height + 31) & (~31))>>is_chroma;
 
399
 
 
400
            vf->priv->temp_stride[i]= w;
 
401
            vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t));
 
402
            vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t));
 
403
#endif
 
404
            avctx_enc=
 
405
            vf->priv->avctx_enc= avcodec_alloc_context();
 
406
            avctx_enc->width = width;
 
407
            avctx_enc->height = height;
 
408
            avctx_enc->time_base= (AVRational){1,25};  // meaningless
 
409
            avctx_enc->gop_size = 300;
 
410
            avctx_enc->max_b_frames= 0;
 
411
            avctx_enc->pix_fmt = PIX_FMT_YUV420P;
 
412
            avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
 
413
            avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
 
414
            avctx_enc->global_quality= 1;
 
415
            avctx_enc->flags2= CODEC_FLAG2_MEMC_ONLY;
 
416
            avctx_enc->me_cmp=
 
417
            avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
 
418
            avctx_enc->mb_cmp= FF_CMP_SSE;
 
419
 
 
420
            switch(vf->priv->mode){
 
421
            case 3:
 
422
                avctx_enc->refs= 3;
 
423
            case 2:
 
424
                avctx_enc->me_method= ME_ITER;
 
425
            case 1:
 
426
                avctx_enc->flags |= CODEC_FLAG_4MV;
 
427
                avctx_enc->dia_size=2;
 
428
//                avctx_enc->mb_decision = MB_DECISSION_RD;
 
429
            case 0:
 
430
                avctx_enc->flags |= CODEC_FLAG_QPEL;
 
431
            }
 
432
 
 
433
            avcodec_open(avctx_enc, enc);
 
434
 
 
435
        }
 
436
        vf->priv->frame= avcodec_alloc_frame();
 
437
 
 
438
        vf->priv->outbuf_size= width*height*10;
 
439
        vf->priv->outbuf= malloc(vf->priv->outbuf_size);
 
440
 
 
441
        return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
 
442
}
 
443
 
 
444
static void get_image(struct vf_instance_s* vf, mp_image_t *mpi){
 
445
    if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
 
446
return; //caused problems, dunno why
 
447
    // ok, we can do pp in-place (or pp disabled):
 
448
    vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
 
449
        mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height);
 
450
    mpi->planes[0]=vf->dmpi->planes[0];
 
451
    mpi->stride[0]=vf->dmpi->stride[0];
 
452
    mpi->width=vf->dmpi->width;
 
453
    if(mpi->flags&MP_IMGFLAG_PLANAR){
 
454
        mpi->planes[1]=vf->dmpi->planes[1];
 
455
        mpi->planes[2]=vf->dmpi->planes[2];
 
456
        mpi->stride[1]=vf->dmpi->stride[1];
 
457
        mpi->stride[2]=vf->dmpi->stride[2];
 
458
    }
 
459
    mpi->flags|=MP_IMGFLAG_DIRECT;
 
460
}
 
461
 
 
462
static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts){
 
463
    mp_image_t *dmpi;
 
464
 
 
465
    if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
 
466
        // no DR, so get a new image! hope we'll get DR buffer:
 
467
        dmpi=vf_get_image(vf->next,mpi->imgfmt,
 
468
            MP_IMGTYPE_TEMP,
 
469
            MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
 
470
            mpi->width,mpi->height);
 
471
        vf_clone_mpi_attributes(dmpi, mpi);
 
472
    }else{
 
473
        dmpi=vf->dmpi;
 
474
    }
 
475
 
 
476
    filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h);
 
477
 
 
478
    return vf_next_put_image(vf,dmpi, pts);
 
479
}
 
480
 
 
481
static void uninit(struct vf_instance_s* vf){
 
482
    if(!vf->priv) return;
 
483
 
 
484
#if 0
 
485
    for(i=0; i<3; i++){
 
486
        if(vf->priv->temp[i]) free(vf->priv->temp[i]);
 
487
        vf->priv->temp[i]= NULL;
 
488
        if(vf->priv->src[i]) free(vf->priv->src[i]);
 
489
        vf->priv->src[i]= NULL;
 
490
    }
 
491
#endif
 
492
    av_freep(&vf->priv->avctx_enc);
 
493
 
 
494
    free(vf->priv->outbuf);
 
495
    free(vf->priv);
 
496
    vf->priv=NULL;
 
497
}
 
498
 
 
499
#endif
 
500
//EOF