FFMPEG 硬件解码API介绍 您所在的位置:网站首页 drm硬解什么意思 FFMPEG 硬件解码API介绍

FFMPEG 硬件解码API介绍

2023-11-25 12:52| 来源: 网络整理| 查看: 265

https://zhuanlan.zhihu.com/p/168240163

软解和硬解的区别:

一般来说我们把使用CPU通用计算单元(无论是Intel还是AMD)就是软解;用专用芯片模组(GPU、QSV等)就是硬解。

主要区别:

底层接口不同、指令集不同、硬件驱动不同。

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是Intel提供的一套集显上的硬件加速方案。

那么,究竟要怎么知道系统当前的FFMPEG究竟支持哪些硬件库?

 

可以通过命令行查看:ffmpeg -hwaccel。在hardware acceleration methods:下面可以看到当前FFMPEG集成的硬解码库。

 

FFMPEG硬解码API:

软解码和硬解码差不多,FFMPEG硬件解码流程图:图中橙色部分是硬解码中有而软解码没有的部分:

 

硬解码Step1. 寻找硬解codec

AVCodec* avcodec_find_decoder_by_name(const char *name)

通过名字来寻找对应的AVCodec。每一个解码器的名字一定是全局唯一的,在AVCodec头文件中有相应的描述:

其实在FFMPEG内部每一个解码器codec都是一个结构体,维护了该解码器自己的信息、具体执行的函数等信息。比如Intel的QSV解码器(在libavcodec/qsvdec_h2645.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",

};

const AVCodecHWConfig * avcodec_get_hw_config (const AVCodec *codec, int index)

紧接着,调用这个函数去获取到该解码器codec的硬件属性,比如可以支持的目标像素格式等。而这个信息就存储在AVCodecHWConfig中:

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;

 

 

enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt);

这是一个回调函数,它的作用就是告诉解码器codec自己的目标像素格式是什么。在上一步骤获取到了硬解码器codec可以支持的目标格式之后,就通过这个回调函数告知给codec,具体做法:

enum AVPixelFormat get_hw_format(struct AVCodecContext *s, const enum AVPixelFormat *fmt) {

for (const enum AVPixelFormat *p = fmt; *p != -1; p++) {

if (*p == hw_pix_fmt) return *p;

}

return AV_PIX_FMT_NONE;

}

我们也可以通过阅读AVCodec结构内对于这个回调函数的定义,可以知道:

fmt是这个解码器codec支持的像素格式,且按照质量优劣进行排序;如果没有特别的需要,这个步骤是可以省略的。内部默认会使用“native”的格式。

* callback to negotiate the pixelFormat

* @param fmt is the list of formats which are supported by the codec, it is terminated by -1 as 0 is a valid format, the formats are ordered by quality. The first is always the native one.

* @note The callback may be called again immediately if initialization for the selected (hardware-accelerated) pixel format failed.

* @warning Behavior is undefined if the callback returns a value not in the fmt list of formats.

* @return the chosen format

* - encoding: unused

* - decoding: Set by user, if not set the native format will be chosen.

 

硬解码Step3. 准备和打开硬解码:

int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, const char *device, AVDictionary *opts, int flags)

这个函数的作用是,创建硬件设备相关的上下文信息AVHWDeviceContext,包括分配内存资源、对硬件设备进行初始化。

准备好硬件设备上下文AVHWDeviceContext后,需要把这个信息绑定到AVCodecContext,就可以像软解一样的流程执行解码操作了。

硬解码Step4. 取回数据:

按照一般软解的流程,在调用avcodec_receive_frame()之后,得到的数据其实还在硬件模组/芯片上,也就是说,如果是用CUDA解码,数据是在显存上(或者说是在显卡encoder/decoder的buffer上)的。对于很多应用而言,解码之后往往还要进行后续操作,比如保存成一幅幅图片之类的,那么就需要把数据取回。

int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags)

这个函数是负责在cpu内存和硬件内存(原文是hw surface)之间做数据交换的。也就是说,它不但可以把数据从硬件surface上搬回系统内存,反向操作也支持;甚至可以直接在硬件内存之间做数据交互。

 

 

 

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有