ffmpeg滤镜

过滤器分类
1.1简单过滤器
在简单过滤器中,只包含一个输入和一个输出,并且输入输出是同一类型。在下面的处理过程中,仅仅是在解码和编码之间加上一个额外的过滤步骤。

简单过滤器由per-stream-filter参数(视频为-vf,音频为-af)配置。一个用于处理视频的简单过滤器大概是这个流程:

一些过滤器只改变数据帧的属性,并不改变数据帧的内容。例如:fps过滤器改变数据帧的个数,并不涉及数据帧的内容。另一个例子是setpts过滤器,它仅仅改变时间戳然后传递这些数据帧而已。
1.2复杂过滤器
复杂过滤器不是简单的将线性操作链应用于一个流(上面简单过滤器过程便是如此)。当有多个输入和输出时,或者输出类型和输入类型不一致时,可以用下面的图来展示复杂过滤器的处理流程:
 
复杂过滤器类型由-filter_complex参数配置。这个参数是全局的,因为复杂过滤器类型本身就不可能只和一个流或文件关联,这是由它的本质决定的。此外-lavfi参数和-filter_complex是等价的。关于复杂过滤器类型一个常用例子是overlay过滤器,它有两个输入,一个输出,其中一个视频覆盖在另外一个上面:     

ffmpeg -i video_1.mkv -i video_2.3gp -filter_complex 'overlay' video_out.mp4


视频加速

1. 加速/减慢视频
可以使用 “setpts"(http://ffmpeg.org/ffmpeg.html#asetpts_002c-setpts)滤镜来改变视频速度。

加速视频命令:
# ./ffmpeg -i input.mkv -filter:v "setpts=0.5*PTS" output.mkv

Note : 这个方法在实现你想要的速度时,会采取丢帧策略。
如果想避免丢帧,可以指定输出的帧率比输入的帧率高的办法。
例如,输入的帧率为4, 指定输出的帧率为4x, 即16fps :
# ./ffmpeg -i input.mkv -r 16 -filter:v "setpts=0.125*PTS" -an output.mkv

减慢视频命令:
# ./ffmpeg -i input.mkv -filter:v "setpts=2.0*PTS" output.mkv

2. 加速/减慢音频
可以使用" atempo" 音频滤镜来加速或减慢音频。如双倍速音频命令:
# ./ffmpeg -i input.mkv -filter:a "atempo=2.0" -vn output.mkv

"atempo"滤镜对音频速度调整限制在0.5 到 2.0 之间,(即半速或倍速)。
如果有必要,可以使用多个atempo滤镜来实现,如下面的命令实现四倍速音频:
# ./ffmpeg -i input.mkv -filter:a "atempo=2.0,atempo=2.0" -vn output.mkv

使用更复杂的滤镜图,可以同时加速视频和音频:

# ./ffmpeg -i input.mkv -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" output.mkv

转换比率

假定大于1为慢速,小于1为快速。
则0.3的转换为,V*3/10,A*10/3, 1.2的转换为V*12/10,A*10/12。


缩小视频

scale可以成比例拉伸。
假设原始视频尺寸是 1080p(即 1920×1080 px,16:9),使用下面命令可以缩小到 480p:
$ ffmpeg -i a.mov -vf scale=853:480 -acodec aac -vcodec h264 out.mp4
-vf scale=853:480 vf 参数用于指定视频滤镜,其中 scale 表示缩放,后面的数字表示缩放至 853×480 px,其中的 853px 是计算而得,因为原始视频的宽高比为 16:9,所以为了让目标视频的高度为 480px,则宽度 = 480 x 9 / 16 = 853。上面的参数 scale=853:480 当中的宽度和高度实际应用场景中通常只需指定一个,比如指定高度为 480 或者 720,至于宽度则可以传入 “-1” 表示由原始视频的宽高比自动计算而得。即参数可以写为:scale=-1:480,当然也可以 scale=480:-1。
对输入视频成比例缩放
改变为源视频一半大小
ffmpeg -i input.mpg -vf scale=iw/2:ih/2 output.mp4
改变为原视频的90%大小:
ffmpeg -i input.mpg -vf scale=iw*0.9:ih*0.9 output.mp4

裁剪视频
有时可能只需要视频的正中一块,而两头的内容不需要,这时可以对视频进行裁剪(crop),比如有一个竖向的视频 1080 x 1920,如果指向保留中间 1080×1080 部分,可以使用下面的命令:
$ ffmpeg -i a.mov -strict -2 -vf crop=1080:1080:0:420 out.mp4
其中的 crop=1080:1080:0:420 才裁剪参数,具体含义是 crop=width:height:x:y,其中 width 和 height 表示裁剪后的尺寸,x:y 表示裁剪区域的左上角坐标。比如当前这个示例,我们只需要保留竖向视频的中间部分,所以 x 不用偏移,故传入0,而 y 则需要向下偏移:(1920 – 1080) / 2 = 420
视频缩放和裁剪是可以同时进行的,如下命令则为将视频缩小至 853×480,然后裁剪保留横向中间部分:
$ ffmpeg -i IMG_4940.MOV -strict -2 -vf scale=853:480,crop=480:480:186:0 out.mp4


填充
在视频帧上增加一快额外额区域,经常用在播放的时候显示不同的横纵比
语法:pad=width[:height:[:x[:y:[:color]]]]

使用FFmpeg给视频增加黑边需要用到 pad 这个滤镜,具体用法如下:
   -vf pad=1280:720:0:93:black
按照从左到右的顺序依次为:
  “宽”、“高”、“X坐标”和“Y坐标”,宽和高指的是输入视频尺寸(包含加黑边的尺寸),XY指的是视频所在位置。

相当于准备一个大的面板,将视频放上去,左上角的坐标为x,y。

比如一个输入视频尺寸是1280x534的源,想要加上黑边变成1280x720,那么用上边的语法可以实现,93是这样得来的,(720-534)/2。
如果视频原始1920x800的话,完整的语法应该是:
   -vf scale=1280:534,pad=1280:720:0:93:black
先将视频缩小到1280x534,然后在加入黑边变成1280x720,将1280x534的视频放置在x=0,y=93的地方,
FFmpeg会自动在上下增加93像素的黑边。
注:black可以不写,默认是黑色

水印

用in.avi作为输入视频,out.avi作为输出视频,pp.png表示要添加的水印图片,是png格式的,调整水印大小(scale = 50:50)和位置(overlay=10:10)
ffmpeg –i in.avi -i /data/move/long.png -filter_complex '[1:v]scale=50:50[s];[0:v][s]overlay=10:10' -b:v 500000 -c:v h264  -s cif -f mpegts out.avi
使用overlay添加透明水印时,位置参数的位置在 -vfilters 里面的 overlay= 的后面的前两个参数,参数之间是冒号分隔的。第一个参数是横向的间距,第二个是纵向的间距。可以结合与视频和水印相关的四个值来设置,这四个值分别是:mainW表示主视频宽度,

mainH表示主视频高度,overlayW表示水印宽度,overlayH表示水印高度。这些值加在overlay参数中,ffmpeg将自动识别。
也就是说要让水印
显示在视频的左上角overlay参数为 overlay=0:0
显示在右上角为 overlay= main_w-overlay_w:0
显示在右下角为 overlay= main_w-overlay_w:main_h-overlay_h
显示在左下角为 overlay=0: main_h-overlay_h
上面的0可以改为5,或10像素,以便多留出一些空白。

map参数的使用

The best way to understand -map option is to think of it like a way to tell FFmpeg which streams do you want to select/copy from input to an output.

1、-map 0 选择第一个文件的所有流
2、-map i:v 从文件序号i(index)中获取所有视频流, -map i:a 获取所有音频流,-map i:s 获取所有字幕流等等。
3、特殊参数-an,-vn,-sn分别排除所有的音频,视频,字幕流。
To select all video and the third audio stream from an input file:
ffmpeg -i INPUT -map 0:v -map 0:a:2 OUTPUT
ffmpeg -i audio.mp3 -i video.mp4 -filter_complex \
"[0:a][1:a]amerge,pan=stereo:c0<c0+c2:c1<c1+c3[out]" \
-map 1:v -map "[out]" -c:v copy -c:a libfdk_aac -shortest output.mp4

This will take the audio stream from the first input (audio.mp3) and the audio stream from the second input (video.mp4). amerge will combine them into a 4 channel stream, then pan will combine the 4 channels into a stereo stream. The output link label is called [out] (you can use almost any arbitrary name).
Then -map 1:v selects the video from the second input as a video source for the output file, and -map "[out]" selects the audio from the filtergraph as an audio source for the output file.
The video is stream copied with -c:v copy, so it is not re-encoded. Filters require re-encoding, so -c:a libfdk_aac is used in this example to re-encode to AAC audio.
The -shortest option will end the output file whenever the shortest input ends which is useful if one input is shorter than the other.

./ffmpeg -f lavfi -i testsrc -f lavfi -i testsrc -f lavfi -i testsrc -f lavfi -i testsrc -filter_complex \
"[0:v]pad=iw*2:ih*2[a]; \
 [1:v]negate[b]; \
 [2:v]hflip[c]; \
 [3:v]edgedetect[d]; \
 [a][b]overlay=w[x]; \
 [x][c]overlay=0:h[y]; \
 [y][d]overlay=w:h[out]" -map "[out]" -c:v ffv1 -t 5 multiple_input_grid.avi

例子:

aac跟另一个mp4的视频合并。

ffmpeg -i cu.aac -i bao.mp4 -map 0 -map 1:v n.mp4     


滤镜列表
滤镜和libavfilter绑定在一起,如 4.3.100(as configured with --enable-gpl). 
使用外部库的滤镜并未列在这里,如frei0r.可以查看FFMPEG的滤镜文档。
滤镜列表约定:
  T.. = Timeline support
  .S. = Slice threading
  ..C = Commmand support
  A = Audio input/output
  V = Video input/output
  N = Dynamic number and/or type of input/output
  | = Source or sink filter


### 开发 FFmpeg 滤镜 开发自定义 FFmpeg 滤镜涉及多个方面,包括理解 FFmpeg 的架构、编写 C 代码以及编译集成到 FFmpeg 中。以下是创建简单滤镜的过程。 #### 创建简单的灰度转换滤镜 为了实现一个将彩色图像转为灰度图的滤镜,可以按照如下方式操作: 1. **初始化项目结构** 建立一个新的目录用于存放源码文件,并下载 FFmpeg 源码作为参考和依赖库。 2. **编写滤镜核心逻辑** 下面是一个简化版本的灰度化滤镜 `vf_grayscale.c` 文件的内容示例[^1]: ```c #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavfilter/buffersink.h" #include "libavfilter/buffer.h" typedef struct GrayscaleContext { const AVClass *class; } GrayscaleContext; #define OFFSET(x) offsetof(GrayscaleContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM static const AVOption grayscale_options[] = { { NULL } }; AVFILTER_DEFINE_CLASS(grayscale); // 初始化函数 static int init(AVFilterContext *ctx){ // 可以在这里设置一些默认参数或分配资源 return 0; } // 执行过滤器的核心算法 static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref){ AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; /* 获取输出缓冲区 */ AVFrame *outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!outpicref) return AVERROR(ENOMEM); uint8_t *src = inpicref->data[0]; // 输入数据指针 uint8_t *dst = outpicref->data[0]; // 输出数据指针 int linesize_in = inpicref->linesize[0]; int linesize_out = outpicref->linesize[0]; for (int y=0; y<inpicref->height; ++y){ for(int x=0; x<inpicref->width*3; x+=3){ // 假设RGB24格式 unsigned char r = src[y*linesize_in+x]; unsigned char g = src[y*linesize_in+x+1]; unsigned char b = src[y*linesize_in+x+2]; // 计算亮度值 Y = 0.299R + 0.587G + 0.114B float gray_value = 0.299*r + 0.587*g + 0.114*b; dst[y*linesize_out+(x/3)] = (unsigned char)(gray_value); } } av_frame_free(&inpicref); return ff_filter_frame(outlink, outpicref); } // 定义静态常量描述符 static const AVFilterPad inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .filter_frame = filter_frame, }, {NULL} }; static const AVFilterPad outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, }, {NULL} }; // 注册此滤镜FFmpeg框架内 AVFilter ff_vf_grayscale = { .name = "grayscale", .description = NULL_IF_CONFIG_SMALL("Convert video to grayscale."), .init = init, .uninit = uninit, .query_formats = query_formats, .priv_size = sizeof(GrayscaleContext), .inputs = inputs, .outputs = outputs, .priv_class=&grayscale_class, }; ``` 这段代码实现了基本的功能——接收输入帧,在内存中将其颜色空间由 RGB 转换为单通道灰度表示形式后再传递给下一个环节。注意这里假设输入像素是以 RGB24 格式存储;实际应用时可能需要考虑更多种情况下的兼容性处理[^3]。 3. **配置与构建** 完成上述工作之后,还需要修改 FFmpeg 构建系统的 Makefile 和其他必要的配置文件来包含新添加的模块。具体来说就是编辑 `filters/filters.c`, 添加一行注册语句以便让整个程序知道有这样一个新的外部插件存在。 最后运行标准流程重新编译整个工程即可使新增加的效果生效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值