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  for(i=0; conversion_map[i].fmt && mpi->imgfmt != conversion_map[i].fmt; i++);
478  picref->format = conversion_map[i].pix_fmt;
479 
480  for(i=0; conversion_map[i].fmt && m->in_pix_fmt != conversion_map[i].pix_fmt; i++);
481  if (mpi->imgfmt == conversion_map[i].fmt)
482  picref->format = conversion_map[i].pix_fmt;
483 
484  memcpy(picref->linesize, mpi->stride, FFMIN(sizeof(picref->linesize), sizeof(mpi->stride)));
485 
486  for(i=0; i<4 && mpi->stride[i]; i++){
487  picref->data[i] = mpi->planes[i];
488  }
489 
490  if(pts != MP_NOPTS_VALUE)
491  picref->pts= pts * av_q2d(outlink->time_base);
492 
493  if(1) { // mp buffers are currently unsupported in libavfilter, we thus must copy
494  AVFrame *tofree = picref;
495  picref = av_frame_clone(picref);
496  av_frame_free(&tofree);
497  }
498 
499  ff_filter_frame(outlink, picref);
500  m->frame_returned++;
501 
502  return 1;
503 fail:
504  av_frame_free(&picref);
505  return 0;
506 }
507 
508 int ff_vf_next_config(struct vf_instance *vf,
509  int width, int height, int d_width, int d_height,
510  unsigned int voflags, unsigned int outfmt){
511 
512  av_assert0(width>0 && height>0);
513  vf->next->w = width; vf->next->h = height;
514 
515  return 1;
516 #if 0
517  int flags=vf->next->query_format(vf->next,outfmt);
518  if(!flags){
519  // hmm. colorspace mismatch!!!
520  //this is fatal for us ATM
521  return 0;
522  }
523  ff_mp_msg(MSGT_VFILTER,MSGL_V,"REQ: flags=0x%X req=0x%X \n",flags,vf->default_reqs);
524  miss=vf->default_reqs - (flags&vf->default_reqs);
525  if(miss&VFCAP_ACCEPT_STRIDE){
526  // vf requires stride support but vf->next doesn't support it!
527  // let's insert the 'expand' filter, it does the job for us:
528  vf_instance_t* vf2=vf_open_filter(vf->next,"expand",NULL);
529  if(!vf2) return 0; // shouldn't happen!
530  vf->next=vf2;
531  }
532  vf->next->w = width; vf->next->h = height;
533  return 1;
534 #endif
535 }
536 
537 int ff_vf_next_control(struct vf_instance *vf, int request, void* data){
538  MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, vf));
539  av_log(m->avfctx, AV_LOG_DEBUG, "Received control %d\n", request);
540  return 0;
541 }
542 
543 static int vf_default_query_format(struct vf_instance *vf, unsigned int fmt){
544  MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, vf));
545  int i;
546  av_log(m->avfctx, AV_LOG_DEBUG, "query %X\n", fmt);
547 
548  for(i=0; conversion_map[i].fmt; i++){
549  if(fmt==conversion_map[i].fmt)
550  return 1; //we suport all
551  }
552  return 0;
553 }
554 
555 
556 static av_cold int init(AVFilterContext *ctx)
557 {
558  MPContext *m = ctx->priv;
559  int cpu_flags = av_get_cpu_flags();
560  char name[256];
561  const char *args;
562  int i;
563 
564  ff_gCpuCaps.hasMMX = cpu_flags & AV_CPU_FLAG_MMX;
565  ff_gCpuCaps.hasMMX2 = cpu_flags & AV_CPU_FLAG_MMX2;
566  ff_gCpuCaps.hasSSE = cpu_flags & AV_CPU_FLAG_SSE;
567  ff_gCpuCaps.hasSSE2 = cpu_flags & AV_CPU_FLAG_SSE2;
568  ff_gCpuCaps.hasSSE3 = cpu_flags & AV_CPU_FLAG_SSE3;
569  ff_gCpuCaps.hasSSSE3 = cpu_flags & AV_CPU_FLAG_SSSE3;
570  ff_gCpuCaps.hasSSE4 = cpu_flags & AV_CPU_FLAG_SSE4;
571  ff_gCpuCaps.hasSSE42 = cpu_flags & AV_CPU_FLAG_SSE42;
572  ff_gCpuCaps.hasAVX = cpu_flags & AV_CPU_FLAG_AVX;
573  ff_gCpuCaps.has3DNow = cpu_flags & AV_CPU_FLAG_3DNOW;
574  ff_gCpuCaps.has3DNowExt = cpu_flags & AV_CPU_FLAG_3DNOWEXT;
575 
576  m->avfctx= ctx;
577 
578  args = m->filter;
579  if(!args || 1!=sscanf(args, "%255[^:=]", name)){
580  av_log(ctx, AV_LOG_ERROR, "Invalid parameter.\n");
581  return AVERROR(EINVAL);
582  }
583  args += strlen(name);
584  if (args[0] == '=')
585  args++;
586 
587  for(i=0; ;i++){
588  if(!filters[i] || !strcmp(name, filters[i]->name))
589  break;
590  }
591 
592  if(!filters[i]){
593  av_log(ctx, AV_LOG_ERROR, "Unknown filter %s\n", name);
594  return AVERROR(EINVAL);
595  }
596 
597  av_log(ctx, AV_LOG_WARNING,
598  "'%s' is a wrapped MPlayer filter (libmpcodecs). This filter may be removed\n"
599  "once it has been ported to a native libavfilter.\n", name);
600 
601  memset(&m->vf,0,sizeof(m->vf));
602  m->vf.info= filters[i];
603 
604  m->vf.next = &m->next_vf;
610  m->vf.default_reqs=0;
611  if(m->vf.info->opts)
612  av_log(ctx, AV_LOG_ERROR, "opts / m_struct_set is unsupported\n");
613 #if 0
614  if(vf->info->opts) { // vf_vo get some special argument
615  const m_struct_t* st = vf->info->opts;
616  void* vf_priv = m_struct_alloc(st);
617  int n;
618  for(n = 0 ; args && args[2*n] ; n++)
619  m_struct_set(st,vf_priv,args[2*n],args[2*n+1]);
620  vf->priv = vf_priv;
621  args = NULL;
622  } else // Otherwise we should have the '_oldargs_'
623  if(args && !strcmp(args[0],"_oldargs_"))
624  args = (char**)args[1];
625  else
626  args = NULL;
627 #endif
628  if(m->vf.info->vf_open(&m->vf, (char*)args)<=0){
629  av_log(ctx, AV_LOG_ERROR, "vf_open() of %s with arg=%s failed\n", name, args);
630  return -1;
631  }
632 
633  return 0;
634 }
635 
636 static av_cold void uninit(AVFilterContext *ctx)
637 {
638  MPContext *m = ctx->priv;
639  vf_instance_t *vf = &m->vf;
640 
641  while(vf){
642  vf_instance_t *next = vf->next;
643  if(vf->uninit)
644  vf->uninit(vf);
649  vf = next;
650  }
651 }
652 
654 {
655  AVFilterFormats *avfmts=NULL;
656  MPContext *m = ctx->priv;
657  enum AVPixelFormat lastpixfmt = AV_PIX_FMT_NONE;
658  int i;
659 
660  for(i=0; conversion_map[i].fmt; i++){
661  av_log(ctx, AV_LOG_DEBUG, "query: %X\n", conversion_map[i].fmt);
662  if(m->vf.query_format(&m->vf, conversion_map[i].fmt)){
663  av_log(ctx, AV_LOG_DEBUG, "supported,adding\n");
664  if (conversion_map[i].pix_fmt != lastpixfmt) {
665  ff_add_format(&avfmts, conversion_map[i].pix_fmt);
666  lastpixfmt = conversion_map[i].pix_fmt;
667  }
668  }
669  }
670 
671  if (!avfmts)
672  return -1;
673 
674  //We assume all allowed input formats are also allowed output formats
675  ff_set_common_formats(ctx, avfmts);
676  return 0;
677 }
678 
679 static int config_inprops(AVFilterLink *inlink)
680 {
681  MPContext *m = inlink->dst->priv;
682  int i;
683  for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
684 
685  av_assert0(conversion_map[i].fmt && inlink->w && inlink->h);
686 
687  m->vf.fmt.have_configured = 1;
688  m->vf.fmt.orig_height = inlink->h;
689  m->vf.fmt.orig_width = inlink->w;
690  m->vf.fmt.orig_fmt = conversion_map[i].fmt;
691 
692  if(m->vf.config(&m->vf, inlink->w, inlink->h, inlink->w, inlink->h, 0, conversion_map[i].fmt)<=0)
693  return -1;
694 
695  return 0;
696 }
697 
698 static int config_outprops(AVFilterLink *outlink)
699 {
700  MPContext *m = outlink->src->priv;
701 
702  outlink->w = m->next_vf.w;
703  outlink->h = m->next_vf.h;
704 
705  return 0;
706 }
707 
708 static int request_frame(AVFilterLink *outlink)
709 {
710  MPContext *m = outlink->src->priv;
711  int ret;
712 
713  av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame\n");
714 
715  for(m->frame_returned=0; !m->frame_returned;){
716  ret=ff_request_frame(outlink->src->inputs[0]);
717  if(ret<0)
718  break;
719  }
720 
721  av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame ret=%d\n", ret);
722  return ret;
723 }
724 
725 static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
726 {
727  MPContext *m = inlink->dst->priv;
728  int i;
729  double pts= MP_NOPTS_VALUE;
730  mp_image_t* mpi = ff_new_mp_image(inpic->width, inpic->height);
731 
732  if(inpic->pts != AV_NOPTS_VALUE)
733  pts= inpic->pts / av_q2d(inlink->time_base);
734 
735  for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
737  m->in_pix_fmt = inlink->format;
738 
739  memcpy(mpi->planes, inpic->data, FFMIN(sizeof(inpic->data) , sizeof(mpi->planes)));
740  memcpy(mpi->stride, inpic->linesize, FFMIN(sizeof(inpic->linesize), sizeof(mpi->stride)));
741 
742  if (inpic->interlaced_frame)
744  if (inpic->top_field_first)
746  if (inpic->repeat_pict)
748 
749  // mpi->flags|=MP_IMGFLAG_ALLOCATED; ?
750  mpi->flags |= MP_IMGFLAG_READABLE;
751  if(!av_frame_is_writable(inpic))
752  mpi->flags |= MP_IMGFLAG_PRESERVE;
753  if(m->vf.put_image(&m->vf, mpi, pts) == 0){
754  av_log(m->avfctx, AV_LOG_DEBUG, "put_image() says skip\n");
755  }else{
756  av_frame_free(&inpic);
757  }
758  ff_free_mp_image(mpi);
759  return 0;
760 }
761 
762 static const AVFilterPad mp_inputs[] = {
763  {
764  .name = "default",
765  .type = AVMEDIA_TYPE_VIDEO,
766  .filter_frame = filter_frame,
767  .config_props = config_inprops,
768  },
769  { NULL }
770 };
771 
772 static const AVFilterPad mp_outputs[] = {
773  {
774  .name = "default",
775  .type = AVMEDIA_TYPE_VIDEO,
776  .request_frame = request_frame,
777  .config_props = config_outprops,
778  },
779  { NULL }
780 };
781 
783  .name = "mp",
784  .description = NULL_IF_CONFIG_SMALL("Apply a libmpcodecs filter to the input video."),
785  .init = init,
786  .uninit = uninit,
787  .priv_size = sizeof(MPContext),
789  .inputs = mp_inputs,
790  .outputs = mp_outputs,
791  .priv_class = &mp_class,
792 };