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