当前位置: 首页 > news >正文

视频编解码(一)之virtio-gpu环境搭建

一、基础概念

VA-API

Video Acceleration API 是一组开源应用API接口,赋能应用(比如VLC播放器、GStreamer等)使用hardware video acceleration(一般是GPU提供硬件视频加速功能),VA-API主要由开源库libva和一些硬件驱动(通常是GPU厂商提供)来实现的

VA-API视频编解码接口独立于平台和窗口系统的,其主要使用场景目标是类Unix系统(如Linux、FreeBSD、Solaris等)和Andriod上X window系统中的直接渲染基础设置(DRI)。加速处理一般包括视频解码、视频编码、子图片混合、渲染

VA-API最初由intel为其GPU特定功能开发的,现在已经扩展到其他硬件厂商平台。
在这里插入图片描述

VA-API如果存在的话,对于某些应用来说可能默认就使用它,比如MPV

VA-API,对于Debian系统中,视频编解码硬件加速驱动:

  1. 对于nouveau和大部分的AMD驱动,VA-API通过安装mesa-va-drivers来支持。

  2. 对于intel,要分免费和付费两种,免费的一般只能decode解码,付费的可支持编码。

  3. 对于Gen 8+ intel硬件,免费的VA-API可通过安装intel-media-va-driver包,付费包是intel-media-va-driver-non-free

  4. 对于比较旧的intel硬件,免费包是i965-va-driver,付费包i965-va-driver-shaders

  5. 可以通过环境变量LIBVA_DRIVER_NAME来指定选择使用哪个driver驱动,比如LIBVA_DRIVER_NAME=i965(指定使用i965-va-driver),LIBVA_DRIVER_NAME=iHD(指定使用intel-media-va-driver驱动)。

我们可以看下我这里ubuntu中的VA-API各种driver安装的驱动

root@p:~# dpkg -L mesa-va-drivers
/usr/lib/x86_64-linux-gnu/dri/nouveau_drv_video.so
/usr/lib/x86_64-linux-gnu/dri/r600_drv_video.so
/usr/lib/x86_64-linux-gnu/dri/radeonsi_drv_video.soroot@pc:~# dpkg -L intel-media-va-driver
/usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.soroot@pc:~# dpkg -L i965-va-driver
/usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so 

VDPAU

Video Decode and Presentation API for Unix 是基于开源库libvdpau开发的免费API库,被Nvidia支持,其目标是实现device drivers如Nvidia GeForce driver、nouveau、amdgpu等,给VLC等终端应用提供视频硬件加速处理功能功能。

VDPAU的目标平台是类Unix系统,包括Linux、FreeBSD、Solaris

VDPAU相对于VA-API来说,有更多的局限

Debian系统上,硬件加速驱动:

  1. 对于AMD驱动(radeon和amdgpu),以及支持Nvidia的开源驱动nouveau来说,可以通过安装vdpau-driver-all来支持实现,同时,该驱动也能支持是OpenGL/VA-API后端的intel GPUs,不过不能支持所有的intel设备(对于intel设备最好还是使用VA-API)。

  2. 对于proprietary nvidia硬件来说,安装nvidia-vdpau-driver来支持。

root@pc:~# dpkg -L mesa-vdpau-drivers
/.
/usr
/usr/lib
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/vdpau
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_nouveau.so.1.0.0
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_r300.so.1.0.0
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_r600.so.1.0.0
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_radeonsi.so.1.0.0
/usr/share
/usr/share/bug
/usr/share/bug/mesa-vdpau-drivers
/usr/share/bug/mesa-vdpau-drivers/control
/usr/share/bug/mesa-vdpau-drivers/script
/usr/share/doc
/usr/share/doc/mesa-vdpau-drivers
/usr/share/doc/mesa-vdpau-drivers/changelog.Debian.gz
/usr/share/doc/mesa-vdpau-drivers/copyright
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_nouveau.so
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_nouveau.so.1
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_nouveau.so.1.0
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_r300.so
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_r300.so.1
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_r300.so.1.0
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_r600.so
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_r600.so.1
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_r600.so.1.0
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_radeonsi.so
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_radeonsi.so.1
/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_radeonsi.so.1.0
root@pc:~# dpkg -L vdpau-driver-all
/.
/usr
/usr/share
/usr/share/bug
/usr/share/bug/vdpau-driver-all
/usr/share/doc
/usr/share/doc/vdpau-driver-all
/usr/share/doc/vdpau-driver-all/changelog.Debian.gz
/usr/share/doc/vdpau-driver-all/copyright

NVENC/NVDEC

Debian系统中:

  1. NVDEC可以通过安装libnvcuvid1来支持。

  2. NVENC可以通过安装libnvidia-encode1来支持。

VA-API/VDPAU/NVENC对比

在Linux平台下,video decoding and encoding的hardware acceleration主要有三种API接口: VA-API, VDPAU, NVEND/NVDEC

Linux平台APIs硬件厂商支持软件应用支持主要缺陷
VA-APIIntel
AMD
Nvidia(只能借助开源驱动nouveau支持)
kodi,VLC,MPV
chromium,firefox等
缺乏对Nvidia的专有驱动的支持(lacking any support in the proprietary Nvidia drivers)
VDPAUfully supported in
AMD
Nvidia(专有驱动或者开源驱动nouveau都支持)
大部分desktop应用都支持,如kodi,VLC,MPV等,但在chromium、firefox中不支持对intel的支持不完善
不支持浏览器上的web video acceleration
NVENC/NVDECNvidia专有的API只能支持较少的应用
支持ffmpeg和OBS studio的编码
支持ffmpeg和MPV的解码
由于其proprietary(专用),不能跨board支持,导致只能支持较少的软硬件

DXVA

DirectX Video Acceleration 是微软平台和Xbox 360平台用于视频解码硬件加速的一组Microsoft API。DXVA2.0扩展了更多的操作,比如视频捕捉和处理的硬件加速。

Windows平台API
DXVA/DXVA2

VirGL

VirGL is a virtual 3D GPU for use inside QEMU virtual machines, that allows the guest operating system to use the capabilities of the host GPU to accelerate 3D rendering. The plan is to have a guest GPU that is fully independent of the host GPU.

virglrender

virglrenderer是一个开源项目virgl3d提供的开源库,它的主要功能是针对虚拟化场景,为QEMU提供一个具有3D图形处理的显卡,其使用方式就是为QEMU提供一组3D图形处理的接口。QEMU通过调用virglrenderer的库接口实现主机侧的3D图形加速处理。
在这里插入图片描述

VM之QEMU中3D加速调用栈:
在这里插入图片描述

virtio-gpu

网上找的一张图解释的很好
在这里插入图片描述

mesa

The Mesa project began as an open-source implementation of the OpenGL specification - a system for rendering interactive 3D graphics.

Mesa是opengl标准的一种开源实现。OpenGL API是定义了一个跨编程语言、 跨平台的应用程序接口(API)的规范, 它用于生成2D和3D图像, 而它仅仅是定义了一种API, 并没有任何实现细节. 而OpenGL API的具体实现有很多, 主要分为开源实现和闭源实现, 闭源实现如各大GPU厂商自己实现的闭源OpenGL图形库, 例如AMD显卡的Catalyst闭源驱动; 而开源实现便是Mesa3D, 它是由Brian Paul在1993年8月开始开发的一个实现了OpenGL API的开源图形库. 它目前隶属于freedesktop.org, 广泛运用在Liunx, BSD等操作系统。

主要由mesa主模块、gallium模块、egl模块、glsl模块和glx等模块组成。

Over the years the project has grown to implement more graphics APIs, including OpenGL ES, OpenCL, OpenMAX, VDPAU, VA-API, Vulkan and EGL。

二、virglrender支持h264/h265编解码

virglrender项目开源仓库地址:https://gitlab.freedesktop.org/virgl/virglrenderer.git

其中,video的支持需要安装libva-devel库,比如virgl_video.c中需要#include <va/va.h>,而/usr/include/va/va.h是由libva-devel安装包提供的:

[root@244:libva#] rpm -ql libva-devel
/usr/include/va
/usr/include/va/va.h
/usr/include/va/va_backend.h
...

其中virglrenderer中已经添加了对h264/h265的编解码vaapi加速支持,主要提交代码修改点这里简要分析下:

mesa改动

1. 增加virgl_video_hw.h

主要将原来的src/gallium/drivers/virgl/virgl_video.h中的部分代码移动到src/virtio/virtio-gpu/virgl_video_hw.h中来管理。

这样,原来的virgl_video.h中就只剩定义两个东西:

  • virgl_video_buffer:用于存储原始YUV格式的数据buffer
  • virgl_video_codec:定义encoder或者decoder

virgl_video_hw.h中主要定义用于guest和host之间交互的数据结构:

  • 4字节对其
  • virgl_picture_desc等相关数据结构主要定义sequence parameters、picture parameters、slice parameters以及用于编解码的context信息等,video backend需要这些参数去重构VA-API calls

2. 保存intra_idr_period数据在context

首先结构体struct pipe_h264_enc_picture_desc中增加该元素数据intra_idr_period

VAEncSequenceParameterBufferH264该结构体是libva库中va_enc_h264.h中定义的。

3. 传递max_references至backend

encoding SPS header是,max_references也是一个重要的sequence parameter值,需要传递。

主要是修改src/gallium/drivers/virgl/virgl_encode.c中,virgl_encode_create_video_codec()函数中判断host_feature_check_version是否大于等于14,是的话就要传递max_references,通过virgl_encoder_write_dword()来写。

4. 实现编码框架并支持h264编码

src/gallium/drivers/virgl/virgl_video.c中增加一个函数virgl_encode_encode_bitstream,主要是给传递指令和资源给backend。

主要修改是virgl_video.c中,其中需要的数据结构增加在virgl_video_hw.h中

virgl_video_hw.h增加了哪些数据结构?

struct virgl_enc_quality_modes {};
enum virgl_video_encode_stat {};
struct virgl_video_encode_feedback {};
//下面是h264相关的
struct virgl_h264_enc_seq_param {};
struct virgl_h264_enc_rate_control {};
struct virgl_h264_enc_motion_estimation {};
struct virgl_h264_enc_pic_control {};
struct virgl_h264_slice_descriptor {};
struct virgl_h264_enc_picture_desc {};

virgl_video.c中增加的函数主要有,框架相关的

static int fill_enc_picture_desc(const struct pipe_picture_desc *desc,union virgl_picture_desc *vdsc)static void virgl_video_encode_bitstream(struct pipe_video_codec *codec,struct pipe_video_buffer *source,struct pipe_resource *target,void **feedback)

h264相关的

static int fill_h264_enc_picture_desc(const struct pipe_picture_desc *desc,union virgl_picture_desc *vdsc)

5. 支持h265编码

virgl_video_hw.h中增加的主要数据结构有:

struct virgl_h265_enc_seq_param {};
struct virgl_h265_enc_pic_param {};
struct virgl_h265_enc_slice_param {};
struct virgl_h265_enc_rate_control {};
struct virgl_h265_slice_descriptor {};
struct virgl_h265_enc_picture_desc {};

virgl_video.c中增加的函数主要

static int fill_h265_enc_picture_desc(const struct pipe_picture_desc *desc,union virgl_picture_desc *vdsc)static int fill_mpeg4_picture_desc(const struct pipe_picture_desc *desc,union virgl_picture_desc *vdsc)
{switch (u_reduce_video_profile(desc->profile)) {case PIPE_VIDEO_FORMAT_MPEG4_AVC:return fill_h264_enc_picture_desc(desc, vdsc);     //h264入口case PIPE_VIDEO_FORMAT_HEVC:return fill_h265_enc_picture_desc(desc, vdsc);  //这里是h265入口 default:return -1;
}

virglrender改动

1. 增加virgl_video_hw.h

类似mesa中一样,将部分数据结构单独领出来放到virgl_video_hw.h中,这样

virgl_video.h中主要就剩余定义

  • virgl_video_buffer:存储原始YUV数据的buffer,在VA-API中一般和surface处理一起出现
  • virgl_video_codec:代表一个编码器或解码器,在VA-API中一般随context处理出现

virgl_video_hw.h中定义数据结构主要有:

struct virgl_base_picture_desc {};
struct virgl_h264_sps {}; //h264 sequence parameter集
struct virgl_h264_pps {}; //h264 picture parameter集
struct virgl_h264_picture_desc {};struct virgl_h265_sps {};
struct virgl_h265_pps {};
struct virgl_h265_picture_desc {};
struct virgl_mpeg4_picture_desc {};
union virgl_picture_desc {};

2. 一些优化代码

为了更好的支持encode,他们对代码进行了优化修改,比如:

  • struct virgl_video_create_buffer_args结构体中增加opaque数据指针
  • 重新实现了export_video_dma_buf()接口使代码看起来更简洁
  • virgl_video_init()的cb参数改成了结构体,这样可以传递更多而callback函数
  • 在virgl_video_end_frame()中总是会调用vaSyncSurface(),原来仅是在decode context中调用
  • 增加level、max_references等参数,在encoding SPS headers中需要使用

3. 支持h264编码

virgl_video_hw.h中增加部分数据结构体:

struct virgl_enc_quality_modes {};
struct virgl_h264_enc_seq_param {};
struct virgl_h264_enc_rate_control {};
struct virgl_h264_enc_motion_estimation {};
struct virgl_h264_enc_pic_control {};
struct virgl_h264_slice_descriptor {};
struct virgl_h264_enc_picture_desc {};
enum virgl_video_encode_stat {};
struct virgl_video_encode_feedback {};

主要修改virgl_video.c

virgl_video.c中实现了一个通用编解码器的接口,主要基于VA-API实现。

  • virgl_video_buffer的实现,用于存放原始YUV数据,其实对VASurface的一层包装

  • virgl_video_codec实现,主要是对VAContext的包装,主要提供功能有:

    • virgl_video_begin_frame()

      该函数会调用vaBeginPicture()来准备编码或解码,对于encoding,它还需要guest端上传raw picture数据至本地VASurface

    • virgl_video_decode_bitstream()

      根据picture desc描述的信息,构造decoding相关的VABuffers,然后调用vaRenderPicture()来decoding

    • virgl_video_encode_bitstream()

      根据picture desc描述信息来构造encoding相关的VABuffer,然后调用vaRenderPicture()来encoding

    • virg_video_end_frame()

      调用vaEndPicure()来结束编码或解码;对于decode,会将raw picture data从VASurface中传回guest端;对于encode,会将VACodedBuffer中的编码结果数据传给guest端

新增的主要函数:

static void encode_upload_picture(struct virgl_video_codec *codec,struct virgl_video_buffer *buffer)static void encode_completed(struct virgl_video_codec *codec,struct virgl_video_buffer *buffer)static VASurfaceID get_enc_ref_pic(struct virgl_video_codec *codec,uint32_t frame_num)static void h264_fill_enc_picture_param(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h264_enc_picture_desc *desc,VAEncPictureParameterBufferH264 *param)static void h264_fill_enc_slice_param(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h264_enc_picture_desc *desc,VAEncSliceParameterBufferH264 *param)static void h264_fill_enc_seq_param(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h264_enc_picture_desc *desc,VAEncSequenceParameterBufferH264 *param)static void h264_fill_enc_misc_param_frame_rate(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h264_enc_picture_desc *desc,VAEncMiscParameterFrameRate *param)static int h264_encode_render_sequence(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h264_enc_picture_desc *desc)static int h264_encode_render_picture(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h264_enc_picture_desc *desc)static int h264_encode_render_slice(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h264_enc_picture_desc *desc)static int h264_encode_bitstream(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h264_enc_picture_desc *desc)int virgl_video_encode_bitstream(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const union virgl_picture_desc *desc)

vrend_decode.c增加了decode相关函数

static int vrend_decode_encode_bitstream(struct vrend_context *ctx,const uint32_t *buf,uint32_t length)

vrend_video.c

static void vrend_video_enocde_upload_picture(struct virgl_video_codec *codec,const struct virgl_video_dma_buf *dmabuf)static void vrend_video_encode_completed(struct virgl_video_codec *codec,const struct virgl_video_dma_buf *src_buf,const struct virgl_video_dma_buf *ref_buf,unsigned num_coded_bufs,const void * const *coded_bufs,const unsigned *coded_sizes)int vrend_video_encode_bitstream(struct vrend_video_context *ctx,uint32_t cdc_handle,uint32_t src_handle,uint32_t dest_handle,uint32_t desc_handle,uint32_t feed_handle)

4. 增加h265编码支持

主要就修改virgl_video.c和virgl_video_hw.h两个文件

virgl_video_hw.h增加数据结构

struct virgl_h265_enc_seq_param {};
struct virgl_h265_enc_pic_param {};
struct virgl_h265_enc_slice_param {};
struct virgl_h265_enc_rate_control {};
struct virgl_h265_slice_descriptor {};
struct virgl_h265_enc_picture_desc {};

virgl_video.c增加函数

static void h265_init_picture(VAPictureHEVC *pic)static void h265_fill_enc_seq_param(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h265_enc_picture_desc *desc,VAEncSequenceParameterBufferHEVC *param)static void h265_fill_enc_picture_param(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h265_enc_picture_desc *desc,VAEncPictureParameterBufferHEVC *param)static void h265_fill_enc_slice_param(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h265_enc_picture_desc *desc,VAEncSliceParameterBufferHEVC *param)static void h265_fill_enc_misc_param_rate_ctrl(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h265_enc_picture_desc *desc,VAEncMiscParameterRateControl *param)static void h265_fill_enc_misc_param_frame_rate(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h265_enc_picture_desc *desc,VAEncMiscParameterFrameRate *param)static int h265_encode_render_sequence(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h265_enc_picture_desc *desc)static int h265_encode_render_picture(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h265_enc_picture_desc *desc)static int h265_encode_render_slice(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h265_enc_picture_desc *desc)static int h265_encode_bitstream(struct virgl_video_codec *codec,struct virgl_video_buffer *source,const struct virgl_h265_enc_picture_desc *desc)

三、虚机环境搭建

在host主机上搭建,我这里主机上有两个显卡:

[root@localhost ubuntu]# lspci | grep VGA
02:00.0 VGA compatible controller: ASPEED Technology, Inc. ASPEED Graphics Family (rev 41)
1b:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Baffin [Radeon RX 550 640SP / RX 560/560X] (rev ff)

主要安装步骤

host准备工作

qemu编译
cd qemu
mkdir build
cd build
../configure --prefix=/root/install --enable-spice --enable-virglrenderer --enable-debug --target-list=x86_64-softmmu
make -j4
virglrenderer编译
cd virglrenderer
meson build --prefix=/root/install -Dvideo=true -Dbackend=ninja -Dbuildtype=debug
cd build
ninja && ninja install

这里的virglrenderer与开源主分支有个区别,添加了个vrend_get_drm_fd()函数,注释掉了暂未支持的AV1处理case:

From 6c403a9544fea082926e3973346cd70275605f3a Mon Sep 17 00:00:00 2001
From: jrg <jrglinuxcn@gmail.com>
Date: Tue, 7 Feb 2023 15:39:15 +0800
Subject: [PATCH 1/2] Add vrend_get_drm_fd() for open /dev/dri/renderD128Signed-off-by: jrg <jrglinuxcn@gmail.com>
---src/virgl_video.c    | 13 +++++-----src/virglrenderer.c  |  2 +-src/vrend_renderer.c | 58 +++++++++++++++++++++++++++++++++++++++++---3 files changed, 62 insertions(+), 11 deletions(-)diff --git a/src/virgl_video.c b/src/virgl_video.c
index 025ce00..1449ebf 100644
--- a/src/virgl_video.c
+++ b/src/virgl_video.c
@@ -152,8 +152,8 @@ static enum pipe_video_profile pipe_profile_from_va(VAProfile profile)return PIPE_VIDEO_PROFILE_VP9_PROFILE0;case VAProfileVP9Profile2:return PIPE_VIDEO_PROFILE_VP9_PROFILE2;
-   case VAProfileAV1Profile0:
-      return PIPE_VIDEO_PROFILE_AV1_MAIN;
+   //case VAProfileAV1Profile0:
+      //return PIPE_VIDEO_PROFILE_AV1_MAIN;case VAProfileNone:return PIPE_VIDEO_PROFILE_UNKNOWN;default:
@@ -247,8 +247,8 @@ static VAProfile va_profile_from_pipe(enum pipe_video_profile profile)return VAProfileVP9Profile0;case PIPE_VIDEO_PROFILE_VP9_PROFILE2:return VAProfileVP9Profile2;
-   case PIPE_VIDEO_PROFILE_AV1_MAIN:
-      return VAProfileAV1Profile0;
+   //case PIPE_VIDEO_PROFILE_AV1_MAIN:
+      //return VAProfileAV1Profile0;case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422:
@@ -557,8 +557,9 @@ int virgl_video_init(int drm_fd,if (!driver || !strstr(driver, "Mesa Gallium")) {virgl_log("only supports mesa va drivers now\n");
-        virgl_video_destroy();
-        return -1;
+        virgl_log("go on ...\n");
+        //virgl_video_destroy();
+        //return -1;}callbacks = cbs;
diff --git a/src/virglrenderer.c b/src/virglrenderer.c
index de8b623..6a00198 100644
--- a/src/virglrenderer.c
+++ b/src/virglrenderer.c
@@ -758,7 +758,7 @@ int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacksrenderer_flags |= VREND_USE_ASYNC_FENCE_CB;if (flags & VIRGL_RENDERER_USE_EXTERNAL_BLOB)renderer_flags |= VREND_USE_EXTERNAL_BLOB;
-      if (flags & VIRGL_RENDERER_USE_VIDEO)
+      //if (flags & VIRGL_RENDERER_USE_VIDEO)renderer_flags |= VREND_USE_VIDEO;ret = vrend_renderer_init(&vrend_cbs, renderer_flags);
diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
index 7e925ba..6fd78ad 100644
--- a/src/vrend_renderer.c
+++ b/src/vrend_renderer.c
@@ -66,6 +66,10 @@#ifdef ENABLE_VIDEO#include <vrend_video.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>#endif/*
@@ -7110,6 +7114,55 @@ static bool use_integer(void) {return false;}+#ifdef ENABLE_VIDEO
+static int vrend_get_drm_fd(const char *rendernode)
+{
+    DIR *dir;
+    struct dirent *e;
+    struct stat st;
+    int r, fd, ret;
+    char p[512];
+
+    if(rendernode) {
+        return open(rendernode, O_RDWR | O_NOCTTY | O_NONBLOCK);
+    }
+
+    dir = opendir("/dev/dri");
+    if(!dir) {
+        return -1;
+    }
+
+    fd = -1;
+    while(( e = readdir(dir))){
+        if (strncmp(e->d_name, "renderD", 7)) {
+            continue;
+        }
+
+        sprintf(p, "dev/dri/%s", e->d_name);
+
+        r = open(p, O_RDWR | O_NOCTTY | O_NONBLOCK);
+        if(r<0){
+            continue;
+        }
+
+        ret = fstat(r, &st);
+        if(ret < 0 || (st.st_mode &S_IFMT) != S_IFCHR){
+            close(r);
+            continue;
+        }
+
+        fd = r;
+        break;
+    }
+
+    closedir(dir);
+    if(fd < 0){
+        return -1;
+    }
+    return fd;
+}
+#endif
+int vrend_renderer_init(const struct vrend_if_cbs *cbs, uint32_t flags){bool gles;
@@ -7252,10 +7305,7 @@ int vrend_renderer_init(const struct vrend_if_cbs *cbs, uint32_t flags)#ifdef ENABLE_VIDEOif (flags & VREND_USE_VIDEO) {
-        if (vrend_clicbs->get_drm_fd)
-            vrend_video_init(vrend_clicbs->get_drm_fd());
-        else
-            vrend_printf("video disabled due to missing get_drm_fd\n");
+      vrend_video_init(vrend_get_drm_fd("/dev/dri/renderD128"));}#endif--
2.27.0
创建ubuntu虚机

我这里使用的是ubuntu-22.04.1版本。

最终,待guest中准备工作做完后,ubuntu虚机启动命令如下:

LD_PRELOAD=/root/install/lib64/libvirglrenderer.so.1 \
/root/install/bin/qemu-system-x86_64 \-enable-kvm \-smp 4 \-m 8G \-device virtio-serial \-chardev spicevmc,id=vdagent,debug=0,name=vdagent \-device virtserialport,chardev=vdagent,name=com.redhat.spice.0 \-drive file=./ubuntu_v01.img,if=virtio \-spice port=8010,addr=172.17.84.241,disable-ticketing=on \-cpu host \-device virtio-gpu-gl \-display egl-headless,gl=on \-machine q35,accel=kvm,usb=on \-device usb-mouse \-vga none

guest准备工作

libva和libva-utils编译
# libva
./autogen.sh
./configure CFLAGS="-g -O0"
make && make install# libva-utils
./autogen.sh --prefix=/root/install
make && make install
cp /root/install/bin/vainfo /usr/bin/vainfo
mesa编译

mesa编译的依赖安装:可以用apt build-dep mesa安装大多数依赖包,但还有几个可能需要手动安装,如meson、bindgen等(meson用pip3安装最为便捷)

 apt install make gcc g++ bisonapt install libncurses-devapt install flexapt install libssl-devapt install libelf-devapt install mesonapt install gitapt install pkg-configapt install cmakeapt install mesa-vdpau-driversapt install libvdpau-devapt install glslang-devapt install glslang-toolsapt install libva-devapt-get install python3 python3-pip python3-setuptools python3-wheel ninja-buildpip3 install meson -i https://pypi.tuna.tsinghua.edu.cn/simpleapt install libomxil-bellagio-devapt install rust-allapt install libclc-devapt install libzstd-devapt install libdrm-devapt install llvm-devdpkg -i libllvmspirvlib14_14.0.0-5_amd64.debdpkg -i libllvmspirvlib-14-dev_14.0.0-5_amd64.debapt install libclang-cpp-devapt install wayland-protocolsapt install libwayland-egl-backend-devapt install libxext-devapt install libxfixes-devapt install libxcb-glx0-devapt install libxcb-shm0-devapt install libx11-xcb-devapt install libxcb-dri2-0-devapt install libxcb-dri3-devapt install libxcb-present-devapt install libxshmfence-devapt install libxxf86vm-devapt install libxrandr-devapt install python3-codegenapt install libclang-devapt install bindgenapt install libsensors-dev

mesa编译:

meson -Dgallium-rusticl=true -Dgallium-opencl=standalone -Dllvm=enabled -Drust_std=2021 -Dvalgrind=disabled -Dopencl-spirv=true -Dshader-cache=true -Dvideo-codecs="vc1dec,h264dec,h265dec,h264enc,h265enc" -Dbuildtype=debug build
cd build
ninja && ninja install
vainfo

执行vainfo可能会报错:

  • export LIBVA_DRIVER_NAME=virtio_gpu

  • cp /usr/local/lib/x86_64-linux-gnu/dri/virtio_gpu_drv_video.so /usr/lib/x86_64-linux-gnu/dri/ (可能是拷贝到/usr/local/lib/dri/,要看libva寻找到路径)

root@pc:~# vainfo
Trying display: wayland
libva info: VA-API version 1.17.0
libva info: User environment variable requested driver 'virtio_gpu'
libva info: Trying to open /usr/local/lib/dri/virtio_gpu_drv_video.so
libva info: Found init function __vaDriverInit_1_17
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.17 (libva 2.17.0.pre1)
vainfo: Driver version: Mesa Gallium driver 23.0.0-devel for virgl (Radeon RX 550 Series (POLARIS11, DRM 3.44.0, 4.18.0-...)
vainfo: Supported profile and entrypointsVAProfileH264ConstrainedBaseline:    VAEntrypointVLDVAProfileH264ConstrainedBaseline:    VAEntrypointEncSliceVAProfileH264Main               :    VAEntrypointVLDVAProfileH264Main               :    VAEntrypointEncSliceVAProfileH264High               :    VAEntrypointVLDVAProfileH264High               :    VAEntrypointEncSliceVAProfileHEVCMain               :    VAEntrypointVLDVAProfileHEVCMain               :    VAEntrypointEncSliceVAProfileNone                   :    VAEntrypointVideoProc

四、验证h264/h265

gdb调试

host主机debug

host环境配置

host主机上需要配置debuginfo相关,创建CentOS-Debug.repo文件,设置其中enabled=1。并使用debuginfo-install命令安装必要的debug库。

[root@localhost ~]# cat /etc/yum.repos.d/CentOS-Debug.repo
#Debug Info
[debuginfo]
name=CentOS-$releasever - DebugInfo
# CentOS-4
#baseurl=http://debuginfo.centos.org/$releasever/
# CentOS-5
baseurl=http://debuginfo.centos.org/$releasever/$basearch/
gpgcheck=0
enabled=1
# CentOS-4
#gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-$releasever
# CentOS-5
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5
protect=1
priority=1
gdb调试qemu和virglrenderer

在host主机上gdb debug跟踪qemu和virglrender。这里的-vga none参数有时会导致guest虚机启动后没有画面,需要先去除-vga none启动一次虚机,再带-vga none重启虚机

gdb --args env LD_PRELOAD=/root/install/virglrenderer/build/src/libvirglrenderer.so.1 \
/root/project/qemu/build/qemu-system-x86_64 \-enable-kvm \-smp 4 \-m 8G \-device virtio-serial \-chardev spicevmc,id=vdagent,debug=0,name=vdagent \-device virtserialport,chardev=vdagent,name=com.redhat.spice.0 \-drive file=/root/ubuntu/ubuntu2204.qcow2,if=virtio \-spice port=8010,addr=172.17.84.241,disable-ticketing=on \-cpu host \-device virtio-gpu-gl \-display egl-headless,gl=on \-machine q35,accel=kvm,usb=on \-device usb-mouse \-vga none

gdb环境刚起来,首先需要在gdb环境中设置,然后再运行r命令

(gdb) handle SIGUSR1 nostop noprint
Signal        Stop      Print   Pass to program Description
SIGUSR1       No        No      Yes             User defined signal 1

然后我这里设置了一个断点:

(gdb) b virgl_video_decode_bitstream
Breakpoint 1 at 0x7ffff7b83367: file ../src/virgl_video.c, line 2249.

然后我再guest中用vlc播放一个视频,host上virglrenderer中就会运行到断点处.

guest端debug

可以使用ffmpeg或者vlc来对视频进行编解码和播放。

gdb调试ffmpeg和mesa

同样,设置mesa中的断点,比如virgl_video_decode_bitstream(),然后用vlc播放视频,便会执行到断点处。

h264流程

h264编码

测试命令:

ffmpeg -vaapi_device /dev/dri/renderD128 -i ../test.mp4 -vf 'format=nv12,hwupload' -c:v h264_vaapi ../output264.mp4

(virglrenderer)virgl_video.c中h264的encode bitstream大体流程:
在这里插入图片描述

h264解码

测试命令,我这里直接用vlc播放刚才编码的h264格式的视频

vlc output264.mp4

经常会出现中间打断vlc播放的话,画面直接卡住(也不是每次必现)

(virglrenderer)virgl_video.c中h264的decode逻辑:
在这里插入图片描述

h265流程

h265编码

测试命令:

/ffmpeg -vaapi_device /dev/dri/renderD128 -i ../test.mp4 -vf 'format=nv12,hwupload' -c:v hevc_vaapi ../out265.mp4

(virglrenderer)virgl_video.c中h265_encode_bitstream代码逻辑:

在这里插入图片描述

使用如下命令./ffmpeg/ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -i test.mp4 -vf 'format=nv12,hwupload' -c:v hevc_vaapi test.h265进行h265转码,生成test.h265文件。

./ffmpeg/ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -i test.mp4 -vf 'format=nv12,hwupload' -c:v hevc_vaapi test.h265
ffmpeg version N-109535-gfcd557a2c2 Copyright (c) 2000-2023 the FFmpeg developersbuilt with gcc 11 (Ubuntu 11.3.0-1ubuntu1~22.04)configuration: libavutil      57. 43.100 / 57. 43.100libavcodec     59. 56.100 / 59. 56.100libavformat    59. 34.102 / 59. 34.102libavdevice    59.  8.101 / 59.  8.101libavfilter     8. 53.100 /  8. 53.100libswscale      6.  8.112 /  6.  8.112libswresample   4.  9.100 /  4.  9.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4':Metadata:major_brand     : mp42minor_version   : 0compatible_brands: mp41isomcreation_time   : 2022-11-25T01:53:42.000000ZDuration: 00:01:18.88, start: 0.000000, bitrate: 6544 kb/sStream #0:0[0x1](und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 6346 kb/s, 30.30 fps, 30 tbr, 30302 tbn (default)Metadata:creation_time   : 2022-11-25T01:53:42.000000Zhandler_name    : VideoHandlervendor_id       : [0][0][0][0]encoder         : AVC CodingStream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 193 kb/s (default)Metadata:creation_time   : 2022-11-25T01:53:42.000000Zhandler_name    : SoundHandlervendor_id       : [0][0][0][0]
Stream mapping:Stream #0:0 -> #0:0 (h264 (native) -> hevc (hevc_vaapi))
Press [q] to stop, [?] for help
[hevc_vaapi @ 0x55eb4baeab00] Driver does not advertise encoder features, using guessed defaults.
[hevc_vaapi @ 0x55eb4baeab00] Driver does not advertise encoder block size, using guessed defaults.
[hevc_vaapi @ 0x55eb4baeab00] No quality level set; using default (25).
[hevc_vaapi @ 0x55eb4baeab00] Driver does not support some wanted packed headers (wanted 0xd, found 0x1).
Output #0, hevc, to 'test.h265':Metadata:major_brand     : mp42minor_version   : 0compatible_brands: mp41isomencoder         : Lavf59.34.102Stream #0:0(und): Video: hevc (Main), vaapi(progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 30 fps, 30 tbn (default)Metadata:creation_time   : 2022-11-25T01:53:42.000000Zhandler_name    : VideoHandlervendor_id       : [0][0][0][0]encoder         : Lavc59.56.100 hevc_vaapi
frame= 2368 fps= 41 q=-0.0 Lsize=   16339kB time=00:01:18.90 bitrate=1696.5kbits/s dup=0 drop=22 speed=1.35x    
video:16339kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%

过程中,virglrenderer支持该过程。然后使用ffplay正常播放test.h265,使用ffprobe查看test.h265文件信息

root@pc:~# ./ffmpeg/ffprobe test.h265 
Input #0, hevc, from 'test.h265':Duration: N/A, bitrate: N/AStream #0:0: Video: hevc (Main), yuv420p(tv), 1920x1088, 25 fps, 25 tbr, 1200k tbn

h265解码

测试命令:

./ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -i ../out265.mp4 ../out265.yuv

(virglrenderer)virgl_video.c中h265的decode逻辑:
在这里插入图片描述

yuv编解码

使用rawvideo转码生成yuv

使用rawvideo生成yuv格式文件,该命令下ffmpeg中未使用vaapi,代码执行未经过host主机上的virglrenderer:

./ffmpeg -i ../test.mp4 -c:v rawvideo -pix_fmt yuv420p ../test.yuv

生成的test.yuv有6.9G大小。

用hevc_vaapi来进行转码,生成的test265.mp4是9.6M大小,目前用vlc测试播放是ok的

./ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -v verbose \
-f rawvideo -pix_fmt yuv420p -s:v 1920x1080 -r:v 30 -i ../test.yuv \
-vf 'format=nv12,hwupload' -c:v hevc_vaapi -b:v 4000k -maxrate 8000k \
-y ../test265.mp4

同样,使用h264_vaapi来进行编码后生成的文件用vlc播放也是没问题的。

使用vaapi转码生成yuv

使用vaapi来转码生成yuv格式,该命令会经过host主机上的virglrenderer:

./ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -i ../test.mp4 -pix_fmt yuv420p ../test.yuv

生成的test.yuv有6.9G大小。

如果用解码生成的test.yuv格式再转码生成mp4,生成的test265.mp4是9.4M大小:

./ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -v verbose \
-f rawvideo -pix_fmt yuv420p -s:v 1920x1080 -r:v 30 -i ../test.yuv \
-vf 'format=nv12,hwupload' -c:v hevc_vaapi -b:v 4000k -maxrate 8000k \
-y ../test265.mp4

经测试,也能正常vlc播放。

测试中发现如果在转yuv的命令中不带"-pix_fmt yuv420p"参数,则后面再转码生成test265.mp4则有39M大小,播放有失真。

MPEG4测试

ffmpeg中应该不支持mpeg4的vaapi加速。

./ffmpeg -i ../test.mp4 -c:v mepg4 ../testmpeg4.mp4,用该命令生成的视频质量一般。

./ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -i ../test.mp4 -c:v mpeg4 ../testmpeg4.mp4,该命令的话会经过host主机上的virglrenderer,同样生成的视频质量一般。

ffmpeg中支持的vaapi有:

encodersvaapi surface
H.262 / MPEG-2 part 2mpeg2_vaapi
H.264 / MPEG-4 part 10(AVC)h264_vaapi
H.265 / MPEG-H part 2(HEVC)h265_vaapi
MJPEG / JPEGmjpeg_vaapi
VP8vp8_vaapi
VP9vp9_vaapi

根据代码看,vaapi中也是不支持MPEG4的,for循环中判断PIPE_VIDEO_FROMAT_MEPG4会continue,但是最终还是会返回VA_STATUS_SUCCESS.

VAStatus
vlVaQueryConfigProfiles(VADriverContextP ctx, VAProfile *profile_list, int *num_profiles)
{struct pipe_screen *pscreen;enum pipe_video_profile p;VAProfile vap;if (!ctx)return VA_STATUS_ERROR_INVALID_CONTEXT;*num_profiles = 0;pscreen = VL_VA_PSCREEN(ctx);for (p = PIPE_VIDEO_PROFILE_MPEG2_SIMPLE; p <= PIPE_VIDEO_PROFILE_AV1_MAIN; ++p) {if (u_reduce_video_profile(p) == PIPE_VIDEO_FORMAT_MPEG4 && !debug_get_option_mpeg4())continue;if (vl_codec_supported(pscreen, p, false) ||vl_codec_supported(pscreen, p, true)) {vap = PipeToProfile(p);if (vap != VAProfileNone)profile_list[(*num_profiles)++] = vap;}}/* Support postprocessing through vl_compositor */profile_list[(*num_profiles)++] = VAProfileNone;return VA_STATUS_SUCCESS;
}

VC1测试

带-hwaccel vaapi参数将wmv9格式转h264

命令:

./ffmpeg/ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -i wmv.wmv -vf 'format=nv12,hwupload' -c:v h264_vaapi test.h264

效果:

其中会报个错:No support for codec wmv3 profile 1。编码过程中会经过virglrenderer(应该是h264经过的)

root@pc:~# ./ffmpeg/ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -i wmv.wmv -vf 'format=nv12,hwupload' -c:v h264_vaapi test.h264
[wmv3 @ 0x56333dad8500] Extra data: 8 bits left, value: 0
Input #0, asf, from 'wmv.wmv':Metadata:IsVBR           : 0MediaFoundationVersion: 2.112Duration: 00:01:02.37, start: 0.000000, bitrate: 1032 kb/sStream #0:0(eng): Video: wmv3 (Main) (WMV3 / 0x33564D57), yuv420p, 1280x720, 1024 kb/s, SAR 1:1 DAR 16:9, 24 fps, 24 tbr, 1k tbn
File 'test.h264' already exists. Overwrite? [y/N] y
[wmv3 @ 0x56333dae9a00] Extra data: 8 bits left, value: 0
[wmv3 @ 0x56333dae9a00] No support for codec wmv3 profile 1.
[wmv3 @ 0x56333dae9a00] Failed setup for format vaapi: hwaccel initialisation returned error.
Stream mapping:Stream #0:0 -> #0:0 (wmv3 (native) -> h264 (h264_vaapi))
Press [q] to stop, [?] for help
[wmv3 @ 0x56333dae9a00] No support for codec wmv3 profile 1.
[wmv3 @ 0x56333dae9a00] Failed setup for format vaapi: hwaccel initialisation returned error.
[h264_vaapi @ 0x56333daeb7c0] No quality level set; using default (20).
[h264_vaapi @ 0x56333daeb7c0] Driver does not support some wanted packed headers (wanted 0xd, found 0).
Output #0, h264, to 'test.h264':Metadata:IsVBR           : 0MediaFoundationVersion: 2.112encoder         : Lavf59.34.102Stream #0:0(eng): Video: h264 (High), vaapi(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 24 fps, 24 tbnMetadata:encoder         : Lavc59.56.100 h264_vaapi
frame= 1497 fps= 50 q=-0.0 Lsize=   19644kB time=00:01:02.33 bitrate=2581.7kbits/s speed= 2.1x    
video:19644kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%

然后播放到也正常

root@pc:~# ./ffmpeg/ffprobe test.h264 
Input #0, h264, from 'test.h264':Duration: N/A, bitrate: N/AStream #0:0: Video: h264 (High), yuv420p(progressive), 1280x720, 25 fps, 25 tbr, 1200k tbn
root@pc:~# ./ffmpeg/ffplay test.h264

不带-hwaccel vaapi参数

./ffmpeg/ffmpeg  -vaapi_device /dev/dri/renderD128 -i wmv.wmv -vf 'format=nv12,hwupload' -c:v h264_vaapi testwmv.mp4

转码也会经过virglrenderer。

root@pc:~# ./ffmpeg/ffmpeg -vaapi_device /dev/dri/renderD128 -i wmv.wmv -vf 'format=nv12,hwupload' -c:v h264_vaapi test.h264
[wmv3 @ 0x562019a69300] Extra data: 8 bits left, value: 0
Input #0, asf, from 'wmv.wmv':Metadata:IsVBR           : 0MediaFoundationVersion: 2.112Duration: 00:01:02.37, start: 0.000000, bitrate: 1032 kb/sStream #0:0(eng): Video: wmv3 (Main) (WMV3 / 0x33564D57), yuv420p, 1280x720, 1024 kb/s, SAR 1:1 DAR 16:9, 24 fps, 24 tbr, 1k tbn
File 'test.h264' already exists. Overwrite? [y/N] y
[wmv3 @ 0x562019a7a7c0] Extra data: 8 bits left, value: 0
Stream mapping:Stream #0:0 -> #0:0 (wmv3 (native) -> h264 (h264_vaapi))
Press [q] to stop, [?] for help
[h264_vaapi @ 0x562019a7c580] No quality level set; using default (20).
[h264_vaapi @ 0x562019a7c580] Driver does not support some wanted packed headers (wanted 0xd, found 0).
Output #0, h264, to 'test.h264':Metadata:IsVBR           : 0MediaFoundationVersion: 2.112encoder         : Lavf59.34.102Stream #0:0(eng): Video: h264 (High), vaapi(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 24 fps, 24 tbnMetadata:encoder         : Lavc59.56.100 h264_vaapi
frame= 1497 fps= 41 q=-0.0 Lsize=   19644kB time=00:01:02.33 bitrate=2581.7kbits/s speed=1.72x      
video:19644kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%

查看其编码信息

root@pc:~# ./ffmpeg/ffprobe test.h264 
Input #0, h264, from 'test.h264':Duration: N/A, bitrate: N/AStream #0:0: Video: h264 (High), yuv420p(progressive), 1280x720, 25 fps, 25 tbr, 1200k tbn

测试遇到的一些问题:

  • 每次改变remote viewer窗口的大小,guest虚机图形界面都会被自动lock,需要重新输入密码登录才可以。

  • vlc播放视频时,有时会花屏,有时会卡死。

相关文章:

视频编解码(一)之virtio-gpu环境搭建

一、基础概念 VA-API Video Acceleration API 是一组开源应用API接口&#xff0c;赋能应用&#xff08;比如VLC播放器、GStreamer等&#xff09;使用hardware video acceleration&#xff08;一般是GPU提供硬件视频加速功能&#xff09;&#xff0c;VA-API主要由开源库libva和…...

JDBC概述三(批处理+事务操作+数据库连接池)

一&#xff08;批处理&#xff09; 1.1 批处理简介 批处理&#xff0c;简而言之就是一次性执行多条SQL语句&#xff0c;在一定程度上可以提升执行SQL语句的速率。批处理可以通过使用Java的Statement和PreparedStatement来完成&#xff0c;因为这两个语句提供了用于处理批处理…...

MappedByteBuffer 详解(图解+秒懂+史上最全)

背景&#xff1a; 在尼恩视频版本里&#xff0c;从架构师视角&#xff0c;尼恩为大家彻底介绍 rocketmq 高可用、高并发中间件的原理与实操。 给大家底层的解读清楚 rocketmq 架构设计、源码设计、工业级高可用实操&#xff0c;含好多复杂度非常高、又非常核心的概念&#xff…...

顶点程序经典案例——树木生长

树木生长Shader一、介绍 大家好&#xff0c;我是阿赵。这次来做一个树木生长的Shader。 顶点程序作为整个渲染管线里面和片段程序并列的两大可控过程之一&#xff0c;一直存在感都比较低。我们平时制作的效果&#xff0c;很多都是在片段程序里面实现的计算&#xff0c;顶点程序…...

在云计算环境下保护Java应用程序的有效措施

云计算&#xff08;Cloud&#xff09;技术是近年来计算机科学的一个重要突破。大多数组织已经通过将自己的应用程序移入云平台而获益。不过&#xff0c;如何保证应用程序在第三方服务器上的安全性&#xff0c;是一项艰巨的挑战。 在本文中&#xff0c;我们将重点讨论Java&…...

vscode-markdown-代码片段及快捷键设置

代码片段及快捷键设置 主要为了插入表格和图片标签节约一点输入时间 代码片段设置 ctrlshiftp 打开面板输入 configure user snippets选择markdowncopy如下设置放入{}中 "tb4*4": {"prefix": "tb4*4","body": ["| $1 | $2 | $…...

ModelNet40数据集

跑PointNet,modelnet40数据集时; 有些人直接用.off文件;——【CAD模型】普林斯顿形状Banchmark中的.off文件遵循以下标准&#xff1a; OFF文件全是以OFF关键字开始的ASCII文件。下一行说明顶点的数量、面片的数量、边的数量。 边的数量可以安全地省略。对模型不会有影响(可以为…...

【都2023年了,还在问网络安全怎么入门】

前言 【都2023年了&#xff0c;还在问网络安全怎么入门】所以这一期就出一一个怎么学习网络安全的学习路线和方法&#xff0c;觉得有用的话点赞收藏下 首先咱们聊聊&#xff0c;学习网络安全方向通常会有哪些问题 1、打基础时间太长 学基础花费很长时间&#xff0c;光语言都有…...

Apple Xcode 14.3 (14E222b) 正式版发布下载

Command Line Tools for Xcode 14, tvOS 16 & watchOS 9 Simulator Runtime 请访问原文链接&#xff1a;https://sysin.org/blog/apple-xcode-14/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Xcode 14 包含了在所有 Ap…...

【Linux】sar常用选项介绍

sar 使用 安装sysstat apt-get install sysstat -y #或 yum install sysstat -y选项 用法: sar [ 选项 ] [ <时间间隔> [ <次数> ] ] 选项&#xff1a; [ -A ] [ -B ] [ -b ] [ -C ] [ -D ] [ -d ] [ -F [ MOUNT ] ] [ -H ] [ -h ] [ -p ] [ -q ] [ -r [ ALL ] ]…...

PHP 单笔转账到支付宝账户,支付宝公钥证书实现版本

支付宝某些业务只能使用公钥证书方式来验签 如&#xff1a;即使转账 红包等 笔者就要实现这样一个功能&#xff0c;【单笔转账到支付宝账户】&#xff0c;采用支付宝公钥证书签名来实现。 话不多说&#xff0c;流程先走起 第一步&#xff1a;下载支付宝秘钥生成器 由于我们使…...

第十四届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组 E 题

颜色平衡树问题描述格式输入格式输出样例输入样例输出评测用例规模与约定解析参考程序问题描述 格式输入 输入的第一行包含一个整数 n &#xff0c;表示树的结点数。 接下来 n 行&#xff0c;每行包含两个整数 Ci , Fi&#xff0c;用一个空格分隔&#xff0c;表示第 i 个结点 …...

Python 小型项目大全 21~25

二十一、DNA 可视化 原文&#xff1a;http://inventwithpython.com/bigbookpython/project21.html 脱氧核糖核酸是一种微小的分子&#xff0c;存在于我们身体的每个细胞中&#xff0c;包含着我们身体如何生长的蓝图。它看起来像一对核苷酸分子的双螺旋结构&#xff1a;鸟嘌呤、…...

MinIO从信息泄漏到RCE

文章目录信息泄露漏洞利用漏洞分析漏洞修复RCE漏洞分析参考文章信息泄露 漏洞利用 如果MinIO以集群方式部署&#xff0c;存在信息泄露漏洞&#xff0c;攻击者可以通过HTTP请求获取目标进程的所有环境变量&#xff0c;包括MINIO_SECRET_KEY和MINIO_ROOT_PASSWORD. vulhub有环…...

202.Spark(九):SparkStreaming案例实操

目录 一、启动zookeeper,kafka基础环境 二、项目导好jar包,并且创建源数据,并在kafka中测试能否消费到数据...

GlusterFS(GFS)分布式文件系统

目录 一.文件系统简介 1.文件系统的组成 2.文件系统的作用 3.文件系统的挂载使用 二.GlusterFS概述 1.GlusterFS是什么&#xff1f; 2.GlusterFS的特点 3.GlusterFS术语介绍 3.1 Brick&#xff08;存储块&#xff09; 3.2 Volume&#xff08;逻辑卷&#xff09; 3.3…...

ChatGPT文本框再次升级,打造出新型操作系统

在ChatGPT到来之前&#xff0c;没有谁能够预见。但是&#xff0c;它最终还是来了&#xff0c;并引起了不小的轰动&#xff0c;甚至有可能颠覆整个行业。 从某种程度上说&#xff0c;ChatGPT可能是历史上增长最快的应用程序&#xff0c;仅在两个多月就拥有了1亿多活跃用户&…...

DPU02国产USB转UART控制芯片替代CP2102

目录DPU02简介DPU02芯片特性应用DPU02简介 DPU02是高度集成的USB转UART的桥接控制芯片&#xff0c;该芯片为RS-232设计更新为USB设计&#xff0c;并简化PCB组件空间提供了一个简单的解决方案。       DPU02包括了一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带…...

Softing新版HART多路复用器软件支持西门子控制器

用于访问配置和诊断数据的HART多路复用器软件——Softing smartLink SW-HT&#xff0c;现在支持西门子的ET200远程IO和FDT/DTM接口。 smartLink SW-HT是一个基于Docker容器的软件应用。通过该软件&#xff0c;用户可以快速地访问以太网远程IO的HART设备&#xff0c;并且无需额外…...

〖Python网络爬虫实战⑫〗- XPATH语法介绍

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付费…...

实例方法、类方法、静态方法、实例属性、类属性

背景&#xff1a;今天在复习类相关知识的时候&#xff0c;突然想到这几种类型的方法的区别和用法&#xff0c;感觉有点模棱两可&#xff0c;于是总结一下&#xff0c;加深记忆。 定义&#xff1a;想要区别和理解几种方法&#xff0c;首先要定义一个类&#xff0c;要在类中加深…...

数据结构---二叉树

专栏&#xff1a;数据结构 个人主页&#xff1a;HaiFan. 专栏简介&#xff1a;这里是HaiFan.的数据结构专栏&#xff0c;今天的内容是二叉树。 二叉树树的概念及结构二叉树概念及结构二叉树的概念二叉树的存储结构二叉树的顺序结构及实现大根堆和小根堆堆的实现及其各个接口堆的…...

CMake——从入门到百公里加速6.7s

目录 一、前言 二、HelloWorld 三、CMAKE 界面 3.1 gui正则表达式 3.2 GUI构建 四 关键字 4.1 add_library 4.2 add_subdirectory 4.3 add_executable 4.4 aux_source_directory 4.5 SET设置变量 4.6 INSTALL安装 4.7 ADD_LIBRARY 4.8 SET_TARGET_PROPERTIES 4.9…...

无公网IP,在外公网远程访问RabbitMQ服务「内网穿透」

文章目录前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基础上…...

Node【二】NPM

文章目录&#x1f31f;前言&#x1f31f;NPM使用&#x1f31f;NPM使用场景&#x1f31f;NPM的常用命令&#x1f31f;NPM命令使用介绍&#x1f31f; 使用NPM安装模块&#x1f31f; 下载三方包&#x1f31f; 全局安装VS本地安装&#x1f31f; 本地安装&#x1f31f; 全局安装&…...

【2023最新】超详细图文保姆级教程:App开发新手入门(2)

上章节我们已经成功的创建了一个 App 项目&#xff0c;接下来我们讲述一下&#xff0c;如何导入项目、编辑代码和提交项目代码。 Let’s Go! 4. 项目导入 当用户创建一个新的应用时&#xff0c;YonStudio 开发工具会自动导入模板项目的默认代码&#xff0c;不需要手动进行代…...

sftp使用

Client端使用Server端的账户username&#xff0c;sftp登录Server&#xff0c;除了IP地址&#xff0c;也可以使用/etc/hosts定义的域名&#xff0c;注意&#xff0c;Client的默认路径&#xff1a;Shell中的当前路径&#xff0c;Server的默认路径&#xff1a;server账户家目录 ​…...

FastGithub---------不再为访问github苦恼

声明&#xff1a;只解决github加速神器&#xff0c;解决github打不开、用户头像无法加载、releases无法上传下载、git-clone、git-pull、git-push失败等问题。 github为什么打不开&#xff1f; 其实不用加速的情况下&#xff0c;使用5G是可以打开的&#xff0c;只是资源加载…...

Spring Boot AOP @Pointcut拦截注解的表达式与运算符

项目场景&#xff1a; 这里主要说下Spring Boot AOP中Pointcut拦截类上面的注解与方法上面的注解&#xff0c;怎么写表达式怎么&#xff0c;还有Pointcut中使用运算符。 PointCut 表达式 拦截注解的表达式有3种&#xff1a;annotation、within、target 1、annotation 匹配有…...

2023年第十四届蓝桥杯javaB组省赛真题

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;练习时长两年半的java博主 &#x1f4d6;个人主页&#xff1a;君临๑ &#x1f39e;️文章介绍&#xff1a;2023年第十四届蓝桥杯javaB组省赛真题 &#x1f389;所属专栏&#xff1a;算法专栏 &#x1f381; ps&#xff1a;点…...