代码之家  ›  专栏  ›  技术社区  ›  spinon

ffmpeg是否可以刻录时间代码?

  •  14
  • spinon  · 技术社区  · 14 年前

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

    7 回复  |  直到 7 年前
        1
  •  3
  •   amphetamachine    14 年前

    简短的回答,不。

    回答很长,是的,但不是不使用单独的库来创建带有渲染时间代码的帧,透明填充其余帧,然后使用ffmpeg覆盖现有视频上的帧。我不知道该怎么做,但我敢肯定,如果你有创造力的话,你一定能想出办法。

    编辑: 我一直在研究这个问题,因为它对我来说是一个有趣的问题/项目。我通过写作在解决问题上走得更远了一点。 a Perl script 会产生一个 .srt 文件,其中嵌入了任何给定视频文件的时间代码,ffmpeg配置为能够读取元数据。它使用 Video::FFmpeg 用于读取持续时间并将副标题文件另存为的库 ${video}.srt . 这将使它在MPlayer中自动呈现,如果您在 ~/.mplayer/config :

    # select subtitle files automatically in the current directory, all files
    # matching the basename of the current playing file
    sub-fuzziness=1
    

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

        2
  •  22
  •   Algoinde stib    8 年前

    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文件的文件夹(使用 -filter 命令它查找名称中带有*.m*的文件,如果执行.avi文件,则必须更改这些文件,而且它的大小稍微小一些,它只使用带有默认设置的libx264作为输出编解码器,不指定字体等。在这种情况下,时间代码会在帧的左上角烧掉。

        3
  •  14
  •   Community kfsone    7 年前

    这个 drawtext 中提到的筛选器 @stib 答案是插入时间的关键。使用 timecode 但是,选项与墙壁时钟时间不匹配。如果你得到 r (时间码速率)参数错误,则您的时间将与播放时间不匹配。

    存在其他选项,例如 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 将只绘制第二个文本。如我上面所示,您可以将过滤器与逗号组合在一起。
        4
  •  2
  •   rogerdpack Blair Conrad    12 年前

    在最近的生成中,可以使用 drawtext 过滤器(它的示例中的“t”是框架的时间戳)来插入文本。它也适用于“当前”系统时间的srtftime。

        5
  •  1
  •   Ddd    9 年前

    我找到的最简单的解决方案是显示文件被捕获时的时钟,而不是它的持续时间和它的工作/基于这篇文章,谢谢!是

    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

        6
  •  0
  •   felwithe    7 年前

    这是我的解决方案,我相信它是正确的,因为它避免了手动设置速率,并且允许您格式化输出。

    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粗体的字体文件,并将其直接放到了工作目录中,这样做很简单。

        7
  •  -1
  •   wrosecrans    14 年前

    ffmpeg将能够完成大部分工作,但并不是全部打包。使用ffmpeg,您可以让它按顺序解码所有帧,并给您“表示时间戳”(在某些格式上可能提供额外的与时间相关的元数据,但pts是您希望开始查找的内容。)然后,您自己就可以真正地将文本绘制到解码后的帧上。我使用qt来处理类似的事情,通过使用qImage上的qPainer来处理帧数据,但是可能还有其他一些API来绘制您发现更明显的图像。然后,使用ffmpeg api制作一个压缩视频,其中有您新绘制的帧。如果你也想要音频的话,会更复杂一点。我自己的工作并不真正关心音频,所以我没有费心学习API的音频方面。基本上,当你进行读循环,从文件中取出数据包时,其中一些数据包将是音频的。您不必像我那样丢弃它们,而是需要保留它们,并在得到它们时将它们写入输出文件。

    我只使用了C API,而不是C,所以我不知道是否有什么特别的问题需要担心。