Using GPU hardware to speed up FFmpeg video transcoding and pit draining

Author: dongdong

Email: ldyldy828@126.com

This article includes:

  • Installing FFmpeg on Linux
  • Video format recognition and transcoding via command line
  • Video transcoding acceleration using GPU on Linux with Nvidia graphics card

FFmpeg Compile Installation

On the FFmpeg website, https://ffmpeg.org/download.html can be downloaded to the ubunto/debian distribution package. Other Linux distributions need to be compiled on their own.Also, if you want to use GPU for hardware acceleration, you must compile FFmpeg yourself, so this section describes how to install FFmpeg from source code (based on RHEL/Centos)

Install Dependent Tools

yum install autoconf automake bzip2 cmake freetype-devel gcc gcc-c++ git libtool make mercurial pkgconfig zlib-devel

Dead work

Create ffmpeg_sources directory under $HOME

HOME=/home/local/

Compile and install dependent Libraries

Dependent libraries in this section are essentially required, and it is recommended that they all be installed

nasm

Assemble compilers required to compile certain dependent Libraries

cd /home/local/ffmpeg_sources
curl -O -L http://www.nasm.us/pub/nasm/releasebuilds/2.13.02/nasm-2.13.02.tar.bz2
tar xjvf nasm-2.13.02.tar.bz2
cd nasm-2.13.02
./autogen.sh
./configure --prefix="/home/local/ffmpeg_build" --bindir="/home/local/bin"
make
make install

yasm

Assemble compilers required to compile certain dependent Libraries

cd /home/local/ffmpeg_sources
curl -O -L http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
tar xzvf yasm-1.3.0.tar.gz
cd yasm-1.3.0
./configure --prefix="/home/local/ffmpeg_build" --bindir="/home/local/bin"
make
make install

libx264

H.264 video encoder, this library is required if you need to output H.264 encoded video, so it is necessary

cd /home/local/ffmpeg_sources
git clone --depth 1 http://git.videolan.org/git/x264
cd x264
PKG_CONFIG_PATH="/home/local/ffmpeg_build/lib/pkgconfig" ./configure --prefix="/home/local/ffmpeg_build" --bindir="/home/local/bin" --enable-static
make
make install

libx265

H.265/HEVC video encoder.
If you don't need this encoder, you can skip and remove--enable-libx265 from ffmpeg's configure command

cd /home/local/ffmpeg_sources
hg clone https://bitbucket.org/multicoreware/x265
cd ~/ffmpeg_sources/x265/build/linux
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="/home/local/ffmpeg_build" -DENABLE_SHARED:bool=off ../../source
make
make install

libfdk_acc

AAC Audio Encoder, Essential

cd /home/local/ffmpeg_sources
git clone --depth 1 --branch v0.1.6 https://github.com/mstorsjo/fdk-aac.git
cd fdk-aac
autoreconf -fiv
./configure --prefix="/home/local/ffmpeg_build" --disable-shared
make
make install

libmp3lame

MP3 audio encoder, essential

cd /home/local/ffmpeg_sources
curl -O -L http://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz
tar xzvf lame-3.100.tar.gz
cd lame-3.100
./configure --prefix="/home/local/ffmpeg_build" --bindir="/home/local/bin" --disable-shared --enable-nasm
make
make install

libops

OPUS Audio Encoder
If you don't need this encoder, you can skip and remove--enable-libopus from ffmpeg's configure command

cd /home/local/ffmpeg_sources
curl -O -L https://archive.mozilla.org/pub/opus/opus-1.2.1.tar.gz
tar xzvf opus-1.2.1.tar.gz
cd opus-1.2.1
./configure --prefix="/home/local/ffmpeg_build" --disable-shared
make
make install

libogg

Dependent on libvorbis

cd /home/local/ffmpeg_sources
curl -O -L http://downloads.xiph.org/releases/ogg/libogg-1.3.3.tar.gz
tar xzvf libogg-1.3.3.tar.gz
cd libogg-1.3.3
./configure --prefix="/home/local/ffmpeg_build" --disable-shared
make
make install

libvorbis

Vorbis Audio Encoder
If you don't need this encoder, you can skip and remove--enable-libvorbis from ffmpeg's configure command

cd /home/local/ffmpeg_sources
curl -O -L http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.gz
tar xzvf libvorbis-1.3.5.tar.gz
cd libvorbis-1.3.5
./configure --prefix="/home/local/ffmpeg_build" --with-ogg="/home/local/ffmpeg_build" --disable-shared
make
make install

libvpx

VP8/VP9 Video Codec/Decoder
If you don't need this codec, you can skip and remove--enable-libvpx from ffmpeg's configure command

cd /home/local/ffmpeg_sources
git clone --depth 1 https://github.com/webmproject/libvpx.git
cd libvpx
./configure --prefix="/home/local/ffmpeg_build" --disable-examples --disable-unit-tests --enable-vp9-highbitdepth --as=yasm
make
make install

Compile and install ffmpeg 3.3.8

cd  /home/local/ffmpeg_sources
curl -O -L https://ffmpeg.org/releases/ffmpeg-3.3.8.tar.bz2
tar xjvf ffmpeg-3.3.8.tar.bz2
cd ffmpeg-3.3.8
PATH="/home/local/ffmpeg_sources/bin:$PATH" PKG_CONFIG_PATH="/home/local/ffmpeg_sources/ffmpeg_build/lib/pkgconfig" ./configure   --prefix="/home/local/ffmpeg_sources/ffmpeg_build" --pkg-config-flags="--static"   --extra-cflags="-I /home/local/ffmpeg_sources/ffmpeg_build/include"   --extra-ldflags="-L /home/local/ffmpeg_sources/ffmpeg_build/lib"   --extra-libs=-lpthread   --extra-libs=-lm   --bindir="$HOME/bin"   --enable-gpl   --enable-libfdk_aac   --enable-libfreetype   --enable-libmp3lame   --enable-libopus   --enable-libvorbis   --enable-libvpx   --enable-libx264   --enable-libx265   --enable-nonfree  --enable-libfreetype
make
make install 
hash -r

Verify Installation

ffmpeg -h

Use FFmpeg

Identify video information

Identify and output video information through ffprobe command

ffprobe -v error -show_streams -print_format json <input>  

To facilitate program parsing, output video information in json format, such as the following:

{
    "streams": [
        {
            "index": 0,
            "codec_name": "h264",
            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
            "profile": "High",
            "codec_type": "video",
            "codec_time_base": "61127/3668400",
            "codec_tag_string": "avc1",
            "codec_tag": "0x31637661",
            "width": 1920,
            "height": 1080,
            "coded_width": 1920,
            "coded_height": 1080,
            "has_b_frames": 0,
            "sample_aspect_ratio": "0:1",
            "display_aspect_ratio": "0:1",
            "pix_fmt": "yuv420p",
            "level": 40,
            "color_range": "tv",
            "color_space": "bt709",
            "color_transfer": "bt709",
            "color_primaries": "bt709",
            "chroma_location": "left",
            "refs": 1,
            "is_avc": "true",
            "nal_length_size": "4",
            "r_frame_rate": "30/1",
            "avg_frame_rate": "1834200/61127",
            "time_base": "1/600",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 61127,
            "duration": "101.878333",
            "bit_rate": "16279946",
            "bits_per_raw_sample": "8",
            "nb_frames": "3057",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "rotate": "90",
                "creation_time": "2018-08-09T09:13:33.000000Z",
                "language": "und",
                "handler_name": "Core Media Data Handler",
                "encoder": "H.264"
            },
            "side_data_list": [
                {
                    "side_data_type": "Display Matrix",
                    "displaymatrix": "\n00000000:            0       65536           0\n00000001:       -65536           0           0\n00000002:     70778880           0  1073741824\n",
                    "rotation": -90
                }
            ]
        },
        {
            "index": 1,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "LC",
            "codec_type": "audio",
            "codec_time_base": "1/44100",
            "codec_tag_string": "mp4a",
            "codec_tag": "0x6134706d",
            "sample_fmt": "fltp",
            "sample_rate": "44100",
            "channels": 1,
            "channel_layout": "mono",
            "bits_per_sample": 0,
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/44100",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 4492835,
            "duration": "101.878345",
            "bit_rate": "91595",
            "max_bit_rate": "96000",
            "nb_frames": "4390",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2018-08-09T09:13:33.000000Z",
                "language": "und",
                "handler_name": "Core Media Data Handler"
            }
        },
        {
            "index": 2,
            "codec_type": "data",
            "codec_tag_string": "mebx",
            "codec_tag": "0x7862656d",
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/600",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 61127,
            "duration": "101.878333",
            "bit_rate": "119",
            "nb_frames": "17",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2018-08-09T09:13:33.000000Z",
                "language": "und",
                "handler_name": "Core Media Data Handler"
            }
        },
        {
            "index": 3,
            "codec_type": "data",
            "codec_tag_string": "mebx",
            "codec_tag": "0x7862656d",
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/600",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 61127,
            "duration": "101.878333",
            "nb_frames": "1",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2018-08-09T09:13:33.000000Z",
                "language": "und",
                "handler_name": "Core Media Data Handler"
            }
        }
    ]
}

You can see that a total of four streams have been returned, of which the 0th is a video stream, the 1st is an audio stream, the 2nd and 3S are additional data, which is not useful
If you want to specify an analysis video or audio stream, you can add the parameter -show_streams -v or -show_streams-a, which will output only the analysis results of the video/audio stream

Transcoding

ffmpeg -i <input> -c:v libx264 -b:v 2048k -vf scale=1280:-1 -y <output>

The above command transcodes the input video to h264 encoded video

  • -c:v: Specify the encoder, the list of encoders can be viewed using ffmpeg-codecs
  • -vf scale: Specifies the width and height of the output video, with a height of -1 representing proportional auto-fit
  • -b:v: Specifies the bit rate of the output video, that is, the number of bits per second of the output video
  • Other parameters supported by libx264 can be queried using the ffmpeg-h encoder=libx264 command, such as transcoding to other codes, or similar commands to query available parameters

Transcoding using the Nvidia graphics card GPU

It's a big hit. There's not much information on this, and I've worked hard to get it done.

CUDA

CUDA is a GPU computing library developed by Nvidia that allows programmers to drive the GPU of Nvidia graphics cards for various tasks, including video codec

Install CUDA

First verify that the graphics card driver is installed

nvidia-smi

If the driver is working properly, this command outputs information about the model, driver version, existing/GPU usage of the graphics card.How to install a graphics card driver is not described in this article, please refer to other information.

Download the distribution packages for the corresponding platforms on the CUDA website at https://developer.nvidia.com/cuda-downloads, where I choose

wget http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda-repo-rhel7-10-2-local-10.2.89-440.33.01-1.0-1.x86_64.rpm
sudo rpm -i cuda-repo-rhel7-10-2-local-10.2.89-440.33.01-1.0-1.x86_64.rpm
sudo yum clean all
sudo yum -y install nvidia-driver-latest-dkms cuda
sudo yum -y install cuda-drivers

There are probably more than 90 dependent libraries to install. Note the post-installation report. When I first installed a library, I didn't know why it failed, and Yum installed the library only once to succeed

Verify Installation

/usr/local/cuda-9.2/bin/nvcc -V

If the installation is successful, similar text will be output:

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2018 NVIDIA Corporation
Built on Tue_Jun_12_23:07:04_CDT_2018
Cuda compilation tools, release 9.2, V9.2.148

Recompile ffmpeg

To enable ffmpeg to use the GPU codec provided by CUDA, ffmpeg must be recompiled to enable it to invoke CUDA through dynamic links

First compile and install the nv-codec-headers Library

git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
make PREFIX="/home/local/ffmpeg_build" BINDDIR="/home/local/bin"
make install PREFIX="/home/local/ffmpeg_build" BINDDIR="/home/local/bin" 

Enter the / home/local/ffmepg_sources/ffmpeg-3.3.8/directory to re-execute ffmpeg compilation and installation
Note the difference between the configure command parameter and the previous configure command parameter

PATH="/home/local/ffmpeg_sources/bin:$PATH" PKG_CONFIG_PATH="/home/local/ffmpeg_sources/ffmpeg_build/lib/pkgconfig" ./configure   --prefix="/home/local/ffmpeg_sources/ffmpeg_build" --pkg-config-flags="--static"   --extra-cflags="-I /home/local/ffmpeg_sources/ffmpeg_build/include -I/usr/local/cuda/include"   --extra-ldflags="-L /home/local/ffmpeg_sources/ffmpeg_build/lib  -L/usr/local/cuda/lib64"   --extra-libs=-lpthread   --extra-libs=-lm   --bindir="$HOME/bin"   --enable-gpl   --enable-libfdk_aac   --enable-libfreetype   --enable-libmp3lame   --enable-libopus   --enable-libvorbis   --enable-libvpx   --enable-libx264   --enable-libx265   --enable-nonfree  --enable-libfreetype --enable-cuda --enable-cuvid  --enable-nvenc --enable-libnpp

Verify Installation

After reinstalling ffmpeg, use the ffmpeg-hwaccels command to see the supported hardware acceleration options

Hardware acceleration methods:
cuvid

You can see one more hardware acceleration option called cuvid, which is the GPU video codec acceleration option provided by CUDA

Then look at the GPU codec ffmpeg-codecs | grep cuvid provided by cuvid

 DEV.LS h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_cuvid ) (encoders: libx264 libx264rgb h264_nvenc nvenc nvenc_h264 )
 DEV.L. hevc                 H.265 / HEVC (High Efficiency Video Coding) (decoders: hevc hevc_cuvid ) (encoders: libx265 nvenc_hevc hevc_nvenc )
 DEVIL. mjpeg                Motion JPEG (decoders: mjpeg mjpeg_cuvid )
 DEV.L. mpeg1video           MPEG-1 video (decoders: mpeg1video mpeg1_cuvid )
 DEV.L. mpeg2video           MPEG-2 video (decoders: mpeg2video mpegvideo mpeg2_cuvid )
 DEV.L. mpeg4                MPEG-4 part 2 (decoders: mpeg4 mpeg4_cuvid )
 D.V.L. vc1                  SMPTE VC-1 (decoders: vc1 vc1_cuvid )
 DEV.L. vp8                  On2 VP8 (decoders: vp8 libvpx vp8_cuvid ) (encoders: libvpx )
 DEV.L. vp9                  Google VP9 (decoders: vp9 libvpx-vp9 vp9_cuvid ) (encoders: libvpx-vp9 )

All with "cuvid" or "nvenc" are GPU codecs provided by CUDA
As you can see, we can now do GPU decoding in h264/hevc/mjpeg/mpeg1/mpeg2/mpeg4/vc1/vp8/vp9 format and GPU encoding in h264/hevc format

Video transcoding using GPU

The command to transcode with GPU is different from the soft transcode command. When the CPU transcodes, we can rely on ffmpeg to identify the encoding format of the input video and select the corresponding decoder, but ffmpeg will only select the CPU decoder automatically. In order for ffmpeg to use the GPU decoder, the encoding format of the input video must be identified with ffprobe first, and then the corresponding GPU decoder can be specified on the command line..

For example, the source video encoded by h264 is converted to a h264 encoded video of a specified size and bit rate:

ffmpeg -hwaccel cuvid -c:v h264_cuvid -i <input> -c:v h264_nvenc -b:v 2048k -vf scale_npp=1280:-1 -y <output>
  • -hwaccel cuvid: Specify using cuvid hardware acceleration
  • -c:v h264_cuvid: use h264_cuvid for video decoding
  • -c:v h264_nvenc: use h264_nvenc for video encoding
  • -vf scale_npp=1280:-1: Specify the width and height of the output video, note that this is not the same as -vf scale=x:x used in soft decoding

During transcoding, use nvidia-smi to check the status of the graphics card, and you can see that ffmpeg is actually transcoding using GPU:

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0     62543      C   ffmpeg                                       193MiB |
+-----------------------------------------------------------------------------+

GPU Transcoding Efficiency Test

On servers equipped with two Intel-E5-2630v3 CPU s and two Nvidia Tesla M4 graphics cards, h264 video transcoding test was performed with the following results:

  • Average GPU transcoding time: 8s
  • Average CPU transcoding time: 25s

When parallel transcoding, the efficiency of CPU soft transferring is improved. When three transcoding tasks are parallel, 32 cores are full. At this time, the performance is improved.

  • Average GPU transcoding time: 8s
  • Average CPU transcoding time: 18s

It is not difficult to see that the GPU transcoding speed does not increase in parallel, so a GPU can only perform one transcoding task at the same time.So, if there are multiple graphics cards plugged into the server, will ffmpeg use multiple GPUs for parallel transcoding?

Unfortunately, the answer is No.

ffmpeg does not have the ability to automatically assign transcoding tasks to different GPUs, but after some investigation, it is found that the GPU used for transcoding tasks can be specified through the -hwaccel_device parameter!

Submit Transcoding Tasks to Different GPU s

ffmpeg -hwaccel cuvid -hwaccel_device 0 -c:v h264_cuvid -i <input> -c:v h264_nvenc -b:v 2048k -vf scale_npp=1280:-1 -y <output>
ffmpeg -hwaccel cuvid -hwaccel_device 1 -c:v h264_cuvid -i <input> -c:v h264_nvenc -b:v 2048k -vf scale_npp=1280:-1 -y <output>
  • -hwaccel_device N: Specifies a GPU to perform transcoding tasks, N is a number

At this point nvidia-smi shows:

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0     96931      C   ffmpeg                                       193MiB |
|    1     96930      C   ffmpeg                                       193MiB |
+-----------------------------------------------------------------------------+

Parallel GPU transcoding is possible!

Then when the server resources are full, the efficiency of GPU and CPU transcoding is as follows:

  • Average GPU transcoding time: 4s
  • Average CPU transcoding time: 18s

GPU efficiency is 4.5 times that of CPU

Pit drainage

1. Error:. /autogen.sh: 4:. /autogen.sh: autoreconf: not found

Solution: yum-y install Autoconf automake libtool  
Then execute

Error: ERROR: freetype2 not found using pkg-config

yum install -y bzip2
wget http://download.savannah.gnu.org/releases/freetype/freetype-2.10.0.tar.bz2
tar -jxvf freetype-2.10.0.tar.bz2
cd freetype-2.10.0
./configure --prefix= /home/local/ffmpeg_sources/ffmpeg_build
make 
make install 

3. Error: configure: error: C compiler cannot create executables See `config.log'for more details make: *** [setup] Error 77

Solution: Uninstall old c++ GCC gcc++ first

Then reinstall

4. Error: make: *** [libavcodec/libfdk-aacenc.o] Error 1

4.1 with BUG Official Download Address

(This step can also use git clone to download the source package, which is essentially the same)

Then recompile it.

Reference link: https://www.jianshu.com/p/59da3d350488

Keywords: Big Data git codec yum curl

Added by volatileboy on Thu, 19 Dec 2019 22:50:25 +0200