ffmpeg可以刻录时间代码吗?

我需要将时间代码刻录到video中,并且想知道这是否是ffmpeg能够做到的事情?

简短的回答,没有。

答案很长,是的,但不是没有使用单独的库来创建具有渲染时间码的帧,透明度填充帧的其余部分,然后使用FFmpeg覆盖现有video上的帧。 我不知道如何做到这一点,但我敢肯定,如果你有创意,你可以搞清楚。

编辑:我一直在研究这个问题,因为对我来说这是一个有趣的问题/项目。 我通过编写一个Perl脚本来进一步解决这个问题, 该脚本将生成一个.srt文件,其中嵌入了时间代码,用于任何给定的video文件,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 

仍在研究如何在video上定位和叠加渲染的字幕,并以相同的格式重新编码。 我会更新这篇文章,因为我知道更多。

FFMPEG的drawtextfilter适合我,你可以指定起始时间码及其格式:

 -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的forms指定时间码格式。 请注意,您必须以时间码格式字符串转义冒号,并且必须指定时间码速率(此处为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 

这会将剪辑的名称和滚动时间码添加到1920×1080帧底部中心的半透明框中

编辑因为我已经走到了黑暗的一面,我现在在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文件的文件夹的mp4s(使用-filter命令查找名称中包含* .M *的文件,如果你在做.AVI文件则必须更改),并且它有点小,它只使用libx264默认设置作为输出编解码器,并没有指定字体等。在这种情况下,时间码在框架的左上方烧毁。

@stib的答案中提到的drawtextfilter是插入时间的关键。 但是,使用timecode选项与挂钟时间不匹配。 如果你的r (timecode_rate)参数错误,那么你的时间将与你的播放时间不符。

存在其他选项,例如text='%{prt}'选项允许您以微秒精度显示经过时间。 命令:

 ffmpeg -i video.mp4 -vf "drawtext=text='%{prt}'" output.mp4 

为了得到一个时钟,我不得不使用弃用的strftime选项。 这有一个未记录的basetime选项,可用于设置以微秒为单位的开始时间。 我将开始时间设置为2013年12月1日中午12点的示例( $(...)部分是由shell完成的shell扩展)并且只显示时间( 有关可能的格式,请参阅strftime手册 ) :

 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相等。
  • 您不能多次指定filter,例如-vf drawtext=text=1 -vf drawtext=text=2将仅绘制第二个文本。 您可以将filter与逗号结合使用,如上所示。

在更新的版本中,您可以使用drawtextfilter(其示例中的“t”,我相信,框架的时间戳)来插入文本。 它也适用于“当前”系统时间的srtftime。

我发现最简单的解决方案是在捕获文件时显示时钟,而不是它的持续时间,并且基于此post工作/谢谢!/是

 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的时间戳,但事实并非如此。 它实际上将video的当前时间(以秒为单位)提供给gmtime,产生的日期为1970年1月1日,然后是午夜后的几秒钟。 所以你只需丢弃日期部分并使用时间部分。

记下pts函数中的三重逃逸冒号,如果你像我上面那样输入它,你将不得不这样做。 您还可以看到我复制了Arial Bold的字体文件,并将其直接放入工作目录中以简化操作。

FFMPEG将能够完成大部分工作,但不会全部打包。 使用FFMPEG,您可以按顺序解码所有帧,并为您提供“演示时间戳”(某些格式可能提供额外的时间相关元数据,但PTS是您想要开始寻找的内容。)然后,您可以自己实际将文本绘制到解码后的帧上。 我使用Qt来表示类似的东西,在QImage上使用带有帧数据的QPainter,但是可能会有一些其他的API可以在你发现更明显的图像上绘制。 然后,使用FFMPEG API制作压缩video,其中包含新绘制的帧。 如果你也想要音频,那会有点复杂。 我自己的工作并不真正关心音频,所以我没有费心去学习API的音频方面。 基本上,当您执行读取循环从文件中获取数据包时,其中一些将是音频。 而不是像我一样丢弃它们,你需要保留它们并将它们写入输出文件中。

我只使用C API,而不是C#,所以我不知道是否有任何特殊的问题需要担心。