Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can ffmpeg burn in time code?

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?

like image 608
spinon Avatar asked Jul 03 '10 01:07

spinon


4 Answers

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.

like image 156
stib Avatar answered Nov 01 '22 19:11

stib


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.
like image 28
Lekensteyn Avatar answered Nov 01 '22 21:11

Lekensteyn


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.

like image 8
amphetamachine Avatar answered Nov 01 '22 20:11

amphetamachine


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.

like image 1
rogerdpack Avatar answered Nov 01 '22 20:11

rogerdpack