I have a need to burn in a time code to a video and am wondering if this is something that ffmpeg is capable of?
Short answer, no.
Long answer, yes, but not without using a separate library to create the frames with the rendered time code on them, with transparency filling the rest of the frame, then using FFmpeg to overlay the frames on the existing video. Off the top of my head I don't know how to do this, but I'm sure if you're creative you can figure it out.
Edit: I've been working on this problem because it is an interesting question/project for me. I have come a little further in the solution by writing a Perl script that will generate a .srt
file with the time code embedded in it for any given video file from which FFmpeg is configured to be able to read the metadata. It uses the Video::FFmpeg
library to read the duration and saves a subtitle file as ${video}.srt
. This will make it so it will render automatically in Mplayer if you insert the following lines in your ~/.mplayer/config
:
# select subtitle files automatically in the current directory, all files
# matching the basename of the current playing file
sub-fuzziness=1
Still working on how to position and overlay the rendered subtitles on a video and re-encode in the same format. I'll update this post as I know more.
FFMPEG's drawtext filter works for me, you specify the starting timecode and its format thusly:
-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"
you have to specify timecode format in the form hh:mm:ss[:;,]ff. Note that you have to escape the colons in the timecode format string, and you have to specify a timecode rate (here 25fps). You can also specify additional text - here it's "TCR:"
You can get the frame rate with ffprobe and a bit of shell fu:
frame_rate=$(ffprobe -i "movie.mov" -show_streams 2>&1|grep fps|sed "s/.*, \([0-9.]*\) fps,.*/\1/")
So you could easily plug it all together in a batch - processing script, eg
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
That would add the clip's name and rolling timecode in a semi-opaque box at the bottom center of a 1920x1080 frame
Edit Since I've come to the dark side I now do this in a Windows Powershell environment, and this is what I use:
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'))}
This creates mp4s given a folder containing .MOV, .MP4 and .MTS files (using the -filter
command it looks for files with *.M* in the name, which you would have to change if you were doing .AVI files), and it's a bit more minimal, it just uses libx264 with default settings as output codec and doesn't specify font etc. The timecode in this case is burnt in at the top left of the frame.
The drawtext filter mentioned in @stib's answer is the key to insert the time. Using the timecode
option, however, does not match the wall clock time. If you get the r
(timecode_rate) parameter wrong, then your the time will not match your playback time.
Other options exist, for instance the text='%{prt}'
option allows you to display the elapsed time with microsecond precision. Command:
ffmpeg -i video.mp4 -vf "drawtext=text='%{prt}'" output.mp4
To get a clock instead, I had to use the deprecated strftime
option. This has an undocumented basetime
option that can be used to set the start time in microseconds. An example where I set the start time to 12:00 PM on 1 December 2013 (the $(...)
part is shell-expansion done by the shell) and have only the time displayed (see the 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
\\:
is used to escape the :
which would otherwise get the meaning of an option separator.
Another example: a command to insert the date + time within a black box, some pixels away from the top-left corner and "some padding" (actually, two spaces and newlines on the edges):
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
Another example to get the microseconds below the clock:
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
This uses the fact that the text is actually three lines long and that both text have a newline (carriage return, ^M
) prepended and appended. (Without this newline, the space gets stripped)
Other hints:
-vf
and-filter:v
are equal.- You cannot specify filters multiple times, e.g.
-vf drawtext=text=1 -vf drawtext=text=2
will only draw the second text. You can combine filters with a comma as I showed above.
in more recent builds, you can use the drawtext filter (the "t" in its examples is, I believe, the timestamp of the frame) to insert text. It also works for srtftime on the "current" system time as well.
The simplest solution i found to show the clock when the file has been captured, not its duration and it working /based on this post, thanks!/ is
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
So simple in timecode - put your starting time, then the counting is going fine! The example is for Windows
Here's my solution, and I believe it is the correct one, because it both avoids having to manually set the rate, and allows you to format the output.
ffmpeg -i test.mp4 -vf \
"drawtext=fontfile=arialbd.ttf:text='%{pts\:gmtime\:0\:%H\\\:%M\\\:%S}'" test.avi
This produces a stamp in the HH:MM:SS format; you can change it to whatever you'd like, using strftime.
It may look like it's going to put in a timestamp with gmtime
, but that's not what happens. It actually feeds the video's current time, in seconds, to gmtime, producing a date which is 1/1/1970, and a time which is however many seconds after midnight. So you just discard the date portion and use the time portion.
Take note of the triple escaped colons within the pts function, which you'll have to do if you enter it like I did above. Also you can see that I copied my font file for Arial Bold and dropped it right into the working directory for simplicity.
FFMPEG will be able to do much of the work, but it won't be all packaged up. Using FFMPEG, you can have it decode all of the frames in sequence, and give you the "Presentation Time Stamp" (additional time related metadata may be available on some formats, but PTS is what you'll want to look for to get started.) Then, you are on your own to actually draw the text onto the decoded frame yourself. I use Qt for similar things, by using QPainter on a QImage with the frame data, but there may be some other API to draw on an image that you find more obvious. Then, use the FFMPEG API to make a compressed video that has your newly drawn-on frames in it. It'll be a little more complicated if you also want audio. My own work doesn't really care about audio, so I haven't bothered to learn the audio aspects of the API. Basically, as you do your read loop getting packets out of the file, some of them will be audio. Instead of discarding them like I do, you'll need to keep them and write them into the output file as you got them.
I've only used the C API, rather than C#, so I don't know if there are any special gotcha's there to be worried about.
来源:https://stackoverflow.com/questions/3169916/can-ffmpeg-burn-in-time-code