Re-encoding VFR Anime

So I preordered a Pandora, and for the past week have been re-encoding videos and music for playing on it. All goes well, until I discovered my favorite anime uses VFR—Variable Frame Rate. This is usually only seen in anime, which tends to use a low frame rate for slow scenes and a higher frame rate for action sequences and 3D renders.

For whatever reason, all the major video tools are completely dumb when it comes to VFR. They expect a constant framerate and will completely screw up anything VFR. This is such a problem that many raw and fansub groups tend to give up and decimate their encodes to a constant 24fps, noticably sacrificing quality.

But there is a light at the end of the tunnel. After several days of searching and tinkering, I’ve found out how to do it. Here are the steps I’m using—they are definitely still not optimal (though it does produce a perfect encode) so if you know of anything better, let me know.

  1. If your source is not MKV, you’ll need to convert it. This can be done using mkvmerge from the MKVToolnix package.
  2. Encode the source like normal with x264.
  3. Use the mkv2vfr utility from the Haali Media Splitter package to extract a timecode file from the source MKV. This is the important step—the timecode file describes the FPS that different segments of your video run at. The mkvextract program from MKVToolnix has a timecode extraction option that looks cleaner, but seems to produce an incompatible or broken timecode file.
  4. Mux the new video with the timecode file and the audio. This is also done with mkvmerge. Make sure you specify the timecode file for the video, not the audio.

Here are the exact commands I used:

# 1. Convert MP4 to MKV
mkvmerge -o "source.mkv" -a 2 -d 1 -S "source.mp4" --track-order 0:1,0:2

# 2. Encode
x264 --crf 26 --ref 8 --mixed-refs --bframes 16 --b-pyramid
     --direct auto --filter 1:1 --subme 7 --trellis 2 --psy-rd 0.6:0
     --partitions p8x8,b8x8,i4x4,i8x8 --8x8dct --vbv-maxrate 25000
     --me umh --threads auto --thread-input --aq-mode 0
     --progress --no-psnr --no-ssim --output "output.mkv" "source.avs"

# 3. Extract timecodes
mkv2vfr "source.mkv" "dummy.avi" "timecodes.txt"

# 4. Mux output with timecodes and original audio.
mkvmerge -o "muxed.mkv" --timecodes "1:timecodes.txt"
         -d 1 -A -S "output.mkv" -a 2 -D -S "source.mkv"
         --track-order 0:1,1:2

With source.avs looking like:

DirectShowSource("source.mkv", audio=false)

crop(2, 0, -4, -2)
Spline36Resize(800, 432)

vecs = last.MVAnalyseMulti(refframes=2, idx=1)
last.MVDegrainMulti(vecs, idx=1)