查看完整版本: [-- Qt音视频开发10-ffmpeg内核硬解码 --]

QTCN开发网 -> Qt基础编程 -> Qt音视频开发10-ffmpeg内核硬解码 [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

liudianwu 2023-01-06 14:59

Qt音视频开发10-ffmpeg内核硬解码



## 一、前言
为了极大的降低CPU的占用,实现硬解码(也叫硬件加速)非常有必要,一个视频文件或者一路视频流还好,如果增加到64路视频流呢,如果是4K、8K这种高分辨率的视频呢,必须安装上硬解码才是上上策。举个例子在电脑上播放4K以上的H265这类的视频文件,如果不开硬解码,很容易出现卡顿现象,在配置高的电脑也容易出现,毕竟非常的耗CPU资源,来不及刷新,上了硬解码之后,明显流畅的不要不要的,怪不得现在的显卡性能越做越牛逼,就是为了在显示这块尽可能的分担CPU的压力,以便留出CPU时间片做其他的事情。

关于ffmpeg解码,网上搜索到的代码绝对是一大堆一大堆,而且很多都讲得很详细,解码的函数流程图非常清晰,关于ffmpeg这块的学习本人推荐雷神的博客,分析的相当细致,我在很久以前刚用Qt+ffmpeg解码的时候,参考的就是雷神的例子,当然这些demo其实在ffmpeg的开发包dev下的examples也是非常详细的,只不过没有什么分析过程,参考雷神的博客可以看到很多分析过程。

硬解码大致流程:

01. 根据硬解码类型查找硬解码设备类型 av_hwdevice_find_type_by_name
02. 根据解码设备类型找到硬解码的格式 find_fmt_by_hw_type
03. 获取解码器格式回调 videoCodecCtx->get_format
04. 创建硬解码设备 av_hwdevice_ctx_create
05. 设备硬解码设备 videoCodecCtx->hw_device_ctx
06. 解码数据包 avcodec_send_packet avcodec_receive_frame
07. 将硬解码后的数据从GPU转换取出来 av_hwframe_transfer_data

## 二、效果图
[attachment=23233]


## 三、体验地址
1. 国内站点:[https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
2. 国际站点:[https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
3. 个人作品:[https://blog.csdn.net/feiyangqingyun/article/details/97565652](https://blog.csdn.net/feiyangqingyun/article/details/97565652)
4. 体验地址:[https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g](https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g) 提取码:01jf 文件名:bin_video_demo/bin_linux_video。

## 四、相关代码
```cpp
bool FFmpegThread::initHardware()
{
    if (hardware == "none") {
        return true;
    }
#if (FFMPEG_VERSION_MAJOR > 2)
    //根据名称自动寻找硬解码
    enum AVHWDeviceType type;
    //发现嵌入式上低版本的库没有av_hwdevice_find_type_by_name函数
#ifdef __arm__
#if (FFMPEG_VERSION_MAJOR < 4)
    return false;
#else
    type = av_hwdevice_find_type_by_name(hardware.toUtf8().data());
#endif
#else
    type = av_hwdevice_find_type_by_name(hardware.toUtf8().data());
#endif
    debug("硬件加速", QString("名称: %1 数值: %2").arg(hardware).arg(type));

    //找到对应的硬解码格式
    FFmpegHelper::hw_pix_fmt = FFmpegHelper::find_fmt_by_hw_type(type);
    if (FFmpegHelper::hw_pix_fmt == -1) {
        debug("加速失败", "错误: 未找到对应加速类型");
        return false;
    }

    int result = -1;
    //解码器格式赋值为硬解码
    videoCodecCtx->get_format = FFmpegHelper::get_hw_format;
    //av_opt_set_int(videoCodecCtx, "refcounted_frames", 1, 0);

    //创建硬解码设备
    AVBufferRef *hw_device_ref;
    result = av_hwdevice_ctx_create(&hw_device_ref, type, NULL, NULL, 0);
    if (result < 0) {
        debug("加速失败", "错误: 创建视频解码器失败 " + FFmpegHelper::getError(result));
        return false;
    }

    videoCodecCtx->hw_device_ctx = av_buffer_ref(hw_device_ref);
    av_buffer_unref(&hw_device_ref);
    return true;
#else
    return false;
#endif
}

int FFmpegHelper::decode(FFmpegThread *thread, AVCodecContext *avctx, AVPacket *packet, AVFrame *frameSrc, AVFrame *frameDst)
{
    int result = -1;
#ifdef videoffmpeg
    QString flag = "硬解出错";
#if (FFMPEG_VERSION_MAJOR > 2)
    result = avcodec_send_packet(avctx, packet);
    if (result < 0) {
        thread->debug(flag, QString("步骤: %1 原因: %2").arg("avcodec_send_packet").arg(getError(result)));
        return result;
    }

    while (result >= 0) {
        result = avcodec_receive_frame(avctx, frameSrc);
        if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
            break;
        } else if (result < 0) {
            thread->debug(flag, QString("步骤: %1 原因: %2").arg("avcodec_receive_frame").arg(getError(result)));
            break;
        }

        //将数据从GPU拷贝到CPU
        result = av_hwframe_transfer_data(frameDst, frameSrc, 0);
        if (result < 0) {
            av_frame_unref(frameDst);
            av_frame_unref(frameSrc);
            thread->debug(flag, QString("步骤: %1 原因: %2").arg("av_hwframe_transfer_data").arg(getError(result)));
            return result;
        }
        goto end;
    }
#endif
    return result;

end:
    //调用线程处理解码后的数据
    thread->decodeVideo2(packet);
#endif
    return result;
}
```


hello_peter 2023-01-07 08:44
大侠,请教下:如果装有2个显卡(Intel集成显卡、英伟达),如何指定硬解码使用显卡?


查看完整版本: [-- Qt音视频开发10-ffmpeg内核硬解码 --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled