FFmpeg常用视频过滤器

官方文档:http://ffmpeg.org/ffmpeg-filters.html

前段时间倒腾在线视频转码的小程序,捣鼓了一段时间FFmpeg

1. ffprobe

  • 使用ffprobe可以查看视频的详细信息(视频流、音频流、码率等等)
ffprobe -v quiet -print_format json -show_format -show_streams test.mp4

2. ffmpeg

-filter_complex 常用于复杂的特效处理场景,相比于 -vf 使用更灵活支持更高级的方法。

1)给视频添加一个LOGO水印

// http://ffmpeg.org/ffmpeg-filters.html#scale2ref
// http://ffmpeg.org/ffmpeg-filters.html#overlay-1

ffmpeg -i src.mp4 -i logo.png -filter_complex [1:v][0:v]scale2ref=w=oh*mdar:h=ih/12[logo][base];[base][logo]overlay=20:main_h-overlay_h-10[base1] out.mp4

// scale2ref:按照给定video输入流,设定logo的尺寸
// 格式:[logo-in][video-in]scale2ref=w={宽度}:h={高度}[logo-out][video-out]

// overlay:将一个视频叠加到一个视频上 x,y
// 格式:[video-in][logo-in]overlay={x位置}:{y位置}

通过上面的简单入门就可以发现使用规律,-filter_complex 的语法先需要熟悉API的(输入参数、输出参数)文档。

  • [0:v] 表示第一个输入流 src.mp4 ,[1:v] 表示 logo.png。
  • 先使用 scale2ref 过滤器将logo.png设置为视频高度的12分之1,这样可以保持在不同的视频分辨率下logo都可以保持相同大小效果。
  • scale2ref=w={w}:h={h}[logo][base][logo][base] 表示 scale2ref 输出的流(可以自己随意命名),多个过滤器使用";"隔开,上一个过滤器的输出流可以被下一个过滤器使用。
  • overlay 过滤器直接使用 scale2ref 输出后的流,如果后续还要继续处理需要再写上输出参数,如:overlay={x位置}:{y位置}[video-out];

2)举一反三,再给视频加一段文字水印

完整这段就是给视频添加一个LOGO水印,并且再添加一个周期显示的文字跑马灯水印

// http://ffmpeg.org/ffmpeg-filters.html#scale-1
// http://ffmpeg.org/ffmpeg-filters.html#Commands-67

ffmpeg -i src.mp4 -i logo.png -filter_complex [1:v][0:v]scale2ref=w=oh*mdar:h=ih/12[logo][base];[base][logo]overlay=20:main_h-overlay_h-10[base1];[base1]scale=1102:620[base3];[base3]drawtext=text='Hello Word':fontfile='msyh.ttf':y='h-line_h-200':x='w-(w+tw)/45*mod(t\,245)':fontcolor='white@0.2':fontsize='round(main_h*0.05)':shadowx='0':shadowy='0' out.mp4

// drawtext=text='文字':fontfile='字体路径';y='Y坐标':x='X坐标':fontcolor='颜色@透明度':fontsize='字体大小':shadowx='X轴文字阴影':shadowy='Y轴文字阴影'
  • scale 改变视频的尺寸,宽高建议是偶数,否则有时候会异常。
  • x='w-(w+tw)/45mod(t\,245)'* 周期滚动,公式如下代码。
public class DrawTextFilter(){
    // 视频高度 - 10
    private String y = "h-line_h-10";
    private String fontColor = "white";
    private int fontSize = 50;
    private int shadowX = 0;
    private int shadowY = 0;
    // 显示时长
    private int rollTime = 20;
    // 显示间隔
    private int rollInterval = 10;
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("drawtext=")
                .append("text='" + text + "'")
                .append(":fontfile='" + fontPath + "'")
                .append(":y='" + y + "'")
                .append(":x='w-(w+tw)/" + rollTime + "*mod(t\\," + (rollTime + rollInterval) + ")'")
                .append(":fontcolor='" + fontColor + "'")
                .append(":fontsize='round(main_h*" + (fontSize / 1000f) + ")'")
                .append(":shadowx='" + shadowX + "'")
                .append(":shadowy='" + shadowY + "'");

        return sb.toString();

}

PS:Java 使用 Process 调用 ffmpeg 命令的会有转义的问题,不需要画蛇添足再添加双引号,否则会导致 Linux 和 Win 不兼容。


3)HLS切片

ffmpeg -y -i test.mp4 -c copy -map 0 -f hls -hls_playlist_type vod -hls_segment_type mpegts -hls_time 4 -hls_segment_filename hls-%03d.ts index.m3u8
  • -hls_time 每个TS片段的时长,仅作参考。和视频关键帧有关,如强行增加视频关键帧会明显增加视频文件大小。

最后写了个生产力玩具