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