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