ffmpeg编译新加的滤镜方法

ffmpeg的优秀在于它的功能强大和良好的系统框架,而滤镜就是其中之一。ffmpeg的自带滤镜不但能对视频进行裁剪,添加logo,还能将多个滤镜组全使用。
更妙之处在于它还可以方便地添加自己定义的各种滤镜。这种可扩展性对于实际应用来说就颇有价值了。

1、例如添加反相滤镜“vf_tnegate.c”:
源码如下:

libavfilter/vf_tnegate.c
#include "libavutil/eval.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavcodec/avcodec.h"
#include "avfilter.h"
typedef struct
{
  int hsub, vsub; // Used for chroma subsampling

}NegContext;

/* */

static int tnegate_config_props(AVFilterLink *link)

{

  NegContext *neg = link->dst->priv;



  avcodec_get_chroma_sub_sample(link->format, &neg->hsub, &neg->vsub);

  switch(link->format)

  {

    case PIX_FMT_YUVJ444P:

    case PIX_FMT_YUVJ422P:

    case PIX_FMT_YUVJ420P:

    case PIX_FMT_YUVJ440P:

      neg->offY =

      neg->offUV = 0;

      break;

    default:

      neg->offY = -4;

      neg->offUV= 1;

  }

  return 0;

}



static void tnegate_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)

{

  NegContext *neg = link->dst->priv;

  //AVFilterPicRef *in = link->cur_pic;

  //AVFilterPicRef *out = link->dst->outputs[0]->outpic;

  AVFilterBufferRef *in = link->cur_buf;

  AVFilterBufferRef *out = link->dst->outputs[0]->out_buf;

  unsigned char *inrow, *outrow;

  int i, j, plane;



  /* luma plane */

  inrow = in-> data[0] + y * in-> linesize[0]; // Get the row position of pixel

  outrow = out->data[0] + y * out->linesize[0];



  for(i = 0; i < h; i++)

  {

    for(j = 0; j < link->w; j++)

      outrow[j] = 255 -inrow[j] + neg->offY;

    outrow += in->linesize[0];

  }



  /* chroma planes */

  for(plane = 1; plane < 3; plane++)

  {
    inrow  = in-> data[plane] + (y >> neg->vsub) * in-> linesize[plane];
    outrow = out->data[plane] + (y >> neg->vsub) * out->linesize[plane];

    for(i = 0; i < (h >> neg->vsub); i++)
    {
      for(j = 0; j < (link->w >> neg->vsub); j++)
        outrow[j] = 255 - inrow[j] + neg->offUV;


      inrow += in-> linesize[plane];

      outrow += out->linesize[plane];

    }

  }

  avfilter_draw_slice(link->dst->outputs[0], y, h, 1);

}



static int tnegate_query_formats(AVFilterContext *ctx)

{

  static const enum PixelFormat pix_fmts[] = {

    PIX_FMT_YUV410P, PIX_FMT_YUV420P, PIX_FMT_GRAY8, PIX_FMT_NV12,

    PIX_FMT_NV21, PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV411P,

    PIX_FMT_NONE

  };

  avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));

  return 0;

}



/* the filter's structure */

AVFilter avfilter_vf_tnegate =

{

  .name = "tnegate", ///< filter name

  .priv_size = sizeof(NegContext), ///< size of private data to allocate for the filter

  .query_formats = tnegate_query_formats, ///< set the format of in/outputs

  

  /* the inputs of the filter */

  .inputs = (AVFilterPad[]){{ .name = "default",

                              .type = AVMEDIA_TYPE_VIDEO,

                              .draw_slice = tnegate_draw_slice, 

                              .config_props = tnegate_config_props, 

                              .min_perms = AV_PERM_READ,}, 

                            { .name = NULL }},

  /* the ouputs of the filter */

  .outputs = (AVFilterPad[]){{ .name = "default",

                               .type = AVMEDIA_TYPE_VIDEO, },

                             { .name = NULL }},

};

2. configure中声明使用的协议

# filters
...
tnegate_filter_deps="gpl"

3. libavfilter/allfilter.c中注册自定义滤镜

void avfilter_register_all(void)
{
    ...
    REGISTER_FILTER (TNEGATE, tnegate, vf);
    ...
}

4.libavfilter/Makfile中添加滤镜的链接

OBJS = allfilters.o \
       avfilter.o \
       avfiltergraph.o \
       defaults.o \
       drawutils.o \
       formats.o \
       graphparser.o \
OBJS-$(CONFIG_AVCODEC) += avcodec.o
...
OBJS-$(CONFIG_TNEGATE_FILTER) += vf_tnegate.o

5.configure设置

./configure \
--enable-gpl --enable-nonfree --enable-version3 \
...
--enable-avfilter --enable-filter=movie \
--enable-avfilter --enable-filter=tnegate

6.编译与运行

#make
#./ffmpeg -i input.flv -vf "tnegate" -y output.flv
点赞