~ubuntu-dev/mplayer/ubuntu-feisty

« back to all changes in this revision

Viewing changes to libmpcodecs/vf_mcdeint.c

  • Committer: Reinhard Tartler
  • Date: 2006-07-08 08:47:54 UTC
  • Revision ID: siretart@tauware.de-20060708084754-c3ff228cc9c2d8de
upgrade to pre8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
 
3
 
 
4
    This program is free software; you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation; either version 2 of the License, or
 
7
    (at your option) any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 
 
14
    You should have received a copy of the GNU General Public License
 
15
    along with this program; if not, write to the Free Software
 
16
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 
17
*/
 
18
 
 
19
 
 
20
/*
 
21
Known Issues:
 
22
* The motion estimation is somewhat at the mercy of the input, if the input
 
23
  frames are created purely based on spatial interpolation then for example
 
24
  a thin black line or another random and not interpolateable pattern
 
25
  will cause problems
 
26
  Note: completly ignoring the "unavailable" lines during motion estimation 
 
27
  didnt look any better, so the most obvious solution would be to improve
 
28
  tfields or penalize problematic motion vectors ...
 
29
 
 
30
* If non iterative ME is used then snow currently ignores the OBMC window
 
31
  and as a result sometimes creates artifacts
 
32
 
 
33
* only past frames are used, we should ideally use future frames too, something
 
34
  like filtering the whole movie in forward and then backward direction seems 
 
35
  like a interresting idea but the current filter framework is FAR from
 
36
  supporting such things
 
37
 
 
38
* combining the motion compensated image with the input image also isnt
 
39
  as trivial as it seems, simple blindly taking even lines from one and
 
40
  odd ones from the other doesnt work at all as ME/MC sometimes simple
 
41
  has nothing in the previous frames which matches the current, the current
 
42
  algo has been found by trial and error and almost certainly can be
 
43
  improved ...
 
44
*/
 
45
 
 
46
#include <stdio.h>
 
47
#include <stdlib.h>
 
48
#include <string.h>
 
49
#include <inttypes.h>
 
50
#include <math.h>
 
51
 
 
52
#include "config.h"
 
53
 
 
54
#include "mp_msg.h"
 
55
#include "cpudetect.h"
 
56
 
 
57
#include "libavcodec/avcodec.h"
 
58
#include "libavcodec/dsputil.h"
 
59
 
 
60
#ifdef HAVE_MALLOC_H
 
61
#include <malloc.h>
 
62
#endif
 
63
 
 
64
#include "img_format.h"
 
65
#include "mp_image.h"
 
66
#include "vf.h"
 
67
#include "libvo/fastmemcpy.h"
 
68
 
 
69
#define MIN(a,b) ((a) > (b) ? (b) : (a))
 
70
#define MAX(a,b) ((a) < (b) ? (b) : (a))
 
71
#define ABS(a) ((a) > 0 ? (a) : (-(a)))
 
72
 
 
73
//===========================================================================//
 
74
 
 
75
struct vf_priv_s {
 
76
    int mode;
 
77
    int qp;
 
78
    int parity;
 
79
#if 0
 
80
    int temp_stride[3];
 
81
    uint8_t *src[3];
 
82
    int16_t *temp[3];
 
83
#endif
 
84
    int outbuf_size;
 
85
    uint8_t *outbuf;
 
86
    AVCodecContext *avctx_enc;
 
87
    AVFrame *frame;
 
88
    AVFrame *frame_dec;
 
89
};
 
90
 
 
91
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){
 
92
    int x, y, i;
 
93
    int out_size;
 
94
 
 
95
    for(i=0; i<3; i++){
 
96
        p->frame->data[i]= src[i];
 
97
        p->frame->linesize[i]= src_stride[i];
 
98
    }
 
99
 
 
100
    p->avctx_enc->me_cmp=
 
101
    p->avctx_enc->me_sub_cmp= FF_CMP_SAD /*| (p->parity ? FF_CMP_ODD : FF_CMP_EVEN)*/;
 
102
    p->frame->quality= p->qp*FF_QP2LAMBDA;
 
103
    out_size = avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->frame);
 
104
    p->frame_dec = p->avctx_enc->coded_frame;
 
105
 
 
106
    for(i=0; i<3; i++){
 
107
        int is_chroma= !!i;
 
108
        int w= width >>is_chroma;
 
109
        int h= height>>is_chroma;
 
110
        int fils= p->frame_dec->linesize[i];
 
111
        int srcs= src_stride[i];
 
112
 
 
113
        for(y=0; y<h; y++){
 
114
            if((y ^ p->parity) & 1){
 
115
                for(x=0; x<w; x++){
 
116
                    if((x-2)+(y-1)*w>=0 && (x+2)+(y+1)*w<w*h){ //FIXME either alloc larger images or optimize this
 
117
                        uint8_t *filp= &p->frame_dec->data[i][x + y*fils];
 
118
                        uint8_t *srcp= &src[i][x + y*srcs];
 
119
                        int diff0= filp[-fils] - srcp[-srcs];
 
120
                        int diff1= filp[+fils] - srcp[+srcs];
 
121
                        int spatial_score= ABS(srcp[-srcs-1] - srcp[+srcs-1])
 
122
                                          +ABS(srcp[-srcs  ] - srcp[+srcs  ])
 
123
                                          +ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1;
 
124
                        int temp= filp[0];
 
125
 
 
126
#define CHECK(j)\
 
127
    {   int score= ABS(srcp[-srcs-1+j] - srcp[+srcs-1-j])\
 
128
                 + ABS(srcp[-srcs  +j] - srcp[+srcs  -j])\
 
129
                 + ABS(srcp[-srcs+1+j] - srcp[+srcs+1-j]);\
 
130
        if(score < spatial_score){\
 
131
            spatial_score= score;\
 
132
            diff0= filp[-fils+j] - srcp[-srcs+j];\
 
133
            diff1= filp[+fils-j] - srcp[+srcs-j];
 
134
 
 
135
                        CHECK(-1) CHECK(-2) }} }}
 
136
                        CHECK( 1) CHECK( 2) }} }}
 
137
#if 0
 
138
                        if((diff0 ^ diff1) > 0){
 
139
                            int mindiff= ABS(diff0) > ABS(diff1) ? diff1 : diff0;
 
140
                            temp-= mindiff;
 
141
                        }
 
142
#elif 1
 
143
                        if(diff0 + diff1 > 0)
 
144
                            temp-= (diff0 + diff1 - ABS( ABS(diff0) - ABS(diff1) )/2)/2;
 
145
                        else
 
146
                            temp-= (diff0 + diff1 + ABS( ABS(diff0) - ABS(diff1) )/2)/2;
 
147
#else
 
148
                        temp-= (diff0 + diff1)/2;
 
149
#endif
 
150
#if 1
 
151
                        filp[0]=
 
152
                        dst[i][x + y*dst_stride[i]]= temp > 255U ? ~(temp>>31) : temp;
 
153
#else
 
154
                        dst[i][x + y*dst_stride[i]]= filp[0];
 
155
                        filp[0]= temp > 255U ? ~(temp>>31) : temp;
 
156
#endif
 
157
                    }else
 
158
                        dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
 
159
                }
 
160
            }
 
161
        }
 
162
        for(y=0; y<h; y++){
 
163
            if(!((y ^ p->parity) & 1)){
 
164
                for(x=0; x<w; x++){
 
165
#if 1
 
166
                    p->frame_dec->data[i][x + y*fils]=
 
167
                    dst[i][x + y*dst_stride[i]]= src[i][x + y*srcs];
 
168
#else
 
169
                    dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils];
 
170
                    p->frame_dec->data[i][x + y*fils]= src[i][x + y*srcs];
 
171
#endif
 
172
                }
 
173
            }
 
174
        }
 
175
    }
 
176
    p->parity ^= 1;
 
177
 
 
178
}
 
179
 
 
180
static int config(struct vf_instance_s* vf,
 
181
        int width, int height, int d_width, int d_height,
 
182
        unsigned int flags, unsigned int outfmt){
 
183
        int i;
 
184
        AVCodec *enc= avcodec_find_encoder(CODEC_ID_SNOW);
 
185
 
 
186
        for(i=0; i<3; i++){
 
187
            AVCodecContext *avctx_enc;
 
188
#if 0
 
189
            int is_chroma= !!i;
 
190
            int w= ((width  + 31) & (~31))>>is_chroma;
 
191
            int h= ((height + 31) & (~31))>>is_chroma;
 
192
 
 
193
            vf->priv->temp_stride[i]= w;
 
194
            vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t));
 
195
            vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t));
 
196
#endif
 
197
            avctx_enc=
 
198
            vf->priv->avctx_enc= avcodec_alloc_context();
 
199
            avctx_enc->width = width;
 
200
            avctx_enc->height = height;
 
201
            avctx_enc->time_base= (AVRational){1,25};  // meaningless
 
202
            avctx_enc->gop_size = 300;
 
203
            avctx_enc->max_b_frames= 0;
 
204
            avctx_enc->pix_fmt = PIX_FMT_YUV420P;
 
205
            avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
 
206
            avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
 
207
            avctx_enc->global_quality= 1;
 
208
            avctx_enc->flags2= CODEC_FLAG2_MEMC_ONLY;
 
209
            avctx_enc->me_cmp=
 
210
            avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
 
211
            avctx_enc->mb_cmp= FF_CMP_SSE;
 
212
 
 
213
            switch(vf->priv->mode){
 
214
            case 3:
 
215
                avctx_enc->refs= 3;
 
216
            case 2:
 
217
                avctx_enc->me_method= ME_ITER;
 
218
            case 1:
 
219
                avctx_enc->flags |= CODEC_FLAG_4MV;
 
220
                avctx_enc->dia_size=2;
 
221
//                avctx_enc->mb_decision = MB_DECISSION_RD;
 
222
            case 0:
 
223
                avctx_enc->flags |= CODEC_FLAG_QPEL;
 
224
            }
 
225
 
 
226
            avcodec_open(avctx_enc, enc);
 
227
 
 
228
        }
 
229
        vf->priv->frame= avcodec_alloc_frame();
 
230
 
 
231
        vf->priv->outbuf_size= width*height*10;
 
232
        vf->priv->outbuf= malloc(vf->priv->outbuf_size);
 
233
 
 
234
        return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
 
235
}
 
236
 
 
237
static void get_image(struct vf_instance_s* vf, mp_image_t *mpi){
 
238
    if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
 
239
return; //caused problems, dunno why
 
240
    // ok, we can do pp in-place (or pp disabled):
 
241
    vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
 
242
        mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height);
 
243
    mpi->planes[0]=vf->dmpi->planes[0];
 
244
    mpi->stride[0]=vf->dmpi->stride[0];
 
245
    mpi->width=vf->dmpi->width;
 
246
    if(mpi->flags&MP_IMGFLAG_PLANAR){
 
247
        mpi->planes[1]=vf->dmpi->planes[1];
 
248
        mpi->planes[2]=vf->dmpi->planes[2];
 
249
        mpi->stride[1]=vf->dmpi->stride[1];
 
250
        mpi->stride[2]=vf->dmpi->stride[2];
 
251
    }
 
252
    mpi->flags|=MP_IMGFLAG_DIRECT;
 
253
}
 
254
 
 
255
static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts){
 
256
    mp_image_t *dmpi;
 
257
 
 
258
    if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
 
259
        // no DR, so get a new image! hope we'll get DR buffer:
 
260
        dmpi=vf_get_image(vf->next,mpi->imgfmt,
 
261
            MP_IMGTYPE_TEMP,
 
262
            MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
 
263
            mpi->width,mpi->height);
 
264
        vf_clone_mpi_attributes(dmpi, mpi);
 
265
    }else{
 
266
        dmpi=vf->dmpi;
 
267
    }
 
268
 
 
269
    filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h);
 
270
 
 
271
    return vf_next_put_image(vf,dmpi, pts);
 
272
}
 
273
 
 
274
static void uninit(struct vf_instance_s* vf){
 
275
    if(!vf->priv) return;
 
276
 
 
277
#if 0
 
278
    for(i=0; i<3; i++){
 
279
        if(vf->priv->temp[i]) free(vf->priv->temp[i]);
 
280
        vf->priv->temp[i]= NULL;
 
281
        if(vf->priv->src[i]) free(vf->priv->src[i]);
 
282
        vf->priv->src[i]= NULL;
 
283
    }
 
284
#endif
 
285
    av_freep(&vf->priv->avctx_enc);
 
286
 
 
287
    free(vf->priv->outbuf);
 
288
    free(vf->priv);
 
289
    vf->priv=NULL;
 
290
}
 
291
 
 
292
//===========================================================================//
 
293
static int query_format(struct vf_instance_s* vf, unsigned int fmt){
 
294
    switch(fmt){
 
295
        case IMGFMT_YV12:
 
296
        case IMGFMT_I420:
 
297
        case IMGFMT_IYUV:
 
298
        case IMGFMT_Y800:
 
299
        case IMGFMT_Y8:
 
300
            return vf_next_query_format(vf,fmt);
 
301
    }
 
302
    return 0;
 
303
}
 
304
 
 
305
static int open(vf_instance_t *vf, char* args){
 
306
 
 
307
    vf->config=config;
 
308
    vf->put_image=put_image;
 
309
    vf->get_image=get_image;
 
310
    vf->query_format=query_format;
 
311
    vf->uninit=uninit;
 
312
    vf->priv=malloc(sizeof(struct vf_priv_s));
 
313
    memset(vf->priv, 0, sizeof(struct vf_priv_s));
 
314
 
 
315
    avcodec_init();
 
316
    avcodec_register_all();
 
317
 
 
318
    vf->priv->mode=0;
 
319
    vf->priv->parity= -1;
 
320
    vf->priv->qp=1;
 
321
 
 
322
    if (args) sscanf(args, "%d:%d:%d", &vf->priv->mode, &vf->priv->parity, &vf->priv->qp);
 
323
 
 
324
    return 1;
 
325
}
 
326
 
 
327
vf_info_t vf_info_mcdeint = {
 
328
    "motion compensating deinterlacer",
 
329
    "mcdeint",
 
330
    "Michael Niedermayer",
 
331
    "",
 
332
    open,
 
333
    NULL
 
334
};