当前位置:萝卜系统 > 硬件软件教程 > 详细页面

如何用FFMPEGAPI做一般的硬解码与软解码?

如何用FFMPEGAPI做一般的硬解码与软解码?

更新时间:2023-07-02 文章作者:未知 信息来源:网络 阅读次数:

显卡是个人计算机基础的组成部分之一,将计算机系统需要的显示信息进行转换驱动显示器,并向显示器提供逐行或隔行扫描信号,控制显示器的正确显示,是连接显示器和个人计算机主板的重要组件,是“人机”的重要设备之一,其内置的并行计算能力现阶段也用于深度学习等运算。

写在前面

本文将介绍如何使用FFMPEG API进行硬件解码。如果您不熟悉解码过程,请先阅读:

我是Xiaobei Dig Haha:视频和视频帧:FFMPEG CPU解码API简介

图标

作者之前也看到过类似的问题:视频硬解码和软解码有什么区别?

本质上没有什么区别,该芯片用于执行编计算。

“软”和“硬”一词很容易引起歧义。从本质上讲,使用CPU通用计算单元(无论是Intel还是AMD)都是一种软解决方案。使用专用芯片模块(GPU,QSV等)是一个很难的解决方案。

因此产生了差异:基础接口不同,指令集不同,硬件驱动程序也不同。由此产生的问题很明显:

首先,因为CPU是通用计算单元,所以接口是通用的,并且可移植性好;专用芯片模块不能移植和互操作;其次,由于CPU接口是通用的,因此编中的许多细节都便于开发人员进行修改。专用的芯片模块,接口和驱动程序都是由不同的制造商提供的,并且其中许多都是非开源的,因此控制内部细节更加困难。最后,在实际测试中,当前使用CPU进行编码和解码的效果将优于专用芯片模块。但是,可以通过优化算法和芯片来解决此问题。这是制造商的业务,我们无法控制。

在现实生活中,是选择硬解码还是软解码?

这取决于不同的情况。例如:

CPU过剩,需要对解码过程进行精确控制,对解码算法进行优化,对通用性要求较高,直接使用软解决方案(即CPU解码);如果还有其他编芯片/模块,而CPU不足,则必须切换到硬解码(即专用芯片解码)。

本文将介绍如何使用FFMPEG API进行常规的硬解码。 “常规硬解码”是指主流FFMEG支持的硬解码类型。作者将结合自己在QSV和CUDA解码方面的经验,最后分享我所涉足的一些陷阱以及一些扩展方面的小问题。

I。 FFMPEG支持的硬解码

首先,让我们看一下FFMPEG原生支持哪些硬解码类型。列出AVHWDeviceType(libavutil / hwcontext.h)本机支持的所有硬解码类型:

enum AVHWDeviceType {
    AV_HWDEVICE_TYPE_NONE,
    AV_HWDEVICE_TYPE_VDPAU,
    AV_HWDEVICE_TYPE_CUDA,
    AV_HWDEVICE_TYPE_VAAPI,
    AV_HWDEVICE_TYPE_DXVA2,
    AV_HWDEVICE_TYPE_QSV,
    AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
    AV_HWDEVICE_TYPE_D3D11VA,
    AV_HWDEVICE_TYPE_DRM,
    AV_HWDEVICE_TYPE_OPENCL,
    AV_HWDEVICE_TYPE_MEDIACODEC,
};

上面的AV_HWDEVICE_TYPE_CUDA是作者当前正在使用的CUDA,是NVIDIA的硬件加速库,而AV_HWDEVICE_TYPE_QSV是以前的QSV,是英特尔提供的一组硬件加速解决方案。

ffmpeg解码流程_ffmpeg调用显卡编解码_ffmpeg多线程解码

那么,您如何知道当前FFMPEG支持哪些硬件库?

您可以通过命令行查看它:ffmpeg -hwaccel。在硬件加速方法中:您可以在下面看到当前的FFMPEG集成硬解码库。

然后,如果发现所需的硬件库不在当前的FFMPEG中,该怎么办?

答案是:您可能需要自己重新编译源代码。每个硬件解码库的集成方法都不同。如果是QSV,请参见

我是小贝挖哈哈:视频和视频帧:FFMPEG + Intel QSV硬件解决方案环境安装文章

图标

如果它是另一个硬解码库,请自己在Internet上搜索。 (作者将在稍后添加如何将CUDA库集成到FFMPEG中,敬请期待)

II。 FFMPEG硬解码API

硬解码步骤类似于软解码步骤。作者绘制了FFMPEG硬件解码流程图:图中的橙色部分是硬解码中包含的部分,软解码中没有。该图的灵感来自博客“ FFmpeg示例硬件解码hw_decode”,这篇文章是推荐的,简洁的和详细的。

ffmpeg调用显卡编解码

ffmpeg调用显卡编解码

FFMPEG硬解码流程图

接下来,我将详细介绍上图的橙色部分以及与硬解码有关的API函数。

硬解码步骤1.查找硬解码codec编实现的名称。该名称在编码器和之间是全局唯一的(但编码器和可以共享相同的名称)。这是从用户角度查找编的主要方法。

实际上,FFMPEG中的每个编都是一种结构,它维护自己的信息,特定功能和其他信息。例如,英特尔的QSV(在libavcodec / qsvdec_h264 5. c中)为:

AVCodec ff_h264_qsv_decoder = {
    .name = "h264_qsv",
    .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration)"),
    .priv_data_size = sizeof(QSVH2645Context),
    .type = AVMEDIA_TYPE_VIDEO,
    .id = AV_CODEC_ID_H264,
    .init = qsv_decode_init,
    .decode = qsv_decode_frame,
    .flush = qsv_decode_flush,
    .close = qsv_decode_close,
    .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID,
    .priv_class = &class,
    .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12,
 AV_PIX_FMT_P010,
 AV_PIX_FMT_QSV,
 AV_PIX_FMT_NONE },
    .hw_configs = ff_qsv_hw_configs,
    .bsfs = "h264_mp4toannexb",
    .wrapper_name = "qsv",
};

ffmpeg调用显卡编解码_ffmpeg解码流程_ffmpeg多线程解码

您可以看到此编支持的编ID为AV_CODEC_ID_H264,支持的目标像素格式为{AV_PIX_FMT_NV12,AV_PIX_FMT_P010,AV_PIX_FMT_QSV,AV_PIX_FMT_NONE}。

是的,硬件与通用不同,只能支持有限的目标像素格式。

让我们看一下CUDA(在libavcodec / cuviddec.c中)。同样,它只能支持有限的目标像素格式:

 AVCodec ff_##x##_cuvid_decoder = { \
        .name = #x "_cuvid", \
        .long_name = NULL_IF_CONFIG_SMALL("Nvidia CUVID " #X " decoder"), \
        .type = AVMEDIA_TYPE_VIDEO, \
        .id = AV_CODEC_ID_##X, \
        .priv_data_size = sizeof(CuvidContext), \
        .priv_class = &x##_cuvid_class, \
        .init = cuvid_decode_init, \
        .close = cuvid_decode_end, \
        .decode = cuvid_decode_frame, \
        .receive_frame = cuvid_output_frame, \
        .flush = cuvid_flush, \
        .bsfs = bsf_name, \
        .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
        .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \
 AV_PIX_FMT_NV12, \
 AV_PIX_FMT_P010, \
 AV_PIX_FMT_P016, \
 AV_PIX_FMT_NONE }, \
        .hw_configs = cuvid_hw_configs, \
        .wrapper_name = "cuvid", \
    };

硬解码步骤2.找到硬解目标像素

在上一节中,我了解到一个事实:硬解码编支持的目标像素是有限的,并且它们可能不相同。因此,在找到经过硬解码的编之后,您必须设置其目标像素(像素格式)。

enum AVHWDeviceType {
 AV_HWDEVICE_TYPE_NONE,
 AV_HWDEVICE_TYPE_VDPAU,
 AV_HWDEVICE_TYPE_CUDA,
 AV_HWDEVICE_TYPE_VAAPI,
 AV_HWDEVICE_TYPE_DXVA2,
 AV_HWDEVICE_TYPE_QSV,
 AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
 AV_HWDEVICE_TYPE_D3D11VA,
 AV_HWDEVICE_TYPE_DRM,
 AV_HWDEVICE_TYPE_OPENCL,
 AV_HWDEVICE_TYPE_MEDIACODEC,
 AV_HWDEVICE_TYPE_VULKAN,
};

此类型和名称之间的关系表要简单得多。它由FFMPEG代码中的hw_type_names关系表维护(在libavutil / hwcontext.c文件中定义):

static const char *const hw_type_names[] = {
  [AV_HWDEVICE_TYPE_CUDA]   = "cuda",
  [AV_HWDEVICE_TYPE_DRM]    = "drm",
  [AV_HWDEVICE_TYPE_DXVA2]  = "dxva2",
  [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va",
  [AV_HWDEVICE_TYPE_OPENCL] = "opencl",
  [AV_HWDEVICE_TYPE_QSV]    = "qsv",
  [AV_HWDEVICE_TYPE_VAAPI]  = "vaapi",
  [AV_HWDEVICE_TYPE_VDPAU]  = "vdpau",
  [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",
  [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",
  [AV_HWDEVICE_TYPE_VULKAN] = "vulkan",
};

 typedef struct AVCodecHWConfig {
 /**
 * A hardware pixel format which the codec can use. !!!硬解码codec支持的像素格式!!!
 */
 enum AVPixelFormat pix_fmt;
 /**
 * Bit set of AV_CODEC_HW_CONFIG_METHOD_* flags, describing the possible
 * setup methods which can be used with this configuration.
 */
 int methods;
 /**
 * The device type associated with the configuration.
 *
 * Must be set for AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX and
 * AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, otherwise unused.
 */
 enum AVHWDeviceType device_type;
} AVCodecHWConfig;


本文来自本站,转载请注明本文网址:
http://www.pc-fly.com/a/shenmilingyu/article-372911-1.html



温馨提示:喜欢本站的话,请收藏一下本站!

本类教程下载

系统下载排行

网站地图xml | 网站地图html