]> git.sesse.net Git - ffmpeg/blob - libavfilter/libmpcodecs/vf_mcdeint.c
lavf/matroskaenc: return an error for unsupported types.
[ffmpeg] / libavfilter / libmpcodecs / vf_mcdeint.c
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
87     int outbuf_size;
88     uint8_t *outbuf;
89     AVCodecContext *avctx_enc;
90     AVFrame *frame;
91     AVFrame *frame_dec;
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);
106     p->frame_dec = p->avctx_enc->coded_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;
186         AVCodec *enc= avcodec_find_encoder(AV_CODEC_ID_SNOW);
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;
208             avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
209             avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
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,
265             MP_IMGTYPE_TEMP,
266             MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
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;
317     vf->query_format=query_format;
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
333 const vf_info_t ff_vf_info_mcdeint = {
334     "motion compensating deinterlacer",
335     "mcdeint",
336     "Michael Niedermayer",
337     "",
338     vf_open,
339     NULL
340 };