Saturday 29 September 2018

Fedora 28: fixing mpv and libOpenCl.so.1: no version info and hardware acceleration

One of the great benefits of Linux is that it can run on a whole host of legacy components and still perform well. Re-purposing an old Dell E520 with a 32bit Intel Core2 Duo cpu, a PCI via vt6321a based IDE raid card, for Fedora 28 install was straight forward until we started to look at hardware accelerated mpv for watching movies files: libOpenCL.so.1: no version information available (required by /lib/libavfilter.so...


This legacy Dell came with a VGA or composite out video card which was no good since none of the monitors available to me supported these connections; a Nvidia GT218/Geforce 310 card (which has DVI and HDMI out) was added to solve the monitor problem with Fedora support coming from the vendor binary only driver. Nvidia's binary drivers have a legacy stream which supports these older cards and for this GT218 card requires the 340.x series of drivers.

Using the card with Fedora28 and pulling down ffmpeg and mpv we observe that neither of those utils work, complaining about libOpenCL.so.1: no version information available (required by /lib/libavfilter.so.... In simplistic terms, it means that ffmpeg (that's where libavfilter belongs) was build and linked against a different version of libOpenCL than the version on this machine, even though the version (at least the DT_SONAME) is a match.

How can this be and how to solve? The Nvidia driver supplies its own libOpenCL.so.1 library - and this is the problem; the vendor binary, whilst updated (the most recent one being updated in June 2018) is not up to date with the newer cards and NOT up to date with the version of libOpenCL.so.1 that ffmpeg is expecting.

The only way to solve this is to rebuild ffmpeg on your local machine after which mpv will work as expected. The only tricky item is to ensure that you find all the dependencies to ensure hardware acceleration (at least for decode) is available at build time.

The base dependencies for the build are:
$ dnf install -y \
gnutls-devel \
gcc gcc-c++ nasm \
libvdpau-devel libva libva-utils libva-vdpau-driver libvdpau-va-gl \
lame-devel pulseaudio-libs-devel fdk-aac-devel

Once set up we need the nvidia CUDA dependencies and in particular the CUDA Toolkit 6.5 i686 which needs a minor hack to get it to install into /usr/local/cuda
$ ./cuda_6.5.14_linux_32.run --tar mxvf && \
mv run_files/InstallUtils.pm /usr/lib/perl5/vendor_perl/ && \
./run_files/cuda-linux-rel-6.5.14-18745345.run
We can ignore the bundled binary driver that comes with this package as its older than the one we have already installed.

With these dependancies in place, we are ready to build

$ git clone https://git.ffmpeg.org/ffmpeg.git && cd ffmpeg && \
PATH=/usr/local/cuda/bin/:$PATH \
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig \
./configure --prefix=/usr --disable-debug --disable-static --enable-shared \
--enable-gnutls \
--enable-nonfree --enable-libmp3lame --enable-libfdk-aac --enable-libpulse \
--enable-cuda --enable-vdpau
--extra-cflags=-I/usr/local/cuda/include \
--extra-ldflags="-L/usr/local/cuda/lib -Wl,-rpath=/usr/local/cuda/lib"
Check that there are _vdpau options listed under the hardware acceleration as these will be the versions we will be using with mpv:
Enabled hwaccels:
h264_nvdec mjpeg_nvdec mpeg2_vdpau vc1_nvdec vp9_nvdec
h264_vdpau mpeg1_nvdec mpeg4_nvdec vc1_vdpau wmv3_nvdec
hevc_nvdec mpeg1_vdpau mpeg4_vdpau vp8_nvdec wmv3_vdpau
hevc_vdpau mpeg2_nvdec
Once this is good, we can make -j4 (or whatever number of cores your old machine has) and then wait and when fully compiled make install

If all goes well, when you run mpv or ffmpeg again they will work as we are linked/running with the legacy version of libOpenCL.so that came with our legacy Nvidia binary driver.
$ ffmpeg -hwaccels
ffmpeg version N-92078-g179ed2d2e0 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 8 (GCC)
configuration: --prefix=/usr --disable-debug --disable-static --enable-shared --enable-nonfree --enable-libmp3lame --enable-libfdk-aac --enable-libpulse --enable-cuda --extra-cflags=-I/usr/local/cuda/include --extra-ldflags='-L/usr/local/cuda/lib -Wl,-rpath=/usr/local/cuda/lib' --enable-vdpau --enable-gnutls
libavutil 56. 19.101 / 56. 19.101
libavcodec 58. 31.101 / 58. 31.101
libavformat 58. 18.103 / 58. 18.103
libavdevice 58. 4.104 / 58. 4.104
libavfilter 7. 33.100 / 7. 33.100
libswscale 5. 2.100 / 5. 2.100
libswresample 3. 2.100 / 3. 2.100
Hardware acceleration methods:

vdpau
cuda
cuvid


Finally, we want to make mpv play our files with hardware acceleration.

$ mpv -hwdec=cuda /export/public/foo.mp4
Playing: /export/public/foo.mp4
(+) Video --vid=1 (*) (h264 1920x1080 23.976fps)
(+) Audio --aid=1 --alang=eng (*) (aac 2ch 48000Hz)
[ffmpeg/video] h264_cuvid: Cannot load cuvidGetDecodeStatus
[ffmpeg/video] h264_cuvid: Failed loading nvcuvid.
Could not open codec.
VO: [gpu] 1920x1080 yuv420p
AO: [pulse] 48000Hz stereo 2ch float
Hmm. It plays but this can't be good - and if we look at top, yes, all the decoding is happening on the CPU. What about cuvid
$ mpv -hwdec=cuvid /export/public/foo.mp4
Playing: /export/public/foo.mp4
(+) Video --vid=1 (*) (h264 1920x1080 23.976fps)
(+) Audio --aid=1 --alang=eng (*) (aac 2ch 48000Hz)
VO: [gpu] 1920x1080 yuv420p
AO: [pulse] 48000Hz stereo 2ch float
AV: 00:00:17 / 00:01:44 (17%) A-V: 0.000 Dropped: 21
Ok, better but its still decoding on the CPU. Now this could just be me being dumb but I could not figure out why the explicit CUDA or CUVID decoders were leading to trouble. Using vdpau however does what we expect:
$ mpv -hwdec=vdpau /export/public/foo.mp4
Playing: /export/public/foo.mp4
(+) Video --vid=1 (*) (h264 1920x1080 23.976fps)
(+) Audio --aid=1 --alang=eng (*) (aac 2ch 48000Hz)
Using hardware decoding (vdpau).
AO: [pulse] 48000Hz stereo 2ch float
VO: [gpu] 1920x1080 vdpau[yuv420p]
AV: 00:00:00 / 00:01:44 (0%) A-V: 0.000 Dropped: 1
To make vdpau the default echo hwdec=vdpau >> /etc/mpv/mpv.conf



For further info, We can check what the vdpau layer is able to provide to us:
$ vdpauinfo
display: :1 screen: 0
API version: 1
Information string: NVIDIA VDPAU Driver Shared Library 340.107 Thu May 24 21:52:13 PDT 2018

Video surface:

name width height types
-------------------------------------------
420 4096 4096 NV12 YV12
422 4096 4096 UYVY YUYV

Decoder capabilities:

name level macbs width height
----------------------------------------------------
MPEG1 0 8192 2048 2048
MPEG2_SIMPLE 3 8192 2048 2048
MPEG2_MAIN 3 8192 2048 2048
H264_BASELINE --- not supported ---
H264_MAIN 41 8192 2048 2048
H264_HIGH 41 8192 2048 2048
VC1_SIMPLE 1 8190 2048 2048
VC1_MAIN 2 8190 2048 2048
VC1_ADVANCED 4 8190 2048 2048
MPEG4_PART2_SP 3 8192 2048 2048
MPEG4_PART2_ASP 5 8192 2048 2048
DIVX4_QMOBILE 0 8192 2048 2048
DIVX4_MOBILE 0 8192 2048 2048
DIVX4_HOME_THEATER 0 8192 2048 2048
DIVX4_HD_1080P 0 8192 2048 2048
DIVX5_QMOBILE 0 8192 2048 2048
DIVX5_MOBILE 0 8192 2048 2048
DIVX5_HOME_THEATER 0 8192 2048 2048
DIVX5_HD_1080P 0 8192 2048 2048
H264_CONSTRAINED_BASELINE --- not supported ---
H264_EXTENDED --- not supported ---
H264_PROGRESSIVE_HIGH --- not supported ---
H264_CONSTRAINED_HIGH --- not supported ---
H264_HIGH_444_PREDICTIVE --- not supported ---
HEVC_MAIN --- not supported ---
HEVC_MAIN_10 --- not supported ---
HEVC_MAIN_STILL --- not supported ---
HEVC_MAIN_12 --- not supported ---
HEVC_MAIN_444 --- not supported ---

Output surface:

name width height nat types
----------------------------------------------------
B8G8R8A8 8192 8192 y Y8U8V8A8 V8U8Y8A8 A4I4 I4A4 A8I8 I8A8
R10G10B10A2 8192 8192 y Y8U8V8A8 V8U8Y8A8 A4I4 I4A4 A8I8 I8A8

Bitmap surface:

name width height
------------------------------
B8G8R8A8 8192 8192
R8G8B8A8 8192 8192
R10G10B10A2 8192 8192
B10G10R10A2 8192 8192
A8 8192 8192

Video mixer:

feature name sup
------------------------------------
DEINTERLACE_TEMPORAL y
DEINTERLACE_TEMPORAL_SPATIAL y
INVERSE_TELECINE y
NOISE_REDUCTION y
SHARPNESS y
LUMA_KEY y
HIGH QUALITY SCALING - L1 y
HIGH QUALITY SCALING - L2 -
HIGH QUALITY SCALING - L3 -
HIGH QUALITY SCALING - L4 -
HIGH QUALITY SCALING - L5 -
HIGH QUALITY SCALING - L6 -
HIGH QUALITY SCALING - L7 -
HIGH QUALITY SCALING - L8 -
HIGH QUALITY SCALING - L9 -

parameter name sup min max
-----------------------------------------------------
VIDEO_SURFACE_WIDTH y 1 4096
VIDEO_SURFACE_HEIGHT y 1 4096
CHROMA_TYPE y
LAYERS y 0 4

attribute name sup min max
-----------------------------------------------------
BACKGROUND_COLOR y
CSC_MATRIX y
NOISE_REDUCTION_LEVEL y 0.00 1.00
SHARPNESS_LEVEL y -1.00 1.00
LUMA_KEY_MIN_LUMA y
LUMA_KEY_MAX_LUMA y

Finally, to prevent the system updater (dnf) from overwriting the work above we need to update dnf's global config file /etc/dnf/dnf.conf by adding the line excludepkgs=ffmpeg*.

Whilst this may seem a little painful, it is worthwhile to be able to use your legacy NVidia cards on a modern Fedora 28 installation with no further mpv: libOpenCl.so.1: no version information available... errors.

No comments:

Post a Comment