FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_mp.c
Go to the documentation of this file.
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 "video.h"
29 #include "formats.h"
30 #include "internal.h"
31 #include "libavutil/avassert.h"
32 #include "libavutil/pixdesc.h"
33 #include "libavutil/intreadwrite.h"
34 #include "libavutil/imgutils.h"
35 
36 #include "libmpcodecs/vf.h"
37 #include "libmpcodecs/img_format.h"
38 #include "libmpcodecs/cpudetect.h"
39 #include "libmpcodecs/vd_ffmpeg.h"
40 #include "libmpcodecs/vf_scale.h"
42 
43 #include "libswscale/swscale.h"
44 
45 
46 //FIXME maybe link the orig in
47 //XXX: identical pix_fmt must be following with each others
48 static const struct {
49  int fmt;
51 } conversion_map[] = {
96 
98 
105 
106  // YUVJ are YUV formats that use the full Y range and not just
107  // 16 - 235 (see colorspaces.txt).
108  // Currently they are all treated the same way.
113 
122  {0, AV_PIX_FMT_NONE}
123 };
124 
125 extern const vf_info_t ff_vf_info_detc;
126 extern const vf_info_t ff_vf_info_dint;
127 extern const vf_info_t ff_vf_info_divtc;
128 extern const vf_info_t ff_vf_info_down3dright;
129 extern const vf_info_t ff_vf_info_dsize;
130 extern const vf_info_t ff_vf_info_eq2;
131 extern const vf_info_t ff_vf_info_eq;
132 extern const vf_info_t ff_vf_info_fil;
133 //extern const vf_info_t ff_vf_info_filmdint;
134 extern const vf_info_t ff_vf_info_fspp;
135 extern const vf_info_t ff_vf_info_harddup;
136 extern const vf_info_t ff_vf_info_il;
137 extern const vf_info_t ff_vf_info_ilpack;
138 extern const vf_info_t ff_vf_info_ivtc;
139 extern const vf_info_t ff_vf_info_kerndeint;
140 extern const vf_info_t ff_vf_info_mcdeint;
141 extern const vf_info_t ff_vf_info_noise;
142 extern const vf_info_t ff_vf_info_ow;
143 extern const vf_info_t ff_vf_info_perspective;
144 extern const vf_info_t ff_vf_info_phase;
145 extern const vf_info_t ff_vf_info_pp7;
146 extern const vf_info_t ff_vf_info_pullup;
147 extern const vf_info_t ff_vf_info_qp;
148 extern const vf_info_t ff_vf_info_sab;
150 extern const vf_info_t ff_vf_info_softskip;
151 extern const vf_info_t ff_vf_info_spp;
152 extern const vf_info_t ff_vf_info_stereo3d;
153 extern const vf_info_t ff_vf_info_telecine;
154 extern const vf_info_t ff_vf_info_tinterlace;
155 extern const vf_info_t ff_vf_info_unsharp;
156 extern const vf_info_t ff_vf_info_uspp;
157 
158 
159 static const vf_info_t* const filters[]={
166  &ff_vf_info_eq,
168 // &ff_vf_info_filmdint, cmmx.h vd.h ‘opt_screen_size_x’
171  &ff_vf_info_il,
177  &ff_vf_info_ow,
182  &ff_vf_info_qp,
192 
193  NULL
194 };
195 
196 /*
197 Unsupported filters
198 1bpp
199 ass
200 bmovl
201 crop
202 dvbscale
203 flip
204 expand
205 format
206 halfpack
207 lavc
208 lavcdeint
209 noformat
210 pp
211 scale
212 tfields
213 vo
214 yadif
215 zrmjpeg
216 */
217 
218 CpuCaps ff_gCpuCaps; //FIXME initialize this so optims work
219 
221  int i;
222  for(i=0; conversion_map[i].fmt && mp != conversion_map[i].fmt; i++)
223  ;
224  return mp == conversion_map[i].fmt ? conversion_map[i].pix_fmt : AV_PIX_FMT_NONE;
225 }
226 
227 static void ff_sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, SwsFilter **dstFilterParam)
228 {
229  static int firstTime=1;
230  *flags=0;
231 
232 #if ARCH_X86
233  if(ff_gCpuCaps.hasMMX)
234  __asm__ volatile("emms\n\t"::: "memory"); //FIXME this should not be required but it IS (even for non-MMX versions)
235 #endif
236  if(firstTime)
237  {
238  firstTime=0;
239  *flags= SWS_PRINT_INFO;
240  }
242 
243  switch(SWS_BILINEAR)
244  {
245  case 0: *flags|= SWS_FAST_BILINEAR; break;
246  case 1: *flags|= SWS_BILINEAR; break;
247  case 2: *flags|= SWS_BICUBIC; break;
248  case 3: *flags|= SWS_X; break;
249  case 4: *flags|= SWS_POINT; break;
250  case 5: *flags|= SWS_AREA; break;
251  case 6: *flags|= SWS_BICUBLIN; break;
252  case 7: *flags|= SWS_GAUSS; break;
253  case 8: *flags|= SWS_SINC; break;
254  case 9: *flags|= SWS_LANCZOS; break;
255  case 10:*flags|= SWS_SPLINE; break;
256  default:*flags|= SWS_BILINEAR; break;
257  }
258 
259  *srcFilterParam= NULL;
260  *dstFilterParam= NULL;
261 }
262 
263 //exact copy from vf_scale.c
264 // will use sws_flags & src_filter (from cmd line)
266 {
267  int flags, i;
268  SwsFilter *dstFilterParam, *srcFilterParam;
269  enum AVPixelFormat dfmt, sfmt;
270 
271  for(i=0; conversion_map[i].fmt && dstFormat != conversion_map[i].fmt; i++);
272  dfmt= conversion_map[i].pix_fmt;
273  for(i=0; conversion_map[i].fmt && srcFormat != conversion_map[i].fmt; i++);
274  sfmt= conversion_map[i].pix_fmt;
275 
276  if (srcFormat == IMGFMT_RGB8 || srcFormat == IMGFMT_BGR8) sfmt = AV_PIX_FMT_PAL8;
277  ff_sws_getFlagsAndFilterFromCmdLine(&flags, &srcFilterParam, &dstFilterParam);
278 
279  return sws_getContext(srcW, srcH, sfmt, dstW, dstH, dfmt, flags , srcFilterParam, dstFilterParam, NULL);
280 }
281 
282 typedef struct {
287 } MPContext;
288 
289 void ff_mp_msg(int mod, int lev, const char *format, ... ){
290  va_list va;
291  va_start(va, format);
292  //FIXME convert lev/mod
293  av_vlog(NULL, AV_LOG_DEBUG, format, va);
294  va_end(va);
295 }
296 
297 int ff_mp_msg_test(int mod, int lev){
298  return 123;
299 }
300 
301 void ff_init_avcodec(void)
302 {
303  //we maybe should init but its kinda 1. unneeded 2. a bit inpolite from here
304 }
305 
306 //Exact copy of vf.c
308  dst->pict_type= src->pict_type;
309  dst->fields = src->fields;
310  dst->qscale_type= src->qscale_type;
311  if(dst->width == src->width && dst->height == src->height){
312  dst->qstride= src->qstride;
313  dst->qscale= src->qscale;
314  }
315 }
316 
317 //Exact copy of vf.c
318 void ff_vf_next_draw_slice(struct vf_instance *vf,unsigned char** src, int * stride,int w, int h, int x, int y){
319  if (vf->next->draw_slice) {
320  vf->next->draw_slice(vf->next,src,stride,w,h,x,y);
321  return;
322  }
323  if (!vf->dmpi) {
324  ff_mp_msg(MSGT_VFILTER,MSGL_ERR,"draw_slice: dmpi not stored by vf_%s\n", vf->info->name);
325  return;
326  }
327  if (!(vf->dmpi->flags & MP_IMGFLAG_PLANAR)) {
328  memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+vf->dmpi->bpp/8*x,
329  src[0], vf->dmpi->bpp/8*w, h, vf->dmpi->stride[0], stride[0]);
330  return;
331  }
332  memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+x, src[0],
333  w, h, vf->dmpi->stride[0], stride[0]);
334  memcpy_pic(vf->dmpi->planes[1]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[1]+(x>>vf->dmpi->chroma_x_shift),
335  src[1], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[1], stride[1]);
336  memcpy_pic(vf->dmpi->planes[2]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[2]+(x>>vf->dmpi->chroma_x_shift),
337  src[2], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[2], stride[2]);
338 }
339 
340 //Exact copy of vf.c
341 void ff_vf_mpi_clear(mp_image_t* mpi,int x0,int y0,int w,int h){
342  int y;
343  if(mpi->flags&MP_IMGFLAG_PLANAR){
344  y0&=~1;h+=h&1;
345  if(x0==0 && w==mpi->width){
346  // full width clear:
347  memset(mpi->planes[0]+mpi->stride[0]*y0,0,mpi->stride[0]*h);
348  memset(mpi->planes[1]+mpi->stride[1]*(y0>>mpi->chroma_y_shift),128,mpi->stride[1]*(h>>mpi->chroma_y_shift));
349  memset(mpi->planes[2]+mpi->stride[2]*(y0>>mpi->chroma_y_shift),128,mpi->stride[2]*(h>>mpi->chroma_y_shift));
350  } else
351  for(y=y0;y<y0+h;y+=2){
352  memset(mpi->planes[0]+x0+mpi->stride[0]*y,0,w);
353  memset(mpi->planes[0]+x0+mpi->stride[0]*(y+1),0,w);
354  memset(mpi->planes[1]+(x0>>mpi->chroma_x_shift)+mpi->stride[1]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
355  memset(mpi->planes[2]+(x0>>mpi->chroma_x_shift)+mpi->stride[2]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
356  }
357  return;
358  }
359  // packed:
360  for(y=y0;y<y0+h;y++){
361  unsigned char* dst=mpi->planes[0]+mpi->stride[0]*y+(mpi->bpp>>3)*x0;
362  if(mpi->flags&MP_IMGFLAG_YUV){
363  unsigned int* p=(unsigned int*) dst;
364  int size=(mpi->bpp>>3)*w/4;
365  int i;
366 #if HAVE_BIGENDIAN
367 #define CLEAR_PACKEDYUV_PATTERN 0x00800080
368 #define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x80008000
369 #else
370 #define CLEAR_PACKEDYUV_PATTERN 0x80008000
371 #define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x00800080
372 #endif
373  if(mpi->flags&MP_IMGFLAG_SWAPPED){
374  for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
375  for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
376  } else {
377  for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN;
378  for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN;
379  }
380  } else
381  memset(dst,0,(mpi->bpp>>3)*w);
382  }
383 }
384 
385 int ff_vf_next_query_format(struct vf_instance *vf, unsigned int fmt){
386  return 1;
387 }
388 
389 //used by delogo
390 unsigned int ff_vf_match_csp(vf_instance_t** vfp,const unsigned int* list,unsigned int preferred){
391  return preferred;
392 }
393 
394 mp_image_t* ff_vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h){
395  MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, next_vf));
396  mp_image_t* mpi=NULL;
397  int w2;
398  int number = mp_imgtype >> 16;
399 
400  av_assert0(vf->next == NULL); // all existing filters call this just on next
401 
402  //vf_dint needs these as it calls ff_vf_get_image() before configuring the output
403  if(vf->w==0 && w>0) vf->w=w;
404  if(vf->h==0 && h>0) vf->h=h;
405 
406  av_assert0(w == -1 || w >= vf->w);
407  av_assert0(h == -1 || h >= vf->h);
408  av_assert0(vf->w > 0);
409  av_assert0(vf->h > 0);
410 
411  av_log(m->avfctx, AV_LOG_DEBUG, "get_image: %d:%d, vf: %d:%d\n", w,h,vf->w,vf->h);
412 
413  if (w == -1) w = vf->w;
414  if (h == -1) h = vf->h;
415 
416  w2=(mp_imgflag&MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE)?((w+15)&(~15)):w;
417 
418  // Note: we should call libvo first to check if it supports direct rendering
419  // and if not, then fallback to software buffers:
420  switch(mp_imgtype & 0xff){
421  case MP_IMGTYPE_EXPORT:
422  if(!vf->imgctx.export_images[0]) vf->imgctx.export_images[0]=ff_new_mp_image(w2,h);
423  mpi=vf->imgctx.export_images[0];
424  break;
425  case MP_IMGTYPE_STATIC:
426  if(!vf->imgctx.static_images[0]) vf->imgctx.static_images[0]=ff_new_mp_image(w2,h);
427  mpi=vf->imgctx.static_images[0];
428  break;
429  case MP_IMGTYPE_TEMP:
430  if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=ff_new_mp_image(w2,h);
431  mpi=vf->imgctx.temp_images[0];
432  break;
433  case MP_IMGTYPE_IPB:
434  if(!(mp_imgflag&MP_IMGFLAG_READABLE)){ // B frame:
435  if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=ff_new_mp_image(w2,h);
436  mpi=vf->imgctx.temp_images[0];
437  break;
438  }
439  case MP_IMGTYPE_IP:
441  mpi=vf->imgctx.static_images[vf->imgctx.static_idx];
442  vf->imgctx.static_idx^=1;
443  break;
444  case MP_IMGTYPE_NUMBERED:
445  if (number == -1) {
446  int i;
447  for (i = 0; i < NUM_NUMBERED_MPI; i++)
448  if (!vf->imgctx.numbered_images[i] || !vf->imgctx.numbered_images[i]->usage_count)
449  break;
450  number = i;
451  }
452  if (number < 0 || number >= NUM_NUMBERED_MPI) return NULL;
453  if (!vf->imgctx.numbered_images[number]) vf->imgctx.numbered_images[number] = ff_new_mp_image(w2,h);
454  mpi = vf->imgctx.numbered_images[number];
455  mpi->number = number;
456  break;
457  }
458  if(mpi){
459  mpi->type=mp_imgtype;
460  mpi->w=vf->w; mpi->h=vf->h;
461  // keep buffer allocation status & color flags only:
462 // mpi->flags&=~(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_DIRECT);
464  // accept restrictions, draw_slice and palette flags only:
466  if(!vf->draw_slice) mpi->flags&=~MP_IMGFLAG_DRAW_CALLBACK;
467  if(mpi->width!=w2 || mpi->height!=h){
468 // printf("vf.c: MPI parameters changed! %dx%d -> %dx%d \n", mpi->width,mpi->height,w2,h);
469  if(mpi->flags&MP_IMGFLAG_ALLOCATED){
470  if(mpi->width<w2 || mpi->height<h){
471  // need to re-allocate buffer memory:
472  av_free(mpi->planes[0]);
474  ff_mp_msg(MSGT_VFILTER,MSGL_V,"vf.c: have to REALLOCATE buffer memory :(\n");
475  }
476 // } else {
477  } {
478  mpi->width=w2; mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
479  mpi->height=h; mpi->chroma_height=(h + (1<<mpi->chroma_y_shift) - 1)>>mpi->chroma_y_shift;
480  }
481  }
482  if(!mpi->bpp) ff_mp_image_setfmt(mpi,outfmt);
483  if(!(mpi->flags&MP_IMGFLAG_ALLOCATED) && mpi->type>MP_IMGTYPE_EXPORT){
484 
485  av_assert0(!vf->get_image);
486  // check libvo first!
487  if(vf->get_image) vf->get_image(vf,mpi);
488 
489  if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
490  // non-direct and not yet allocated image. allocate it!
491  if (!mpi->bpp) { // no way we can allocate this
493  "ff_vf_get_image: Tried to allocate a format that can not be allocated!\n");
494  return NULL;
495  }
496 
497  // check if codec prefer aligned stride:
498  if(mp_imgflag&MP_IMGFLAG_PREFER_ALIGNED_STRIDE){
499  int align=(mpi->flags&MP_IMGFLAG_PLANAR &&
500  mpi->flags&MP_IMGFLAG_YUV) ?
501  (8<<mpi->chroma_x_shift)-1 : 15; // -- maybe FIXME
502  w2=((w+align)&(~align));
503  if(mpi->width!=w2){
504 #if 0
505  // we have to change width... check if we CAN co it:
506  int flags=vf->query_format(vf,outfmt); // should not fail
507  if(!(flags&3)) ff_mp_msg(MSGT_DECVIDEO,MSGL_WARN,"??? ff_vf_get_image{vf->query_format(outfmt)} failed!\n");
508 // printf("query -> 0x%X \n",flags);
509  if(flags&VFCAP_ACCEPT_STRIDE){
510 #endif
511  mpi->width=w2;
512  mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
513 // }
514  }
515  }
516 
518 // printf("clearing img!\n");
519  ff_vf_mpi_clear(mpi,0,0,mpi->width,mpi->height);
520  }
521  }
522  av_assert0(!vf->start_slice);
524  if(vf->start_slice) vf->start_slice(vf,mpi);
525  if(!(mpi->flags&MP_IMGFLAG_TYPE_DISPLAYED)){
526  ff_mp_msg(MSGT_DECVIDEO,MSGL_V,"*** [%s] %s%s mp_image_t, %dx%dx%dbpp %s %s, %d bytes\n",
527  "NULL"/*vf->info->name*/,
528  (mpi->type==MP_IMGTYPE_EXPORT)?"Exporting":
529  ((mpi->flags&MP_IMGFLAG_DIRECT)?"Direct Rendering":"Allocating"),
530  (mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)?" (slices)":"",
531  mpi->width,mpi->height,mpi->bpp,
532  (mpi->flags&MP_IMGFLAG_YUV)?"YUV":((mpi->flags&MP_IMGFLAG_SWAPPED)?"BGR":"RGB"),
533  (mpi->flags&MP_IMGFLAG_PLANAR)?"planar":"packed",
534  mpi->bpp*mpi->width*mpi->height/8);
535  ff_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",
536  mpi->imgfmt, mpi->planes[0], mpi->planes[1], mpi->planes[2],
537  mpi->stride[0], mpi->stride[1], mpi->stride[2],
540  }
541 
542  mpi->qscale = NULL;
543  mpi->usage_count++;
544  }
545 // printf("\rVF_MPI: %p %p %p %d %d %d \n",
546 // mpi->planes[0],mpi->planes[1],mpi->planes[2],
547 // mpi->stride[0],mpi->stride[1],mpi->stride[2]);
548  return mpi;
549 }
550 
551 
552 int ff_vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
553  MPContext *m= (void*)vf;
554  AVFilterLink *outlink = m->avfctx->outputs[0];
555  AVFilterBuffer *pic = av_mallocz(sizeof(AVFilterBuffer));
557  int i;
558 
559  av_assert0(vf->next);
560 
561  av_log(m->avfctx, AV_LOG_DEBUG, "ff_vf_next_put_image\n");
562 
563  if (!pic || !picref)
564  goto fail;
565 
566  picref->buf = pic;
567  picref->buf->free= (void*)av_free;
568  if (!(picref->video = av_mallocz(sizeof(AVFilterBufferRefVideoProps))))
569  goto fail;
570 
571  pic->w = picref->video->w = mpi->w;
572  pic->h = picref->video->h = mpi->h;
573 
574  /* make sure the buffer gets read permission or it's useless for output */
575  picref->perms = AV_PERM_READ | AV_PERM_REUSE2;
576 // av_assert0(mpi->flags&MP_IMGFLAG_READABLE);
577  if(!(mpi->flags&MP_IMGFLAG_PRESERVE))
578  picref->perms |= AV_PERM_WRITE;
579 
580  pic->refcount = 1;
581  picref->type = AVMEDIA_TYPE_VIDEO;
582 
583  for(i=0; conversion_map[i].fmt && mpi->imgfmt != conversion_map[i].fmt; i++);
584  pic->format = picref->format = conversion_map[i].pix_fmt;
585 
586  memcpy(pic->data, mpi->planes, FFMIN(sizeof(pic->data) , sizeof(mpi->planes)));
587  memcpy(pic->linesize, mpi->stride, FFMIN(sizeof(pic->linesize), sizeof(mpi->stride)));
588  memcpy(picref->data, pic->data, sizeof(picref->data));
589  memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
590 
591  if(pts != MP_NOPTS_VALUE)
592  picref->pts= pts * av_q2d(outlink->time_base);
593 
594  ff_filter_frame(outlink, picref);
595  m->frame_returned++;
596 
597  return 1;
598 fail:
599  if (picref && picref->video)
600  av_free(picref->video);
601  av_free(picref);
602  av_free(pic);
603  return 0;
604 }
605 
606 int ff_vf_next_config(struct vf_instance *vf,
607  int width, int height, int d_width, int d_height,
608  unsigned int voflags, unsigned int outfmt){
609 
610  av_assert0(width>0 && height>0);
611  vf->next->w = width; vf->next->h = height;
612 
613  return 1;
614 #if 0
615  int flags=vf->next->query_format(vf->next,outfmt);
616  if(!flags){
617  // hmm. colorspace mismatch!!!
618  //this is fatal for us ATM
619  return 0;
620  }
621  ff_mp_msg(MSGT_VFILTER,MSGL_V,"REQ: flags=0x%X req=0x%X \n",flags,vf->default_reqs);
622  miss=vf->default_reqs - (flags&vf->default_reqs);
623  if(miss&VFCAP_ACCEPT_STRIDE){
624  // vf requires stride support but vf->next doesn't support it!
625  // let's insert the 'expand' filter, it does the job for us:
626  vf_instance_t* vf2=vf_open_filter(vf->next,"expand",NULL);
627  if(!vf2) return 0; // shouldn't happen!
628  vf->next=vf2;
629  }
630  vf->next->w = width; vf->next->h = height;
631  return 1;
632 #endif
633 }
634 
635 int ff_vf_next_control(struct vf_instance *vf, int request, void* data){
636  MPContext *m= (void*)vf;
637  av_log(m->avfctx, AV_LOG_DEBUG, "Received control %d\n", request);
638  return 0;
639 }
640 
641 static int vf_default_query_format(struct vf_instance *vf, unsigned int fmt){
642  MPContext *m= (void*)vf;
643  int i;
644  av_log(m->avfctx, AV_LOG_DEBUG, "query %X\n", fmt);
645 
646  for(i=0; conversion_map[i].fmt; i++){
647  if(fmt==conversion_map[i].fmt)
648  return 1; //we suport all
649  }
650  return 0;
651 }
652 
653 
654 static av_cold int init(AVFilterContext *ctx, const char *args)
655 {
656  MPContext *m = ctx->priv;
657  char name[256];
658  int i;
659 
660  m->avfctx= ctx;
661 
662  if(!args || 1!=sscanf(args, "%255[^:=]", name)){
663  av_log(ctx, AV_LOG_ERROR, "Invalid parameter.\n");
664  return AVERROR(EINVAL);
665  }
666  args += strlen(name);
667  if (args[0] == '=')
668  args++;
669 
670  for(i=0; ;i++){
671  if(!filters[i] || !strcmp(name, filters[i]->name))
672  break;
673  }
674 
675  if(!filters[i]){
676  av_log(ctx, AV_LOG_ERROR, "Unknown filter %s\n", name);
677  return AVERROR(EINVAL);
678  }
679 
680  av_log(ctx, AV_LOG_WARNING,
681  "'%s' is a wrapped MPlayer filter (libmpcodecs). This filter may be removed\n"
682  "once it has been ported to a native libavfilter.\n", name);
683 
684  memset(&m->vf,0,sizeof(m->vf));
685  m->vf.info= filters[i];
686 
687  m->vf.next = &m->next_vf;
693  m->vf.default_reqs=0;
694  if(m->vf.info->opts)
695  av_log(ctx, AV_LOG_ERROR, "opts / m_struct_set is unsupported\n");
696 #if 0
697  if(vf->info->opts) { // vf_vo get some special argument
698  const m_struct_t* st = vf->info->opts;
699  void* vf_priv = m_struct_alloc(st);
700  int n;
701  for(n = 0 ; args && args[2*n] ; n++)
702  m_struct_set(st,vf_priv,args[2*n],args[2*n+1]);
703  vf->priv = vf_priv;
704  args = NULL;
705  } else // Otherwise we should have the '_oldargs_'
706  if(args && !strcmp(args[0],"_oldargs_"))
707  args = (char**)args[1];
708  else
709  args = NULL;
710 #endif
711  if(m->vf.info->vf_open(&m->vf, (char*)args)<=0){
712  av_log(ctx, AV_LOG_ERROR, "vf_open() of %s with arg=%s failed\n", name, args);
713  return -1;
714  }
715 
716  return 0;
717 }
718 
719 static av_cold void uninit(AVFilterContext *ctx)
720 {
721  MPContext *m = ctx->priv;
722  vf_instance_t *vf = &m->vf;
723 
724  while(vf){
725  vf_instance_t *next = vf->next;
726  if(vf->uninit)
727  vf->uninit(vf);
732  vf = next;
733  }
734 }
735 
737 {
738  AVFilterFormats *avfmts=NULL;
739  MPContext *m = ctx->priv;
740  enum AVPixelFormat lastpixfmt = AV_PIX_FMT_NONE;
741  int i;
742 
743  for(i=0; conversion_map[i].fmt; i++){
744  av_log(ctx, AV_LOG_DEBUG, "query: %X\n", conversion_map[i].fmt);
745  if(m->vf.query_format(&m->vf, conversion_map[i].fmt)){
746  av_log(ctx, AV_LOG_DEBUG, "supported,adding\n");
747  if (conversion_map[i].pix_fmt != lastpixfmt) {
748  ff_add_format(&avfmts, conversion_map[i].pix_fmt);
749  lastpixfmt = conversion_map[i].pix_fmt;
750  }
751  }
752  }
753 
754  if (!avfmts)
755  return -1;
756 
757  //We assume all allowed input formats are also allowed output formats
758  ff_set_common_formats(ctx, avfmts);
759  return 0;
760 }
761 
762 static int config_inprops(AVFilterLink *inlink)
763 {
764  MPContext *m = inlink->dst->priv;
765  int i;
766  for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
767 
768  av_assert0(conversion_map[i].fmt && inlink->w && inlink->h);
769 
770  m->vf.fmt.have_configured = 1;
771  m->vf.fmt.orig_height = inlink->h;
772  m->vf.fmt.orig_width = inlink->w;
773  m->vf.fmt.orig_fmt = conversion_map[i].fmt;
774 
775  if(m->vf.config(&m->vf, inlink->w, inlink->h, inlink->w, inlink->h, 0, conversion_map[i].fmt)<=0)
776  return -1;
777 
778  return 0;
779 }
780 
781 static int config_outprops(AVFilterLink *outlink)
782 {
783  MPContext *m = outlink->src->priv;
784 
785  outlink->w = m->next_vf.w;
786  outlink->h = m->next_vf.h;
787 
788  return 0;
789 }
790 
791 static int request_frame(AVFilterLink *outlink)
792 {
793  MPContext *m = outlink->src->priv;
794  int ret;
795 
796  av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame\n");
797 
798  for(m->frame_returned=0; !m->frame_returned;){
799  ret=ff_request_frame(outlink->src->inputs[0]);
800  if(ret<0)
801  break;
802  }
803 
804  av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame ret=%d\n", ret);
805  return ret;
806 }
807 
808 static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
809 {
810  MPContext *m = inlink->dst->priv;
811  int i;
812  double pts= MP_NOPTS_VALUE;
813  mp_image_t* mpi = ff_new_mp_image(inpic->video->w, inpic->video->h);
814 
815  if(inpic->pts != AV_NOPTS_VALUE)
816  pts= inpic->pts / av_q2d(inlink->time_base);
817 
818  for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
820 
821  memcpy(mpi->planes, inpic->data, FFMIN(sizeof(inpic->data) , sizeof(mpi->planes)));
822  memcpy(mpi->stride, inpic->linesize, FFMIN(sizeof(inpic->linesize), sizeof(mpi->stride)));
823 
824  //FIXME pass interleced & tff flags around
825 
826  // mpi->flags|=MP_IMGFLAG_ALLOCATED; ?
827  mpi->flags |= MP_IMGFLAG_READABLE;
828  if(!(inpic->perms & AV_PERM_WRITE))
829  mpi->flags |= MP_IMGFLAG_PRESERVE;
830  if(m->vf.put_image(&m->vf, mpi, pts) == 0){
831  av_log(m->avfctx, AV_LOG_DEBUG, "put_image() says skip\n");
832  }else{
833  avfilter_unref_buffer(inpic);
834  }
835  ff_free_mp_image(mpi);
836  return 0;
837 }
838 
839 static const AVFilterPad mp_inputs[] = {
840  {
841  .name = "default",
842  .type = AVMEDIA_TYPE_VIDEO,
843  .filter_frame = filter_frame,
844  .config_props = config_inprops,
845  .min_perms = AV_PERM_READ,
846  },
847  { NULL }
848 };
849 
850 static const AVFilterPad mp_outputs[] = {
851  {
852  .name = "default",
853  .type = AVMEDIA_TYPE_VIDEO,
854  .request_frame = request_frame,
855  .config_props = config_outprops,
856  },
857  { NULL }
858 };
859 
861  .name = "mp",
862  .description = NULL_IF_CONFIG_SMALL("Apply a libmpcodecs filter to the input video."),
863  .init = init,
864  .uninit = uninit,
865  .priv_size = sizeof(MPContext),
867  .inputs = mp_inputs,
868  .outputs = mp_outputs,
869 };