FFmpeg為什麼遲遲不啟用vaapi解碼/編碼?

很顯然,英特爾的vaapi已經準備好了,mpv已經實現了vaapi的解碼,但FFmpeg怎麼到現在都編譯不出h264_vaapi來的?

然後實現vaapi編碼是太過複雜了嗎?到現在還沒有軟體實現。


首先什麼是VAAPI

視頻圖像大小從標清,高清,升到超高清,編碼器標準從H.263,H.264升到H.265,包括目前很火的VR和AR,視頻應用對視頻處理和編解碼器的運算量要求越來越高,而GPU相比CPU更適合處理圖形圖像這樣的矩陣運算。

如何使用GPU的圖像處理能力呢,VAAPI是一個方案。

視頻加速應用程序介面 (Video Acceleration API, 縮寫為VA-API) 是一套類unix平台提供視頻硬體加速的開源庫和標準。

VAAPI免費開源,以MIT許可證發布。MIT許可證源自麻省理工學院(Massachusetts Institute of Technology, MIT),又稱"X條款"(X License)或"X11條款"(X11 License) MIT內容與三條款BSD許可證(3-clause BSD license)內容頗為近似,但是賦予軟體被授權人更大的權利與更少的限制。有許多團體均採用MIT許可證。例如著名的ssh連接軟體PuTTY與X Windows System (X11)。Expat, Mono開發平台庫,Ruby on Rails, Lua 5.0 onwards等等也都採用MIT授權條款。

應用層用戶可以通過VAAPI介面直接訪問加速設備驅動,使用硬體(如GPU)來加速視頻處理的應用,如視頻編碼,視頻解碼,視頻融合疊加,視頻顯示。

VAAPI是Intel發起的,之初是為Intel自己的GMA(Graphics Media Accelerator)系列GPU加速。Intel也想用VAAPI替代已有的XvMC標準。但VAAPI發展到現在它不僅是針對Intel的視頻加速設備,其他廠商也能完全免費的通過VAAPI這個開放介面實現硬體圖形加速。

VAAPI是偏向類unix平台的,對應windows平台的技術是 Microsoft Windows DirectX Video Acceleration(DxVA)。VAAPI可以應用在Linux, FreeBSD, Solaris和Android等類unix平台。

VAAPI當初的設計偏向於硬體加速解碼器的視頻演算法如VLD, IDCT, motion compensation, deblocking。現在VAAPI不僅支持解碼,還支持主流的編碼,並且支持圖像後處理和圖像增強。隨著intel的核芯顯卡越來越強,VAAPI的功能也隨之強大。

從架構圖可知VAAPI通過GPU設備驅動實現四個模塊顯存控制,編碼,解碼,圖像處理,其中編解碼器模塊可分為同一類。

顯存控制:通過用戶態的DRM訪問內核顯存。

編解碼器:用戶態把編解碼器的指令傳給內核態驅動,內核態驅動再操作實體編解碼硬體。

圖像處理:先調用顯示介面,通過顯示介面直接調用硬體或通過調用內核Gfx模式操作硬體。

從VAAPI的架構可看出它是依賴於配套的DRM,設備驅動,內核模塊和實體硬體。以intel為例,使用VAAPI最好使用intel發布的一組套件。

VAAPI編碼H264常式

代碼片段如下:

/*打開VA GPU設備,並初始化*/

va_dpy = va_open_display();

va_status = vaInitialize(va_dpy, major_ver, minor_ver);

/*查詢硬體支持的H.264 profile等級*/

h264_profile = profile_list[i];

vaQueryConfigEntrypoints(va_dpy, h264_profile, entrypoints, num_entrypoints);

for (slice_entrypoint = 0; slice_entrypoint &< num_entrypoints; slice_entrypoint++) {

if (entrypoints[slice_entrypoint] == VAEntrypointEncSlice) {

support_encode = 1;

break;

}

}

/*查詢H.264 屬性介面,是否支持VBR,CBR等。是否支持多slice等*/

va_status = vaGetConfigAttributes(va_dpy, h264_profile, VAEntrypointEncSlice,

attrib[0], VAConfigAttribTypeMax);

CHECK_VASTATUS(va_status, "vaGetConfigAttributes");

/*在指定設備上創建H.264配置*/

va_status = vaCreateConfig(va_dpy, h264_profile, VAEntrypointEncSlice,

config_attrib[0], config_attrib_num, config_id);

CHECK_VASTATUS(va_status, "vaCreateConfig");

/* 創建源設備表面 */

/* create source surfaces */

va_status = vaCreateSurfaces(va_dpy,

VA_RT_FORMAT_YUV420, frame_width_mbaligned,

frame_height_mbaligned,

src_surface[0], SURFACE_NUM,

NULL, 0);

CHECK_VASTATUS(va_status, "vaCreateSurfaces");

/* 創建參考設備表面 */

/* create reference surfaces */

va_status = vaCreateSurfaces(

va_dpy,

VA_RT_FORMAT_YUV420, frame_width_mbaligned, frame_height_mbaligned,

ref_surface[0], SURFACE_NUM,

NULL, 0

);

CHECK_VASTATUS(va_status, "vaCreateSurfaces");

tmp_surfaceid = calloc(2 * SURFACE_NUM, sizeof(VASurfaceID));

memcpy(tmp_surfaceid, src_surface, SURFACE_NUM * sizeof(VASurfaceID));

memcpy(tmp_surfaceid + SURFACE_NUM, ref_surface, SURFACE_NUM * sizeof(VASurfaceID));

/*創建編碼器管道,因為是異構系統用管道的方式*/

/* Create a context for this encode pipe */

va_status = vaCreateContext(va_dpy, config_id,

frame_width_mbaligned, frame_height_mbaligned,

VA_PROGRESSIVE,

tmp_surfaceid, 2 * SURFACE_NUM,

context_id);

CHECK_VASTATUS(va_status, "vaCreateContext");

free(tmp_surfaceid);

/*為編碼申請設備上的全局指令空間 cmdbuf,控制和數據空間要分開申請,數據空間可實時申請*/

codedbuf_size = (frame_width_mbaligned * frame_height_mbaligned * 400) / (16*16);

for (i = 0; i &< SURFACE_NUM; i++) {

va_status = vaCreateBuffer(va_dpy,context_id,VAEncCodedBufferType,

codedbuf_size, 1, NULL, coded_buf[i]);

CHECK_VASTATUS(va_status,"vaCreateBuffer");

}

/*裝載編碼數據到顯存*/

upload_surface_yuv(va_dpy, surface_id,

srcyuv_fourcc, frame_width, frame_height,

src_Y, src_U, src_V);

va_status = vaCreateBuffer(va_dpy,context_id,VAEncSliceParameterBufferType,

sizeof(slice_param),1,slice_param,slice_param_buf);

CHECK_VASTATUS(va_status,"vaCreateBuffer");

/*準備編碼數據給目標表面*/

va_status = vaBeginPicture(va_dpy, context_id, src_surface[current_slot]);

CHECK_VASTATUS(va_status,"vaBeginPicture");

/*推送數據給GPU,編碼,完成後buffer自動釋放銷毀*/

va_status = vaRenderPicture(va_dpy,context_id, slice_param_buf, 1);

CHECK_VASTATUS(va_status,"vaRenderPicture");

/*讓設備執行*/

va_status = vaEndPicture(va_dpy,context_id);

CHECK_VASTATUS(va_status,"vaEndPicture");

/*釋放資源*/

vaDestroySurfaces(va_dpy,src_surface[0],SURFACE_NUM);

vaDestroySurfaces(va_dpy,ref_surface[0],SURFACE_NUM);

for (i = 0; i &< SURFACE_NUM; i++)

vaDestroyBuffer(va_dpy,coded_buf[i]);

vaDestroyContext(va_dpy,context_id);

vaDestroyConfig(va_dpy,config_id);

從上面代碼片段可看出,VAAPI使用類似C/S架構,CPU側是client, GPU是server。GPU提供有限的功能,部分編碼器的細節需要在CPU側用戶自己完成,如封nal頭等,這樣意味著如果要用VAAPI開發編解碼器,需要對編解碼器內部細節非常清楚。

所以直接使用VAAPI的技術門檻很高。

VAAPI是unix平台,那麼對應windows平台的GPU加速介面就是DxVA。

因為windows的霸主地位和windows天生對媒體能力親合支持(unix/liunx到目前還沒有統一的媒體平台,而windows一直有),加上windows和intel的聯合(intel有自己的核心顯卡),讓DxVA成為GPU加速最高效的工具沒有之一。

DirectX Video Acceleration(DXVA)是一種在Microsoft Windows和Xbox 360平台的Microsoft API規範,能讓應用程序使用硬體GPU的運算能力。DxVA 1.0最早是在Windows 2000以及Windows 98版本開始引入的API,可以使用於VMR 7/9之上。DxVA 2.0僅適用於Windows Vista, Windows 7以及更新的版本。

這裡就不展開介紹DxVA了。

VAAPI支持的設備和軟體

設備:

Broadcom Crystal HD (work-in-progress):

http://gitorious.org/crystalhd-video

Intel Embedded Graphics Drivers (IEGD):

Intel? Embedded Graphics Drivers for Intel? Architecture

Intel Embedded Media and Graphics Drivers (EMGD):

Intel? Embedded Media and Graphics Driver (Intel? EMGD)

Intel GMA500 driver (OEM only):

https://launchpad.net/~ubuntu-mobile/+archive/ppa

Intel integrated G45 graphics chips:

vaapi/intel-driver

IMG VXD375/385 and VXE250/285 video engines:

vaapi/pvr-driver

VDPAU back-end for NVIDIA and VIA chipsets:

vaapi/vdpau-driver

VIA / S3 Graphics Accelerated Linux Driver:

Welcome to S3 Graphics

XvBA / ATI Graphics Backend (for proprietary driver only)

vaapi/xvba-driver

從上面的列表可看出,目前對VAAPI支持最好的還是intel自己。

軟體:

Clutter toolkit (through clutter-gst, thus GStreamer):

http://clutter-project.org/

FFmpeg (upstream SVN tree &>= 2010/01/18 / version 0.6.x and onwards):

FFmpeg

Fluendo video codec pack for Intel Atom (GStreamer):

http://www.fluendo.com/

Gnash flash player:

http://wiki.gnashdev.org/Hardware_Video_decoding

GStreamer:

GitHub - 01org/gstreamer-vaapi: *WARNING* this repository is not maintained anymore. Please use https://cgit.freedesktop.org/gstreamer/gstreamer-vaapi

Lightspark flash player:

Lightspark

MPlayer/VAAPI:

GitHub - gbeauchesne/mplayer-vaapi: Original MPlayer with VA-API support

MythTV (work-in-progress):

VAAPI - MythTV Official Wiki

?RealPlayer for MID:

https://community.helixcommunity.org/Licenses/realplayer_for_mid_faq.html

Totem movie player (simply requires GStreamer VA-API plug-ins):

http://projects.gnome.org/totem/

VideoLAN - VLC media player:

http://www.videolan.org/

XBMC:

Kodi | Open Source Home Theater Software

Xine:

GitHub - huceke/xine-lib-vaapi at vaapi

從上面的軟體列表可看出FFMPEG和gstreamer都支持VAAPI,特別是gstreamer已把vaapi納入他的准里,所以在類unix平台和開源GPU訪問控制方案中,VAAPI已是一支獨秀。

最後

從VAAPI官網的信息可知,FFMPEG早就支持vaapi了。

FFmpeg (upstream SVN tree &>= 2010/01/18 / version 0.6.x and onwards):。

參考

vaapi

VAAPI | 01.org


ffmpeg 3.1終於支持了

FFmpeg 3.1 "Laplace", a new
major release, is now available! Some of the highlights:

  • DXVA2-accelerated HEVC Main10 decoding
  • fieldhint filter
  • loop video filter and aloop audio filter
  • Bob Weaver deinterlacing filter
  • firequalizer filter
  • datascope filter
  • bench and abench filters
  • ciescope filter
  • protocol blacklisting API
  • MediaCodec H264 decoding
  • VC-2 HQ RTP payload format (draft v1) depacketizer and packetizer
  • VP9 RTP payload format (draft v2) packetizer
  • AudioToolbox audio decoders
  • AudioToolbox audio encoders
  • coreimage filter (GPU based image filtering on OSX)
  • libdcadec removed
  • bitstream filter for extracting DTS core
  • ADPCM IMA DAT4 decoder
  • musx demuxer
  • aix demuxer
  • remap filter
  • hash and framehash muxers
  • colorspace filter
  • hdcd filter
  • readvitc filter
  • VAAPI-accelerated format conversion and scaling
  • libnpp/CUDA-accelerated format conversion and scaling
  • Duck TrueMotion 2.0 Real Time decoder
  • Wideband Single-bit Data (WSD) demuxer
  • VAAPI-accelerated H.264/HEVC/MJPEG encoding
  • DTS Express (LBR) decoder
  • Generic OpenMAX IL encoder with support for Raspberry Pi
  • IFF ANIM demuxer decoder
  • Direct Stream Transfer (DST) decoder
  • loudnorm filter
  • MTAF demuxer and decoder
  • MagicYUV decoder
  • OpenExr improvements (tile data and B44/B44A support)
  • BitJazz SheerVideo decoder
  • CUDA CUVID H264/HEVC decoder
  • 10-bit depth support in native utvideo decoder
  • libutvideo wrapper removed
  • YUY2 Lossless Codec decoder
  • VideoToolbox H.264 encoder


We strongly recommend users, distributors, and system integrators to
upgrade unless they use current git master.


intel有提供一個ffvademo(https://github.com/gbeauchesne/ffvademo),可以啟用vaapi解碼。最新的ffmpeg 3.1已經啟用在ffmpeg命令里啟用了vaapi加速,真好。

之前以為編碼沒放ffmpeg中,可能是為了qsv(Quick Sync Video)收費所以這樣吧。ffmpeg 2.8有包含qsv的編碼。

Linux世界有一個非常不好的地方就是沒有一個標準是大家都用的,vaapi的amd支持xvba 上一次更新還是2011年,vaapi的vdpau支持也是2012年後不更新,或許未來vulkan能夠統一硬編碼也說不定。


最新ffmpeg代碼裡面有vaapi


c++ - How to use hardware acceleration with ffmpeg 不負責任的給一個鏈接,看看是否有幫助


推薦閱讀:

yuv和rgb各有什麼優點?

TAG:英特爾Intel | 視頻編碼格式 | Linux | FFmpeg | h264 |