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

news2024/11/28 8:45:29

一、基础概念

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.so


root@pc:~# dpkg -L intel-media-va-driver
/usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so


root@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/renderD128

Signed-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_callbacks
          renderer_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_VIDEO
    if (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++ bison
 apt install libncurses-dev
 apt install flex
 apt install libssl-dev
 apt install libelf-dev
 apt install meson
 apt install git
 apt install pkg-config
 apt install cmake
 apt install mesa-vdpau-drivers
 apt install libvdpau-dev
 apt install glslang-dev
 apt install glslang-tools
 apt install libva-dev
 apt-get install python3 python3-pip python3-setuptools python3-wheel ninja-build
 pip3 install meson -i https://pypi.tuna.tsinghua.edu.cn/simple
 apt install libomxil-bellagio-dev
 apt install rust-all
 apt install libclc-dev
 apt install libzstd-dev
 apt install libdrm-dev
 apt install llvm-dev
 dpkg -i libllvmspirvlib14_14.0.0-5_amd64.deb
 dpkg -i libllvmspirvlib-14-dev_14.0.0-5_amd64.deb
 apt install libclang-cpp-dev
 apt install wayland-protocols
 apt install libwayland-egl-backend-dev
 apt install libxext-dev
 apt install libxfixes-dev
 apt install libxcb-glx0-dev
 apt install libxcb-shm0-dev
 apt install libx11-xcb-dev
 apt install libxcb-dri2-0-dev
 apt install libxcb-dri3-dev
 apt install libxcb-present-dev
 apt install libxshmfence-dev
 apt install libxxf86vm-dev
 apt install libxrandr-dev
 apt install python3-codegen
 apt install libclang-dev
 apt install bindgen
 apt 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 entrypoints
      VAProfileH264ConstrainedBaseline:    VAEntrypointVLD
      VAProfileH264ConstrainedBaseline:    VAEntrypointEncSlice
      VAProfileH264Main               :    VAEntrypointVLD
      VAProfileH264Main               :    VAEntrypointEncSlice
      VAProfileH264High               :    VAEntrypointVLD
      VAProfileH264High               :    VAEntrypointEncSlice
      VAProfileHEVCMain               :    VAEntrypointVLD
      VAProfileHEVCMain               :    VAEntrypointEncSlice
      VAProfileNone                   :    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 developers
  built with gcc 11 (Ubuntu 11.3.0-1ubuntu1~22.04)
  configuration: 
  libavutil      57. 43.100 / 57. 43.100
  libavcodec     59. 56.100 / 59. 56.100
  libavformat    59. 34.102 / 59. 34.102
  libavdevice    59.  8.101 / 59.  8.101
  libavfilter     8. 53.100 /  8. 53.100
  libswscale      6.  8.112 /  6.  8.112
  libswresample   4.  9.100 /  4.  9.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: mp41isom
    creation_time   : 2022-11-25T01:53:42.000000Z
  Duration: 00:01:18.88, start: 0.000000, bitrate: 6544 kb/s
  Stream #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.000000Z
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
      encoder         : AVC Coding
  Stream #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.000000Z
      handler_name    : SoundHandler
      vendor_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     : mp42
    minor_version   : 0
    compatible_brands: mp41isom
    encoder         : Lavf59.34.102
  Stream #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.000000Z
      handler_name    : VideoHandler
      vendor_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/A
  Stream #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           : 0
    MediaFoundationVersion: 2.112
  Duration: 00:01:02.37, start: 0.000000, bitrate: 1032 kb/s
  Stream #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           : 0
    MediaFoundationVersion: 2.112
    encoder         : Lavf59.34.102
  Stream #0:0(eng): Video: h264 (High), vaapi(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 24 fps, 24 tbn
    Metadata:
      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/A
  Stream #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           : 0
    MediaFoundationVersion: 2.112
  Duration: 00:01:02.37, start: 0.000000, bitrate: 1032 kb/s
  Stream #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           : 0
    MediaFoundationVersion: 2.112
    encoder         : Lavf59.34.102
  Stream #0:0(eng): Video: h264 (High), vaapi(tv, progressive), 1280x720 [SAR 1:1 DAR 16:9], q=2-31, 24 fps, 24 tbn
    Metadata:
      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/A
  Stream #0:0: Video: h264 (High), yuv420p(progressive), 1280x720, 25 fps, 25 tbr, 1200k tbn

测试遇到的一些问题:

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/428642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习算法系列(三)

机器学习算法之–对数几率回归&#xff08;逻辑斯蒂回归&#xff09;算法 上个算法&#xff08;算法系列二&#xff09;介绍了如何使用线性模型进行回归学习&#xff0c;但若要做的是分类任务&#xff0c;则需要找一个单调可微函数将分类任务的真实标记y与线性回归模型的预测值…

Scons自动大型系统构建工具

1、先了解一下make 在Linux系统上做过c/c++开发的同学们都知道一个项目工程管理工具:make和Makefile。 make 这个工具自上个世纪 70 年代 Stuart Feldman 在贝尔实验室开发出以来,就一直是类 UNIX 程序员的最爱之一。 通过检查文件的修改时间,make 工具可以知道编译目标文…

关于原子服务的思考

在我们以往的工作中经常会遇到“原子服务”或“原子化服务”的概念&#xff0c;如果没有一个清晰的概念边界&#xff0c;会使大家的沟通和讨论无法在同一个共识上展开&#xff0c;大家不在同一频道上&#xff0c;割裂于不同的领域空间&#xff0c;难以产生一致性的进展。那么&a…

SAR ADC系列26:系统设计

目录 串一下知识点&#xff1a; 设计一个高速异步SAR ADC 设计目标&#xff1a; 电路架构&#xff1a;&#xff08;具体电路看前文&#xff09; 采样网络&#xff1a; 采样电容&#xff1a; CDAC开关切换策略&#xff1a; CDAC阵列冗余设计&#xff1a; SAR 逻辑 比…

谈谈内存模型happen-before讲的什么?

大家好我是易安&#xff01; 今天我要讲述的是Java内存模型中的happen-before。 Java语言在设计之初就引入了线程的概念&#xff0c;以充分利用现代处理器的计算能力。多线程机制既带来了强大、灵活的优势&#xff0c;也带来了线程安全等令人混淆的问题。在这种情况下&#xff…

二叉查找树

目录 一、二叉查找树概念 二、结点内部类代码实现&#xff1a; 三、二叉查找树的插入原理​编辑 四、遍历的方式&#xff08;中序遍历&#xff09;&#xff1a; 五、二叉查找树实现指定值删除对应的结点 六、main方法测试 一、二叉查找树概念 二、结点内部类代码实现&…

聚类问题的算法总结

目录 一、K-means算法 1、算法原理 2、如何确定K值 3、算法优缺点 二、DBScan聚类 1、算法原理 2、处理步骤 3、算法优缺点 聚类代码实现 聚类算法属于无监督学习&#xff0c;与分类算法这种有监督学习不同的是&#xff0c;聚类算法事先并不需要知道数据的类别标签&am…

高效释放数据价值,数智融合平台有门道

在数字经济时代&#xff0c;数据上升为新的关键生产要素&#xff0c;逐渐超越土地、资本等传统要素&#xff0c;成为社会经济发展和企业创新更加重要的驱动力。 但如何充分释放数据价值在当下依然是一个世界性难题。一方面&#xff0c;企业与组织逐渐拥有海量数据规模和丰富应…

基于CBC、ECB、CTR、OCF、CFB模式的AES加密算法

1、什么是AES加密算法 什么是加密算法&#xff1f;我在文章《从个人角度看什么是加密算法》中描述了我对加密算法的一些浅薄的理解。我不是信息安全领域的大神&#xff0c;只求有一个入门罢了&#xff01; 这篇文章是文章《从个人角度看什么是加密算法》的延伸&#xff0c;所…

【C++初阶】:缺省函数和函数重载

c入门一.缺省函数二.函数重载1.参数类型不同2.参数个数不同3.参数顺序不同一.缺省函数 缺省函数&#xff0c;顾名思义就是可以在传参时不传或者少传参数的函数。这里举个例子&#xff1a; 完全缺省 上面的就属于全缺省&#xff0c;可以不传任何参数&#xff0c;当然也可以传参…

Codeforces Round 862 (Div. 2) -- D. A Wide, Wide Graph(树的直径 贪心 简单的树形dp)

题目如下&#xff1a; 题意简说&#xff1a; 树上两点 u,vu, vu,v&#xff0c;如果 u,vu, vu,v 的距离大于等于 kkk 则在图 GkG_kGk​ 上 u,vu, vu,v 有一条无向边。 求当 kkk 等于 [1, n] 的时候&#xff0c;图 GkG_kGk​ 的连通块数量。 思路 or 题解&#xff1a; 我们可以…

【服务器】Dell PowerEdge R750 安装GPU

各种教程 官方教程 https://www.dell.com/support/manuals/zh-cn/poweredge-r750/per750_ism_pub/%E5%AE%89%E8%A3%85-gpu?guidguid-6bb1c301-7595-4c6d-b631-b6a5761c6052&langzh-cn 手册PDF版&#xff1a; https://dl.dell.com/content/manual16153190-dell-emc-powe…

OKR与敏捷开发的结合

当你想达成某件事情时&#xff0c;你在内心会有一个设想的期望结果。这是一个非常简单、基本的概念&#xff0c;并且是从很多人小时候就培养起来的。我们可以将这种现象总结一句话&#xff1a; 通过 ________ 来衡量__________ 。 这就是 John Doerr 在其著作《Measure what Ma…

JavaWeb开发 —— Maven

目录 一、概述 1. 介绍 2. 安装 二、maven-idea 集成 1. 配置及创建Maven项目 2. IDEA 创建Maven项目 3. IDEA导入 Maven 项目 三、依赖管理 1. 依赖配置 2. 依赖传递 3. 依赖范围 4. 生命周期 一、概述 1. 介绍 ① Apache Maven 是一个项目管理和构建工…

【UDP报文和TCP协议特性】

目录1.UDP报文1.1报文长度1.2校验和2.TCP协议特性2.1确认应答2.2超时重传2.3连接管理2.3.1三次握手2.3.2四次挥手2.4滑动窗口2.5流量控制2.6拥塞控制2.7延时应答2.8捎带应答2.9面向字节流2.10异常情况3.小结3.1tcp小结3.2tcp和UDp应用场景的差异4.寄语1.UDP报文 udp是传输层最…

【Android】之【内存管理】

一、Android内存运行是如何运行的&#xff1f; 物理内存即移动设备上的ram&#xff0c;当启动一个android程序时&#xff0c;会启动一个dalvik vm进程&#xff0c;系统会给它分配固定的内存空间【16m,32m,64m,不定&#xff0c;没有统一标准&#xff0c;每个虚拟机会有堆内存阈…

【Minecraft开服教程】使用 MCSM 面板一键搭建我的世界服务器,并内网穿透公网远程联机

文章目录前言1.Mcsmanager安装2.创建Minecraft服务器3.本地测试联机4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射内网端口5.远程联机测试6. 配置固定远程联机端口地址6.1 保留一个固定TCP地址6.2 配置固定TCP地址7. 使用固定公网地址远程联机前言 MCSManager是一个开源…

C++ float 数据的保存格式

总体上&#xff0c;在计算机中&#xff0c; float 数据的的保存按照如下转换逻辑&#xff1a;10进制数 >二进制数>科学计数法二进制数>c 条件下下浮点数在内存中的保存格式&#xff08;这里面有个转换算法&#xff0c;需要理清楚&#xff09;。 下面举出一个案例&…

Python+selenium自动化测试实战项目(全面,完整,详细)

前言 之前的文章说过&#xff0c; 要写一篇自动化实战的文章&#xff0c; 这段时间比较忙再加回家过清明一直没有更新&#xff0c;今天整理一下实战项目的代码共大家学习。&#xff08;注:项目是针对我们公司内部系统的测试&#xff0c;只能内部网络访问&#xff0c;外部网络无…

使用fetch()异步请求API数据实现汇率转换器

任务8 https://segmentfault.com/a/1190000038998601 https://chinese.freecodecamp.org/news/how-to-master-async-await-with-this-real-world-example/ 跟随上面的指示&#xff0c;理解异步函数的编写&#xff0c;并且实现这个汇率转换器。 第一步&#xff1a;在工作区初始…