【问题标题】:using ffmpeg hwaccel from C++使用来自 C++ 的 ffmpeg hwaccel
【发布时间】:2011-08-24 12:35:00
【问题描述】:

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

我编写了一个使用 ffmpeg 的视频播放器。 我已经使用"av_hwaccel_next" 检查了支持,发现mpeg2_dxva

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

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

我还没有找到任何有关这方面的信息,有人知道好的来源吗?

【问题讨论】:

    标签: c++ ffmpeg hardware-acceleration


    【解决方案1】:

    从阅读 ffmpeg 文档开始:https://trac.ffmpeg.org/wiki/HWAccelIntro 和更好的答案 How to use hardware acceleration with ffmpeg(对于 linux 检查页面 https://wiki.archlinux.org/index.php/Hardware_video_acceleration

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

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

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

    例如在 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);
    

    ff_find_hwaccel 检查图像的编解码器和像素格式对以及所有可用的硬件加速器。

    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;
    }
    

    例如,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),
    };
    

    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. 
    

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

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

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

    输入文件(对于 mpeg1/2)不应为灰度,它应具有小于 2 的 s->chroma_format(4:2:0 Chroma subsampling,这对于 ISO/IEC MPEG 和 ITU-T VCEG H. 26x;但不适用于某些 MPEG-4 Part 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 */
        }
    }
    

    【讨论】:

    • 那么我是否需要手动将avctx的pix_fmt覆盖为PIX_FMT_DXVA2_VLD?当我查看 ffmpeg 代码时,我只看到这个值被读取,从未设置。
    • 没有文件将是 PIX_FMT_DXVA2_VLD 格式。似乎 FFmpeg hwaccel 上不存在任何文档...
    • @Maypeur,文档现已正式发布:trac.ffmpeg.org/wiki/HWAccelIntro,另请查看wiki.archlinux.org/index.php/Hardware_video_acceleration。您的问题不需要详细信息(ffmpeg 的版本,操作系统 Linux/Windows/其他;您的硬件解码器是什么,是否安装了它,它的 API 是什么,您的文件是什么,您是如何启动 ffmpeg 的,启动时硬件解码是否有效? ffmpeg 来自命令行)并且无法回答。但是我原来的答案不是很正确("doesn't solve anything"),所以我更新了一下。
    • 他的问题是关于如何将hwaccel集成到程序中,官方文档只涉及hwo通过ffmpeg.exe使用它。它缺少 avctx->pix_fmt = mpeg_get_pixelformat(avctx);调用前 avctx->hwaccel = ff_find_hwaccel(avctx->codec->id, avctx->pix_fmt);这似乎改变了什么!感谢您的完整回复,我今天将尝试。
    • @Maypeur,同样有用的是 ffmpeg.exe 的代码来解析 hwaccel 命令行选项:github.com/FFmpeg/FFmpeg/blob/… MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st); if (hwaccel) & int show_hwaccels() & github.com/FFmpeg/FFmpeg/blob/…
    猜你喜欢
    • 2019-08-31
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 2018-01-06
    • 2011-12-05
    • 1970-01-01
    • 2019-08-28
    相关资源
    最近更新 更多