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