Hardware accelerated transcode

While reading the Linux Magazine on the bowl this morning, I discovered that ffmpeg has hardware support for decoding and encoding. Since I do that quite often, I figured it’s time to try it out. Lo and behold, it works better than I expected! Not on hadante, though. ffmpeg just segfaulted, because the card is way too old and the kernel module doesn’t seem to support it.

On othalla (my almost 4 year old laptop), it works like a charm. ffmpeg said encoding  at 5.5 times the original speed, even over NFS!

The command line I used:

$ ffmpeg -hwaccel cuvid -c:v h264_cuvid -resize 1280x720\
-i in.mkv -acodec copy -scodec copy\
-c:v h264_nvenc -preset slow -b:v 4000K -minrate 4000K out.mkv

It has a NVIDIA GPU, as well as an Intel pixel manager, but cuvid and nvenc only works the (proprietary) NVIDIA driver. Anyhow, as always it’s important where you place the options. Any options before -i is for decoding, anything after is for encoding. This makes:

-hwaccel cuvid -c:v h264_cuvid -resize 1280x720

ffmpeg decode everything via cuvid on the GPU and resize it to 720p. Source was 1080p.

-acodec copy -scodec copy

says: Just copy the audio stream and the subtitle stream to output. Now comes the important:

-c:v h264_nvenc -preset slow -b:v 4000K -minrate 4000K

tells it to let the GPU encode it to x264, preset slow and a minimum bitrate of 4000K. If I do the same via software decoder and encoder, I get barely more than real time speed, perhaps 1.1 or 1.2, depending on the source. With cuvid I get 5.5. Even Hadante with its 12 processors and 32GB only gets a speed of 2.0 to 2.2 max, and it’s hardware is much more current! Like it!

How to crop and split a movie

Cropping

I just leaned about a very valuable feature of mplayer: you can graphically determine the crop region with -vf rectangle!

To do so, create a new config file with this:

RIGHT change_rectangle 2  10
LEFT  change_rectangle 2 -10
UP    change_rectangle 3 -10
DOWN  change_rectangle 3  10
KP6   change_rectangle 0  10
KP4   change_rectangle 0 -10
KP8   change_rectangle 1  10
KP2   change_rectangle 1 -10

Then view the movie with

$ mplayer -vf rectangle -input conf=</path/to/conf> <movie_file>

You’ll see a white rectangle in the view area. Change the size with the keypad and the position with the cursor keys. The keypad down key enlarges the height, keypad down reduces it. Keypad left reduces the width, keypad right enlarges it.

Once you’re done, quit mplayer and use the rectangle geometry as crop parameter for ffmpeg:

$ ffmpeg -vf crop=<rectangle_data> ...

Splitting

Splitting isn’t as easy as it seems. You need 2 parameters:

  • -ss hh:mm:ss
  • -t hh:mm:ss

The latter is not a position in the file, but a duration! So, if you want to cut out everything from position 00:33:42 to 00:46:43, use -ss 00:33:42 -t 00:13:01 (33:42 + 13:02 = 46:43).

Also, -ss is a positional parameter. Use it as an input parameter, i.e. before -i if you don’t want silence and a black screen up front!

Example

Split out 13:02 minutes from position 33:42:

$ mplayer -ss 00:33:42 -t 00:13:02 -i <source> -acodec copy -vcodec copy out.file

Use the rectangle feature:

$ mplayer -vf rectangle -input conf=</path/to/conf> in.file

Reencode the split movie to mkv with the rectangle data:

$ ffmpeg -i <in.file> -acodec copy -vcodec libx264 -preset slow -threads 0 -x264opts fast_pskip=0:crf=21 <out.mkv>

Re-encode 1912×1072 vids

To reencode them to proper 720p, use this:

ffmpeg -y -i <infile> \
-acodec copy \
-vf "pad=width=1920:height=1080:x=4:y=4" \
-s hd720 \
-vcodec libx264 -preset slow -threads 0 \
-x264opts fast_pskip=0:crf=20 out.mkv

This pads the video with 4px wide bars on each side and resizes it to a proper 16:9 (1280×720) aspect ratio from 1080p.

Splitting big mp3 files

When splitting big mp3 files (like audiobooks) into digestible chunks (say 20 minutes) with ffmpeg, there are several things to keep in mind:

  1. It really, really matters where you put the -ss option on the command line! If you use it as an output option (i.e. after -i), input is read but discarded, so you end up with a file containing silence at the start. You have to use it as an input option (i.e. before -i) to get the proper result.
  2. Same goes for -t, only that you have to use this one as an output option (i.e. after -i but before the output file name. Also note that -t denotes a duration, not a position!
  3. If you want to transfer the split files to an Android device, you need to adjust the IDv3-tag “title”. Android uses that plus the original extension as the display file name. If the title-tag does not contain some string to differentiate files, you end up with identical file names. So you have to fix the title to something like “audiobook – 01 of 37”. Of course the track-tag is ignored (why bother with something so obvious 🙁 ).

But do not fret. I put this all together in a quick and dirty quick and dirty perl script. First argument is the input file, second the base for output file names and third the base for the title tag:

$ splitmp3.pl "Big Input file.mp3" "Output file" "Name"

outputs files like this:

Output file - 01.mp3
Output file - 02.mp3
...

with titles like this:

Name - 01 of 37
Name - 02 of 37
...

That’s all, folks!

Convert 1080 Bluray-Rip DTS to 720p-AC3

1. Convert video:

ffmpeg -i <infile> \
 -an -sn \
 -preset slow \
 -tune film \
 -s hd720 \
 -c:v libx264 -threads 0 \
 -x264opts fast_pskip=0 \
 -b:v 4300k \
 -minrate 4000k \
 -maxrate 4400k \
 <outfile.mkv>

Minimum bitrate 4000kb/s, maximum 4400kb/s, average 4300kb/s.

2. Convert audio:

ffmpeg -i <infile> \
 -vn -sn \
 -acodec ac3 \
 <outfile.ac3>

3. Extract subs:

mkvextract tracks <infile> <trno>:<outfile>

Convert it to SRT with Subtitle Edit

4. Merge it:

mkvmerge <outfile_from_1> <outfile_from_2> <outfile_from_3> \
 -o <final_out.mkv>

That’s it!

flac + cue to mp3

To convert a single flac file with a cue sheet to mp3, first split it up:

$ shnsplit -f <sheet.cue> <source.flac>

Then convert the wav-files to mp3 with ffmpeg:

for i in *.wav ; do ffmpeg -i ${i} -codec:a libmp3lame -qscale:a 2 ${i%%wav}mp3 ; done

Or, if you have individual flac files:

for i in *.flac; do ffmpeg -i ${i} -codec:a libmp3lame -qscale:a 2 ${i%%flac}mp3 ; done

qscale:a 2 produces mp3s with an average bitrate around 170-210 kbit/s. It should be close to lossless.