Monday, August 12, 2013

ffmpeg burnt-in timecode

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: , ,

Saturday, May 28, 2011

Kill the Final Cut registration screen

I came across this nicely detailed post explaining how to get rid of the forced registration screen of Final Cut Pro/Studio, which always pops up when you really don't want to be bothered with this idiocy.

But I felt the solution was worse than the problem. It involved far too much clicking around for my taste. And you need the Property List Editor. You only have that once you have installed over 1 GB (!!) of developer tools. If you can remember where you put your OS X disk, that is.

Surely, there must be a better way to do it, by just copying a command from some web page and pasting it into Terminal?

It turned out to be 3 commands. And getting them right was much worse than the solution I din't like. You need your machine ID, which is in an XML file that defaults read doesn't want to read. And in that file it is encoded in Base64. You need to put this ID into a property list file as data. That can be done with defaults write, but the data needs to be in hex. I should just have registered, I guess...

Anyway, the detailed explanations are in the link of the first sentence, and the 3 ridiculous commands to paste into Terminal are here:

id=$(perl -MMIME::Base64 -ne '/^\s+(\S{64})\s*$/ && print unpack("H*",decode_base64($1));' "/Library/Application Support/ProApps/Final Cut Studio System ID"|tail -1)
sudo defaults write /Library/Preferences/com.apple.RegFinalCutStudio "{ AECoreTechRegister=1; AECoreTechRegSent=1; }"
sudo defaults write /Library/Preferences/com.apple.RegFinalCutStudio AECoreTechRegInfo -data "$id"

Labels: , , , , ,

Wednesday, March 18, 2009

Installing latest FFMPEG on Debian Etch

How to install the latest FFMPEG on a Debian 4 ("Etch") server? This post encouraged me to try it, despite the fact that it needs compiling from source, and that Etch isn't even the current "stable" Debian anymore. PhillC's post helped a lot, but it still didn't work for me exactly as described there. So here is how it eventually did work for me.

# echo "deb http://www.debian-multimedia.org etch main" >>/etc/apt/sources.list

or

# echo "deb http://www.debian-multimedia.org stable main" >>/etc/apt/sources.list

(I used both, and fiddled with enabling and disabling that repository, so I'm not sure anymore which one ended up being useful).

aptitude update gave me a GPG error, so I had to add the key it mentioned:

# gpg --keyserver hkp://wwwkeys.eu.pgp.net --recv-keys 07DC563D1F41B907
# gpg --armor --export 07DC563D1F41B907 | apt-key add -
# aptitude update

The following didn't work, or only worked partially:

# apt-get build-dep ffmpeg
Reading package lists... Done
Building dependency tree... Done
E: Unable to find a source package for ffmpegcvs
I continued anyway with the long install line of various libraries. I had to remove some of these libraries from the suggested install line. Particularly, since I had to recompile libx264 anyway, I should have removed libx264-dev at this point. It is removed in the line below:
# aptitude install liblame-dev libfaad-dev libfaac-dev libxvidcore4-dev liba52-0.7.4 liba52-0.7.4-dev build-essential subversion

# cd /usr/src
# svn checkout svn://svn.mplayerhq.hu/ffmpeg/trunk ffmpeg

And so I got the current version as of March 17:

Checked out external at revision 28979.
Checked out revision 18021.

And I tried configure:

# cd /usr/src/ffmpeg
# ./configure --enable-gpl --enable-pp --enable-libvorbis --enable-liba52 --enable-libdc1394 --enable-libgsm --enable-libmp3lame --enable-libfaad --enable-libfaac --enable-pthreads --enable-libx264 -enable-libxvid

After various errors, and removing options, I ended up with this error:

ERROR: libx264 version must be >= 0.65.

And trying to install that from the debian-multimedia.org repository didn't work either:

# aptitude install libx264-65
The following packages have unmet dependencies:
libx264-65: Depends: libc6 (>= 2.7-1) but 2.3.6.ds1-13etch8 is installed and it is kept back.
So this thread came to rescue, and I embarked on getting x264 and compiling that from source too:
# aptitude install git git-core

Trying to use Git at this point gives an error, but suggests the solution:

# update-alternatives --config git
There are 2 alternatives which provide `git'.
Selection    Alternative
-----------------------------------------------
*+        1    /usr/bin/git.transition
        2    /usr/bin/git-scm

Press enter to keep the default[*], or type selection number: 2

Next steps:

# cd /usr/src/
# git clone git://git.videolan.org/x264.git
# cd x264
# ./configure --enable-shared

This gave an error about yasm, which was not the right version. I could have tried to compile that too, as shown on the Ubuntu forum, but impatiently decided to try the suggested disable option instead. So the x264 part which worked:

# ./configure --enable-shared --disable-asm
# make
# make install
# ldconfig

And finally, ffmpeg:

# cd /usr/src/ffmpeg/
# ./configure --enable-gpl --enable-postproc --enable-pthreads --enable-libfaac --enable-libfaad --enable-libmp3lame --enable-libx264 --enable-libxvid
# make
# make install
I also had to remove the old ffmpeg version (aptitude purge ffmpeg) which I had installed some time before this, and finally did this:
# echo /usr/local/lib >> /etc/ld.so.conf.d/local.conf
# ldconfig

Since I had a leftover libx264 installed with aptitude and which was too old, that caused a segmentation fault when I tried to encode with ffmpeg. After searching (aptitude search x264), I found i had to aptitude purge libx264-54 libx264-dev . Then, just to be sure, I re-did the ./configure, make clean, make, make install incantations for both x264 and ffmpeg.

In the end, ffmpeg is working. I suppose the --disable-asm option on x264 will make encoding slower, so it may be worth compiling yasm, and re-compiling x264 again.

Now that ffmpeg is working, the main problem is trying to understand it's myriad of incomprehensible and cryptically documented options.

Labels: , , , , , ,

Friday, January 23, 2009

Encoding video sizes

Video compression usually works on square blocks of pixels. These can have sizes of 8x8 or 16x16 or other powers of 2. H264 (AVC) for example, uses macroblocks of 16x16.

So when compressing video, it helps if the frame size is such that both width and height are evenly divisible by 16 or at least by 8. This is why videos encoded for the web or for portable video players are often not exactly in a 16/9 aspect ratio. The PSP's screen, for example, is 480 x 272 even though true 16/9 would require 480 x 270. But 270 is not divisible by 16 whereas 272 is. Youtube uses 640x360, which is true 16/9 and divisible by 8. If you use other sizes, FFmpeg will print a message like

width or height not divisible by 16 (480x270), compression will suffer.

So what are the sizes which are both the right aspect ratio and nicely divisible by 16 or by 8? This little Perl script will let us know:

#!/usr/bin/perl

my $aspect_width  = 16;
my $aspect_height = 9;
my $max_height = 1200;
my @dividers = (16, 8);

for my $divider (@dividers) {

print "$aspect_width/$aspect_height with both ",
     "width and height divisible by $divider :\n\n";

# try sizes up to Full HD
for my $i (1..$max_height/$aspect_height) {
   my $h = $aspect_height * $i;
   unless ($h % $divider) {
       my $w = $aspect_width * $i;
       printf "$aspect_width/$aspect_height divisible by %2d : %4d x %4d\n",
              $divider, $w, $h;
   }
}

print "\n";
}

For 16/9, this gives, among others, numbers like

16/9 divisible by 16 :  256 x  144
16/9 divisible by 16 :  512 x  288
16/9 divisible by 16 :  768 x  432
16/9 divisible by 16 : 1024 x  576
16/9 divisible by 16 : 1280 x  720

For sizes divisible by 8, you obviously have all of the above, plus (among others):

16/9 divisible by  8 :  384 x  216
16/9 divisible by  8 :  640 x  360
16/9 divisible by  8 :  896 x  504
16/9 divisible by  8 : 1920 x 1080
16/9 divisible by  8 : 2048 x 1152

Labels: , , , , ,