]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_mp.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavfilter / vf_mp.c
1 /*
2  * Copyright (c) 2011 Michael Niedermayer
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg 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  * FFmpeg 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
17  * along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  * Parts of this file have been stolen from mplayer
21  */
22
23 /**
24  * @file
25  */
26
27 #include "avfilter.h"
28 #include "libavutil/avassert.h"
29 #include "libavutil/pixdesc.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/imgutils.h"
32
33 #include "libmpcodecs/vf.h"
34 #include "libmpcodecs/img_format.h"
35 #include "libmpcodecs/cpudetect.h"
36 #include "libmpcodecs/vd_ffmpeg.h"
37 #include "libmpcodecs/vf_scale.h"
38 #include "libmpcodecs/libvo/fastmemcpy.h"
39
40 #include "libswscale/swscale.h"
41
42
43 //FIXME maybe link the orig in
44 //XXX: identical pix_fmt must be following with each others
45 static const struct {
46     int fmt;
47     enum PixelFormat pix_fmt;
48 } conversion_map[] = {
49     {IMGFMT_ARGB, PIX_FMT_ARGB},
50     {IMGFMT_BGRA, PIX_FMT_BGRA},
51     {IMGFMT_BGR24, PIX_FMT_BGR24},
52     {IMGFMT_BGR16BE, PIX_FMT_RGB565BE},
53     {IMGFMT_BGR16LE, PIX_FMT_RGB565LE},
54     {IMGFMT_BGR15BE, PIX_FMT_RGB555BE},
55     {IMGFMT_BGR15LE, PIX_FMT_RGB555LE},
56     {IMGFMT_BGR12BE, PIX_FMT_RGB444BE},
57     {IMGFMT_BGR12LE, PIX_FMT_RGB444LE},
58     {IMGFMT_BGR8,  PIX_FMT_RGB8},
59     {IMGFMT_BGR4,  PIX_FMT_RGB4},
60     {IMGFMT_BGR1,  PIX_FMT_MONOBLACK},
61     {IMGFMT_RGB1,  PIX_FMT_MONOBLACK},
62     {IMGFMT_RG4B,  PIX_FMT_BGR4_BYTE},
63     {IMGFMT_BG4B,  PIX_FMT_RGB4_BYTE},
64     {IMGFMT_RGB48LE, PIX_FMT_RGB48LE},
65     {IMGFMT_RGB48BE, PIX_FMT_RGB48BE},
66     {IMGFMT_ABGR, PIX_FMT_ABGR},
67     {IMGFMT_RGBA, PIX_FMT_RGBA},
68     {IMGFMT_RGB24, PIX_FMT_RGB24},
69     {IMGFMT_RGB16BE, PIX_FMT_BGR565BE},
70     {IMGFMT_RGB16LE, PIX_FMT_BGR565LE},
71     {IMGFMT_RGB15BE, PIX_FMT_BGR555BE},
72     {IMGFMT_RGB15LE, PIX_FMT_BGR555LE},
73     {IMGFMT_RGB12BE, PIX_FMT_BGR444BE},
74     {IMGFMT_RGB12LE, PIX_FMT_BGR444LE},
75     {IMGFMT_RGB8,  PIX_FMT_BGR8},
76     {IMGFMT_RGB4,  PIX_FMT_BGR4},
77     {IMGFMT_BGR8,  PIX_FMT_PAL8},
78     {IMGFMT_YUY2,  PIX_FMT_YUYV422},
79     {IMGFMT_UYVY,  PIX_FMT_UYVY422},
80     {IMGFMT_NV12,  PIX_FMT_NV12},
81     {IMGFMT_NV21,  PIX_FMT_NV21},
82     {IMGFMT_Y800,  PIX_FMT_GRAY8},
83     {IMGFMT_Y8,    PIX_FMT_GRAY8},
84     {IMGFMT_YVU9,  PIX_FMT_YUV410P},
85     {IMGFMT_IF09,  PIX_FMT_YUV410P},
86     {IMGFMT_YV12,  PIX_FMT_YUV420P},
87     {IMGFMT_I420,  PIX_FMT_YUV420P},
88     {IMGFMT_IYUV,  PIX_FMT_YUV420P},
89     {IMGFMT_411P,  PIX_FMT_YUV411P},
90     {IMGFMT_422P,  PIX_FMT_YUV422P},
91     {IMGFMT_444P,  PIX_FMT_YUV444P},
92     {IMGFMT_440P,  PIX_FMT_YUV440P},
93
94     {IMGFMT_420A,  PIX_FMT_YUVA420P},
95
96     {IMGFMT_420P16_LE,  PIX_FMT_YUV420P16LE},
97     {IMGFMT_420P16_BE,  PIX_FMT_YUV420P16BE},
98     {IMGFMT_422P16_LE,  PIX_FMT_YUV422P16LE},
99     {IMGFMT_422P16_BE,  PIX_FMT_YUV422P16BE},
100     {IMGFMT_444P16_LE,  PIX_FMT_YUV444P16LE},
101     {IMGFMT_444P16_BE,  PIX_FMT_YUV444P16BE},
102
103     // YUVJ are YUV formats that use the full Y range and not just
104     // 16 - 235 (see colorspaces.txt).
105     // Currently they are all treated the same way.
106     {IMGFMT_YV12,  PIX_FMT_YUVJ420P},
107     {IMGFMT_422P,  PIX_FMT_YUVJ422P},
108     {IMGFMT_444P,  PIX_FMT_YUVJ444P},
109     {IMGFMT_440P,  PIX_FMT_YUVJ440P},
110
111     {IMGFMT_XVMC_MOCO_MPEG2, PIX_FMT_XVMC_MPEG2_MC},
112     {IMGFMT_XVMC_IDCT_MPEG2, PIX_FMT_XVMC_MPEG2_IDCT},
113     {IMGFMT_VDPAU_MPEG1,     PIX_FMT_VDPAU_MPEG1},
114     {IMGFMT_VDPAU_MPEG2,     PIX_FMT_VDPAU_MPEG2},
115     {IMGFMT_VDPAU_H264,      PIX_FMT_VDPAU_H264},
116     {IMGFMT_VDPAU_WMV3,      PIX_FMT_VDPAU_WMV3},
117     {IMGFMT_VDPAU_VC1,       PIX_FMT_VDPAU_VC1},
118     {IMGFMT_VDPAU_MPEG4,     PIX_FMT_VDPAU_MPEG4},
119     {0, PIX_FMT_NONE}
120 };
121
122 //copied from vf.c
123 extern const vf_info_t vf_info_vo;
124 extern const vf_info_t vf_info_rectangle;
125 extern const vf_info_t vf_info_bmovl;
126 extern const vf_info_t vf_info_crop;
127 extern const vf_info_t vf_info_expand;
128 extern const vf_info_t vf_info_pp;
129 extern const vf_info_t vf_info_scale;
130 extern const vf_info_t vf_info_format;
131 extern const vf_info_t vf_info_noformat;
132 extern const vf_info_t vf_info_flip;
133 extern const vf_info_t vf_info_rotate;
134 extern const vf_info_t vf_info_mirror;
135 extern const vf_info_t vf_info_palette;
136 extern const vf_info_t vf_info_lavc;
137 extern const vf_info_t vf_info_zrmjpeg;
138 extern const vf_info_t vf_info_dvbscale;
139 extern const vf_info_t vf_info_cropdetect;
140 extern const vf_info_t vf_info_test;
141 extern const vf_info_t vf_info_noise;
142 extern const vf_info_t vf_info_yvu9;
143 extern const vf_info_t vf_info_lavcdeint;
144 extern const vf_info_t vf_info_eq;
145 extern const vf_info_t vf_info_eq2;
146 extern const vf_info_t vf_info_gradfun;
147 extern const vf_info_t vf_info_halfpack;
148 extern const vf_info_t vf_info_dint;
149 extern const vf_info_t vf_info_1bpp;
150 extern const vf_info_t vf_info_2xsai;
151 extern const vf_info_t vf_info_unsharp;
152 extern const vf_info_t vf_info_swapuv;
153 extern const vf_info_t vf_info_il;
154 extern const vf_info_t vf_info_fil;
155 extern const vf_info_t vf_info_boxblur;
156 extern const vf_info_t vf_info_sab;
157 extern const vf_info_t vf_info_smartblur;
158 extern const vf_info_t vf_info_perspective;
159 extern const vf_info_t vf_info_down3dright;
160 extern const vf_info_t vf_info_field;
161 extern const vf_info_t vf_info_denoise3d;
162 extern const vf_info_t vf_info_hqdn3d;
163 extern const vf_info_t vf_info_detc;
164 extern const vf_info_t vf_info_telecine;
165 extern const vf_info_t vf_info_tinterlace;
166 extern const vf_info_t vf_info_tfields;
167 extern const vf_info_t vf_info_ivtc;
168 extern const vf_info_t vf_info_ilpack;
169 extern const vf_info_t vf_info_dsize;
170 extern const vf_info_t vf_info_decimate;
171 extern const vf_info_t vf_info_softpulldown;
172 extern const vf_info_t vf_info_pullup;
173 extern const vf_info_t vf_info_filmdint;
174 extern const vf_info_t vf_info_framestep;
175 extern const vf_info_t vf_info_tile;
176 extern const vf_info_t vf_info_delogo;
177 extern const vf_info_t vf_info_remove_logo;
178 extern const vf_info_t vf_info_hue;
179 extern const vf_info_t vf_info_spp;
180 extern const vf_info_t vf_info_uspp;
181 extern const vf_info_t vf_info_fspp;
182 extern const vf_info_t vf_info_pp7;
183 extern const vf_info_t vf_info_yuvcsp;
184 extern const vf_info_t vf_info_kerndeint;
185 extern const vf_info_t vf_info_rgbtest;
186 extern const vf_info_t vf_info_qp;
187 extern const vf_info_t vf_info_phase;
188 extern const vf_info_t vf_info_divtc;
189 extern const vf_info_t vf_info_harddup;
190 extern const vf_info_t vf_info_softskip;
191 extern const vf_info_t vf_info_screenshot;
192 extern const vf_info_t vf_info_ass;
193 extern const vf_info_t vf_info_mcdeint;
194 extern const vf_info_t vf_info_yadif;
195 extern const vf_info_t vf_info_blackframe;
196 extern const vf_info_t vf_info_geq;
197 extern const vf_info_t vf_info_ow;
198 extern const vf_info_t vf_info_fixpts;
199 extern const vf_info_t vf_info_stereo3d;
200
201
202 static const vf_info_t* const filters[]={
203     &vf_info_2xsai,
204     &vf_info_blackframe,
205     &vf_info_boxblur,
206     &vf_info_cropdetect,
207     &vf_info_decimate,
208     &vf_info_delogo,
209     &vf_info_denoise3d,
210     &vf_info_detc,
211     &vf_info_dint,
212     &vf_info_divtc,
213     &vf_info_down3dright,
214     &vf_info_dsize,
215     &vf_info_eq2,
216     &vf_info_eq,
217     &vf_info_field,
218     &vf_info_fil,
219 //    &vf_info_filmdint, cmmx.h vd.h ‘opt_screen_size_x’
220     &vf_info_fixpts,
221     &vf_info_framestep,
222     &vf_info_fspp,
223     &vf_info_geq,
224     &vf_info_gradfun,
225     &vf_info_harddup,
226     &vf_info_hqdn3d,
227     &vf_info_hue,
228     &vf_info_il,
229     &vf_info_ilpack,
230     &vf_info_ivtc,
231     &vf_info_kerndeint,
232     &vf_info_mcdeint,
233     &vf_info_mirror,
234     &vf_info_noise,
235     &vf_info_ow,
236     &vf_info_palette,
237     &vf_info_perspective,
238     &vf_info_phase,
239     &vf_info_pp7,
240     &vf_info_pullup,
241     &vf_info_qp,
242     &vf_info_rectangle,
243     &vf_info_remove_logo,
244     &vf_info_rgbtest,
245     &vf_info_rotate,
246     &vf_info_sab,
247     &vf_info_screenshot,
248     &vf_info_smartblur,
249     &vf_info_softpulldown,
250     &vf_info_softskip,
251     &vf_info_spp,
252     &vf_info_swapuv,
253     &vf_info_telecine,
254     &vf_info_test,
255     &vf_info_tile,
256     &vf_info_tinterlace,
257     &vf_info_unsharp,
258     &vf_info_uspp,
259     &vf_info_yuvcsp,
260     &vf_info_yvu9,
261
262     NULL
263 };
264
265 /*
266 Unsupported filters
267 1bpp
268 ass
269 bmovl
270 crop
271 dvbscale
272 flip
273 expand
274 format
275 halfpack
276 lavc
277 lavcdeint
278 noformat
279 pp
280 scale
281 stereo3d
282 tfields
283 vo
284 yadif
285 zrmjpeg
286 */
287
288 CpuCaps gCpuCaps; //FIXME initialize this so optims work
289
290
291 static void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, SwsFilter **dstFilterParam)
292 {
293         static int firstTime=1;
294         *flags=0;
295
296 #if ARCH_X86
297         if(gCpuCaps.hasMMX)
298                 __asm__ volatile("emms\n\t"::: "memory"); //FIXME this should not be required but it IS (even for non-MMX versions)
299 #endif
300         if(firstTime)
301         {
302                 firstTime=0;
303                 *flags= SWS_PRINT_INFO;
304         }
305         else if( mp_msg_test(MSGT_VFILTER,MSGL_DBG2) ) *flags= SWS_PRINT_INFO;
306
307         switch(SWS_BILINEAR)
308         {
309                 case 0: *flags|= SWS_FAST_BILINEAR; break;
310                 case 1: *flags|= SWS_BILINEAR; break;
311                 case 2: *flags|= SWS_BICUBIC; break;
312                 case 3: *flags|= SWS_X; break;
313                 case 4: *flags|= SWS_POINT; break;
314                 case 5: *flags|= SWS_AREA; break;
315                 case 6: *flags|= SWS_BICUBLIN; break;
316                 case 7: *flags|= SWS_GAUSS; break;
317                 case 8: *flags|= SWS_SINC; break;
318                 case 9: *flags|= SWS_LANCZOS; break;
319                 case 10:*flags|= SWS_SPLINE; break;
320                 default:*flags|= SWS_BILINEAR; break;
321         }
322
323         *srcFilterParam= NULL;
324         *dstFilterParam= NULL;
325 }
326
327 //exact copy from vf_scale.c
328 // will use sws_flags & src_filter (from cmd line)
329 struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat)
330 {
331         int flags, i;
332         SwsFilter *dstFilterParam, *srcFilterParam;
333         enum PixelFormat dfmt, sfmt;
334
335         for(i=0; conversion_map[i].fmt && dstFormat != conversion_map[i].fmt; i++);
336         dfmt= conversion_map[i].pix_fmt;
337         for(i=0; conversion_map[i].fmt && srcFormat != conversion_map[i].fmt; i++);
338         sfmt= conversion_map[i].pix_fmt;
339
340         if (srcFormat == IMGFMT_RGB8 || srcFormat == IMGFMT_BGR8) sfmt = PIX_FMT_PAL8;
341         sws_getFlagsAndFilterFromCmdLine(&flags, &srcFilterParam, &dstFilterParam);
342
343         return sws_getContext(srcW, srcH, sfmt, dstW, dstH, dfmt, flags , srcFilterParam, dstFilterParam, NULL);
344 }
345
346 typedef struct {
347     vf_instance_t vf;
348     vf_instance_t next_vf;
349     AVFilterContext *avfctx;
350     int frame_returned;
351 } MPContext;
352
353 void mp_msg(int mod, int lev, const char *format, ... ){
354     va_list va;
355     va_start(va, format);
356     //FIXME convert lev/mod
357     av_vlog(NULL, AV_LOG_DEBUG, format, va);
358     va_end(va);
359 }
360
361 int mp_msg_test(int mod, int lev){
362     return 123;
363 }
364
365 void init_avcodec(void)
366 {
367     //we maybe should init but its kinda 1. unneeded 2. a bit inpolite from here
368 }
369
370 //Exact copy of vf.c
371 void vf_clone_mpi_attributes(mp_image_t* dst, mp_image_t* src){
372     dst->pict_type= src->pict_type;
373     dst->fields = src->fields;
374     dst->qscale_type= src->qscale_type;
375     if(dst->width == src->width && dst->height == src->height){
376         dst->qstride= src->qstride;
377         dst->qscale= src->qscale;
378     }
379 }
380
381 //Exact copy of vf.c
382 void vf_next_draw_slice(struct vf_instance *vf,unsigned char** src, int * stride,int w, int h, int x, int y){
383     if (vf->next->draw_slice) {
384         vf->next->draw_slice(vf->next,src,stride,w,h,x,y);
385         return;
386     }
387     if (!vf->dmpi) {
388         mp_msg(MSGT_VFILTER,MSGL_ERR,"draw_slice: dmpi not stored by vf_%s\n", vf->info->name);
389         return;
390     }
391     if (!(vf->dmpi->flags & MP_IMGFLAG_PLANAR)) {
392         memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+vf->dmpi->bpp/8*x,
393             src[0], vf->dmpi->bpp/8*w, h, vf->dmpi->stride[0], stride[0]);
394         return;
395     }
396     memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+x, src[0],
397         w, h, vf->dmpi->stride[0], stride[0]);
398     memcpy_pic(vf->dmpi->planes[1]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[1]+(x>>vf->dmpi->chroma_x_shift),
399         src[1], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[1], stride[1]);
400     memcpy_pic(vf->dmpi->planes[2]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[2]+(x>>vf->dmpi->chroma_x_shift),
401         src[2], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[2], stride[2]);
402 }
403
404 //Exact copy of vf.c
405 void vf_mpi_clear(mp_image_t* mpi,int x0,int y0,int w,int h){
406     int y;
407     if(mpi->flags&MP_IMGFLAG_PLANAR){
408         y0&=~1;h+=h&1;
409         if(x0==0 && w==mpi->width){
410             // full width clear:
411             memset(mpi->planes[0]+mpi->stride[0]*y0,0,mpi->stride[0]*h);
412             memset(mpi->planes[1]+mpi->stride[1]*(y0>>mpi->chroma_y_shift),128,mpi->stride[1]*(h>>mpi->chroma_y_shift));
413             memset(mpi->planes[2]+mpi->stride[2]*(y0>>mpi->chroma_y_shift),128,mpi->stride[2]*(h>>mpi->chroma_y_shift));
414         } else
415         for(y=y0;y<y0+h;y+=2){
416             memset(mpi->planes[0]+x0+mpi->stride[0]*y,0,w);
417             memset(mpi->planes[0]+x0+mpi->stride[0]*(y+1),0,w);
418             memset(mpi->planes[1]+(x0>>mpi->chroma_x_shift)+mpi->stride[1]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
419             memset(mpi->planes[2]+(x0>>mpi->chroma_x_shift)+mpi->stride[2]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
420         }
421         return;
422     }
423     // packed:
424     for(y=y0;y<y0+h;y++){
425         unsigned char* dst=mpi->planes[0]+mpi->stride[0]*y+(mpi->bpp>>3)*x0;
426         if(mpi->flags&MP_IMGFLAG_YUV){
427             unsigned int* p=(unsigned int*) dst;
428             int size=(mpi->bpp>>3)*w/4;
429             int i;
430 #if HAVE_BIGENDIAN
431 #define CLEAR_PACKEDYUV_PATTERN 0x00800080
432 #define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x80008000
433 #else
434 #define CLEAR_PACKEDYUV_PATTERN 0x80008000
435 #define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x00800080
436 #endif
437             if(mpi->flags&MP_IMGFLAG_SWAPPED){
438                 for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
439                 for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
440             } else {
441                 for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN;
442                 for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN;
443             }
444         } else
445             memset(dst,0,(mpi->bpp>>3)*w);
446     }
447 }
448
449 int vf_next_query_format(struct vf_instance *vf, unsigned int fmt){
450     return 1;
451 }
452
453 //used by delogo
454 unsigned int vf_match_csp(vf_instance_t** vfp,const unsigned int* list,unsigned int preferred){
455     return preferred;
456 }
457
458 mp_image_t* vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h){
459     MPContext *m= ((uint8_t*)vf) - offsetof(MPContext, next_vf);
460   mp_image_t* mpi=NULL;
461   int w2;
462   int number = mp_imgtype >> 16;
463
464   av_assert0(vf->next == NULL); // all existing filters call this just on next
465
466   //vf_dint needs these as it calls vf_get_image() before configuring the output
467   if(vf->w==0 && w>0) vf->w=w;
468   if(vf->h==0 && h>0) vf->h=h;
469
470   av_assert0(w == -1 || w >= vf->w);
471   av_assert0(h == -1 || h >= vf->h);
472   av_assert0(vf->w > 0);
473   av_assert0(vf->h > 0);
474
475   av_log(m->avfctx, AV_LOG_DEBUG, "get_image: %d:%d, vf: %d:%d\n", w,h,vf->w,vf->h);
476
477   if (w == -1) w = vf->w;
478   if (h == -1) h = vf->h;
479
480   w2=(mp_imgflag&MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE)?((w+15)&(~15)):w;
481
482   // Note: we should call libvo first to check if it supports direct rendering
483   // and if not, then fallback to software buffers:
484   switch(mp_imgtype & 0xff){
485   case MP_IMGTYPE_EXPORT:
486     if(!vf->imgctx.export_images[0]) vf->imgctx.export_images[0]=new_mp_image(w2,h);
487     mpi=vf->imgctx.export_images[0];
488     break;
489   case MP_IMGTYPE_STATIC:
490     if(!vf->imgctx.static_images[0]) vf->imgctx.static_images[0]=new_mp_image(w2,h);
491     mpi=vf->imgctx.static_images[0];
492     break;
493   case MP_IMGTYPE_TEMP:
494     if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=new_mp_image(w2,h);
495     mpi=vf->imgctx.temp_images[0];
496     break;
497   case MP_IMGTYPE_IPB:
498     if(!(mp_imgflag&MP_IMGFLAG_READABLE)){ // B frame:
499       if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=new_mp_image(w2,h);
500       mpi=vf->imgctx.temp_images[0];
501       break;
502     }
503   case MP_IMGTYPE_IP:
504     if(!vf->imgctx.static_images[vf->imgctx.static_idx]) vf->imgctx.static_images[vf->imgctx.static_idx]=new_mp_image(w2,h);
505     mpi=vf->imgctx.static_images[vf->imgctx.static_idx];
506     vf->imgctx.static_idx^=1;
507     break;
508   case MP_IMGTYPE_NUMBERED:
509     if (number == -1) {
510       int i;
511       for (i = 0; i < NUM_NUMBERED_MPI; i++)
512         if (!vf->imgctx.numbered_images[i] || !vf->imgctx.numbered_images[i]->usage_count)
513           break;
514       number = i;
515     }
516     if (number < 0 || number >= NUM_NUMBERED_MPI) return NULL;
517     if (!vf->imgctx.numbered_images[number]) vf->imgctx.numbered_images[number] = new_mp_image(w2,h);
518     mpi = vf->imgctx.numbered_images[number];
519     mpi->number = number;
520     break;
521   }
522   if(mpi){
523     mpi->type=mp_imgtype;
524     mpi->w=vf->w; mpi->h=vf->h;
525     // keep buffer allocation status & color flags only:
526 //    mpi->flags&=~(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_DIRECT);
527     mpi->flags&=MP_IMGFLAG_ALLOCATED|MP_IMGFLAG_TYPE_DISPLAYED|MP_IMGFLAGMASK_COLORS;
528     // accept restrictions, draw_slice and palette flags only:
529     mpi->flags|=mp_imgflag&(MP_IMGFLAGMASK_RESTRICTIONS|MP_IMGFLAG_DRAW_CALLBACK|MP_IMGFLAG_RGB_PALETTE);
530     if(!vf->draw_slice) mpi->flags&=~MP_IMGFLAG_DRAW_CALLBACK;
531     if(mpi->width!=w2 || mpi->height!=h){
532 //      printf("vf.c: MPI parameters changed!  %dx%d -> %dx%d   \n", mpi->width,mpi->height,w2,h);
533         if(mpi->flags&MP_IMGFLAG_ALLOCATED){
534             if(mpi->width<w2 || mpi->height<h){
535                 // need to re-allocate buffer memory:
536                 av_free(mpi->planes[0]);
537                 mpi->flags&=~MP_IMGFLAG_ALLOCATED;
538                 mp_msg(MSGT_VFILTER,MSGL_V,"vf.c: have to REALLOCATE buffer memory :(\n");
539             }
540 //      } else {
541         } {
542             mpi->width=w2; mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
543             mpi->height=h; mpi->chroma_height=(h + (1<<mpi->chroma_y_shift) - 1)>>mpi->chroma_y_shift;
544         }
545     }
546     if(!mpi->bpp) mp_image_setfmt(mpi,outfmt);
547     if(!(mpi->flags&MP_IMGFLAG_ALLOCATED) && mpi->type>MP_IMGTYPE_EXPORT){
548
549         av_assert0(!vf->get_image);
550         // check libvo first!
551         if(vf->get_image) vf->get_image(vf,mpi);
552
553         if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
554           // non-direct and not yet allocated image. allocate it!
555           if (!mpi->bpp) { // no way we can allocate this
556               mp_msg(MSGT_DECVIDEO, MSGL_FATAL,
557                      "vf_get_image: Tried to allocate a format that can not be allocated!\n");
558               return NULL;
559           }
560
561           // check if codec prefer aligned stride:
562           if(mp_imgflag&MP_IMGFLAG_PREFER_ALIGNED_STRIDE){
563               int align=(mpi->flags&MP_IMGFLAG_PLANAR &&
564                          mpi->flags&MP_IMGFLAG_YUV) ?
565                          (8<<mpi->chroma_x_shift)-1 : 15; // -- maybe FIXME
566               w2=((w+align)&(~align));
567               if(mpi->width!=w2){
568 #if 0
569                   // we have to change width... check if we CAN co it:
570                   int flags=vf->query_format(vf,outfmt); // should not fail
571                   if(!(flags&3)) mp_msg(MSGT_DECVIDEO,MSGL_WARN,"??? vf_get_image{vf->query_format(outfmt)} failed!\n");
572 //                printf("query -> 0x%X    \n",flags);
573                   if(flags&VFCAP_ACCEPT_STRIDE){
574 #endif
575                       mpi->width=w2;
576                       mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
577 //                  }
578               }
579           }
580
581           mp_image_alloc_planes(mpi);
582 //        printf("clearing img!\n");
583           vf_mpi_clear(mpi,0,0,mpi->width,mpi->height);
584         }
585     }
586     av_assert0(!vf->start_slice);
587     if(mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)
588         if(vf->start_slice) vf->start_slice(vf,mpi);
589     if(!(mpi->flags&MP_IMGFLAG_TYPE_DISPLAYED)){
590             mp_msg(MSGT_DECVIDEO,MSGL_V,"*** [%s] %s%s mp_image_t, %dx%dx%dbpp %s %s, %d bytes\n",
591                   "NULL"/*vf->info->name*/,
592                   (mpi->type==MP_IMGTYPE_EXPORT)?"Exporting":
593                   ((mpi->flags&MP_IMGFLAG_DIRECT)?"Direct Rendering":"Allocating"),
594                   (mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)?" (slices)":"",
595                   mpi->width,mpi->height,mpi->bpp,
596                   (mpi->flags&MP_IMGFLAG_YUV)?"YUV":((mpi->flags&MP_IMGFLAG_SWAPPED)?"BGR":"RGB"),
597                   (mpi->flags&MP_IMGFLAG_PLANAR)?"planar":"packed",
598                   mpi->bpp*mpi->width*mpi->height/8);
599             mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"(imgfmt: %x, planes: %p,%p,%p strides: %d,%d,%d, chroma: %dx%d, shift: h:%d,v:%d)\n",
600                 mpi->imgfmt, mpi->planes[0], mpi->planes[1], mpi->planes[2],
601                 mpi->stride[0], mpi->stride[1], mpi->stride[2],
602                 mpi->chroma_width, mpi->chroma_height, mpi->chroma_x_shift, mpi->chroma_y_shift);
603             mpi->flags|=MP_IMGFLAG_TYPE_DISPLAYED;
604     }
605
606   mpi->qscale = NULL;
607   }
608   mpi->usage_count++;
609 //    printf("\rVF_MPI: %p %p %p %d %d %d    \n",
610 //      mpi->planes[0],mpi->planes[1],mpi->planes[2],
611 //      mpi->stride[0],mpi->stride[1],mpi->stride[2]);
612   return mpi;
613 }
614
615
616 int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
617     MPContext *m= (void*)vf;
618     AVFilterLink *outlink     = m->avfctx->outputs[0];
619     AVFilterBuffer    *pic    = av_mallocz(sizeof(AVFilterBuffer));
620     AVFilterBufferRef *picref = av_mallocz(sizeof(AVFilterBufferRef));
621     int i;
622
623     av_assert0(vf->next);
624
625     av_log(m->avfctx, AV_LOG_DEBUG, "vf_next_put_image\n");
626
627     if (!pic || !picref)
628         goto fail;
629
630     picref->buf = pic;
631     picref->buf->please_use_av_free= av_free;
632     if (!(picref->video = av_mallocz(sizeof(AVFilterBufferRefVideoProps))))
633         goto fail;
634
635     pic->w = picref->video->w = mpi->w;
636     pic->h = picref->video->h = mpi->h;
637
638     /* make sure the buffer gets read permission or it's useless for output */
639     picref->perms = AV_PERM_READ | AV_PERM_REUSE2;
640 //    av_assert0(mpi->flags&MP_IMGFLAG_READABLE);
641     if(!(mpi->flags&MP_IMGFLAG_PRESERVE))
642         picref->perms |= AV_PERM_WRITE;
643
644     pic->refcount = 1;
645     picref->type = AVMEDIA_TYPE_VIDEO;
646
647     for(i=0; conversion_map[i].fmt && mpi->imgfmt != conversion_map[i].fmt; i++);
648     pic->format = picref->format = conversion_map[i].pix_fmt;
649
650     memcpy(pic->data,        mpi->planes,   FFMIN(sizeof(pic->data)    , sizeof(mpi->planes)));
651     memcpy(pic->linesize,    mpi->stride,   FFMIN(sizeof(pic->linesize), sizeof(mpi->stride)));
652     memcpy(picref->data,     pic->data,     sizeof(picref->data));
653     memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
654
655     if(pts != MP_NOPTS_VALUE)
656         picref->pts= pts * av_q2d(outlink->time_base);
657
658     avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0));
659     avfilter_draw_slice(outlink, 0, picref->video->h, 1);
660     avfilter_end_frame(outlink);
661     avfilter_unref_buffer(picref);
662     m->frame_returned++;
663
664     return 1;
665 fail:
666     if (picref && picref->video)
667         av_free(picref->video);
668     av_free(picref);
669     av_free(pic);
670     return 0;
671 }
672
673 int vf_next_config(struct vf_instance *vf,
674         int width, int height, int d_width, int d_height,
675         unsigned int voflags, unsigned int outfmt){
676
677     av_assert0(width>0 && height>0);
678     vf->next->w = width; vf->next->h = height;
679
680     return 1;
681 #if 0
682     int flags=vf->next->query_format(vf->next,outfmt);
683     if(!flags){
684         // hmm. colorspace mismatch!!!
685         //this is fatal for us ATM
686         return 0;
687     }
688     mp_msg(MSGT_VFILTER,MSGL_V,"REQ: flags=0x%X  req=0x%X  \n",flags,vf->default_reqs);
689     miss=vf->default_reqs - (flags&vf->default_reqs);
690     if(miss&VFCAP_ACCEPT_STRIDE){
691         // vf requires stride support but vf->next doesn't support it!
692         // let's insert the 'expand' filter, it does the job for us:
693         vf_instance_t* vf2=vf_open_filter(vf->next,"expand",NULL);
694         if(!vf2) return 0; // shouldn't happen!
695         vf->next=vf2;
696     }
697     vf->next->w = width; vf->next->h = height;
698 #endif
699     return 1;
700 }
701
702 int vf_next_control(struct vf_instance *vf, int request, void* data){
703     MPContext *m= (void*)vf;
704     av_log(m->avfctx, AV_LOG_DEBUG, "Received control %d\n", request);
705     return 0;
706 }
707
708 static int vf_default_query_format(struct vf_instance *vf, unsigned int fmt){
709     MPContext *m= (void*)vf;
710     int i;
711     av_log(m->avfctx, AV_LOG_DEBUG, "query %X\n", fmt);
712
713     for(i=0; conversion_map[i].fmt; i++){
714         if(fmt==conversion_map[i].fmt)
715             return 1; //we suport all
716     }
717     return 0;
718 }
719
720
721 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
722 {
723     MPContext *m = ctx->priv;
724     char name[256];
725     int i;
726
727     av_log(ctx, AV_LOG_WARNING,
728 "This is a unholy filter, it will be purified by the ffmpeg exorcist team\n"
729 "which will change its syntax from dark -vf mp to light -vf.\n"
730 "Thou shalst not make spells or scripts that depend on it\n");
731
732     m->avfctx= ctx;
733
734     if(!args || 1!=sscanf(args, "%255[^:=]", name)){
735         av_log(ctx, AV_LOG_ERROR, "Invalid parameter.\n");
736         return AVERROR(EINVAL);
737     }
738     args+= strlen(name)+1;
739
740     for(i=0; ;i++){
741         if(!filters[i] || !strcmp(name, filters[i]->name))
742             break;
743     }
744
745     if(!filters[i]){
746         av_log(ctx, AV_LOG_ERROR, "Unknown filter %s\n", name);
747         return AVERROR(EINVAL);
748     }
749
750     memset(&m->vf,0,sizeof(m->vf));
751     m->vf.info= filters[i];
752
753     m->vf.next        = &m->next_vf;
754     m->vf.put_image   = vf_next_put_image;
755     m->vf.config      = vf_next_config;
756     m->vf.query_format= vf_default_query_format;
757     m->vf.control     = vf_next_control;
758     m->vf.default_caps=VFCAP_ACCEPT_STRIDE;
759     m->vf.default_reqs=0;
760     if(m->vf.info->opts)
761         av_log(ctx, AV_LOG_ERROR, "opts / m_struct_set is unsupported\n");
762 #if 0
763     if(vf->info->opts) { // vf_vo get some special argument
764       const m_struct_t* st = vf->info->opts;
765       void* vf_priv = m_struct_alloc(st);
766       int n;
767       for(n = 0 ; args && args[2*n] ; n++)
768         m_struct_set(st,vf_priv,args[2*n],args[2*n+1]);
769       vf->priv = vf_priv;
770       args = NULL;
771     } else // Otherwise we should have the '_oldargs_'
772       if(args && !strcmp(args[0],"_oldargs_"))
773         args = (char**)args[1];
774       else
775         args = NULL;
776 #endif
777     if(m->vf.info->vf_open(&m->vf, args)<=0){
778         av_log(ctx, AV_LOG_ERROR, "vf_open() of %s with arg=%s failed\n", name, args);
779         return -1;
780     }
781
782     return 0;
783 }
784
785 static int query_formats(AVFilterContext *ctx)
786 {
787     AVFilterFormats *avfmts=NULL;
788     MPContext *m = ctx->priv;
789     enum PixelFormat lastpixfmt = PIX_FMT_NONE;
790     int i;
791
792     for(i=0; conversion_map[i].fmt; i++){
793         av_log(ctx, AV_LOG_DEBUG, "query: %X\n", conversion_map[i].fmt);
794         if(m->vf.query_format(&m->vf, conversion_map[i].fmt)){
795             av_log(ctx, AV_LOG_DEBUG, "supported,adding\n");
796             if (conversion_map[i].pix_fmt != lastpixfmt) {
797                 avfilter_add_format(&avfmts, conversion_map[i].pix_fmt);
798                 lastpixfmt = conversion_map[i].pix_fmt;
799             }
800         }
801     }
802
803     //We assume all allowed input formats are also allowed output formats
804     avfilter_set_common_pixel_formats(ctx, avfmts);
805     return 0;
806 }
807
808 static int config_inprops(AVFilterLink *inlink)
809 {
810     MPContext *m = inlink->dst->priv;
811     int i;
812     for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
813
814     av_assert0(conversion_map[i].fmt && inlink->w && inlink->h);
815
816     m->vf.fmt.have_configured = 1;
817     m->vf.fmt.orig_height     = inlink->h;
818     m->vf.fmt.orig_width      = inlink->w;
819     m->vf.fmt.orig_fmt        = conversion_map[i].fmt;
820
821     if(m->vf.config(&m->vf, inlink->w, inlink->h, inlink->w, inlink->h, 0, conversion_map[i].fmt)<=0)
822         return -1;
823
824     return 0;
825 }
826
827 static int config_outprops(AVFilterLink *outlink)
828 {
829     MPContext *m = outlink->src->priv;
830
831     outlink->w = m->next_vf.w;
832     outlink->h = m->next_vf.h;
833
834     return 0;
835 }
836
837 static int request_frame(AVFilterLink *outlink)
838 {
839     MPContext *m = outlink->src->priv;
840     int ret;
841
842     av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame\n");
843
844     for(m->frame_returned=0; !m->frame_returned;){
845         ret=avfilter_request_frame(outlink->src->inputs[0]);
846         if(ret<0)
847             break;
848     }
849
850     av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame ret=%d\n", ret);
851     return ret;
852 }
853
854 static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
855 {
856 }
857
858 static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
859 {
860 }
861
862 static void end_frame(AVFilterLink *inlink)
863 {
864     MPContext *m = inlink->dst->priv;
865     AVFilterBufferRef *inpic  = inlink->cur_buf;
866     int i;
867     double pts= MP_NOPTS_VALUE;
868     mp_image_t* mpi = new_mp_image(inpic->video->w, inpic->video->h);
869
870     if(inpic->pts != AV_NOPTS_VALUE)
871         pts= inpic->pts / av_q2d(inlink->time_base);
872
873     for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
874     mp_image_setfmt(mpi,conversion_map[i].fmt);
875
876     memcpy(mpi->planes, inpic->data,     FFMIN(sizeof(inpic->data)    , sizeof(mpi->planes)));
877     memcpy(mpi->stride, inpic->linesize, FFMIN(sizeof(inpic->linesize), sizeof(mpi->stride)));
878
879     //FIXME pass interleced & tff flags around
880
881     // mpi->flags|=MP_IMGFLAG_ALLOCATED; ?
882     mpi->flags |= MP_IMGFLAG_READABLE;
883     if(!(inpic->perms & AV_PERM_WRITE))
884         mpi->flags |= MP_IMGFLAG_PRESERVE;
885     if(m->vf.put_image(&m->vf, mpi, pts) == 0){
886         av_log(m->avfctx, AV_LOG_DEBUG, "put_image() says skip\n");
887     }
888     free_mp_image(mpi);
889
890     avfilter_unref_buffer(inpic);
891 }
892
893 AVFilter avfilter_vf_mp = {
894     .name      = "mp",
895     .description = NULL_IF_CONFIG_SMALL("libmpcodecs wrapper."),
896     .init = init,
897     .priv_size = sizeof(MPContext),
898     .query_formats = query_formats,
899
900     .inputs    = (AVFilterPad[]) {{ .name            = "default",
901                                     .type            = AVMEDIA_TYPE_VIDEO,
902                                     .start_frame     = start_frame,
903                                     .draw_slice      = null_draw_slice,
904                                     .end_frame       = end_frame,
905                                     .config_props    = config_inprops,
906                                     .min_perms       = AV_PERM_READ, },
907                                   { .name = NULL}},
908     .outputs   = (AVFilterPad[]) {{ .name            = "default",
909                                     .type            = AVMEDIA_TYPE_VIDEO,
910                                     .request_frame   = request_frame,
911                                     .config_props    = config_outprops, },
912                                   { .name = NULL}},
913 };