Tuesday 19 March 2019

Raspberry Pi 3b+ Video Encoding with ffmpeg libx264 and h264_omx

Raspberry Pi 3b+ Video Encoding with ffmpeg libx264 and h264_omx


Note that this is a live page that will be updated regularly. 

Please give your corrections and suggestions at the bottom of the page. 

Constructive comments only !

Introduction

This page describes how to use ffmpeg to encode videos using the h.264 codec on the Raspberry Pi 3b+.

There are two ffmpeg h.264 encoders available for the Raspberry Pi:
  1. Software (CPU) based h.264 encoder libx264 
  2. Hardware (GPU) based h.264 encoder h264_omx
libx264 provides high quality output and offers most of the x264 options. The downside is that as it is software based (i.e. it uses the CPU) it encodes at about 0.53x, i.e. a one hour video takes nearly two hours to encode,

h264_omx uses the GPU (video card) rather than the CPU and so is very fast. It encodes at about 1.2x, i.e. a one hour video takes less than one hour to encode. The output from h264_omx is inferior to that of libx264. Also the only encoding option available with h264_omx  is to set the video bit rate (e.g. -b:v 3000k).   

So you have a choice between a high quality, slow h.264 encoder with lots of x264 options, i.e. libx264, or a fast h.264 encoder with really just one option (setting the video bit rate) that produces inferior single pass output, i.e. h264_omx


Recommendation

The best combination of encoding speed and video quality was obtained by using h264_omx with 2 pass encoding. The h264_omx video quality results were significantly better than using with single pass h264_omx encoding.

Example 2 pass h264_omx encoding:
ffmpeg -i inputfile -c:v h264_omx -b:v 3000k -pass 1 -an -y -f mp4 /dev/null && ffmpeg -i inputfile -movflags +faststart -c:v h264_omx -b:v 3000k -pass 2 -c:a aac -b:a 256k -ac 2 -ar 48000 -y outputfilename.mp4 

Adjust the video bit rate -b:v 3000k and audio bit rate -b:a 256k to taste.

2 pass encoding with h264_omx was found to be significantly faster than 1 pass encoding with libx264
As long as you have the time and patience, and your CPU doesn't overheat, then libx264 does produce superior results to h264_omx

If you require the absolutely highest possible video encoding quality in a reasonable time frame, then it is recommended to use Handbrake or ffmpeg running on Linux with an recent i7 processor.
For most user cases though, 2 pass encoding with h264_omx will produce good quality video as long as you don't need to resize the video.


Assumptions

It is assumed that you are:
  1. Using Raspberry Pi 3b+ (not tested with earlier Pis)
  2. Raspbian (Raspbian Stretch with desktop)
  3. You have installed ffmpeg :
    sudo apt-get install ffmpeg 
  4. You have installed VLC for video testing purposes:
    sudo apt-get install vlc
  5. You have a basic familiarity with ffmpeg and the Linux bash shell.
Note that as of late 2018 VLC comes with hardware h.264 decoding enabled, thereby making it simple to watch h.264 videos on the Raspberry Pi.


Single Pass Examples

These two examples encode the first minute of the input test video Mike06.mkv (an mpeg 2 DVD file simply ripped to MKV without any codec change using MakeMKV on an i7 Linux Mint PC).

Remove -ss 00:00:00 -to 00:01:00 to encode the full video.

h264_omx
ffmpeg -i Mike06.mkv -ss 00:00:00 -to 00:01:00 -c:v h264_omx -b:v 1500k -c:a aac -b:a 256k -ac 2 -ar 48000 -y mike06-h264_omx-1500.mp4 

Adjust -b:v 1500k to change the video bitrate (quality).

libx264
ffmpeg -i Mike06.mkv -ss 00:00:00 -to 00:01:00 -c:v libx264 -crf 20 -preset medium -profile:v high -level:v 4.0 -c:a aac -b:a 256k -ac 2 -ar 48000 -y mike06-libx264-crf20.mp4 

In the above 1 minute test video a 12.8 MB output file corresponded to:
-c:v libx264 -crf 20 
and 
-c:v h264_omx -b:v 1500k 

The libx264 encoder produced better video quality than h264_omx even though the output file sizes were similar. The libx264 encoding time was however more than double that of h264_omx

In another test that had a very high quality h.264 encoded input file (1920x1080) with an original bit rate around 16 MB the libx264 encoder was encoding at around 7% of original speed with  -crf 20 meaning that a 1 hour encode would take 14+ hours ! 
This is too long to be useful and was aborted well before completion.
Not Recommended.

Using 2 pass encoding with -b:v 16000k and h264_omx produced very watchable high quality video quality. 
Strongly Recommended.

The best combination of encoding speed and video quality was obtained by using h264_omx with 2 pass encoding.
The h264_omx video quality results were significantly better than using with single pass h264_omx encoding.

Example 2 pass h264_omx encoding:

ffmpeg -i inputfile -c:v h264_omx -b:v 3000k -pass 1 -an -y -f mp4 /dev/null && ffmpeg -i inputfile -movflags +faststart -c:v h264_omx -b:v 3000k -pass 2 -c:a aac -b:a 256k -ac 2 -ar 48000 -y outputfilename.mp4 

Adjust the video bit rate -b:v 3000k and audio bit rate -b:a 256k to taste.


Tips

Apart from varying the video bitrate here isn't much else you can change for the h264_omx encoder.
You can NOT use h264_omx with -crf
You can ONLY use h264_omx with -b:v
You can also change the video dimensions but at the expense of speed, however I have not tested this option myself. 

For libx264, slower presets than the default -preset medium can be used, however the encoding times become VERY long and the CPU gets extremely hot.
Not Recommended.

Adding -movflags +faststart works for both encoders and enables videos to be instantly streamed without the need to first download the entire video.
Recommended.

While the video profile and level for libx264 can be set up to
-profile:v high -level:v 4.0
the h264_omx encoder automatically sets High@L4 

So while you can control the video profile and level for libx264, these options are not available for the h264_omx encoder.

A reasonable range for the -crf for the libx264 seems to be 20 to 23.  
You can go down to -crf 16 but at the expense of significantly longer encoding times than those for -crf 20  

The libx264 encoding produced the better video quality results of the two encoders using single pass encoding.

A large increase in encoding speed (from 1.2x to 2.5x) can be obtained for the h264_omx encoder by using the MP3 encoder libmp3lame in place of the Advance Audio Codec encoder aac

For example:
ffmpeg -i Mike06.mkv -ss 00:00:00 -to 00:01:00 -c:v h264_omx -b:v 1500k -c:a libmp3lame -b:a 256k -ac 2 -ar 48000 -y mike06-h264_omx-1500-mp3.mp4

The problem with using MP3, is that for mp4 containers (which contain both video and audio) Apple devices expect the audio in an mp4 container to be encoded with AAC not MP3
Consequently mp4 files encoded with mp3 audio will not have any sound on Apple devices. 
Note this does not apply to the more general user case of using  MP3 in audio only files (e.g. m4a).

Using the MP3 encoder libmp3lame in combination with the libx264 encoder didn't improve upon the encoding speed using aac :
ffmpeg -i Mike06.mkv -ss 00:00:00 -to 00:01:00 -c:v libx264 -crf 20 -preset medium -profile:v high -level:v 4.0 -c:a libmp3lame -b:a 256k -ac 2 -ar 48000 -y mike06-libx264-crf20-mp3.mp4 

In fact the encoding with the libx264 and libmp3lame combination was actually slower than using aac ! 
Your results may vary. 
Try it !
 

Example 2 Pass Encoding Outputs from h264_omx


The original input files Mike06.mkv-Mike10.mkv are all mpeg 2 files with a video bitrate of 2MB - 3MB.
These files consist of a language tutor teaching in front of a white board.
Other than the tutor's Hawaiian shirts there isn't much detail in the video.
There isn't much movement and the original video quality is just 'fair'.

ffprobe -i Mike06.mkv
Stream #0:0(eng): Video: mpeg2video (Main), yuv420p(tv, progressive), 720x576 [SAR 64:45 DAR 16:9], 25 fps, 25 tbr, 1k tbn, 50 tbc
Stream #0:1(eng): Audio: mp2, 48000 Hz, stereo, s16p, 224 kb/s (default)

The same ffprobe results are also obtained for Mike07.mkv-Mike10.mkv

In the below ffmpeg outputs, note how the h264_omx first pass encoding takes around 4x speed and the second  h264_omx pass encoding around 1.5x speed, given an overall encoding time of around 55 minutes for a 60 minute video (i.e.60 / 4 = 15 mins + 60/1.5 = 40 =55 minutes) or 0.92x speed.
This compares with around 0.5x speed for a single pass libx264 for a modest overall improvement in video quality. 

Mike06.mkv
frame=90864 fps= 95 q=-0.0 Lsize=  927507kB time=01:00:34.52 bitrate=2090.5kbits/s speed= 3.8x 
frame=90864 fps= 35 q=-0.0 Lsize= 1043451kB time=01:00:34.56 bitrate=2351.9kbits/s speed= 1.4x

Mike07.mkv
frame=114092 fps= 98 q=-0.0 Lsize= 1178330kB time=01:16:03.64 bitrate=2115.2kbits/s speed=3.93x
frame=114092 fps= 37 q=-0.0 Lsize= 1325673kB time=01:16:03.69 bitrate=2379.6kbits/s speed= 1.5x

Mike08.mkv
frame=97683 fps=107 q=-0.0 Lsize=  997178kB time=01:05:07.28 bitrate=2090.7kbits/s speed=4.29x
frame=97683 fps= 39 q=-0.0 Lsize= 1122635kB time=01:05:07.32 bitrate=2353.7kbits/s speed=1.55x

Mike09.mkv
frame=86881 fps=106 q=-0.0 Lsize= 1170912kB time=00:57:55.20 bitrate=2760.2kbits/s speed=4.26x 
frame=86881 fps= 33 q=-0.0 Lsize= 1279450kB time=00:57:55.26 bitrate=3016.0kbits/s speed=1.31x 

Mike10.mkv
frame=132565 fps=106 q=-0.0 Lsize= 1738525kB time=01:28:22.56 bitrate=2685.9kbits/s speed=4.25x
frame=132565 fps= 39 q=-0.0 Lsize= 1909932kB time=01:28:22.61 bitrate=2950.7kbits/s speed=1.57x

Very High Quality Input file

The very high quality h.264 encoded input file (1920x1080) with an original bit rate of around 16 MB (briefly described above), has the following attributes:

ffprobe -i VS2017.mp4
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'VS2017.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    creation_time   : 2017-12-03T09:29:42.000000Z
    encoder         : HandBrake 1.0.7 2017040900
  Duration: 00:42:30.28, start: 0.000000, bitrate: 16300 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 15961 kb/s, 29.94 fps, 29.97 tbr, 90k tbn, 180k tbc (default)
    Metadata:
      creation_time   : 2017-12-03T09:29:42.000000Z
      handler_name    : VideoHandler
    Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 328 kb/s (default)
    Metadata:
      creation_time   : 2017-12-03T09:29:42.000000Z
      handler_name    : Stereo

This very high quality input file is taken from the 2017 Victoria Secret Shanghai show.
Given the high level of detail in the clothes, skin tones, makeup and rapid onstage movement, the Victoria Secret shows provide an excellent video encoding test.

The 2 pass h264_omx encoder produced very good results when encoding this very high quality Victoria Secret 2017 input file.

By contrast, the libx264 encoder was encoding at around 7% of original speed with a quality of  -crf 20 meaning that a 1 hour encode would take 14+ hours ! 
This is too long to be useful and was aborted well before completion.
Not Recommended.

Using 2 pass encoding with -b:v 16000k and h264_omx produced very watchable high quality video quality. 
Strongly Recommended.


More Content to Follow


ffmpeg -i input.mp4 -c:v h264_omx -b:v 16000k -c:a aac -b:a 256k -ac 2 -ar 48000 -y output.mp4


ffmpeg -i input -c:v h264_omx -b:v 16000k -pass 1 -an -y -f mp4 /dev/null && ffmpeg -i input -movflags +faststart -c:v h264_omx -b:v 16000k -pass 2 -c:a aac -b:a 256k -ac 2 -ar 48000 -y output.mp4

ffmpeg -i input -c:v libx264 -crf 20 -preset medium -profile:v high -level:v 4.0 -c:a aac -b:a 256k -ac 2 -ar 48000 -y output.mp4 


ffmpeg -i VS2018-CRF16-veryslow-fastdecode-web-high4-HB.mp4 -c:v h264_omx -b:v 16000k -pass 1 -an -y -f mp4 /dev/null && ffmpeg -i VS2018-CRF16-veryslow-fastdecode-web-high4-HB.mp4 -movflags +faststart -c:v h264_omx -b:v 16000k -pass 2 -c:a aac -b:a 256k -ac 2 -ar 48000 -y VS2018-ICE-16MB.mp4



ffmpeg -i Wilt\ \(1989\).mkv -movflags +faststart -c:v libx264 -crf 20 -c:a aac -b:a 256k -ac 2 -ar 48000 -y Wilt-1pass-libx264-CRF20.mp4

Starting second pass: moving the moov atom to the beginning of the file1.07x   
frame=133046 fps= 27 q=-1.0 Lsize=  876248kB time=01:28:41.72 bitrate=1348.9kbits/s speed=1.07x



Links






1 comment:

  1. Hey thanks so much for sharing. I'm just starting to learn about this and found it very useful.

    I'm trying to set up an IP camera to stream its video to Youtube live which I believe uses RTMP so the video needs to be encoded.

    I'm wondering if a Raspberry Pi 3 B+ would be able to works as such encoder with h264_omx and handle this job.

    Do you know if it's possible and feasible in real scenario achieving a good streaming viewing experience?

    I'd really appreciate any input in the matter. Thank you!

    ReplyDelete