VLC核顯編解碼簡介 + Linux平臺vlc編譯

概要:

vlc編譯, 硬解基於libva庫(VAAPI), live555(liblivemedia-dev), --enable-live555才能播放rtsp流, 基於liveMedia庫, vlc對ffmpeg是運行時依賴,把libavcodec_plugin.so刪了就可以。

ps:

重點章節:
“二、VLC編譯與安裝” :
“1.依賴相關”
“2.VLC編譯”
“4.vainfo”

該章節是我親自編譯的記錄,基於Ubuntu 16.04。
另外,本來想用intel核顯解碼,但可惜libva庫的VAAPI驅動一直未調通。

一、VLC中GPU解碼簡介

參考:(https://wiki.videolan.org/VLC_VAAPI/)

1.VLC基於libva庫(VAAPI):

一個開源庫和API規範,可以訪問圖形硬件加速功能以進行視頻處理。它由一個主庫和每個支持的硬件供應商的特定於驅動程序的加速後端組成。
另請參閱:VLC GPU解碼:https://wiki.videolan.org/VLC_GPU_Decoding/
在某些情況下,VLC框架可以使用您的圖形卡(也稱爲GPU)來解碼H.264流(錯誤地稱爲HD視頻)。
VLC在其模塊化方法及其轉碼/流媒體功能中,僅在解碼階段在GPU中進行解碼,然後將數據恢復到其他階段(流式傳輸,過濾或插入任何視頻輸出)。
這意味着,與其他一些實現相比,VLC中的GPU解碼速度較慢,因爲它需要從GPU獲取數據。 但您可以將任何視頻輸出(接收器)插入其中並使用所有VLC視頻過濾器。

2.VAAPI的介紹

此頁面是關於在Linux上支持GPU加速的VLC編譯。
這個howto由Jean-Baptiste Kempf編寫並使用nVidia GPU進行測試。
vaapi:https://www.freedesktop.org/wiki/Software/vaapi/
在Linux / X11上,有兩個用於硬件視頻解碼的競爭接口:
來自Intel的VA-API,和來自NVIDIA的VDPAU。
通常,VAAPI用於Intel和Broadcom圖形卡,而VDPAU用於AMD / ATI和NVIDIA卡。

VA-API:

在Ubuntu發行版上,首先安裝硬件支持包:i965-va-driver,libva-intel-vaapi-driver和vainfo,然後在Preferences→Input&Codecs中激活GPU硬件加速。

  • $ sudo apt-get install i965-va-driver libva-intel-vaapi-driver vainfo
VDPAU:

自VLC版本2.1.0起,VDPAU支持解碼,自VLC 2.2.0起支持後處理和渲染(截至2013年底仍處於開發階段)。
默認情況下,VLC版本2.2.0以後將自動啓用VDPAU。
有關技術詳細信息,請參閱http://www.remlab.net/op/vlc-vdpau.shtml。

3.在編譯vlc之前保證以下正確安裝

安裝libva(注:We do not support other libraries than the one from Mr Beauchesne.)
https://github.com/intel/libvahttps://www.freedesktop.org/wiki/Software/vaapi/)
nvidia驅動(注:Use at least version 0.6.2 )
ATI(注:Use at least 0.6.4.)

#檢查是否正確配置了libva環境變量:
$ set | grep LIBVA
#應輸出如下內容:
LIBVA_DRIVER_NAME=xvba
LIBVA_DRIVERS_PATH=/usr/lib64/va/drivers
#如果沒有,請根據庫路徑將這些添加到系統環境變量(/etc/environment ?)

VLC基於FFmpeg插件。
FFmpeg: https://github.com/FFmpeg/FFmpeg

./configure --enable-gpl --enable-postproc --prefix=/path/to/ --enable-shared --enable-vaapi
make -j12
make install
#將vaapi.h複製到includes

二、VLC編譯與安裝

1.依賴相關

sudo apt install libva-dev
sudo apt -y install libvdpau-dev
sudo apt -y install vdpau-va-driver
sudo apt -y install vdpauinfo
sudo apt -y install libavcodec-dev
sudo apt -y install libvdpau-va-gl1
sudo apt install libdrm-dev
sudo apt-get install autoconf automake libtool //運行autogen.sh用
sudo apt-get install libffi-dev
sudo apt-get install libx11-dev libxext-dev libxfixes-dev
sudo apt install libxcb-dev //提供X window protocol access
sudo apt install libpciaccess-dev //提供PCI access

以下是我在實際編譯的時候仍然缺少的,和異常的依賴項:

sudo apt install -y libmad-ocaml-dev
sudo apt install -y libgstreamer-ocaml-dev
sudo apt install -y liba52-0.7.4
sudo apt install -y liba52-0.7.4-dev
sudo apt install -y libxcb-composite0-dev
sudo apt install -y libxcb-xv0-dev
sudo apt install -y libxcb-randr0-dev
sudo apt install -y libxcb-keysyms1-dev
sudo apt install -y wayland-protocols
sudo apt install -y libalsa-ocaml-dev
sudo apt install -y libxcb-xkb-dev
sudo apt install -y libsidplay2-dev
sudo apt install -y libogg-dev
sudo apt install -y libdca-dev
sudo apt install -y libflac-dev
sudo apt install -y libmpeg2-4-dev
sudo apt install -y libvorbis-dev
sudo apt install -y libspeex-dev
sudo apt install -y libtheora-dev
sudo apt install -y libfreetype6-dev
sudo apt install -y libcaca-dev
sudo apt install -y libncursesw5-dev
sudo apt install libbluray-dev
sudo apt install -y libssh2-1-dev
sudo apt install -y libvncserver-dev
sudo apt install -y libfreerdp-dev
sudo apt install libdvbpsi-dev
sudo apt install -y libpulse-dev
sudo apt install -y libcddb2-dev
sudo apt install -y libdbus-1-dev
sudo apt install -y libsystemd-dev
sudo apt install -y libsmbclient-dev

# 版本太高,configure: error: libavutil versions 55 and later are not supported.
#sudo apt purge libavutil-dev
#sudo apt purge libavutil-ffmpeg54

# 依賴問題:configure: error: Could not find the LUA byte compiler.
# 可以在編譯時使用--disable-lua。或者安裝lua,如下:
sudo apt install liblua5.2-dev
sudo apt install liblua50-dev
sudo apt install liblualib50-dev

# 編譯問題:yacc: command not found
sudo apt install byacc

# ERROR: flex is not installed.
sudo apt install flex

# ERROR: GNU bison is not installed.
sudo apt install bison

# configure: error: No package 'Qt5Core' found
# No package 'Qt5Widgets' found
# No package 'Qt5Gui' found
# No package 'Qt5Quick' found
# No package 'Qt5QuickWidgets' found
# No package 'Qt5QuickControls2' found
# No package 'Qt5Svg' found. If you want to build VLC without GUI, pass --disable-qt.
# 對上述問題,我使用的是:$ ./configure --disable-qt
# 也可以參考下面一句,自行安裝:(我好像這樣試過,然而不行)
sudo apt install -y qt5-default qtcreator libqt5svg5-dev

# configure: error: Skins2 interface requires FreeType, libxpm, libxext and libxinerama
sudo apt install -y libfreetype6 libfreetype6-dev libxpm-dev libxext-dev libxinerama-dev

# Makefile:1806: recipe for target 'lua/intf/modules/httprequests.luac' failed
# make[2]: *** [lua/intf/modules/httprequests.luac] Error 1
#   LUAC   lua/intf/telnet.luac
sudo apt install -y liblua5.1-0-dev liblua5.1-bitop-dev liblua5.1-rrd-dev liblua5.2-dev liblua5.3-dev
sudo apt install -y lua5.1-policy-dev
sudo apt install -y libghc-hslua-dev libluabind-dev libluajit-5.1-dev libtexlua52-dev libtexluajit-dev
sudo apt install -y libtolua++5.1-dev libtolua-dev lua-ansicolors-dev lua-apr-dev lua-bit32-dev lua-cjson-dev
sudo apt install -y lua-cliargs-dev lua-curl-dev lua-curses-dev lua-cyrussasl-dev lua-dbi-mysql-dev
sudo apt install -y lua-dbi-postgresql-dev lua-dbi-sqlite3-dev lua-discount-dev lua-dkjson-dev
sudo apt install -y lua-event-dev lua-expat-dev lua-filesystem-dev lua-iconv-dev lua-ldap-dev lua-leg-dev
sudo apt install -y lua-lemock-dev lua-lgi-dev lua-lpeg-dev lua-lpty-dev lua-luassert-dev lua-md5-dev
sudo apt install -y lua-mediator-dev lua-messagepack-dev lua-penlight-dev lua-posix-dev lua-redis-dev
sudo apt install -y lua-rex-gnu-dev lua-rex-onig-dev lua-rex-pcre-dev lua-rex-posix-dev lua-rex-tre-dev
sudo apt install -y lua-rings-dev lua-rrd-dev lua-say-dev lua-sec-dev lua-socket-dev lua-sql-mysql-dev
sudo apt install -y lua-sql-postgres-dev lua-sql-sqlite3-dev lua-svn-dev lua-term-dev lua-uri-dev
sudo apt install -y lua-wsapi-fcgi-dev lua-yaml-dev lua-zip-dev lua-zlib-dev

需要–enable-live555才能播放rtsp流,基於liveMedia庫。
注意:不要用apt直接安裝live555(liblivemedia-dev),我剛開始就這樣操作,導致vlc打開rtsp時出現段錯誤。
手動下載live555編譯安裝後,手動建立文件(索引包):/usr/lib/x86_64-linux-gnu/pkgconfig/live555.pc

sudo vim /usr/lib/x86_64-linux-gnu/pkgconfig/live555.pc

寫入如下內容:(注:路徑根據自己的系統,自行修改)

prefix=/usr/local
libdir=/usr/local/lib #庫路徑目錄,注:源碼編譯出來的庫是.la庫。
includedir=${prefix}/include #安裝的頭文件的目錄
Name: live555
Description: multimedia RTSP streaming library
Version: 2016.02.09
Cflags: -I${includedir}/liveMedia -I${includedir}/groupsock -I${includedir}/BasicUsageEnvironment -I${includedir}/UsageEnvironment
Libs: -L${libdir} -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment

2.VLC編譯

源碼編譯:

或者直接下載現成的軟件應用:

依賴項(有點多。。。)
注:除了前面的“1.依賴相關”裏安裝的依賴項之外,這裏我也同樣操作過下面的命令,安裝了以下依賴項:
sudo apt-get install libvorbis-dev libogg-dev libtheora-dev speex libspeex-dev flac libflac-dev x264 libx264-dev a52-0.7.4 liba52-0.7.4-dev mpeg2dec libmpeg2-4-dev faad libfaad-dev faac libfaac-dev lame libmp3lame-dev libavdevice-dev libmad0 libmad0-dev libschroedinger-dev libebml-dev libdca-dev twolame libtwolame-dev libmpcdec-dev libvorbisidec1 libvorbisidec-dev libass-dev libmatroska-dev libdvbpsi-dev libmodplug1 libmodplug-dev libshout3 libshout3-dev libdvdread4 libdvdnav4 libdvdnav-dev livemedia-utils liblivemedia-dev libcddb2 libcddb2-dev libcdio13 libcdio-dev libxcb-composite0-dev libcdio-utils vcdimager libvcdinfo0 libvcdinfo-dev libgpg-error0 libgpg-error-dev libgcrypt11-dev gnutls-bin libgnutls-dev libdap-bin libdap-dev libxml2 libxml2-dev libpng12-0 libpng12-dev libjpeg8 libtiff5 libsdl1.2-dev libsdl-image1.2 libsdl-image1.2-dev libc-bin gettext libfreetype6 libfreetype6-dev libfribidi-dev libfribidi0 zlib1g zlib1g-dev libtag1-dev libcaca0 libcaca-dev caca-utils libqt4-dev libportaudio2 libupnp-dev libupnp6 libexpat1 libexpat1-dev yasm libxcb-xv0 libxcb-xv0-dev libx11-xcb1 libx11-xcb-dev liblua5.2-dev libswscale-dev

編譯:
# 源碼clone
git clone https://github.com/videolan/vlc.git

# 查看版本信息
git log

# 根據需要,可以更新到指定release版本:
#例vlc-4.0.0: 
#git checkout 1f2e534f3033aab9dd31442f7b3956728b62b3d3
#例vlc-3.0.0: 
#git checkout 8d432b090e08f141ce9156dc728afbed4636301b

# 開始編譯(注:備註:要支持播放rtsp流,必須enable live。要能打印debug,也要enable debug選項。)
./bootstrap
mkdir build; cd build
#../configure --disable-lua --disable-qt --enable-live555 --enable-debug  --enable-x264
../configure --enable-avcodec --enable-avformat --enable-swscale --enable-mad --enable-a52 --enable-libmpeg2 --enable-faad --enable-vorbis --enable-ogg --enable-theora --enable-freetype --enable-fribidi --enable-speex --enable-flac --enable-live555 --enable-caca --enable-alsa --enable-ncurses --enable-debug --enable-x264 --disable-lua --disable-qt --enable-dsm --enable-dvbpsi --enable-dvdnav --enable-dvdread --enable-bluray --enable-nfs --enable-pulse --enable-freerdp --enable-sftp --enable-vnc --enable-run-as-root --enable-archive --enable-dc1394 --enable-dv1394 --enable-smbclient
sudo make -j12 #或者 ./compile
sudo make install
啓動VLC:
#直接在命令行上:
vlc --ffmpeg-hw #hw:硬解  sw:軟解
#其實可以直接啓動:
vlc
#Exemple: on playback log output (with -v debug and ATI VAAPI)
[0x7f8c4cc03ba8] avcodec decoder: Using VA API version 0.32 for hardware decoding.

以下“3.”“4.”“5.”節,與VLC硬解相關

3.libva-2.1.1編譯安裝

#依賴
$ sudo apt install -y libc6 libdrm-intel1 libdrm2 libva-x11-1 libva1 multiarch-support
#源碼
$ git clone https://github.com/intel/libva.git
$ cd libva
#編譯
$ sudo ./autogen.sh -with-drivers-path=/usr/lib/x86_64-linux-gnu/dri
$ sudo make -j12
$ sudo make install

4.vainfo

vainfo工具用於查看libva庫調用信息。

$ sudo apt install vainfo
$ vainfo
# 將會輸出一些調用信息
libva info: VA-API version 0.39.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'i965'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so
libva info: va_openDriver() returns -1
vaInitialize failed with error code -1 (unknown libva error),exit

vainfo支持調用nvidia顯卡,但需要先安裝nvidia_video驅動:

$ sudo apt install vdpau-va-driver
#查看庫文件
$ ll /usr/lib/x86_64-linux-gnu/dri/
#將查看到有個nvidia_drv_video.so文件
lrwxrwxrwx   1 root root       18 4月   7  2016 nvidia_drv_video.so -> vdpau_drv_video.so
#此時使用vainfo查看調用情況
$ vainfo
libva info: VA-API version 0.39.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'nvidia'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/nvidia_drv_video.so
libva info: Found init function __vaDriverInit_0_39
libva info: va_openDriver() returns 0
vainfo: VA-API version: 0.39 (libva 1.7.0)
vainfo: Driver version: Splitted-Desktop Systems VDPAU backend for VA-API - 0.7.4
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            :	VAEntrypointVLD
      VAProfileMPEG2Main              :	VAEntrypointVLD
      VAProfileMPEG4Simple            :	VAEntrypointVLD
      VAProfileMPEG4AdvancedSimple    :	VAEntrypointVLD
      VAProfileH264Baseline           :	VAEntrypointVLD
      VAProfileH264Main               :	VAEntrypointVLD
      VAProfileH264High               :	VAEntrypointVLD
      VAProfileVC1Simple              :	VAEntrypointVLD
      VAProfileVC1Main                :	VAEntrypointVLD
      VAProfileVC1Advanced            :	VAEntrypointVLD

vainfo支持調用intel核顯,但需要先安裝i965-va-driver驅動:
但是我的i965-va-driver庫調用一直是下面的問題,無法解決。

#查看是否安裝了驅動
$ apt list i965-va-driver
Listing... Done
i965-va-driver/xenial,now 1.7.0-1 amd64 [installed,automatic]
#如果沒有安裝,則進行安裝
$ sudo apt install -y i965-va-driver

#此時使用vainfo查看調用情況(注:要先將libva調用庫改爲i965,即intel的VAAPI庫。)
$ export LIBVA_DRIVER_NAME=i965
$ vainfo
libva info: VA-API version 0.39.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'i965'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so
libva info: Found init function __vaDriverInit_0_39
vainfo: intel_driver.c:100: intel_driver_init: Assertion `(((struct drm_state *)(ctx)->drm_state)->auth_type == (VA_DRM_AUTH_DRI1)) || (((struct drm_state *)(ctx)->drm_state)->auth_type == (VA_DRM_AUTH_DRI2)) || (((struct drm_state *)(ctx)->drm_state)->auth_type == (VA_DRM_AUTH_CUSTOM))' failed.
Aborted (core dumped)

可能是直接使用apt安裝存在支持問題,於是嘗試自己編譯intel的vaapi驅動:

$ sudo apt-get install libx11-dev libtool libdrm-dev build-essential autoconf libva-dev
$ git clone https://github.com/intel/intel-vaapi-driver.git
$ cd intel-vaapi-driver/
$ ./autogen.sh
#此時存在一些依賴項的版本問題:
#configure: error: Package requirements (libva >= 1.4.0) were not met:
#Requested 'libva >= 1.4.0' but version of libva is 1.3.0
$ git clone https://github.com/intel/libva.git
$ cd libva/
$ ./autogen.sh -with-drivers-path=/usr/lib/x86_64-linux-gnu/dri
$ make -j12
$ sudo make install
#完成後返回intel-vaapi-driver目錄,再次配置並編譯:
$ cd ../intel-vaapi-driver/
$ ./autogen.sh
#我在配置路徑的時候發現配置無用,路徑仍然是默認的/usr/local/lib/dri/
#沒去深究,我繼續編譯安裝,最後手動將/usr/local/lib/dri/i965_drv_video.so庫鏈接到/usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so
#後來發現是libva必須要先修改安裝路徑,然後intel-vaapi-driver的修改才能起作用
$ ./configure --prefix=/usr/lib/x86_64-linux-gnu/dri/
$ make -j12
$ sudo make install
#$ sudo ln -s /usr/local/lib/dri/i965_drv_video.so /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so
#$ sudo ln -s /usr/local/lib/dri/i965_drv_video.la /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.la

此時使用vainfo查看調用情況,這次異常不一樣了,似乎是某函數問題:

$ vainfo
libva info: VA-API version 0.39.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'i965'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so
libva error: /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so has no function __vaDriverInit_0_32
libva info: va_openDriver() returns -1
vaInitialize failed with error code -1 (unknown libva error),exit

我在GitHub上有找到類似的問題,但並不能解決我這出現的情況,後來提了issue:https://github.com/intel/intel-vaapi-driver/issues/455


繼續嘗試,經過仔細考慮懷疑是這些驅動的版本兼容問題,比如我查到的大部分人們的版本爲:libva info: VA-API version 0.34.0,而我的是0.39.0。
經查詢:0.34.0對應的libva版本是1.2.1,所以下載對應版本:https://github.com/intel/libva/archive/libva-1.2.1.tar.gz
解壓後進入目錄,進行編譯安裝:

$ ./autogen.sh -with-drivers-path=/usr/lib/x86_64-linux-gnu/dri
$ make -j12
$ sudo make install
#完成後使用vainfo查看
$ vainfo
libva info: VA-API version 0.34.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'i965'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so
libva error: /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so has no function __vaDriverInit_0_32
libva info: va_openDriver() returns -1
vaInitialize failed with error code -1 (unknown libva error),exit
#可以看到VA-API版本已經爲0.34.0了,接下來重新編譯intel-vaapi-driver
$ cd intel-vaapi-driver
$ ./autogen.sh
#會出現錯誤:
configure: error: Package requirements (libva >= 1.4.0) were not met:
Requested 'libva >= 1.4.0' but version of libva is 0.34.0

我們的intel-vaapi-driver也應該使用舊版本,經檢查應該使用:intel-vaapi-driver_1.2.1版本。下載:https://github.com/intel/intel-vaapi-driver/archive/1.2.1.tar.gz
解壓後進入目錄,進行編譯安裝:

$ cd ../intel-vaapi-driver-1.2.1/
$ ./autogen.sh
$ make -j12

但是編譯出現了錯誤,問題可能出在源碼裏吧,因爲新版本編譯都正常,`
只可惜新版本運行有問題,舊版本又編譯不過。

Traceback (most recent call last):
  File "../../gpp.py", line 200, in <module>
    writeblocks(outfile, blocks)
  File "../../gpp.py", line 168, in writeblocks
    do_writeblock(block, [])
  File "../../gpp.py", line 161, in do_writeblock
    while check_cond(block.param_op, for_curs[0], block.param_limit):
  File "../../gpp.py", line 138, in check_cond
    assert type(cur) == int
AssertionError
make[5]: Leaving directory '/home/toson/soft/intel-vaapi-driver-1.2.0/src/shaders/post_processing/gen5_6'
Makefile:376: recipe for target 'all-recursive' failed
make[4]: *** [all-recursive] Error 1
make[4]: Leaving directory '/home/toson/soft/intel-vaapi-driver-1.2.0/src/shaders/post_processing'
Makefile:377: recipe for target 'all-recursive' failed
make[3]: *** [all-recursive] Error 1
make[3]: Leaving directory '/home/toson/soft/intel-vaapi-driver-1.2.0/src/shaders'
Makefile:941: recipe for target 'all-recursive' failed
make[2]: *** [all-recursive] Error 1
make[2]: Leaving directory '/home/toson/soft/intel-vaapi-driver-1.2.0/src'
Makefile:533: recipe for target 'all' failed
make[1]: *** [all] Error 2
make[1]: Leaving directory '/home/toson/soft/intel-vaapi-driver-1.2.0/src'
Makefile:410: recipe for target 'all-recursive' failed
make: *** [all-recursive] Error 1

5.檢查版本

#查看libva版本
dpkg-query --showformat='${Package}: ${Version}\n' --show | grep libva
#查看vainfo版本
dpkg-query --showformat='${Package}: ${Version}\n' --show | grep vainfo
#查看i965版本
dpkg-query --showformat='${Package}: ${Version}\n' --show | grep i965

例:(我運行的結果)

# List installed libva packages
$ dpkg-query --showformat='${Package}: ${Version}\n' --show | grep libva
libva-dev: 1.7.0-1ubuntu0.1
libva-drm1: 1.7.0-1ubuntu0.1
libva-egl1: 1.7.0-1ubuntu0.1
libva-glx1: 1.7.0-1ubuntu0.1
libva-tpi1: 1.7.0-1ubuntu0.1
libva-wayland1: 1.7.0-1ubuntu0.1
libva-x11-1: 1.7.0-1ubuntu0.1
libva1: 1.7.0-1ubuntu0.1
libva1: 1.7.0-1ubuntu0.1
# The vainfo installed
$ dpkg-query --showformat='${Package}: ${Version}\n' --show | grep vainfo
vainfo: 1.7.0-1ubuntu0.1
# List installed i915 Intel VAAPI driver
$ dpkg-query --showformat='${Package}: ${Version}\n' --show | grep i965
i965-va-driver: 1.7.0-1

6.我在編譯VLC時問過的問題

依賴庫編譯與調用:

Toson_桐:有誰知道編譯vlc的時候怎樣讓它不依賴ffmpeg的那些解碼模塊?
不斷電的夢:依不依賴是代碼調用時決定的, 不是編譯時決定的.
Toson_桐:編譯時可以加編譯參數“–disable-***”,但是沒有–disable-ffmpeg這個
Toson_桐:vlc是不是必須依賴ffmpeg
爨纛鼟:那你得自己編ffmpeg禁用那些模塊 然後再編vlc 鏈你自己編的那版ffmpeg
爨纛鼟:@Toson_桐 你直接把libavcodec_plugin.so刪了就行
爨纛鼟:vlc對ffmpeg是運行時依賴 你把插件一刪就沒有了
爨纛鼟:ffmpeg的解碼器比較全面 我不知道你爲什麼要禁用它 但是我告訴你可以通過運行時參數指定使用哪個解碼器 如果你要自己寫一個解碼器 可以把分數設得比ffmpeg高 這樣會優先找你的
Toson_桐:@爨纛鼟 厲害了!,問一下禁用ffmpeg會不會vlc對某些編碼格式就不支持了
爨纛鼟:肯定的啊
Toson_桐:我主要想看vlc自己的解碼能力,做個對比
爨纛鼟: libvlc什麼功能都沒有 vlc所有的功能都是插件提供的
爨纛鼟:libvlccore是插件加載器 libvlc實現音視頻播放邏輯和負責線程調度
Toson_桐:我明白了,vlc依賴的x264也是它的插件了,我是解碼相機的H264格式視頻流,我可以跳過vlc直接使用底下的插件庫,應該可以達到快速解碼吧
Toson_桐:現在我這掛載20多個攝像頭之後,cpu資源全耗光了
Eric:牛逼
Toson_桐:聽說vlc解碼效果好,就來研究
爨纛鼟:用硬編硬解 你有顯卡沒有
Toson_桐:剛開始就想用核顯,linux上編譯,一直沒調通。獨顯倒是能用,不過獨顯都拿去跑模型用了
爨纛鼟:跑模型跟編解碼不是同一塊核心
爨纛鼟:跑模型用的是cuda核心 編碼是nvenc 解碼是cuvid


三、VLC代碼

參考雷霄驊文檔:https://blog.csdn.net/leixiaohua1020/article/details/42363079

流程圖中包含了3個結構體:
libvlc_instance_t:代表一個libVLC的實例。
libvlc_media_t:代表一個可以播放的媒體。
libvlc_media_player_t:代表一個VLC媒體播放器(一個視頻播放器播放一個視頻)。注意VLC並不僅僅用於媒體播放。

創建或者以上3個結構體通過以下6個函數:

libvlc_new():創建libvlc_instance_t。
libvlc_media_new_path():創建libvlc_media_t。
libvlc_media_player_new_from_media():創建libvlc_media_player_t。
libvlc_media_player_release():釋放libvlc_media_player_t
libvlc_media_release():釋放libvlc_media_t。
libvlc_release():釋放libvlc_instance_t。
可以通過下面的函數控制媒體的播放或者暫停:

這些函數都需要使用libvlc_media_player_t作爲參數。這裏處於簡化的目的,只使用了播放和停止函數。

libvlc_media_player_play():播放。
libvlc_media_player_pause():暫停。
libvlc_media_player_stop():停止。
獲取視頻的時長,寬,高等信息:

在libVLC中可以通過如下等函數獲取。

libvlc_media_player_get_length()
//libvlc_video_get_width()
//libvlc_video_get_height()
實測已經沒有上述2個函數,以下面一個函數代替:
libvlc_video_get_size(mp, 0, &width, &height);

但是有一個很奇怪的現象:如果在調用完libvlc_media_player_play()之後,立即調用上述3個函數的話,返回的值都是0,只有“等待”一段時間(例如調用sleep())後再調用上述函數,才能得到正確的數值。


四、例程

以下是我運行過的程序,實現vlc代碼提取攝像機圖像:

//
// Created by toson on 19-4-15.
//
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vlc/vlc.h>
#include <opencv2/opencv.hpp>

#include "unistd.h"

using namespace std;
using namespace cv;

int IMG_WIDTH = 3840;//2592//1920;//1280//1280
int IMG_HEIGHT= 2160;//1520//1080;//960//720

namespace vlcreader_ns {

//#pragma comment(lib,"libvlc.so.5")
//#pragma comment(lib,"libvlccore.so.8")

    class VLCReader
    {
    public:
        VLCReader(char* url = 0);
        ~VLCReader();
        void start(int wantW = IMG_WIDTH, int wantH = IMG_HEIGHT);
        void pause(bool paused);
        void ctrl(const char *psz_options);
        cv::Mat frame() { return img; }
        unsigned int w, h;

    private:
        char* rtspAddress = "rtsp://admin:[email protected]:554/cam/realmonitor?channel=1&subtype=0";
        libvlc_instance_t *inst;
        libvlc_media_player_t *mp;
        unsigned char *pixel;
        cv::Mat img;
        libvlc_media_t *media;

        static void *cb_lock(void *opaque, void **plane);
        static void cb_unlock(void *opaque, void *picture, void * const *plane);
        static void cb_display(void *opaque, void *picture);
        unsigned char * updataSize();
    };

    VLCReader::VLCReader(char*url)
            : inst(0), mp(0), pixel(0), w(0), h(0), rtspAddress(url)
    {
        const char * vlc_args[] = {
                "--ipv4", //將會默認爲所有連接使用 IPv4。 (默認關閉)
                "--no-prefer-system-codecs", //無論是否有可用的選擇都優先使用您系統中的原生插件替代VLC自己的插件。 (默認關閉)
                "--rtsp-caching=300", //延遲速度ms //允許您修改 RTSP 流的默認緩存值。此值必須以毫秒爲單位設置。
                "--network-caching=500", //設高可減少花屏 //遠程文件額外增加的緩存值,以毫秒爲單位。
                "--demux=h264", //去複用器被用於分離 "複合" 流 (類似音頻和視頻流)。
                "--rtsp-tcp", //--rtsp-host //--rtsp-tcp //使用 RTP over RTSP (TCP) (默認關閉)
        };
        std::string rstp_str(rtspAddress);
        if (rstp_str.substr(0, 4) == "file")
        {
            vlc_args[4] = "";
            vlc_args[5] = "";
        }

        inst = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
        mp = libvlc_media_player_new(inst);

        libvlc_video_set_callbacks(mp, cb_lock, cb_unlock, cb_display, this);
    }

    VLCReader::~VLCReader()
    {
        libvlc_media_player_stop(mp);
        libvlc_media_player_release(mp);
        libvlc_release(inst);
    }

    void VLCReader::start(int wantW, int wantH)
    {
        libvlc_media_player_pause(mp);
        media = libvlc_media_new_location(inst, rtspAddress);
        libvlc_media_player_set_media(mp, media);
        libvlc_media_release(media);

        libvlc_video_set_format(mp, "RV24", wantW, wantH, wantW * 3);
        libvlc_media_player_play(mp);
    }

    void VLCReader::pause(bool paused)
    {
        if (mp) {
            libvlc_media_player_set_pause(mp, paused);
        }
    }

    unsigned char * VLCReader::updataSize()
    {
        libvlc_video_get_size(mp, 0, &w, &h);
        //int w = libvlc_video_get_width(mp);
        //int h = libvlc_video_get_height(mp);
        if (!w || !h)
            return 0;
        if (pixel && (this->w != w || this->h != h)) {
            delete[] pixel;
            pixel = 0;
        }
        if (!pixel) {
            pixel = new unsigned char[w*h * 3];
            this->w = w;
            this->h = h;
        }
        return pixel;
    }

    void* VLCReader::cb_lock(void *opaque, void **plane)
    {
        VLCReader *p = (VLCReader*)opaque;
        *plane = p->updataSize(); //tell VLC to put decoded data to this buffer
        return *plane;
    }
    void VLCReader::cb_unlock(void *opaque, void *picture, void * const *plane)
    {
        VLCReader *p = (VLCReader*)opaque;
        unsigned char *pix = (unsigned char*)picture;
        if (pix) {
            p->img = cv::Mat(p->h, p->w, CV_8UC3, pix);
        }
    }
    void VLCReader::cb_display(void *opaque, void *picture)
    {
        VLCReader *p = (VLCReader*)opaque;
        if (!p->img.empty()) {
//            cv::cvtColor(p->img, p->img, cv::COLOR_BGR2RGB);
//            cv::namedWindow("1", CV_WINDOW_NORMAL);
//            resize(p->img, p->img, Size(0,0), 0.5, 0.5, INTER_LINEAR);
            cv::imshow("1", p->img);
            cv::waitKey(1);
        }
    }

    void VLCReader::ctrl(const char *psz_options)
    {
        libvlc_media_add_option(media, psz_options);
    }
}
using namespace vlcreader_ns;

int main(int argc, char* argv[])
{
    VLCReader vlc_reader("rtsp://admin:[email protected]:554/cam/realmonitor?channel=1&subtype=0");
//    VLCReader vlc_reader("file:////home/toson/videos/BigBuckBunny_320x180.mp4");
    vlc_reader.start();
    sleep(3);
    vlc_reader.pause(true); //暫停
    sleep(3);
    vlc_reader.pause(false);
    sleep(3);
//    vlc_reader.ctrl("-f"); //"--fullscreen"
    sleep(3);
    sleep(100);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章