视频编解码(一)之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.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播放视频时,有时会花屏,有时会卡死。

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值