FFmpeg
 All Data Structures Namespaces 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 #include "libavutil/opt.h"
36 
37 #include "libmpcodecs/vf.h"
38 #include "libmpcodecs/img_format.h"
39 #include "libmpcodecs/cpudetect.h"
40 #include "libmpcodecs/av_helpers.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 
114 #if FF_API_XVMC
117 #endif /* FF_API_XVMC */
118 
125  {0, AV_PIX_FMT_NONE}
126 };
127 
128 extern const vf_info_t ff_vf_info_eq2;
129 extern const vf_info_t ff_vf_info_eq;
130 extern const vf_info_t ff_vf_info_fspp;
131 extern const vf_info_t ff_vf_info_ilpack;
132 extern const vf_info_t ff_vf_info_pp7;
134 
135 static const vf_info_t* const filters[]={
137  &ff_vf_info_eq,
142  NULL
143 };
144 
145 /*
146 Unsupported filters
147 1bpp
148 ass
149 bmovl
150 crop
151 dvbscale
152 flip
153 expand
154 format
155 halfpack
156 lavc
157 lavcdeint
158 noformat
159 pp
160 scale
161 tfields
162 vo
163 yadif
164 zrmjpeg
165 */
166 
167 CpuCaps ff_gCpuCaps; //FIXME initialize this so optims work
168 
170  int i;
171  for(i=0; conversion_map[i].fmt && mp != conversion_map[i].fmt; i++)
172  ;
173  return mp == conversion_map[i].fmt ? conversion_map[i].pix_fmt : AV_PIX_FMT_NONE;
174 }
175 
176 typedef struct {
177  const AVClass *class;
182  char *filter;
184 } MPContext;
185 
186 #define OFFSET(x) offsetof(MPContext, x)
187 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
188 static const AVOption mp_options[] = {
189  { "filter", "set MPlayer filter name and parameters", OFFSET(filter), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
190  { NULL }
191 };
192 
194 
195 void ff_mp_msg(int mod, int lev, const char *format, ... ){
196  va_list va;
197  va_start(va, format);
198  //FIXME convert lev/mod
199  av_vlog(NULL, AV_LOG_DEBUG, format, va);
200  va_end(va);
201 }
202 
203 int ff_mp_msg_test(int mod, int lev){
204  return 123;
205 }
206 
207 void ff_init_avcodec(void)
208 {
209  //we maybe should init but its kinda 1. unneeded 2. a bit impolite from here
210 }
211 
212 //Exact copy of vf.c
214  dst->pict_type= src->pict_type;
215  dst->fields = src->fields;
216  dst->qscale_type= src->qscale_type;
217  if(dst->width == src->width && dst->height == src->height){
218  dst->qstride= src->qstride;
219  dst->qscale= src->qscale;
220  }
221 }
222 
223 //Exact copy of vf.c
224 void ff_vf_next_draw_slice(struct vf_instance *vf,unsigned char** src, int * stride,int w, int h, int x, int y){
225  if (vf->next->draw_slice) {
226  vf->next->draw_slice(vf->next,src,stride,w,h,x,y);
227  return;
228  }
229  if (!vf->dmpi) {
230  ff_mp_msg(MSGT_VFILTER,MSGL_ERR,"draw_slice: dmpi not stored by vf_%s\n", vf->info->name);
231  return;
232  }
233  if (!(vf->dmpi->flags & MP_IMGFLAG_PLANAR)) {
234  memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+vf->dmpi->bpp/8*x,
235  src[0], vf->dmpi->bpp/8*w, h, vf->dmpi->stride[0], stride[0]);
236  return;
237  }
238  memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+x, src[0],
239  w, h, vf->dmpi->stride[0], stride[0]);
240  memcpy_pic(vf->dmpi->planes[1]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[1]+(x>>vf->dmpi->chroma_x_shift),
241  src[1], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[1], stride[1]);
242  memcpy_pic(vf->dmpi->planes[2]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[2]+(x>>vf->dmpi->chroma_x_shift),
243  src[2], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[2], stride[2]);
244 }
245 
246 //Exact copy of vf.c
247 void ff_vf_mpi_clear(mp_image_t* mpi,int x0,int y0,int w,int h){
248  int y;
249  if(mpi->flags&MP_IMGFLAG_PLANAR){
250  y0&=~1;h+=h&1;
251  if(x0==0 && w==mpi->width){
252  // full width clear:
253  memset(mpi->planes[0]+mpi->stride[0]*y0,0,mpi->stride[0]*h);
254  memset(mpi->planes[1]+mpi->stride[1]*(y0>>mpi->chroma_y_shift),128,mpi->stride[1]*(h>>mpi->chroma_y_shift));
255  memset(mpi->planes[2]+mpi->stride[2]*(y0>>mpi->chroma_y_shift),128,mpi->stride[2]*(h>>mpi->chroma_y_shift));
256  } else
257  for(y=y0;y<y0+h;y+=2){
258  memset(mpi->planes[0]+x0+mpi->stride[0]*y,0,w);
259  memset(mpi->planes[0]+x0+mpi->stride[0]*(y+1),0,w);
260  memset(mpi->planes[1]+(x0>>mpi->chroma_x_shift)+mpi->stride[1]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
261  memset(mpi->planes[2]+(x0>>mpi->chroma_x_shift)+mpi->stride[2]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
262  }
263  return;
264  }
265  // packed:
266  for(y=y0;y<y0+h;y++){
267  unsigned char* dst=mpi->planes[0]+mpi->stride[0]*y+(mpi->bpp>>3)*x0;
268  if(mpi->flags&MP_IMGFLAG_YUV){
269  unsigned int* p=(unsigned int*) dst;
270  int size=(mpi->bpp>>3)*w/4;
271  int i;
272 #if HAVE_BIGENDIAN
273 #define CLEAR_PACKEDYUV_PATTERN 0x00800080
274 #define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x80008000
275 #else
276 #define CLEAR_PACKEDYUV_PATTERN 0x80008000
277 #define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x00800080
278 #endif
279  if(mpi->flags&MP_IMGFLAG_SWAPPED){
280  for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
281  for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
282  } else {
283  for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN;
284  for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN;
285  }
286  } else
287  memset(dst,0,(mpi->bpp>>3)*w);
288  }
289 }
290 
291 int ff_vf_next_query_format(struct vf_instance *vf, unsigned int fmt){
292  return 1;
293 }
294 
295 //used by delogo
296 unsigned int ff_vf_match_csp(vf_instance_t** vfp,const unsigned int* list,unsigned int preferred){
297  return preferred;
298 }
299 
300 mp_image_t* ff_vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h){
301  MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, next_vf));
302  mp_image_t* mpi=NULL;
303  int w2;
304  int number = mp_imgtype >> 16;
305 
306  av_assert0(vf->next == NULL); // all existing filters call this just on next
307 
308  //vf_dint needs these as it calls ff_vf_get_image() before configuring the output
309  if(vf->w==0 && w>0) vf->w=w;
310  if(vf->h==0 && h>0) vf->h=h;
311 
312  av_assert0(w == -1 || w >= vf->w);
313  av_assert0(h == -1 || h >= vf->h);
314  av_assert0(vf->w > 0);
315  av_assert0(vf->h > 0);
316 
317  av_log(m->avfctx, AV_LOG_DEBUG, "get_image: %d:%d, vf: %d:%d\n", w,h,vf->w,vf->h);
318 
319  if (w == -1) w = vf->w;
320  if (h == -1) h = vf->h;
321 
322  w2=(mp_imgflag&MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE)?((w+15)&(~15)):w;
323 
324  // Note: we should call libvo first to check if it supports direct rendering
325  // and if not, then fallback to software buffers:
326  switch(mp_imgtype & 0xff){
327  case MP_IMGTYPE_EXPORT:
328  if(!vf->imgctx.export_images[0]) vf->imgctx.export_images[0]=ff_new_mp_image(w2,h);
329  mpi=vf->imgctx.export_images[0];
330  break;
331  case MP_IMGTYPE_STATIC:
332  if(!vf->imgctx.static_images[0]) vf->imgctx.static_images[0]=ff_new_mp_image(w2,h);
333  mpi=vf->imgctx.static_images[0];
334  break;
335  case MP_IMGTYPE_TEMP:
336  if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=ff_new_mp_image(w2,h);
337  mpi=vf->imgctx.temp_images[0];
338  break;
339  case MP_IMGTYPE_IPB:
340  if(!(mp_imgflag&MP_IMGFLAG_READABLE)){ // B frame:
341  if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=ff_new_mp_image(w2,h);
342  mpi=vf->imgctx.temp_images[0];
343  break;
344  }
345  case MP_IMGTYPE_IP:
347  mpi=vf->imgctx.static_images[vf->imgctx.static_idx];
348  vf->imgctx.static_idx^=1;
349  break;
350  case MP_IMGTYPE_NUMBERED:
351  if (number == -1) {
352  int i;
353  for (i = 0; i < NUM_NUMBERED_MPI; i++)
354  if (!vf->imgctx.numbered_images[i] || !vf->imgctx.numbered_images[i]->usage_count)
355  break;
356  number = i;
357  }
358  if (number < 0 || number >= NUM_NUMBERED_MPI) return NULL;
359  if (!vf->imgctx.numbered_images[number]) vf->imgctx.numbered_images[number] = ff_new_mp_image(w2,h);
360  mpi = vf->imgctx.numbered_images[number];
361  mpi->number = number;
362  break;
363  }
364  if(mpi){
365  mpi->type=mp_imgtype;
366  mpi->w=vf->w; mpi->h=vf->h;
367  // keep buffer allocation status & color flags only:
368 // mpi->flags&=~(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_DIRECT);
370  // accept restrictions, draw_slice and palette flags only:
372  if(!vf->draw_slice) mpi->flags&=~MP_IMGFLAG_DRAW_CALLBACK;
373  if(mpi->width!=w2 || mpi->height!=h){
374 // printf("vf.c: MPI parameters changed! %dx%d -> %dx%d \n", mpi->width,mpi->height,w2,h);
375  if(mpi->flags&MP_IMGFLAG_ALLOCATED){
376  if(mpi->width<w2 || mpi->height<h){
377  // need to re-allocate buffer memory:
378  av_free(mpi->planes[0]);
380  ff_mp_msg(MSGT_VFILTER,MSGL_V,"vf.c: have to REALLOCATE buffer memory :(\n");
381  }
382 // } else {
383  } {
384  mpi->width=w2; mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
385  mpi->height=h; mpi->chroma_height=(h + (1<<mpi->chroma_y_shift) - 1)>>mpi->chroma_y_shift;
386  }
387  }
388  if(!mpi->bpp) ff_mp_image_setfmt(mpi,outfmt);
389  if(!(mpi->flags&MP_IMGFLAG_ALLOCATED) && mpi->type>MP_IMGTYPE_EXPORT){
390 
391  av_assert0(!vf->get_image);
392  // check libvo first!
393  if(vf->get_image) vf->get_image(vf,mpi);
394 
395  if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
396  // non-direct and not yet allocated image. allocate it!
397  if (!mpi->bpp) { // no way we can allocate this
399  "ff_vf_get_image: Tried to allocate a format that can not be allocated!\n");
400  return NULL;
401  }
402 
403  // check if codec prefer aligned stride:
404  if(mp_imgflag&MP_IMGFLAG_PREFER_ALIGNED_STRIDE){
405  int align=(mpi->flags&MP_IMGFLAG_PLANAR &&
406  mpi->flags&MP_IMGFLAG_YUV) ?
407  (8<<mpi->chroma_x_shift)-1 : 15; // -- maybe FIXME
408  w2=((w+align)&(~align));
409  if(mpi->width!=w2){
410 #if 0
411  // we have to change width... check if we CAN co it:
412  int flags=vf->query_format(vf,outfmt); // should not fail
413  if(!(flags&3)) ff_mp_msg(MSGT_DECVIDEO,MSGL_WARN,"??? ff_vf_get_image{vf->query_format(outfmt)} failed!\n");
414 // printf("query -> 0x%X \n",flags);
415  if(flags&VFCAP_ACCEPT_STRIDE){
416 #endif
417  mpi->width=w2;
418  mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
419 // }
420  }
421  }
422 
424 // printf("clearing img!\n");
425  ff_vf_mpi_clear(mpi,0,0,mpi->width,mpi->height);
426  }
427  }
428  av_assert0(!vf->start_slice);
430  if(vf->start_slice) vf->start_slice(vf,mpi);
431  if(!(mpi->flags&MP_IMGFLAG_TYPE_DISPLAYED)){
432  ff_mp_msg(MSGT_DECVIDEO,MSGL_V,"*** [%s] %s%s mp_image_t, %dx%dx%dbpp %s %s, %d bytes\n",
433  "NULL"/*vf->info->name*/,
434  (mpi->type==MP_IMGTYPE_EXPORT)?"Exporting":
435  ((mpi->flags&MP_IMGFLAG_DIRECT)?"Direct Rendering":"Allocating"),
436  (mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)?" (slices)":"",
437  mpi->width,mpi->height,mpi->bpp,
438  (mpi->flags&MP_IMGFLAG_YUV)?"YUV":((mpi->flags&MP_IMGFLAG_SWAPPED)?"BGR":"RGB"),
439  (mpi->flags&MP_IMGFLAG_PLANAR)?"planar":"packed",
440  mpi->bpp*mpi->width*mpi->height/8);
441  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",
442  mpi->imgfmt, mpi->planes[0], mpi->planes[1], mpi->planes[2],
443  mpi->stride[0], mpi->stride[1], mpi->stride[2],
446  }
447 
448  mpi->qscale = NULL;
449  mpi->usage_count++;
450  }
451 // printf("\rVF_MPI: %p %p %p %d %d %d \n",
452 // mpi->planes[0],mpi->planes[1],mpi->planes[2],
453 // mpi->stride[0],mpi->stride[1],mpi->stride[2]);
454  return mpi;
455 }
456 
457 int ff_vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
458  MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, vf));
459  AVFilterLink *outlink = m->avfctx->outputs[0];
460  AVFrame *picref = av_frame_alloc();
461  int i;
462 
463  av_assert0(vf->next);
464 
465  av_log(m->avfctx, AV_LOG_DEBUG, "ff_vf_next_put_image\n");
466 
467  if (!picref)
468  goto fail;
469 
470  picref->width = mpi->w;
471  picref->height = mpi->h;
472 
473  for(i=0; conversion_map[i].fmt && mpi->imgfmt != conversion_map[i].fmt; i++);
474  picref->format = conversion_map[i].pix_fmt;
475 
476  for(i=0; conversion_map[i].fmt && m->in_pix_fmt != conversion_map[i].pix_fmt; i++);
477  if (mpi->imgfmt == conversion_map[i].fmt)
478  picref->format = conversion_map[i].pix_fmt;
479 
480  memcpy(picref->linesize, mpi->stride, FFMIN(sizeof(picref->linesize), sizeof(mpi->stride)));
481 
482  for(i=0; i<4 && mpi->stride[i]; i++){
483  picref->data[i] = mpi->planes[i];
484  }
485 
486  if(pts != MP_NOPTS_VALUE)
487  picref->pts= pts * av_q2d(outlink->time_base);
488 
489  if(1) { // mp buffers are currently unsupported in libavfilter, we thus must copy
490  AVFrame *tofree = picref;
491  picref = av_frame_clone(picref);
492  av_frame_free(&tofree);
493  }
494 
495  ff_filter_frame(outlink, picref);
496  m->frame_returned++;
497 
498  return 1;
499 fail:
500  av_frame_free(&picref);
501  return 0;
502 }
503 
504 int ff_vf_next_config(struct vf_instance *vf,
505  int width, int height, int d_width, int d_height,
506  unsigned int voflags, unsigned int outfmt){
507 
508  av_assert0(width>0 && height>0);
509  vf->next->w = width; vf->next->h = height;
510 
511  return 1;
512 #if 0
513  int flags=vf->next->query_format(vf->next,outfmt);
514  if(!flags){
515  // hmm. colorspace mismatch!!!
516  //this is fatal for us ATM
517  return 0;
518  }
519  ff_mp_msg(MSGT_VFILTER,MSGL_V,"REQ: flags=0x%X req=0x%X \n",flags,vf->default_reqs);
520  miss=vf->default_reqs - (flags&vf->default_reqs);
521  if(miss&VFCAP_ACCEPT_STRIDE){
522  // vf requires stride support but vf->next doesn't support it!
523  // let's insert the 'expand' filter, it does the job for us:
524  vf_instance_t* vf2=vf_open_filter(vf->next,"expand",NULL);
525  if(!vf2) return 0; // shouldn't happen!
526  vf->next=vf2;
527  }
528  vf->next->w = width; vf->next->h = height;
529  return 1;
530 #endif
531 }
532 
533 int ff_vf_next_control(struct vf_instance *vf, int request, void* data){
534  MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, vf));
535  av_log(m->avfctx, AV_LOG_DEBUG, "Received control %d\n", request);
536  return 0;
537 }
538 
539 static int vf_default_query_format(struct vf_instance *vf, unsigned int fmt){
540  MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, vf));
541  int i;
542  av_log(m->avfctx, AV_LOG_DEBUG, "query %X\n", fmt);
543 
544  for(i=0; conversion_map[i].fmt; i++){
545  if(fmt==conversion_map[i].fmt)
546  return 1; //we suport all
547  }
548  return 0;
549 }
550 
551 
552 static av_cold int init(AVFilterContext *ctx)
553 {
554  MPContext *m = ctx->priv;
555  int cpu_flags = av_get_cpu_flags();
556  char name[256];
557  const char *args;
558  int i;
559 
560  ff_gCpuCaps.hasMMX = cpu_flags & AV_CPU_FLAG_MMX;
561  ff_gCpuCaps.hasMMX2 = cpu_flags & AV_CPU_FLAG_MMX2;
562  ff_gCpuCaps.hasSSE = cpu_flags & AV_CPU_FLAG_SSE;
563  ff_gCpuCaps.hasSSE2 = cpu_flags & AV_CPU_FLAG_SSE2;
564  ff_gCpuCaps.hasSSE3 = cpu_flags & AV_CPU_FLAG_SSE3;
565  ff_gCpuCaps.hasSSSE3 = cpu_flags & AV_CPU_FLAG_SSSE3;
566  ff_gCpuCaps.hasSSE4 = cpu_flags & AV_CPU_FLAG_SSE4;
567  ff_gCpuCaps.hasSSE42 = cpu_flags & AV_CPU_FLAG_SSE42;
568  ff_gCpuCaps.hasAVX = cpu_flags & AV_CPU_FLAG_AVX;
569  ff_gCpuCaps.has3DNow = cpu_flags & AV_CPU_FLAG_3DNOW;
570  ff_gCpuCaps.has3DNowExt = cpu_flags & AV_CPU_FLAG_3DNOWEXT;
571 
572  m->avfctx= ctx;
573 
574  args = m->filter;
575  if(!args || 1!=sscanf(args, "%255[^:=]", name)){
576  av_log(ctx, AV_LOG_ERROR, "Invalid parameter.\n");
577  return AVERROR(EINVAL);
578  }
579  args += strlen(name);
580  if (args[0] == '=')
581  args++;
582 
583  for(i=0; ;i++){
584  if(!filters[i] || !strcmp(name, filters[i]->name))
585  break;
586  }
587 
588  if(!filters[i]){
589  av_log(ctx, AV_LOG_ERROR, "Unknown filter %s\n", name);
590  return AVERROR(EINVAL);
591  }
592 
593  av_log(ctx, AV_LOG_WARNING,
594  "'%s' is a wrapped MPlayer filter (libmpcodecs). This filter may be removed\n"
595  "once it has been ported to a native libavfilter.\n", name);
596 
597  memset(&m->vf,0,sizeof(m->vf));
598  m->vf.info= filters[i];
599 
600  m->vf.next = &m->next_vf;
606  m->vf.default_reqs=0;
607  if(m->vf.info->opts)
608  av_log(ctx, AV_LOG_ERROR, "opts / m_struct_set is unsupported\n");
609 #if 0
610  if(vf->info->opts) { // vf_vo get some special argument
611  const m_struct_t* st = vf->info->opts;
612  void* vf_priv = m_struct_alloc(st);
613  int n;
614  for(n = 0 ; args && args[2*n] ; n++)
615  m_struct_set(st,vf_priv,args[2*n],args[2*n+1]);
616  vf->priv = vf_priv;
617  args = NULL;
618  } else // Otherwise we should have the '_oldargs_'
619  if(args && !strcmp(args[0],"_oldargs_"))
620  args = (char**)args[1];
621  else
622  args = NULL;
623 #endif
624  if(m->vf.info->vf_open(&m->vf, (char*)args)<=0){
625  av_log(ctx, AV_LOG_ERROR, "vf_open() of %s with arg=%s failed\n", name, args);
626  return -1;
627  }
628 
629  return 0;
630 }
631 
632 static av_cold void uninit(AVFilterContext *ctx)
633 {
634  MPContext *m = ctx->priv;
635  vf_instance_t *vf = &m->vf;
636 
637  while(vf){
638  vf_instance_t *next = vf->next;
639  if(vf->uninit)
640  vf->uninit(vf);
645  vf = next;
646  }
647 }
648 
650 {
651  AVFilterFormats *avfmts=NULL;
652  MPContext *m = ctx->priv;
653  enum AVPixelFormat lastpixfmt = AV_PIX_FMT_NONE;
654  int i;
655 
656  for(i=0; conversion_map[i].fmt; i++){
657  av_log(ctx, AV_LOG_DEBUG, "query: %X\n", conversion_map[i].fmt);
658  if(m->vf.query_format(&m->vf, conversion_map[i].fmt)){
659  av_log(ctx, AV_LOG_DEBUG, "supported,adding\n");
660  if (conversion_map[i].pix_fmt != lastpixfmt) {
661  ff_add_format(&avfmts, conversion_map[i].pix_fmt);
662  lastpixfmt = conversion_map[i].pix_fmt;
663  }
664  }
665  }
666 
667  if (!avfmts)
668  return -1;
669 
670  //We assume all allowed input formats are also allowed output formats
671  ff_set_common_formats(ctx, avfmts);
672  return 0;
673 }
674 
675 static int config_inprops(AVFilterLink *inlink)
676 {
677  MPContext *m = inlink->dst->priv;
678  int i;
679  for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
680 
681  av_assert0(conversion_map[i].fmt && inlink->w && inlink->h);
682 
683  m->vf.fmt.have_configured = 1;
684  m->vf.fmt.orig_height = inlink->h;
685  m->vf.fmt.orig_width = inlink->w;
686  m->vf.fmt.orig_fmt = conversion_map[i].fmt;
687 
688  if(m->vf.config(&m->vf, inlink->w, inlink->h, inlink->w, inlink->h, 0, conversion_map[i].fmt)<=0)
689  return -1;
690 
691  return 0;
692 }
693 
694 static int config_outprops(AVFilterLink *outlink)
695 {
696  MPContext *m = outlink->src->priv;
697 
698  outlink->w = m->next_vf.w;
699  outlink->h = m->next_vf.h;
700 
701  return 0;
702 }
703 
704 static int request_frame(AVFilterLink *outlink)
705 {
706  MPContext *m = outlink->src->priv;
707  int ret;
708 
709  av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame\n");
710 
711  for(m->frame_returned=0; !m->frame_returned;){
712  ret=ff_request_frame(outlink->src->inputs[0]);
713  if(ret<0)
714  break;
715  }
716 
717  av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame ret=%d\n", ret);
718  return ret;
719 }
720 
721 static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
722 {
723  MPContext *m = inlink->dst->priv;
724  int i;
725  double pts= MP_NOPTS_VALUE;
726  mp_image_t* mpi = ff_new_mp_image(inpic->width, inpic->height);
727 
728  if(inpic->pts != AV_NOPTS_VALUE)
729  pts= inpic->pts / av_q2d(inlink->time_base);
730 
731  for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
733  m->in_pix_fmt = inlink->format;
734 
735  memcpy(mpi->planes, inpic->data, FFMIN(sizeof(inpic->data) , sizeof(mpi->planes)));
736  memcpy(mpi->stride, inpic->linesize, FFMIN(sizeof(inpic->linesize), sizeof(mpi->stride)));
737 
738  if (inpic->interlaced_frame)
740  if (inpic->top_field_first)
742  if (inpic->repeat_pict)
744 
745  // mpi->flags|=MP_IMGFLAG_ALLOCATED; ?
746  mpi->flags |= MP_IMGFLAG_READABLE;
747  if(!av_frame_is_writable(inpic))
748  mpi->flags |= MP_IMGFLAG_PRESERVE;
749  if(m->vf.put_image(&m->vf, mpi, pts) == 0){
750  av_log(m->avfctx, AV_LOG_DEBUG, "put_image() says skip\n");
751  }else{
752  av_frame_free(&inpic);
753  }
754  ff_free_mp_image(mpi);
755  return 0;
756 }
757 
758 static const AVFilterPad mp_inputs[] = {
759  {
760  .name = "default",
761  .type = AVMEDIA_TYPE_VIDEO,
762  .filter_frame = filter_frame,
763  .config_props = config_inprops,
764  },
765  { NULL }
766 };
767 
768 static const AVFilterPad mp_outputs[] = {
769  {
770  .name = "default",
771  .type = AVMEDIA_TYPE_VIDEO,
772  .request_frame = request_frame,
773  .config_props = config_outprops,
774  },
775  { NULL }
776 };
777 
779  .name = "mp",
780  .description = NULL_IF_CONFIG_SMALL("Apply a libmpcodecs filter to the input video."),
781  .init = init,
782  .uninit = uninit,
783  .priv_size = sizeof(MPContext),
785  .inputs = mp_inputs,
786  .outputs = mp_outputs,
787  .priv_class = &mp_class,
788 };