The Password is Courage

I’m not a big anime watcher, usually only falling back on it when I’m in a coding slump and feeling really bored. It was on one such occasion that I picked up Soul Eater. It’s rare to get such a character-driven story out of mainstream anime. The characters, music, art design, style… all of it clicked with me. I fell in love with it from the first episode.

I stopped watching about a month before the story ended so that I could see the final five episodes all in one go. Well, it ended late last month and I only just got around to watching them. Maybe because I was busy, maybe because I didn’t want to admit to myself that it was over. Little of both, probably.

In the end it was a disappointment. Soul Eater could have been so much more, if only they had focused on the characters instead of devolving into a huge action battle. I guess such an ending it is to be expected from something based on a shōnen manga, though from what I’ve heard it deviated quite a bit from the source, which is still ongoing. Maybe I’ll pick that up.

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)