2022年7月25日 星期一

首先什麼是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以及更新的版本。

VAAPI支持的設備和軟件

設備:

Broadcom Crystal HD (work-in-progress):

Intel Embedded Graphics Drivers (IEGD):

Intel Embedded Media and Graphics Drivers (EMGD):

Intel GMA500 driver (OEM only):

Intel integrated G45 graphics chips:

IMG VXD375/385 and VXE250/285 video engines:

VDPAU back-end for NVIDIA and VIA chipsets:

VIA / S3 Graphics Accelerated Linux Driver:

XvBA / ATI Graphics Backend (for proprietary driver only)

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

軟件:

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

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

Fluendo video codec pack for Intel Atom (GStreamer):

Gnash flash player:

GStreamer:

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

MPlayer/VAAPI:

MythTV (work-in-progress):

?RealPlayer for MID:

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

VideoLAN - VLC media player:

XBMC:

Xine:

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

最後

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

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

參考

沒有留言:

張貼留言