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