2013-08-12

burnt-in timecode with ffmpeg

Burning-in timecode is easy in Avid or Final Cut, but if for any reason you need to do it the hard way with command-line ffmpeg, here is how.

To not make it harder than necessary, there are links to pre-compiled versions of ffmpeg on their download page. For Mac OS X, as of August 2013, there were these 2 versions:

  •  http://ffmpegmac.net, which unfortunately didn't have the needed filter. It would give the error
    "AVFilterGraph ...] No such filter: 'drawtext'".
  • the version 2.0.1 built by Helmut Tessarek worked fine. Unfortunately, it is compressed with 7-zip, so you may need to get a decompressor first. I used Keka (not open source, but free).

Below is the command I used to quickly encode Sony mpeg2 MXF files into H264 Quicktimes, preserving the original timecode in the QT TC track (ffmpeg does this automatically), and also burning it into the picture.

Since the command itself is quite awful, it is best to predefine variables, so that the long command itself can be copy/pasted directly, without further editing, or at least not too much...

# set variables for the input and output files:

in=/path/to/input_file
out=/path/to/ouput_file.mov

# the timecode rate must be set. Should be identical to the FPS.

tc_rate=25

# select a monospaced font file on your machine. On Linux, try:

font="/usr/share/fonts/truetype/droid/DroidSansMono.ttf"

# or on Mac:

font="/Library/Fonts/Andale Mono.ttf"

# size and position:

fontsize=46
position="x=w-text_w-(text_w/6):y=text_h" # top right

# For bottom right, try this instead: position="x=(w-tw)/2: y=h-(2*lh)"

# get the timecode, and escape the ":" to be able to use it in the burn-in filter

timecode=$( ffmpeg -i "$in" 2>&1 | awk '$1 ~ /^timecode/ {print $NF}' )
tc_escaped=${timecode//:/\\:}

# To test encoding only the first x seconds, use:

test_secs="-t 20"

# or for the whole video, leave this empty:

test_secs=

# quality/size/speed : (try crf between 18 and 25? lower is better quality and bigger file.)

crf=23
preset=ultrafast # (superfast, fast, slow, ...)

# And finally (with de-interlacing and without scaling):

ffmpeg -threads 0 -i "$in" $test_secs -acodec copy -vcodec libx264 -preset $preset -crf $crf -deinterlace -vf "drawtext=fontfile=$font: timecode='$tc_escaped': r=$tc_rate: $position: fontcolor=white: fontsize=$fontsize: box=1: boxcolor=black@0.2" "$out"

or to keep only video with audio channel 1 (throwing away audio channels 2, etc. ):

ffmpeg -threads 0 -i "$in" $test_secs -map 0:0 -map 0:1 -acodec copy -vcodec libx264 -preset $preset -crf $crf -deinterlace -vf "drawtext=fontfile=$font: timecode='$tc_escaped': r=$tc_rate: $position: fontcolor=white: fontsize=$fontsize: box=1: boxcolor=black@0.2" "$out"

 

Labels: , , ,

6 Comments:

Blogger Unknown said...

Is there any way to make it an AppleScript or something, so one can just drop a file onto it (or one of a few different applescripts in a folder that are different frame rates for example) and that's it?

13 January, 2018 10:00  
Blogger Milivoj. said...

@Evan: Sure. The easiest would probably be to first put things together into a full Bash script. Then you can test it by dragging files from the Finder into the Terminal window to give the arguments to the script.
Once it works as you want, it should be easy to wrap your shell script with Automator / Apple script / Platypus or whatever so that dropped files are given as arguments to the script.

13 January, 2018 11:30  
Blogger DMC said...

Hey Milivoj, I'm struggling to get this to work. Trying to write a bash script with it but I keep getting the error "Unable to parse timecode, syntax: hh:mm:ss[:;.]ff"

But my TC is in that format. Would you mind talking me through it? Thanks!

10 December, 2020 19:24  
Blogger Milivoj. said...

@DMC: Show the command that produces the error, and the value of your $tc_escaped variable. In the command given to ffmpeg, the TC needs to have it's colons escaped:

ffmpeg ... -vf "drawtext= ...: timecode='10\:00\:00\:00': ..." ...

10 December, 2020 20:01  
Blogger DMC said...

This is my bash script:

#!/bin/bash

in=/path/to/input_file
out=/path/to/ouput_file.mov
timecode=$( ffmpeg -i "$in" 2>&1 | awk '$1 ~ /^timecode/ {print $NF}' )
tc_escaped=${timecode//:/\\:}
tc_rate=25

for video in *.mov
do
ffmpeg -i "$video" -vf crop="in_w:in_h-120:0:60",pad="in_w:in_h+120:0:-60",subtitles="${video%.*}.srt:force_style='Alignment=0,MarginL=2,MarginV=272,Fontname=Tahoma,fontsize=10,PrimaryColour=&H4DFFFFFF'",drawtext="fontsize=30:fontcolor=white@0.5:fontfile=FreeSerif.ttf:text='${video%.*}':x=10:y=1040",drawtext="timecode='$tc_escaped':r=$tc_rate:fontsize=30:fontcolor=white@0.5:font='/Library/Fonts/Andale Mono.ttf':x=1800:y=10" -ss 5 -t 10 testoutput/"${video%.*}_h264.mov"
done

10 December, 2020 23:05  
Blogger Milivoj. said...

I'm afraid blog comments are not well suited for debugging scripts. Maybe try https://video.stackexchange.com ?

11 December, 2020 00:48  

Post a Comment

<< Home