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