如何映射用ffmpeg和视频字幕提取的帧? (帧精度问题)
Posted
技术标签:
【中文标题】如何映射用ffmpeg和视频字幕提取的帧? (帧精度问题)【英文标题】:How to map frame extracted with ffmpeg and subtitle of a video? (frame accuracy problem) 【发布时间】:2019-11-12 15:12:09 【问题描述】:想为使用 ffmpeg 提取的帧生成文本文件,如果有的话,包含帧的字幕,在我也使用 ffmpeg 刻录字幕的视频上。
我使用带有pysrt
的python 脚本来打开subrip 文件并生成文本文件。
我正在做的是每个帧都由 ffmpeg 用帧号命名,然后由于它们以恒定速率提取,我可以使用公式 t1 = fnum/fps
轻松检索帧的时间位置,其中fnum
是使用文件名检索的帧数,fps
是传递给 ffmpeg 以进行帧提取的频率。
即使我使用相同的字幕文件来检索时间轴中的文本位置,也就是视频中使用的那个,我仍然会遇到准确性错误。大多数我有一些文本文件丢失或一些不应该存在。
因为在谈论帧时时间并不是真正连续的,所以我尝试使用带有硬编码字幕的视频的 fps 重新校准 t
,让我们将 fps vfps
称为视频 fps(我已确保视频 fps字幕刻录前后相同)。我得到公式:t2 = int(t1*vfps)/vfps
。
它仍然不是 100% 准确。
例如,我的视频是 30fps (vfps=30
),我以 4fps (fps=4
) 提取帧。
提取的第 166 帧 (fnum=166
) 没有显示字幕。在 subrip 文件中,前一个字幕以t_prev=41.330
结尾,下一个字幕从t_next=41.400
开始,这意味着t_sub
应该满足:t_prev < t_sub and t_sub < t_next
,但我无法做到这一点。
我试过的公式:
t1 = fnum/fps # 41.5 > t_next
t2 = int(fnum*vfps/fps)/vfps # 41.5 > t_next
# is it because of a indexing problem? No:
t3 = (fnum-1)/fps # 41.25 < t_prev
t4 = int((fnum-1)*vfps/fps)/vfps # 41.23333333 < t_prev
t5 = int(fnum*vfps/fps - 1)/vfps # 41.466666 > t_next
t6 = int((fnum-1)*vfps/fps + 1)/vfps # 41.26666 < t_prev
使用的命令:
# burning subtitles
# (previously)
# ffmpeg -r 25 -i nosub.mp4 -vf subtitles=sub.srt withsub.mp4
# now:
ffmpeg -i nosub.mp4 -vf subtitles=sub.srt withsub.mp4
# frames extraction
ffmpeg -i withsub.mp4 -vf fps=4 extracted/%05.bmp -hide_banner
为什么会发生这种情况,我该如何解决?
我注意到的一件事是,如果我提取原始视频和字幕的帧,对帧进行差异处理,结果不仅是字幕,背景也有变化(这不应该发生)。如果我两次使用相同的视频做相同的体验,差异为null,这意味着帧提取是一致的。
区别代码:
ffmpeg -i withsub.mp4 -vf fps=4 extracted/%05.bmp -hide_banner
ffmpeg -i no_sub.mp4 -vf fps=4 extracted_no_sub/%05.bmp -hide_banner
for img in no_sub/*.bmp; do
convert extracted/$img##*/ $img -compose minus -composite diff/$img##*/
done
谢谢。
【问题讨论】:
ffmpeg -r 25 -i nosub.mp4 --> 这将重新定时帧并破坏原始时间戳。除非您知道自己在做什么,否则您不想这样做。 不是真的...我想在不改变帧率的情况下刻录字幕。所以我先试试这个:ffmpeg -i nosub.mp4 -vf subtitles=sub.srt withsub.mp4
但是它把帧率从25改成了30,所以我手动设置了帧率,好像不对。我不是 ffmpeg 的大用户。我在 Google 上搜索了如何使用 ffmpeg 保留帧率并找到了这个 superuser.com/questions/460332/…,但它没有被接受的答案。
分享您最初尝试的日志。
我的错,原来的 fps 是 30,所以我第一次尝试刻录字幕并没有改变帧速率。然而问题依然存在。并且在字幕刻录前后进行帧减法显示出比字幕更多的差异。请让我提醒一下,这不是我要解决的问题,但可能是我的问题的原因。你想看什么日志?
还值得注意的是,在示例中,区间的边界乘以帧提取得到:t_prev*fps=165.32
和 t_next*fps=165.6
,这意味着,如果 ffmpeg 提取的帧是1/fps
的因素,那么我不应该让第 166 帧位于两个字幕之间,而是显示第二个字幕(或者前一个字幕)。如果通过视频 fps 进行校正也是一样的:int(t_next*vfps)*fps/vfps=165.2
, int(t_next*vfps)*fps/vfps=165.6
【参考方案1】:
您可以提取具有准确时间戳的帧,因此
ffmpeg -i nosub.mp4 -vf subtitles=sub.srt,settb=AVTB,select='if(eq(n\,0)\,1\,floor(4*t)-floor(4*prev_t))' -vsync 0 -r 1000 -frame_pts true extracted/%08d.bmp
这将从每四分之一秒中提取第一帧。输出文件名长度为 8 个字符,其中前 5 位是秒,后三位是毫秒。您可以根据最大文件持续时间更改字段大小。
【讨论】:
您能否详细介绍一下参数?我也收到一个错误:Missing ')' or too many args in 'if(eq(n,0)'
settb 过滤器用于将时基设置为 1 微秒,选择过滤器表达式将选择第一帧,然后选择最接近上一季度秒的每一帧。 -r 1000 将时间戳转换为毫秒精度(否则文件名会变得更长)。 vsync 确保 ffmpeg 不会改变时间戳。 frame_pts 将时间戳打印到文件名中。
编辑 cmd 以转义所有逗号以上是关于如何映射用ffmpeg和视频字幕提取的帧? (帧精度问题)的主要内容,如果未能解决你的问题,请参考以下文章