惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
AWS News Blog
AWS News Blog
Spread Privacy
Spread Privacy
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Security Latest
Security Latest
Simon Willison's Weblog
Simon Willison's Weblog
C
Cybersecurity and Infrastructure Security Agency CISA
G
GRAHAM CLULEY
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
I
Intezer
S
Securelist
Google DeepMind News
Google DeepMind News
S
Schneier on Security
T
Troy Hunt's Blog
Help Net Security
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
V
V2EX
Security Archives - TechRepublic
Security Archives - TechRepublic
O
OpenAI News
博客园 - Franky
G
Google Developers Blog
Stack Overflow Blog
Stack Overflow Blog
TaoSecurity Blog
TaoSecurity Blog
MyScale Blog
MyScale Blog
P
Privacy International News Feed
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Google Online Security Blog
Google Online Security Blog
Latest news
Latest news
Vercel News
Vercel News
T
The Blog of Author Tim Ferriss
博客园_首页
S
Security Affairs
PCI Perspectives
PCI Perspectives
WordPress大学
WordPress大学
C
Cisco Blogs
Recent Announcements
Recent Announcements
L
LangChain Blog
GbyAI
GbyAI
F
Fortinet All Blogs
N
News and Events Feed by Topic
T
Tor Project blog
IT之家
IT之家
P
Palo Alto Networks Blog
D
DataBreaches.Net
小众软件
小众软件
宝玉的分享
宝玉的分享
F
Full Disclosure

FFmpeg

[FFmpeg 的实时性太糟糕了] 后续 - V2EX intel qsv ffmpeg 编码问题 - V2EX FFmpeg 的实时性太糟糕了 - V2EX 早就听说过 ffmpeg,但是一直不知道有多牛 - V2EX 使用 FFmpeg 和 GPU 实现最简“图片+无损音频=视频”的方法 - V2EX FFmpegKit has been officially retired. There will be no further ffmpeg-kit releases. - V2EX 有没有精通 ffmpeg 的大佬帮我看下这个视频是怎么制作的 - V2EX 使用 FFmpeg 试图做个人用的转码点播服务端, 但 mpegts 多个切片间音频偶尔不连续? - V2EX 求助大佬们, FFmpeg 指令拉实时流转推的正确姿势到底是什么? - V2EX 在几乎不损失画质的前提下,怎么用 ffmpeg 把 h.264 格式的视频转换成 h.265 格式的? - V2EX 我又来询问 ffmpeg 问题了!这次是硬件加速! - V2EX 大佬们, nodejs 和 Python 做类似 jellyfin 实时转码是不是只能用 ffmpeg 实现了 - V2EX 有大佬开发过 ffmpeg 吗?用 c++调用 ffmpeg API 解码视频流 CPU 占用率高,求解决办法 - V2EX ffmpeg 视频录制切分问题请教 - V2EX 通过 ffmpeg 压缩视频很慢 时间敏感的需求该怎么设置参数呢? - V2EX ffmpeg 处理后视频时长问题 - V2EX 请教一个关于 ffmpeg 的问题 - V2EX 如何下载官方的 ffmpeg 二进制发布 - V2EX 视频模板替换图片,有偿 - V2EX 关于我在 fcp 导入视频时出现的无法解决的问题,请求各位 ffmpeg 大佬的帮忙 - V2EX go + ffmpeg pipe 怎么确定当前转码操作已经结束,可以停了 - V2EX 给人声视频加入背景声音,如何做到自动调整背景的音量 - V2EX 使用 ffmpeg 用 aes 加密 m3u8 文件的疑惑 - V2EX 把歌曲压缩至 7 kbps, FFmpeg 之父发布音频压缩工具 TSAC - V2EX 求助使用 ffmpeg 压缩.mov 视频输出后丢失元数据问题如何解决 - V2EX homebrew 安装的 fmpeg 转码速度比较慢?直接编译可以提高速度吗? - V2EX 使用 nodejs 调用和在 macos 终端里直接调用 ffmpeg 转 m3u8,两者花费时间相差巨大 - V2EX FFmpeg 如何录屏时排除录制指定的某个窗口 - V2EX ffmpeg 最近大版本发布为啥这么快 - V2EX ffmpeg 如何加快解码速度?算力不变的情况下,不在乎解码质量 - V2EX FFmpeg 怎么支持 segment_size 选项? - V2EX 为什么 ffmpeg 的体积会这么大?多复杂的算法编译后也不会有几十 MB 吧? - V2EX FFmpeg 使用 debug_ts 打印全过程的 pts - V2EX ffmpeg 如何更快速的查询视频的"缺帧" - V2EX 如何将 AVS3 8KHDR 视频转码为 HEVC 8KHDR 视频? - V2EX 请教大佬们,在线网站抓到 m3u8 能播放,但是用 ffmpeg 下载的时候 “403 forbidden” 或者 “Output file #0 does not contain any stream” 应该怎么解决 - V2EX FFmpeg 使用 qsv 加速失败 - V2EX 使用 ffmepg 把图片和长音频转换为视频的时候,视频和音频的时间对不上,声音也减少了一半 - V2EX FFmpeg 解码器如何识别码流格式变了? - V2EX ffmpeg 提取音频中有声部分并单独生成文件 - V2EX ffplay 如何并行下载 m3u8 - V2EX 如何用 ffmpeg 找到损坏的视频 50 块钱悬赏答案 - V2EX ffmpeg 如何压缩 h.265 的视频不丢帧? - V2EX 有没有 win 下已编译好的 FLV 标准支持 H265 的 ffmpeg? - V2EX 为什么有些视频体积这么大但是画质这么差? - V2EX lalserver 流媒体(直播音视频网络传输)服务器 v0.30.1 2022.6.15 - V2EX [求助] mp4 录制,怎么才能不缓冲在内存中 - V2EX ffmpeg 怎么处理 h265 切 h264 的直播流? - V2EX 为什么 ffmpeg 加不上 rotate 旋转参数 - V2EX
ffmpeg 过滤器 xfade 自定义动画的研究 - V2EX
jifengg · 2024-07-03 · via FFmpeg

本文无任何推广,请放心阅读。
本文无任何推广,请放心阅读。
本文无任何推广,请放心阅读。

前前言

hello ,兄弟们,我又来分享我的 ffmpeg 脚本啦。
上次分享了一个使用 ffmpeg ,将多张图片转换成类似幻灯片的视频,支持多种转场效果,说过在研究自定义效果,目前有点小成果,于是有了本文。

本次没有新增脚本,而是增强了ffmpeg.img2video.js,预置了一些自定义效果,并支持自己添加效果。

以下的都是本次的技术分享。如果你不感兴趣,可以直接到 GitHub 更新脚本。

开源地址

GitHub 地址:https://github.com/jifengg/ffmpeg-script

前言

使用xfade过滤器做视频转场切换效果,本身 ffmpeg 已经提供了 56 种效果,能满足大部分需求。不过,更复杂的过渡效果(例如翻页)还没有。
根据文档,使用 transition=custom+expr ,可以实现自定义的效果。但是,官方文档并没有对expr如何编写做详细说明,也没有 google 到。
因此,对其进行了一番研究,尝试实现了几种效果。简单做一个使用教程,希望能够帮助到有需要的人。

效果预览(点击查看视频,视频均小于 1MB )

水滴

https://github.com/jifengg/ffmpeg-script/assets/17020523/b3cec5b1-d747-46bd-aae1-924289aaddce

百叶窗

https://github.com/jifengg/ffmpeg-script/assets/17020523/1bef9ae3-41c3-4747-ae41-9056ae4e6892

简易翻页

https://github.com/jifengg/ffmpeg-script/assets/17020523/30c810a1-7522-4829-8450-4602c8203853

ffmpeg 官方 wiki

https://trac.ffmpeg.org/wiki/Xfade

以下翻译自FFmpeg xfade 官方文档

xfade

将淡入淡出从一个输入视频流应用到另一个输入视频流。淡入淡出将持续指定的时间。
两个输入必须是恒定帧速率,并且具有相同的分辨率、像素格式、帧速率和时间基准。

该过滤器接受以下选项:

transition
    'custom'
    [忽略]

duration
    设置交叉淡入淡出持续时间(以秒为单位)。范围为 0 至 60 秒。默认持续时间为 1 秒。

offset
    设置相对于第一个输入流的交叉淡入淡出开始时间(以秒为单位)。默认偏移量为 0 。

expr
    设置自定义过渡效果的表达式。
    表达式可以使用以下变量和函数:

    X
    Y
        当前样本的坐标。

    W
    H
        图像的宽度和高度。

    P
        过渡效果的进展。
         [译注] 过渡开始时,P=1.0 ,过渡结束时,P=0.0 。

    PLANE
        目前正在处理的平面。
         [译注] 这里的平面,其实就是指像素格式的分量。
         [译注] 取值范围由输入流的像素格式 pix_fmt 决定,如 yuv420p ,则取值范围是 0 ,1 ,2 ;如 rgba ,则取值范围是 0 ,1 ,2 ,3 。

    A
        返回第一个输入流在当前位置和平面的值。

    B
        返回第二个输入流在当前位置和平面的值。

    a0(x,y)
    a1(x,y)
    a2(x,y)
    a3(x,y)
        返回第一个输入的第一/第二/第三/第四个分量的 位置 (x,y) 处的像素的值。
         [译注] 例如,像素格式是 yuv420p ,a0 返回的是 Y 分量。a1 返回的是 U 分量。a2 返回的是 V 分量。没有 a3

    b0(x,y)
    b1(x,y)
    b2(x,y)
    b3(x,y)
        返回第二个输入的第一/第二/第三/第四个分量的 位置 (x,y) 处的像素的值。

理解 P

一般来说,ffmpeg 中支持时间轴编辑的过滤器,都有tn参数可以用在表达式中,其中t表示时间秒,n表示帧数。
但是 xfade 里却是用的 P ,它不是tn。如果你理解错了,会发现自定义效果完全没效。
因为,它表示的是过渡效果的进度,而且,重要的是,它是个递减的数。

  • 过渡动画开始的时候,P=1.0 ;
  • 过渡动画结束的时候,P=0.0 ;
  • 它的值是按帧线性递减的,例如,duration=4 ,fps=25 ,那么第二帧的时候,P=1.0-1/(4*25)=0.99 ;
  • 可以通过数学函数来改变 P 的“线性”,例如 P*P*(3-2P),(Smoothstep函数图)。
    • 注意,P 是从 1.0 到 0.0 ,因此查看函数图的时候要注意从右往左看。
    • 如果你觉得从右往左看不直观,把所有 P 都改成(1-P)吧。
    • win11 自带的计算器有一个“绘图”功能,能够很好的显示各种数学函数的图形,可以用来辅助理解。

理解 X,Y,W,H

X,Y 表示坐标,是指“当前正在计算表达式的像素的坐标”,按照我们要实现的效果,决定该像素对应的颜色码。

W,H 是图像的宽高,这个在整个渐变过程是保持不变的。

理解 PLANE,A,B,a0(x,y),...,b0(x,y),...

a0(x,y)表示第一个视频坐标 x,y 处的像素的第一个分量值。 PLANE 表示当前是计算的第几个分量值。 A 是一个简写,当 PLANE=0 时,A=a0(X,Y); PLANE=1 时,A=a1(X,Y); PLANE=2 时,A=a2(X,Y);以此类推。 b 和 B 同 a 和 A 。

注意,无法通过类似a(plane,x,y)的方法来获得指定坐标指定分量的值,因此在像素有位移的时候,表达式会比较长。如if(eq(PLANE,0),a0(X,Y),if(eq(PLANE,1),a1(X,Y),if(eq(PLANE,2),a2(X,Y),0)))

理解 expr

xfadeexpr,返回一个值,但是这个值是什么含义呢,一般人看文档很难理解。
300x200 的输入源为例,假设其像素格式是 yuv420p ,则其分量个数是 3 。( ffmpeg 支持的像素格式及格式信息,可以通过ffmpeg -pix_fmts查看)。 像素点是60000个,每一帧的像素分量总数就是60000*3=18 万个。
那么,过渡开始的第一帧,ffmpeg 会遍历每个像素点的每个分量,分别调用expr,并设置 X,Y,PLANE 等值。总共调用18 万次获得对应的值,来完成第一帧的渲染。 如果我们希望每一帧就是显示第一个视频的画面,那么可以写expr=A即可。A表示的就是第一个视频当前像素当前分量的值。

尝试 1 ,实现渐隐渐显效果

如果我们希望实现第一个视频渐渐变透明,第二个视频由透明渐渐显现,类似xfade默认的效果fade,那么可以写expr='A*P+B*(1-P)'
因为 P 是从 1.0 线性变成 0.0 的。所以一开始 P=1 ,表达式计算结果=A,看到的就是只有第一个视频画面,到一半时,P=0.5 ,结果=0.5A+0.5B,画面就是两个视频分别半透明叠加在一起。最后 P=0.0 时,结果=B,就只剩下第二个视频的画面了。

尝试 2 ,实现擦除效果

同样的,如果我们希望实现一个从右往左擦除的效果(图片引用自https://trac.ffmpeg.org/wiki/Xfade):
wipeleft

分析一下,分割线在画面水平线上的位置 X ,除以宽度 W ,其实就是等于 P ,于是,我们可以让分割线左边的显示画面 A ,右边的显示画面 B 。 expr='if(lt(X/W,P),A,B)':当X/W<P的时候,说明 X 在分割线左边,于是显示 A ,否则显示 B 。

分割线上显示 A 还是 B ,影响不大。这里是显示了 B ,如果要显示 A ,可以用lte代替lt

尝试 3 ,实现推走效果

从上面两个例子你大概能理解 expr 要返回什么内容了。我们接着第三个例子。 如果我们希望实现的是一个从右往左推走的效果:
slideleft

你会发现,变得更复杂了。你可以先暂停试试自己能否写出来。

为什么更复杂了?以坐标(0,0)为例,他显示的像素时刻都在变化(因为画面在往左移动)。
例如,在 P=0.8 的时候,它(0,0)应该是视频 A X=W*0.2,Y=0 坐标处的像素值。(这里需要好好理解,参考下图帮忙理解)

image

X/W>P的地方,应该显示视频 B 的画面,其坐标转换关系是(X-P*W,Y)。
注意,此时你没法再用值AB了,因为它们是坐标(X,Y)的分量,而我们要在(X,Y)处显示别的坐标的像素,这个我们在上面理解 PLANE,A,B,a0(x,y),...,b0(x,y),...的地方说过了。

那么这个表达式要怎么写呢?

expr='if(lt(X/W,P),^
if(eq(PLANE,0),a0(X+(1-P)*W,Y),^
if(eq(PLANE,1),a1(X+(1-P)*W,Y),^
if(eq(PLANE,2),a2(X+(1-P)*W,Y),0)))^
,^
if(eq(PLANE,0),b0(X-P*W,Y),^
if(eq(PLANE,1),b1(X-P*W,Y),^
if(eq(PLANE,2),b2(X-P*W,Y),0)))^
)'

我测试的时候用的是 windows 的 bat 脚本,为了方便理解和修改,用^进行了换行。注意不要有空格,否则会报错。
测试的时候用的是 yuv420p 像素格式,因此表达式没有用到 a3 ,如果是用了 4 个分量的像素格式需要把 a3 按照上面的格式加进去。

其中,分割线左边显示视频 A 的画面,且 x 坐标左移了(1-P)*W 个像素,因此其 x 坐标表达式是X+(1-P)*W
右边显示视频 B 的画面,且 x 坐标右移到了分割线右边,因此其 x 坐标表达式是X-P*W
因为是水平移动,所以 y 坐标保持Y即可。

于是,随着 P 从 1.0 渐变到 0.0 ,视频 A 就像被视频 B 从右边推到了左边,完成了一个过渡效果。

小结

现在,你已经了解了 expr 要怎么编写来实现过渡效果了。我还实现了一些其它效果,包括示例里的,你可以在 GitHub 上查看

性能

在 windows 下创建 2 个 bat 文件,分别输入测试命令:

@echo off
@REM 使用 custom 实现 slideleft 效果
ffmpeg -y -hide_banner ^
-f lavfi -i "pal100bars=r=1/1000" ^
-f lavfi -i "colorchart=r=1/1000" ^
-filter_complex ^
[0:v]format=yuv420p,scale=960:480,fps=25,trim=duration=40[v1];^
[1:v]format=yuv420p,scale=960:480,fps=25,trim=duration=40.04[v2];^
[v1][v2]xfade=duration=40:offset=0:transition=custom:^
expr='if(lt(X/W,P),^
if(eq(PLANE,0),a0(X+(1-P)*W,Y),^
if(eq(PLANE,1),a1(X+(1-P)*W,Y),^
if(eq(PLANE,2),a2(X+(1-P)*W,Y),0)))^
,^
if(eq(PLANE,0),b0(X-P*W,Y),^
if(eq(PLANE,1),b1(X-P*W,Y),^
if(eq(PLANE,2),b2(X-P*W,Y),0)))^
)' ^
-crf 23 -c:v h264 -pix_fmt yuv420p -movflags +faststart -r 25 -aspect 960:480 ^
out1.mp4
@echo off
@REM 使用内置的 slideleft 效果
ffmpeg -y -hide_banner ^
-f lavfi -i "pal100bars=r=1/1000" ^
-f lavfi -i "colorchart=r=1/1000" ^
-filter_complex ^
[0:v]format=yuv420p,scale=960:480,fps=25,trim=duration=40[v1];^
[1:v]format=yuv420p,scale=960:480,fps=25,trim=duration=40.04[v2];^
[v1][v2]xfade=duration=40:offset=0:transition=slideleft ^
-crf 23 -c:v h264 -pix_fmt yuv420p -movflags +faststart -r 25 -aspect 960:480 ^
out2.mp4

这里使用的动画时长是 40 秒,可以自行修改成 0~60 秒。
在我电脑上运行,耗时分别是:自定义17.514 秒,内置1.605 秒
可以看出,使用自定义的效果,远比内置效果更耗时。原因我们在“理解 expr”有提过,因为每一帧需要调用 expr 次数=960×480×3=1,382,400 。一百多万次。而且是纯 CPU 运算,因此效率自然底下。

好在一般的过场时长是 3 、4 秒左右,影响还在可接受范围内。

如果你在寻找更高效的自定义效果,可以考虑使用xfade_opencl过滤器,或者自行编译 ffmpeg ,加入gl-transition过滤器。

其它转场过滤器

xfade_opencl

要使用xfade_opencl,需要编译的时候加入--enable-opencl,且运行的机器有支持 opencl 的设备(一般指显卡)。
要查看当前机器有哪些 opencl 的设备,可以运行以下命令:

ffmpeg -v debug -init_hw_device opencl

打印出类似信息:

[AVHWDeviceContext @ 0000027894f28400] 1 OpenCL platforms found.
[AVHWDeviceContext @ 0000027894f28400] 1 OpenCL devices found on platform "NVIDIA CUDA".
[AVHWDeviceContext @ 0000027894f28400] 0.0: NVIDIA CUDA / NVIDIA GeForce RTX *****

其中0.0就是可用的 opencl 设备编号,在 ffmpeg 命令中指定使用该设备:

ffmpeg -y -hide_banner -init_hw_device opencl=ocldev:0.0 -filter_hw_device ocldev ^
-f lavfi -r 25 -t 40 -i "pal100bars" ^
-f lavfi -r 25 -t 40.04 -i "colorchart" ^
-filter_complex ^
[0:v]format=yuv420p,scale=960:480,hwupload[v0];^
[1:v]format=yuv420p,scale=960:480,hwupload[v1];^
[v0][v1]xfade_opencl=duration=40:offset=0:transition=slideleft,hwdownload,format=yuv420p ^
-c:v h264_nvenc -pix_fmt yuv420p -movflags +faststart -r 25 -aspect 960:480 ^
out3.mp4

性能比自定义 xfade 效果好很多,唯一要求就是需要支持 opencl 的设备(一般指显卡)。
且,xfade_opencl也是支持自定义效果的,官方文档
内置的几个效果的源码可以查看 GitHub 上 ffmpeg 的源码:https://github.com/FFmpeg/FFmpeg/blob/master/libavfilter/opencl/xfade.cl

gl-transition

gl-transitions是由开发者 Gilles Lamothe 创建的,它封装了大量的 GPU 加速过渡效果,包括但不限于溶解、推拉、旋转等多种类型。这些过渡效果可以轻松地整合到你的图形应用程序中,无论你是开发游戏、视频编辑软件还是实验性的艺术项目。
它使用 OpenGL 进行加速,因此,也需要支持 OpenGL 的设备(一般指显卡)。
它不是 ffmpeg 专属的,但是可以做为一个过滤器添加到 ffmpeg 中。参考这个 GitHub 项目transitive-bullshit/ffmpeg-gl-transition。 编译后,你将可以使用其官网上的所有效果,当然也可以自己编写自定义的效果。

性能方面,因为我没有自行编译测试,所以无法给出具体数据。

它使用 GLSL 语言编写,如果你看了上面 OpenCL 的部分,你会发现它们有很多共同点。
甚至,我在编写xfade自定义表达式的时候,也参考了它的 GLSL 代码。比如效果预览中的水滴,就是参考了WaterDrop

结语

不知道是 ffmpeg 官方觉得 xfade 的 expr 编写太过容易,还是觉得性能不行不建议使用,反正官方文档及 wiki 都没有示例,也没有提及如何编写。
我自己基本上是自己看着文档猜测、尝试,慢慢的摸索出来一些门道。想着网上没有一个类似的教程,于是变写了这个文章。
如果你发现文章哪里有问题,欢迎指出,大家共同进步。

本文存档:https://github.com/jifengg/ffmpeg-script/blob/main/docs/ffmpeg.xfade.md