流媒体开发11ffmpeg命令过滤器(裁剪水印画中画多宫格)

Posted 叮咚咕噜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了流媒体开发11ffmpeg命令过滤器(裁剪水印画中画多宫格)相关的知识,希望对你有一定的参考价值。

一、裁剪

  • 裁剪: 是指从原图中抠出一个区域,那么需要裁剪一个区域需要哪些参数呢?

    • 左上角起始点的坐标
    • 需要裁剪的宽高
  • ffmpeg命令语法:crop=ow[:oh[:x[:y[:keep_aspect]]]]

  • 举例说明:

  • 裁剪左边1/3

ffmpeg -i input -vf crop=iw/3:ih:0:0 output
ffplay -i input -vf crop=iw/3:ih:0:0
  • 裁剪中间1/3
ffmpeg -i input -vf crop=iw/3:ih:iw/3:0 output
ffplay -i input -vf crop=iw/3:ih:iw/3:0
  • 裁剪右边1/3
ffmpeg -i input -vf crop=iw/3:ih:iw/3*2:0 output
ffplay -i input -vf crop=iw/3:ih:iw/3*2:0
  • 输入文件不管是图片还是视频都可以使用该命令进行裁剪

二、 FFmpeg 滤镜 Filter 内置变量

在使用 Filter 时,经常会用到根据时间轴进行操作的需求,在使用 FFmpeg 的 Filter 时可以使用 Filter 的时间相关的内置变量,下面先来了解一下这些相关的变量,见下表。

变量说明
t以秒表示的时间戳,如果输入的时间是未知的则是 NAN
n输入帧的顺序编号,从 0 开始
pos输入帧的位置(字节在文件中偏移的位置),如果未知的则是 NAN,无效值
w输入视频帧的宽度
h输入视频帧的高度

三、水印

3.1文字水印

在视频中增加文字水印需要准备的条件比较多,需要有文字字库处理的相关文件,在编译 FFmpeg 时需要支持 FreeType、FontConfig、iconv,系统中需要有相关的字库,在FFmpeg 中增加纯字母水印可以使用 drawtext滤镜进行支持,下面就来看一下 drawtext 的滤镜参数

参数类型说明
text字符串文字
textfile字符串文字文件(字符串太长可以写到文件中)
box布尔文字区域背景框(缺省 false)
boxcolor色彩展示字体区域块的颜色
font字符串字体名称(默认为 Sans 字体)
fontsize整数显示字体的大小
x字符串缺省为 0 y 字符串 缺省为 0
alpha浮点数透明度(默认为 1),值从 0~1
  • 1、将文字的水印加在视频的左上角:
    • 引号中间是整个Filter的,每个参数用冒号隔开
ffplay -i input.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello world':x=20:y=20"
## 将字体的颜色设置为绿色:
ffplay -i input.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello world':fontcolor=green"
## 如果想调整文字水印显示的位置,调整 x 与 y 参数的数值即可
ffplay -i input.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello world':fontcolor=green:x=400:y=200"
## 修改透明度
ffplay -i input.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello world':fontcolor=green:x=400:y=200:alpha=0.5"
  • 2、文字水印还可以增加一个框,然后给框加上背景颜色:
ffplay -i input.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='hello  world':fontcolor=green:box=1:boxcolor=yellow"

至此,文字水印的基础功能已经添加完成。

  • 3、有些时候文字水印希望以本地时间作为水印内容,可以在 drawtext 滤镜中配合一些特殊用法来完成,在 text 中显示本地当前时间,格式为年月日时分秒的方式:
ffplay -i input.mp4 -vf "drawtext=fontsize=60:fontfile=FreeSerif.ttf:text='%{localtime\\:%Y\\-%m\\-%d %H-%M-%S}':fontcolor=green:box=1:boxcolor=yellow"

在使用 ffmpeg 转码存储到文件时需要加上-re(表示按照时间戳来打水印,因为是在转码,1s会有多帧,按照当前时间显示会有异常),否则时间不对

ffmpeg -re -i input.mp4 -vf "drawtext=fontsize=60:fontfile=FreeSerif.ttf:text='%{localtime\\:%Y\\-%m\\-%d %H-%M-%S}':fontcolor=green:box=1:boxcolor=yellow" out.mp4
  • 4、在个别场景中,需要定时显示水印,定时不显示水印,这种方式同样可以配合 drawtext 滤镜进行处理,使用 drawtext 与 enable 配合即可,例如每 3 秒钟显示一次文字水印:
ffplay -i input.mp4 -vf "drawtext=fontsize=60:fontfile=FreeSerif.ttf:text='test':fontcolor=green:box=1:boxcolor=yellow:enable=lt(mod(t\\,3)\\,1)"

在使用 ffmpeg 转码存储到文件时需要加上-re,否则时间不对。
表达式参考:http://www.ffmpeg.org/ffmpeg-utils.html 3 Expression Evaluation
lt(x, y) Return 1 if x is lesser than y, 0 otherwise。x小于y返回1,否则返回0
mod(x, y) Compute the remainder of division of x by y,x对y取余

  • 5、跑马灯效果
    • 跑马灯是指文字水印在视频界面上波动,也是根据mod公式动态的修改水平的x,y坐标达到跑马灯的效果
ffplay -i input.mp4 -vf "drawtext=fontsize=100:fontfile=FreeSerif.ttf:text='helloworld':x=mod(100*t\\,w):y=abs(sin(t))*h*0.7"

修改字体透明度,修改字体颜色

ffplay -i input.mp4 -vf "drawtext=fontsize=40:fontfile=FreeSerif.ttf:text='liaoqingfu':x=mod(50*t\\,w):y=abs(sin(t))*h*0.7:alpha=0.5:fontcolor=white:enable=lt(mod(t\\,3)\\,1)"

3.2图片水印

FFmpeg 除了可以向视频添加文字水印之外,还可以向视频添加图片水印、视频跑马灯等,本节将重点介绍如何为视频添加图片水印;为视频添加图片水印可以使用 movie 滤镜,下面就来熟悉一下 movie 滤镜的参数

参数类型说明
filename字符串输入的文件名,可以是文件,协议,设备
format_name, f字符串输入的封装格式
stream_index, si整数输入的流索引编号
seek_point, sp浮点数Seek 输入流的时间位置
streams, s字符串输入的多个流的流信息
loop整数循环次数
discontinuity时间差值支持跳动的时间戳差值
ffmpeg -i input.mp4 -vf "movie=logo.png[watermark];[in][watermark]overlay=x=10:y=10[out]" output.mp4

➢ 原始视频文件路径:input.mp4
➢ 水印图片路径:logo.png
➢ 水印位置:(x,y)=(10,10)<=(left,top)距离左侧、顶部各 10 像素;
➢ 输出文件路径:output.mp4
➢ in:表示的是input.mp4,名字可以随便定
➢ watermark:表示待叠加的logo.png,名字可以随便定

参数说明
main_w视频单帧图像宽度
main_h视频单帧图像高度
overlay_w水印图片的宽度
overlay_h水印图片的高度

对应地可以将 overlay 参数设置成如下值来改变水印图片的位置:

水印图片位置overlay 值
左上角10:10
右上角main_w-overlay_w-10:10
左下角10:main_h-overlay_h-10
右下角main_w-overlay_w-10:main_h-overlay_h-10


在 FFmpeg 中加入图片水印有两种方式,一种是通过 movie 指定水印文件路径,另外一种方式是通过filter 读取输入文件的流并指定为水印,这里重点介绍如何读取 movie 图片文件作为水印。

  • 1、图片 logo.png 将会打入到 input.mp4 视频中,显示在 x 坐标 50、y 坐标 20 的位置
ffplay -i input.mp4 -vf "movie=logo.png[logo];[in][logo]overlay=50:10[out]"

由于 logo.png 图片的背景色是白色,所以显示起来比较生硬,如果水印图片是透明背景的,效果会更好,下面找一张透明背景色的图片试一下:

ffplay -i input.mp4 -vf "movie=logo2.png[watermark];[in][watermark]overlay=50:10[out]"
  • 2、显示位置
ffplay -i input.mp4 -vf "movie=logo.png[watermark];[in][watermark]overlay=10:10[out]"
ffplay -i input.mp4 -vf "movie=logo.png[watermark];[in][watermark]overlay=main_w-overlay_w-10:10[out]"
ffplay -i input.mp4 -vf "movie=logo.png[watermark];[in][watermark]overlay=10:main_h-overlay_h-10[out]"
ffplay -i input.mp4 -vf "movie=logo.png[watermark];[in][watermark]overlay=main_w-overlay_w-10:main_hoverlay_h-10[out]"
  • 3、跑马灯效果
ffplay -i input.mp4 -vf "movie=logo.png[watermark];[in][watermark]overlay=x=mod(50*t\\,main_w):y=abs(sin(t))*h*0.7[out]"

四、生成画中画

  • 画中画顾名思义就是播放的一个视频上面有叠加了另一个视频在播放
  • 在使用 FFmpeg 处理流媒体文件时,有时需要使用画中画的效果。在 FFmpeg 中,可以通过 overlay 将多个视频流、多个多媒体采集设备、多个视频文件合并到一个界面中,生成画中画的效果。在前面的滤镜使用中,以至于以后的滤镜使用中,与视频操作相关的处理,大多数都会与 overlay 滤镜配合使用,尤其是用在图层处理与合并场景中,下面就来了解一下 overlay 的参数
参数类型说明
x字符串X 坐标
y字符串Y 坐标
eof_action整数遇到 eof 表示时的处理方式,默认为重复 ➢ repeat(值为 0):重复前一帧(子画面保存前一帧) ➢ endcall(值为 1):停止所有的流(主画面和子画面全部停止) ➢ pass(值为 2):保留主图层(子画面关闭)
shortest布尔终止最短的视频时全部终止(默认 false)
format整数设置 output 的像素格式,默认为 yuv420,➢ yuv420 (值为 0) ➢ yuv422 (值为 1) ➢ yuv444 (值为 2) ➢ rgb (值为 3)

(1)显示画中画效果
ffplay -i input.mp4 -vf “movie=sub_320x240.mp4[sub];[in][sub]overlay=x=20:y=20[out]”

  • [sub]就表示要叠加的子画面
  • [in]表示输入的视频
  • [in][sub]overlay=x=20:y=20[out] 表示输入和sub子画面叠加,叠加的位置由x,y决定,out表示输出,sub子画面的名字可以随意修改

(2)子画面停止退出显示,主画面正常播放

ffplay -i input.mp4 -vf "movie=sub_320x240.mp4[sub];[in][sub]overlay=x=20:y=20:eof_action=2[out]"

(3)最短的视频播完则整个画面停止播放
ffplay -i input.mp4 -vf “movie=sub_320x240.mp4[sub];[in][sub]overlay=x=20:y=20:shortest =1[out]”

(4)任意的缩放子画面尺寸

ffplay -i input.mp4 -vf "movie=sub_320x240.mp4,scale=640x480[sub];[in][sub]overlay=x=20:y=20[out]"

(5)跑马灯效果

ffplay -i input.mp4 -vf "movie=sub_320x240.mp4[test];[in][test]overlay= x=mod(50*t\\,main_w):y=abs(sin(t))*main_h*0.7[out]"

五、视频多宫格处理

视频除了画中画显示,还有一种场景为以多宫格的方式呈现出来,除了可以输入视频文件,还可以输入视频流、采集设备等。从前文中可以看出进行视频图像处理时,overlay 滤镜为关键画布,可以通过 FFmpeg建立一个画布,也可以使用默认的画布。如果想以多宫格的方式展现,则可以自己建立一个足够大的画布,下面就来看一下多宫格展示的例子:

ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 -filter_complex "nullsrc=size=640x480[base];[0:v] setpts=PTS-STARTPTS,scale=320x240[upperleft];[1:v]setpts=PTS-STARTPTS,scale=320x240[upperright];[2:v]setpts=PTS-STARTPTS, scale=320x240[lowerleft];[3:v]setpts=PTS-STARTPTS,scale=320x240[lowerright];[base][upperleft]overlay=shortest=1[tmp1];[tmp1][upperright]overlay=shortest=1:x=320[tmp2];[tmp2][lowerleft]overlay=shortest=1:y=240[tmp3];[tmp3][lowerright]overlay=shortest=1:x=320:y=240" out.mp4

看到这么长的命令可能已经晕了,其实将命令拆分解析一下就很简单了,对命令进行拆分解析:

ffmpeg -i 1.mp4 -i 2.mp4 -i 3.mp4 -i 4.mp4 #所有输入
-filter_complex "nullsrc=size=640x480[base];   #创建了一个base的画面,大小640*480
[0:v] setpts=PTS-STARTPTS,scale=320x240[upperleft];   #视频1命令为upperleft,缩放为320x240
[1:v]setpts=PTS-STARTPTS,scale=320x240[upperright];   #视频2命令为upperright,缩放为320x240
[2:v]setpts=PTS-STARTPTS, scale=320x240[lowerleft];   #视频3命令为lowerleft,缩放为320x240
[3:v]setpts=PTS-STARTPTS,scale=320x240[lowerright];   #视频4命令为lowerright,缩放为320x240
[base][upperleft]overlay=shortest=1[tmp1];    # [base][upperleft]叠加生成[tmp1],upperleft没设置就是叠加在(0,0)位置
[tmp1][upperright]overlay=shortest=1:x=320[tmp2];     #[tmp1][upperright]叠加生成[tmp2],叠加在(320,0)位置
[tmp2][lowerleft]overlay=shortest=1:y=240[tmp3];		#[tmp2][lowerleft]叠加生成[tmp3]
[tmp3][lowerright]overlay=shortest=1:x=320:y=240" 		#[tmp3][lowerright]叠加生成最终的输出
out.mp4

1.2.3.4.mp4 为文件路径,out.MP4 为输出文件路径,通过 nullsrc 创建 overlay 画布,画布大小 640:480,使用[0:v][1:v][2:v][3:v]将输入的 4 个视频流去除,分别进行缩放处理,然后基于 nullsrc 生成的画布进行视频平铺,命令中自定义 upperleft,upperright,lowerleft,lowerright 进行不同位置平铺。


显示输出:

以上是关于流媒体开发11ffmpeg命令过滤器(裁剪水印画中画多宫格)的主要内容,如果未能解决你的问题,请参考以下文章

Android NDK开发之FFmpeg视频添加水印

ffmpeg处理视频命令

使用 FFMPEG 裁剪视频时出错

ffmpeg # 画中画中的视频进行循环

带有水印和音频的 FFmpeg 连接“过滤器图描述中的流说明符不匹配任何流”。

Android NDK开发之旅38--FFmpeg视频添加水印