【发布时间】:2011-03-11 08:09:39
【问题描述】:
我需要在视频中刻录时间码,我想知道这是否是 ffmpeg 能够做到的?
【问题讨论】:
-
所以我假设您想将“视频的当前时间”刻录到视频本身?或者您想使用 libav* 在此处使用您自己的时间码向视频添加文本?
标签: c# ffmpeg video-processing timecodes
我需要在视频中刻录时间码,我想知道这是否是 ffmpeg 能够做到的?
【问题讨论】:
标签: c# ffmpeg video-processing timecodes
FFMPEG 的 drawtext 过滤器适用于我,您可以指定起始时间码及其格式:
-vf drawtext="fontsize=15:fontfile=/Library/Fonts/DroidSansMono.ttf:\
timecode='00\:00\:00\:00':rate=25:text='TCR\:':fontsize=72:fontcolor='white':\
boxcolor=0x000000AA:box=1:x=860-text_w/2:y=960"
您必须以 hh:mm:ss[:;,]ff 的形式指定时间码格式。请注意,您必须对时间码格式字符串中的冒号进行转义,并且必须指定时间码速率(此处为 25fps)。您还可以指定其他文本 - 这里是“TCR:”
你可以用ffprobe和一点shell fu来获取帧率:
frame_rate=$(ffprobe -i "movie.mov" -show_streams 2>&1|grep fps|sed "s/.*, \([0-9.]*\) fps,.*/\1/")
因此您可以轻松地将它们全部集成到批处理脚本中,例如
for i in *.mov
frame_rate=$(ffprobe -i "$i" -show_streams 2>&1|grep fps|sed "s/.*, \([0-9.]*\) fps,.*/\1/")
clipname=${(basename "$i")/\.*/}
ffmpeg -i "$i" -vcodec whatever -acodec whatever \
-vf drawtext="fontsize=15:fontfile=/Library/Fonts/DroidSansMono.ttf:\
timecode='00\:00\:00\:00':rate=$frame_rate:text='$clipname' TCR:':\
fontsize=72:fontcolor='white':boxcolor=0x000000AA:\
box=1:x=860-text_w/2:y=960" "${i/.mov/_tc.mov}"
done
这会将剪辑的名称和滚动时间码添加到 1920x1080 帧底部中心的半透明框中
编辑 由于我已经陷入黑暗面,我现在在 Windows Powershell 环境中执行此操作,这就是我使用的:
ls -R -File -filter *.M*|%{
ffmpeg -n -i $_.fullname -vf drawtext="fontsize=72:x=12:y=12:`
timecode='00\:00\:00\:00':rate=25:fontcolor='white':`
boxcolor=0x000000AA:box=1" `
("c:\path\to\destination\{0}" -F ($_.name -replace 'M[OPT][V4S]', 'mp4'))}
这会在给定包含 .MOV、.MP4 和 .MTS 文件的文件夹的情况下创建 mp4(使用-filter 命令,它会查找名称中带有 *.M* 的文件,如果您正在使用 . AVI 文件),而且它有点小,它只是使用 libx264 和默认设置作为输出编解码器,并且没有指定字体等。在这种情况下,时间码被刻录在帧的左上角。
【讨论】:
12.34 fps等分数。
rate 参数将起作用,因此如果您说“24000/1001”它对我有用。
@stib的回答中提到的drawtext过滤器是插入时间的关键。但是,使用 timecode 选项与挂钟时间不匹配。如果r (timecode_rate) 参数错误,那么您的时间将与您的播放时间不匹配。
存在其他选项,例如text='%{prt}' 选项允许您以微秒精度显示经过的时间。命令:
ffmpeg -i video.mp4 -vf "drawtext=text='%{prt}'" output.mp4
为了获得时钟,我不得不使用已弃用的 strftime 选项。这有一个未记录的basetime 选项,可用于以微秒 为单位设置开始时间。我将开始时间设置为 2013 年 12 月 1 日下午 12:00 的示例($(...) 部分是由 shell 完成的 shell 扩展)并且只显示时间(参见strftime manual for possible formats):
ffmpeg -i video.mp4 -vf "drawtext=expansion=strftime: \
basetime=$(date +%s -d'2013-12-01 12:00:00')000000: \
text='%H\\:%S\\:%S'" output.mp4
\\: 用于转义 :,否则会得到选项分隔符的含义。
另一个例子:在一个黑盒子中插入日期+时间的命令,距离左上角一些像素和“一些填充”(实际上是边缘上的两个空格和换行符):
newline=$'\r'
ffmpeg -i video.mp4 -vf "drawtext=x=8:y=8:box=1:fontcolor=white:boxcolor=black: \
expansion=strftime:basetime=$(date +%s -d'2013-12-01 12:00:00')000000: \
text='$newline %Y-%m-%d %H\\:%M\\:%S $newline'" output.mp4
获取时钟以下微秒的另一个示例:
newline=$'\r'
ffmpeg -i video.mp4 -vf "drawtext=expansion=strftime: \
basetime=$(date +%s -d'2013-12-01 12:00:00')000000: \
text='$newline %H\\:%M\\:%S $newline':fontcolor=white:box=1:boxcolor=black, \
drawtext=text='$newline %{pts} $newline': \
y=2*th/3:box=1:fontcolor=white:boxcolor=black:" output.mp4
这利用了文本实际上是三行长并且两个文本都有一个换行符(回车,^M)前置和附加的事实。 (没有这个换行符,空间就会被剥夺)
其他提示:
-vf 和 -filter:v 相等。-vf drawtext=text=1 -vf drawtext=text=2 只会绘制第二个文本。如上所示,您可以使用逗号组合过滤器。【讨论】:
ffplay -i video.mp4 -vf drawtext='expansion=normal:text=%{localtime\\:%a %b %d %Y}'
简短的回答,不。
长答案,是的,但不是不使用单独的库来创建带有渲染时间码的帧,用透明度填充帧的其余部分,然后使用 FFmpeg 覆盖现有视频上的帧。我不知道该怎么做,但我敢肯定,如果你有创意,你就能弄明白。
编辑:我一直在研究这个问题,因为这对我来说是一个有趣的问题/项目。我通过编写a Perl script 在解决方案中走得更远一点,它将生成一个.srt 文件,其中嵌入了时间码,用于将FFmpeg 配置为能够从中读取元数据的任何给定视频文件。它使用Video::FFmpeg 库读取持续时间并将字幕文件保存为${video}.srt。如果您在 ~/.mplayer/config 中插入以下行,它将使其在 Mplayer 中自动呈现:
# select subtitle files automatically in the current directory, all files
# matching the basename of the current playing file
sub-fuzziness=1
仍在研究如何在视频上定位和覆盖渲染的字幕,并以相同的格式重新编码。当我知道更多时,我会更新这篇文章。
【讨论】:
在最近的版本中,您可以使用drawtext 过滤器(我相信其示例中的“t”是帧的时间戳)插入文本。它也适用于“当前”系统时间的 srtftime。
【讨论】:
t 选项。它is named basetime。无论如何,我无法让它正常工作。
t 似乎是一个文档错误,它应该是 basetime(仅适用于 expansion=strftime)。
t在FFMPEG 4.1中,可以使用ffmpeg -i input.mp4 -vf drawtext="fontsize=60:fontcolor=yellow:text='%{e\:t*1000}':x=(w-text_w):y=(h-text_h)" output.mp4。
我找到的最简单的解决方案是在文件被捕获时显示时钟,而不是它的持续时间,它工作/基于这篇文章,谢谢!/ 是
D:\Temp\2>ffmpeg.exe -i test.avi -vf "drawtext=fontfile=C\\:/Windows/Fonts/arial.ttf:timecode='00\:20\:10\:00':rate=25:text='TCR\:':fontsize=46:fontcolor=white:x=500:y=50: box=1: boxcolor=0x00000000@1" -f mp4 textts.mp4
时间码如此简单 - 输入您的开始时间,然后计数就可以了!该示例适用于 Windows
【讨论】:
这是我的解决方案,我相信它是正确的,因为它既避免了手动设置速率,又允许您格式化输出。
ffmpeg -i test.mp4 -vf \
"drawtext=fontfile=arialbd.ttf:text='%{pts\:gmtime\:0\:%H\\\:%M\\\:%S}'" test.avi
这会生成 HH:MM:SS 格式的印章;您可以使用 strftime 将其更改为您想要的任何内容。
它可能会在时间戳中添加gmtime,但事实并非如此。它实际上将视频的当前时间(以秒为单位)提供给 gmtime,生成日期为 1970 年 1 月 1 日,以及午夜后几秒的时间。因此,您只需丢弃日期部分并使用时间部分。
注意 pts 函数中的 三重 转义冒号,如果你像我上面那样输入它,你必须这样做。您还可以看到,为了简单起见,我复制了 Arial Bold 字体文件并将其直接放入工作目录中。
【讨论】:
FFMPEG 将能够完成大部分工作,但不会全部打包。使用 FFMPEG,您可以让它按顺序解码所有帧,并为您提供“Presentation Time Stamp”(某些格式可能提供与时间相关的其他元数据,但 PTS 是您要开始寻找的内容.) 然后,您自己将文本实际绘制到解码帧上。我将 Qt 用于类似的事情,通过在带有帧数据的 QImage 上使用 QPainter,但可能有一些其他 API 可以在您发现更明显的图像上绘制。然后,使用 FFMPEG API 制作包含新绘制帧的压缩视频。如果您还想要音频,它会有点复杂。我自己的工作并不真正关心音频,所以我没有费心去学习 API 的音频方面。基本上,当您执行读取循环从文件中获取数据包时,其中一些将是音频。不要像我一样丢弃它们,您需要保留它们并在获得它们时将它们写入输出文件。
我只使用了 C API,而不是 C#,所以我不知道是否有什么特别的问题需要担心。
【讨论】: