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