首页 > 编程语言 >FFmpeg中转场滤镜xfade的时间参数(duration和offset)与算法解读

FFmpeg中转场滤镜xfade的时间参数(duration和offset)与算法解读

时间:2022-10-19 12:04:23浏览次数:66  
标签:FFmpeg time ts xfade 滤镜 offset duration pts


xfade转场滤镜小科普

最近在研究音视频合成的相关功能,现已有两个视频剪辑。拼合成一个文件显然用concat可以完成,但是过渡生硬,而xfade滤镜可以很方便实现更加缓和的场景切换。

xfade滤镜在FFmpeg 4.3中才出现,因此低于此版本的FFmpeg都无法使用该滤镜。

在xfade转场滤镜中,有这么几个名词:A场、B场,持续时长和起始位置。
A场:按照时间顺序,转场前的画面叫做A场(下图中蓝色画面);
B场:按照时间顺序,转场后的画面叫做B场(下图中青色画面);
起始位置:offset,指转场效果在A场输入源的何处开始起作用,
持续时长:duration,指转场特效持续的时长。

FFmpeg中转场滤镜xfade的时间参数(duration和offset)与算法解读_视频处理


举个例子:

      |<--offset
|<--duration-->|
AAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBBB

应用后的输出

      |<--duration-->|
AAAAAAABABABABABABABABBBBBBBBBBBB

关于时间的疑问

在官方FFmpeg官方文档中,关于的duration和offset的描述比较简单:

duration
Set cross fade duration in seconds. Default duration is 1 second.

offset
Set cross fade start relative to first input stream in seconds. Default offset is 0.

通过文档可知,这两个参数都是以“秒”为单位的。如果编程实现自动化生成带转场视频,秒级单位很显然不如毫秒更为方便(当然可以使用小数来精确到毫秒,但在程序中,某些时候整数处理要比小数处理容易)。那么参数有办法使用毫秒吗?

另外,转场后视频的精确时间如何计算?

查看源码

作为滤镜,xfade的源码所在位置:

https://github.com/FFmpeg/FFmpeg/blob/master/libavfilter/vf_xfade.c

来看下该滤镜的参数定义部分:

static const AVOption xfade_options[] = {
...
{ "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=1000000}, 0, 60000000, FLAGS },
{ "offset", "set cross fade start relative to first input stream", OFFSET(offset), AV_OPT_TYPE_DURATION, {.i64=0}, INT64_MIN, INT64_MAX, FLAGS },
...
};

可以看到,duration和offset参数的类型,都是AV_OPT_TYPE_DURATION,因此和其他滤镜中关于时间的参数一样,均支持形如:5s,300ms,2:28这样的格式。最终经过parseutils.c中的av_parse_time处理后,统一转换为64位的基于微秒(microsecond)的整数数据。

在视音频编码中,码流的时钟同步是通过pts(Presentation TimeStamps)来实现的。例如使用ffprobe命令查看码流信息:

"time_base": "1/12800",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 269824,
"duration": "21.080000",

pts(start_pts,duration_ts)为64位整数类型。
对应的,在呈现时还有一个时间基(time_base),表示一个pts展示的时长,单位:秒。
上面的例子如果将时间基取倒数,也可以解释为1秒钟会包含12800个pts。

因此可以得知:

duration(单位:秒) = duration_ts * time_base
21.08 = 269824 * 1 / 12800

由于不同码流可以采用自己不同的时间基。如何将输入的duration和offset精确对应到码流的某个时间点呢?
FFmpeg引入了一个系统的标准时间基,刚才讲到,处理时间相关的参数时,会统一转换为以微秒为单位的整数数据。
因此系统标准时间基为:AV_TIME_BASE_Q(在avutil.h中定义),值为:1/1,000,000,即1秒钟包含一百万个pts。

那么时间到目标流的pts算法就是一个等比例缩放的关系(滤镜源码在config_output中使用了av_rescale_q):

duration * AV_TIME_BASE_Q = target_pts * target_time_base

即:

target_pts = (duration * AV_TIME_BASE_Q) / target_time_base

在上述计算中,涉及到了除法。当除不尽时,最后结果将针对小数点后1位进行四舍五入,取整

转场后视频的精确时间如何计算?

正常的例子

假设有如下两个文件:
video_a.mp4:

"time_base": "1/12800",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 65024,
"duration": "5.080000"

video_b.mp4

"time_base": "1/12800",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 197120,
"duration": "15.400000"

使用如下命令转场:

ffmpeg -i video_a.mp4 -i video_b.mp4 -filter_complex "[0:v][1:v]xfade=transition=fade:offset=5s:duration=80ms" -c copy trans.mp4

可以看到,输出视频的信息为:

"time_base": "1/12800",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 261120,
"duration": "20.400000"

指定的offset为5s,转换为内部的微秒为 5,000,000,综合时间基等比例缩放到video_a的pts:

(5,000,000 * (1 / 1,000,000)) / (1 / 12800)

即offset映射到的pts为:64,000

此值小于video_a的duration_ts(即:65024),说明滤镜将会被激活。
从offset开始,其实在A场景的底层,B场景已经开始播放了。

计算输出视频的总duration_ts时,由于B场景的时间基与A场景一致,因此直接累加B的duration_ts即可:

total_duration_ts = offset + b_duration_ts
= 64,000 + 197,120
= 261,120

可以看到,结果与上述生成的视频结果一致。

两个时间基不一样的场景如何转场

xfade滤镜在输出时,将会参考A场视频的时间基参数。若B场的时间基与A场不同,在计算合成后的视频长度时,
应当对B场的时间基进行统一化,映射到与A场景同样的时间基:

b_new_duration_ts = b_old_duration_ts * b_old_time_base / a_time_base

一些特殊例子

指定的offset超过了A场的总时长

当offset超过了A场的总时长时,xfade滤镜没有机会启用,因此经过此滤镜的输出流仍然是A场内容,B场内容将会被忽略。

指定的offset没有超过A场总时长

从offset开始算起,此时又有两种可能:
加上duration后,超过了A场的总时长和小于等于总时长;

无论是哪种情况,只要offset位于A场视频中,滤镜就会被激活。

offset+duration超过A场总时长

   |<--duration-->
AAAAAAAA
BBBBBBBBBBBBBBBBB

特效的目标是明确的,就是A场转B场。
以淡出滤镜为例,就是将A场的全部像素RGBA数据中的Alpha通道从1降到0。
假设duration为2秒, 那么就是在这2秒中均匀地递减Alpha值,每一次减多少都是事先算好的。

因此在每一帧经过滤镜时,滤镜只是按照之前的规划对像素进行调整。
A场没有数据了,或者duration超过了,则自动将A场内容屏蔽掉。
视频总长度:

total_pts = a_offset_pts + b_duration_ts

offset+duration小于等于A场总时长

   |<--duration-->|
AAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBB

这种情况下,滤镜已经完成了转场通能,超出部分会被截掉。
视频总长度:

total_pts = a_offset_pts + b_duration_ts

标签:FFmpeg,time,ts,xfade,滤镜,offset,duration,pts
From: https://blog.51cto.com/u_3932467/5769527

相关文章

  • 由于FFmpeg的amerge滤镜导致的iOS中无法载入视频
    amerge引发的问题一段视频,在合成后可能需要增加一段背景音乐来烘托气氛。然而在使用amerge进行混音时,如果不小心会出现问题。例如将合成好的视频通过AirDrop发送到iOS(因为......
  • 从FFmpeg输出日志中分析问题原因——记一次输出流顺序异常
    输出流的顺序怎么无法改变一个视频文件,常规地,会将视频流放在第一个位置,其次将音频流放到第二个位置。对于一些特殊的视频,想要改变其顺序,也是非常方便的,直接使用FFmpeg提供的......
  • FFmpeg中使用loop输入流与shortest参数后,音视频流时长被改变
    问题来自于制作视频水印需求给一段视频加上一张静态图片制作的logo,在网上已经有很多例子了,只要把它放置在视频的固定位置即可,这个功能非常容易实现:ffmpeg-ivideo.mp4-il......
  • FFmpeg:FIFO + PIPE
    FIFO将某些内容流式传输到stdout管道,即使在临时故障(网络中断)的情况下也继续以实时速率处理流,并尝试无限期地每秒恢复流式传输。ffmpeg-re-stream_loop-1-ihttps://f......
  • centos7环境下二进制编译安装ffmpeg
    centos7环境下二进制编译安装ffmpeg mkdir-p/usr/local/src/ffmpeg_sourcescd/usr/local/src/ffmpeg_sources#安装nasmcd/usr/local/src/ffmpeg_sourcescurl......
  • 【C#】【FFmpeg】获取电脑可用音视频设备并输出到下拉列表框
    要使用的FFmpeg命令ffmpeg-list_devicestrue-fdshow-idummy会输出的信息通过正则取出设备名称List<string>videoList=newList<string>();for......
  • FFmpeg中的音频文件的封装格式和编码格式
    1.FFmpeg的音频封装格式的学习MP3是我们在日常生活中最常见的音频格式之一,也是一种音频封装格式。1.1查看ffmpeg支持的封装的格式列表ffmpeg-formats|grepmp31.2ffpl......
  • 24_用Qt和FFmpeg实现简单的YUV播放器
    前面文章FFmpeg像素格式转换中我们使用FFmpeg实现了一个像素格式转换工具类,现在我们就可以在Qt中利用QImage很容易的实现一个简单的YUV播放器了。播放器功能很简单,只有播......
  • ffmpeg数据结构学习(AVpacket & AVframe)
     其中的AVBufferRef是一个AVbuffer的指针:图片来源于网络 关于AVframe:音频解码API avcodec_decode_audio4在新版中已废弃,替换为使用更为简单的avcodec_send_packet......
  • FFmpeg H265解码总结
    背景:项目开发需要,通过TCP协议与视频板进行通信,获取图像数据,对图像数据进行解码后显示。关键词:C#、FFmpeg、FFmpeg.AutoGen.dll、WriteableBitmap、H265、HEVC1.初设计......