使用 C++ 中的 ffmpeg hwaccel

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5985273/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:17:20  来源:igfitidea点击:

using ffmpeg hwaccel from C++

c++ffmpeghardware-acceleration

提问by ronag

How do I decode a file with hardware acceleration with ffmpeg?

如何使用 ffmpeg 使用硬件加速解码文件?

I have written a working video player that uses ffmpeg. I have checked for support using "av_hwaccel_next"and found mpeg2_dxva.

我编写了一个使用 ffmpeg 的工作视频播放器。我已经检查了使用支持"av_hwaccel_next"并找到了mpeg2_dxva.

However, when I load an mpeg2 file (as usual) I do not get any hardware acceleration. AVCodecContext->hwacceland AVCodecContext->hwaccelcontextare both null.

但是,当我加载一个 mpeg2 文件(像往常一样)时,我没有得到任何硬件加速。AVCodecContext->hwaccel并且AVCodecContext->hwaccelcontext都是空的。

Do I have to pass some flag somewhere in order to enable hw-acceleration?

我是否必须在某处传递一些标志才能启用硬件加速?

I haven't been able to find any information regarding this, anyone know of a good source?

我一直无法找到有关此的任何信息,有人知道好的来源吗?

回答by osgx

Start from reading ffmpeg documentation: https://trac.ffmpeg.org/wiki/HWAccelIntroand better answer How to use hardware acceleration with ffmpeg(and for linux check page https://wiki.archlinux.org/index.php/Hardware_video_acceleration)

从阅读 ffmpeg 文档开始:https: //trac.ffmpeg.org/wiki/HWAccelIntro和更好的答案如何使用 ffmpeg 的硬件加速(以及 linux 检查页面https://wiki.archlinux.org/index.php/Hardware_video_acceleration)

When using FFmpeg the tool, HW-assisted decoding is enabled using through the -hwacceloption, which enables a specific decoder. Each decoder may have specific limitations (for example an H.264 decoder may only support baseline profile). HW-assisted encoding is enabled through the use of a specific encoder (for example h264_nvenc). Filtering HW-assisted processing is only supported in a few filters .. There are several hardware acceleration standards API, some of which are supportedto some extent by FFmpeg.

使用 FFmpeg 工具时,通过-hwaccel启用特定解码器的选项启用硬件辅助解码。每个解码器可能有特定的限制(例如,H.264 解码器可能仅支持基线配置文件)。通过使用特定编码器(例如 h264_nvenc)启用硬件辅助编码。仅在少数过滤器中支持过滤硬件辅助处理.. 有几种硬件加速标准 API,其中一些在一定程度上被 FFmpeg支持

hwaccel activation was controlled by code like (bit reformatted after 2013 https://github.com/FFmpeg/FFmpeg/commit/08303d774132775d49d4ba767092de5d426f089d)

hwaccel 激活由类似代码控制(在 2013 年之后重新格式化https://github.com/FFmpeg/FFmpeg/commit/08303d774132775d49d4ba767092de5d426f089d

avctx->hwaccel = ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);

For example, in libavcodec/mpeg12dec.c https://github.com/FFmpeg/FFmpeg/blob/6c7254722ad43712db5686feee8bf75c74d8635b/libavcodec/mpeg12dec.c

例如,在 libavcodec/mpeg12dec.c https://github.com/FFmpeg/FFmpeg/blob/6c7254722ad43712db5686feee8bf75c74d8635b/libavcodec/mpeg12dec.c

avctx->pix_fmt = mpeg_get_pixelformat(avctx);
avctx->hwaccel = ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);

The ff_find_hwaccelchecks codec and pixelformat pair of image and of all available hwaccelerators.

ff_find_hwaccel检查编解码器和图像的和所有可用的hwaccelerators对像素格式。

AVHWAccel *ff_find_hwaccel(enum CodecID codec_id, enum PixelFormat pix_fmt)
{
    AVHWAccel *hwaccel=NULL;

    while((hwaccel= av_hwaccel_next(hwaccel))){
        if (   hwaccel->id      == codec_id
            && hwaccel->pix_fmt == pix_fmt)
            return hwaccel;
    }
    return NULL;
}

For example, dxva2 (https://en.wikipedia.org/wiki/DirectX_Video_Acceleration) has:

例如,dxva2 ( https://en.wikipedia.org/wiki/DirectX_Video_Acceleration) 具有:

AVHWAccel mpeg2_dxva2_hwaccel = {
    .name           = "mpeg2_dxva2",
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = CODEC_ID_MPEG2VIDEO,
    .pix_fmt        = PIX_FMT_DXVA2_VLD,
    .capabilities   = 0,
    .start_frame    = start_frame,
    .decode_slice   = decode_slice,
    .end_frame      = end_frame,
    .priv_data_size = sizeof(struct dxva2_picture_context),
};

And libavutil/pixfmt.hlists all supported hw decoders / accelerators by their pixel formats https://ffmpeg.org/doxygen/3.2/pixfmt_8h.html

libavutil/pixfmt.h列出了它们的像素格式支持的所有硬件解码器/加速器https://ffmpeg.org/doxygen/3.2/pixfmt_8h.html

AV_PIX_FMT_XVMC_MPEG2_MC    - XVideo Motion Acceleration via common packet passing.
AV_PIX_FMT_XVMC_MPEG2_IDCT  - undocumented
AV_PIX_FMT_XVMC         - undocumented
AV_PIX_FMT_VDPAU_H264   - H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_VDPAU_MPEG1  - MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_VDPAU_MPEG2  - MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_VDPAU_WMV3   - WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_VDPAU_VC1    - VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers. 
AV_PIX_FMT_VAAPI_MOCO   - HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers.
AV_PIX_FMT_VAAPI_IDCT   - HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers.
AV_PIX_FMT_VAAPI_VLD    - HW decoding through VA API, Picture.data[3] contains a VASurfaceID. 
AV_PIX_FMT_VDPAU_MPEG4  - MPEG-4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers.
AV_PIX_FMT_DXVA2_VLD    - HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer. 
AV_PIX_FMT_VDPAU        - HW acceleration through VDPAU, Picture.data[3] contains a VdpVideoSurface. 
AV_PIX_FMT_VDA          - HW acceleration through VDA, data[3] contains a CVPixelBufferRef. 
AV_PIX_FMT_QSV          - HW acceleration through QSV, data[3] contains a pointer to the mfxFrameSurface1 structure.
AV_PIX_FMT_MMAL         - HW acceleration though MMAL, data[3] contains a pointer to the MMAL_BUFFER_HEADER_T structure.
AV_PIX_FMT_D3D11VA_VLD  - HW decoding through Direct3D11, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer.
AV_PIX_FMT_CUDA         - HW acceleration through CUDA. data[i] contain CUdeviceptr pointers exactly as for system memory frames. 

Actual selection of pixel formats is in function called before ff_find_hwaccel, the static enum PixelFormat mpeg_get_pixelformat(AVCodecContext *avctx)of libavcodec/mpeg12dec.cfor mpeg1/2. In earlier versions of ffmpeg/libavcodec it checks avctx->xvmc_accelerationand/or avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAUor calls avctx->get_format(avctx,ff_hwaccel_pixfmt_list_420);to enable hw decoding in some cases.

像素格式的实际选择在之前调用的函数ff_find_hwaccelstatic enum PixelFormat mpeg_get_pixelformat(AVCodecContext *avctx)libavcodec/mpeg12dec.c对于 mpeg1/2。在 ffmpeg/libavcodec 的早期版本中,它会在某些情况下检查avctx->xvmc_acceleration和/avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU或调用avctx->get_format(avctx,ff_hwaccel_pixfmt_list_420);以启用硬件解码。

In recent version (2017) it and several nearby function do the selection of hw coder https://github.com/FFmpeg/FFmpeg/blob/aff8cf18cb0b1fa4f2e3d163c3da2f25aa6d1906/libavcodec/mpeg12dec.c#L1189.

在最近的版本(2017)中,它和附近的几个函数会选择硬件编码器https://github.com/FFmpeg/FFmpeg/blob/aff8cf18cb0b1fa4f2e3d163c3da2f25aa6d1906/libavcodec/mpeg12dec.c#L1189

Basically: hardware decoder and its api (obsolete XVMC, VDPAU, VA API, MS DXVAor MS Direct3D11, or videotoolbox) should be enabled in your build of ffmpeg and supported by your hardwareand its driver/libraries (many are proprietary and should be downloaded separately). Sometimes -hwacceloption should be given to ffmpeg, or plugin loaded. In linux you may use vainfoand vdpauinfocommands to test availability and supported profiles with most popular standard video hw decoding APIs.

基本上:硬件解码器及其 api(过时的XVMCVDPAUVA API、 MS DXVA或 MS Direct3D11或 videotoolbox)应该在您的 ffmpeg 构建中启用,并由您的硬件及其驱动程序/库支持(许多是专有的,应该是单独下载)。有-hwaccel时应为 ffmpeg 提供选项,或加载插件。在 linux 中,您可以使用vainfovdpauinfo命令来测试可用性和支持的配置文件与最流行的标准视频硬件解码 API。

Input file (for mpeg1/2) should be not Grayscale, it should have s->chroma_formatless of 2 (4:2:0 Chroma subsampling, which is usual for ISO/IEC MPEG and ITU-T VCEG H.26x; but not for some MPEG-4 Part 2 and not for high 4:4:4 variants of H.264/MPEG-4 AVC).

输入文件(对于 mpeg1/2)不应该是灰度,它应该s->chroma_format小于 2(4:2:0 Chroma subsampling,这对于 ISO/IEC MPEG 和 ITU-T VCEG H.26x 是常见的;但对于某些 MPEG 来说不是-4 第 2 部分,不适用于 H.264/MPEG-4 AVC 的高 4:4:4 变体)。

static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = {
#if CONFIG_MPEG2_XVMC_HWACCEL
    AV_PIX_FMT_XVMC,
#endif
#if CONFIG_MPEG_VDPAU_DECODER && FF_API_VDPAU
    AV_PIX_FMT_VDPAU_MPEG2,
#endif
#if CONFIG_MPEG2_VDPAU_HWACCEL
    AV_PIX_FMT_VDPAU,
#endif
#if CONFIG_MPEG2_DXVA2_HWACCEL
    AV_PIX_FMT_DXVA2_VLD,
#endif
#if CONFIG_MPEG2_D3D11VA_HWACCEL
    AV_PIX_FMT_D3D11VA_VLD,
#endif
#if CONFIG_MPEG2_VAAPI_HWACCEL
    AV_PIX_FMT_VAAPI,
#endif
#if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL
    AV_PIX_FMT_VIDEOTOOLBOX,
#endif
    AV_PIX_FMT_YUV420P,
    AV_PIX_FMT_NONE
};

static const enum AVPixelFormat mpeg12_pixfmt_list_422[] = {
    AV_PIX_FMT_YUV422P,
    AV_PIX_FMT_NONE
};

static const enum AVPixelFormat mpeg12_pixfmt_list_444[] = {
    AV_PIX_FMT_YUV444P,
    AV_PIX_FMT_NONE
};

#if FF_API_VDPAU
static inline int uses_vdpau(AVCodecContext *avctx) {
    return avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG1 || avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG2;
}
#endif

static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx)
{
    Mpeg1Context *s1  = avctx->priv_data;
    MpegEncContext *s = &s1->mpeg_enc_ctx;
    const enum AVPixelFormat *pix_fmts;

    if (CONFIG_GRAY && (avctx->flags & AV_CODEC_FLAG_GRAY))
        return AV_PIX_FMT_GRAY8;

    if (s->chroma_format < 2)
        pix_fmts = avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO ?
                                mpeg1_hwaccel_pixfmt_list_420 :
                                mpeg2_hwaccel_pixfmt_list_420;
    else if (s->chroma_format == 2)
        pix_fmts = mpeg12_pixfmt_list_422;
    else
        pix_fmts = mpeg12_pixfmt_list_444;

    return ff_thread_get_format(avctx, pix_fmts);
}

static void setup_hwaccel_for_pixfmt(AVCodecContext *avctx)
{
    // until then pix_fmt may be changed right after codec init
    if (avctx->hwaccel
#if FF_API_VDPAU
        || uses_vdpau(avctx)
#endif
        )
        if (avctx->idct_algo == FF_IDCT_AUTO)
            avctx->idct_algo = FF_IDCT_SIMPLE;

    if (avctx->hwaccel && avctx->pix_fmt == AV_PIX_FMT_XVMC) {
        Mpeg1Context *s1 = avctx->priv_data;
        MpegEncContext *s = &s1->mpeg_enc_ctx;

        s->pack_pblocks = 1;
#if FF_API_XVMC
FF_DISABLE_DEPRECATION_WARNINGS
        avctx->xvmc_acceleration = 2;
FF_ENABLE_DEPRECATION_WARNINGS
#endif /* FF_API_XVMC */
    }
}