ffmpeg开发播放器学习笔记 - 硬解码,OpenGL渲染YUV

该节是ffmpeg开发播放器学习笔记的第四节《硬解码,OpenGL渲染YUV》

硬解码基本上(这里也可以指特定的硬件)指的是GPU来完成解码。
CPU被设计成能用处理器,它有着高灵活性,高可移植性。而GPU则侧重于计算运算量大但任务相对单一的处理器,它有着极强的并行计算能力,利用GPU来完成视频帧的解码将会减少CPU的使用率。
硬解码利用了GPU特定的电路设计,所以不同平台的GPU支持的硬解码格式也是有限的。 比如iOS/macOS平台支持H264与H265的硬件解码,利用的是videotoolbox来完成;基于intel芯片的QSV,基于NVIDA的CUDA。
 

✅ 第一节 - Hello FFmpeg
✅ 第二节 - 软解视频流,渲染 RGB24
✅ 第三节 - 认识YUV
第四节 - 硬解码,OpenGL渲染YUV
第五节 - Metal 渲染YUV
第六节 - 解码音频,使用AudioQueue 播放
第七节 - 音视频同步
第八节 - 完善播放控制
第九节 - 倍速播放
第十节 - 增加视频过滤效果
第十一节 - 音频变声

该节 Demo 地址:github.com/czqasngit/f…

实例代码提供了Objective-CSwift两种实现,为了方便说明,文章引用的是Objective-C代码,因为Swift代码指针看着不简洁。

该节最终效果如下图:

目标

  • 了解ffmpeg硬解码与软解码的差异
  • 添加硬解码功能
  • 了解OpenGL渲染流程
  • 搭建OpenGL环境
  • 利用OpenGL渲染YUV420P格式的数据

了解ffmpeg硬解码与软解码的差异

ffmpeg中支持的硬件类型定义如下:

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

下图为硬解码视频流完整流程图:

大致的差异如下:

  • 1.创建好AVCodecContext的时候设置它的硬解码上下文hw_device_ctx。
  • 2.可选设置AVCodecContext的目标格式回调函数get_format,在运行时告知ffmpeg解码器解码的目标格式
  • 3.将解码好的数据从显存中读取到内存

添加硬解码功能

1.完善硬解码时的初始化

在macOS中利用VideoToolBox完成硬解码,这里指定格式为: AV_HWDEVICE_TYPE_VIDEOTOOLBOX。 也可以通过以下函数来查找

 av_hwdevice_find_type_by_name("h264_videotoolbox")

VideoToolBox的硬解码器信息定义如下:

const AVHWAccel ff_h264_videotoolbox_hwaccel = {
    .name           = "h264_videotoolbox",
    .type           = AVMEDIA_TYPE_VIDEO,
    .id             = AV_CODEC_ID_H264,
    .pix_fmt        = AV_PIX_FMT_VIDEOTOOLBOX,
    .alloc_frame    = ff_videotoolbox_alloc_frame,
    .start_frame    = ff_videotoolbox_h264_start_frame,
    .decode_slice   = ff_videotoolbox_h264_decode_slice,
    .decode_params  = videotoolbox_h264_decode_params,
    .end_frame      = videotoolbox_h264_end_frame,
    .frame_params   = videotoolbox_frame_params,
    .init           = videotoolbox_common_init,
    .uninit         = videotoolbox_uninit,
    .priv_data_size = sizeof(VTContext),
};

判断当前运行环境下的AVCodec是否支持AV_HWDEVICE_TYPE_VIDEOTOOLBOX

int hwConfigIndex = 0;
    bool supportAudioToolBox = false;
    /// 判断当前解码器是否支持AV_HWDEVICE_TYPE_VIDEOTOOLBOX硬解
    /// 某些视频格式的视频解码器不支持
    while (true) {
        const AVCodecHWConfig *config = avcodec_get_hw_config(self->codec, hwConfigIndex);
        if(!config) break;
        if(config->device_type == AV_HWDEVICE_TYPE_VIDEOTOOLBOX) {
            supportAudioToolBox = true;
            break;
        }
        hwConfigIndex ++;
    }

通过调用avcodec_get_hw_config函数来枚举支持的硬件解码配置,读取AVCodecHWConfig是否支持AV_HWDEVICE_TYPE_VIDEOTOOLBOX。
创建硬件解码的实例,设置AVCodecContext->hw_device_ctx硬解码上下文。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对您的问题,我来简单回答一下。 首先,要明确的是,FFmpeg 是一个开源的跨平台音视频处理库,支持包括解码、编码、封装、解封装等功能。而解封装(Demuxing)是指将音视频封装格式中的音视频流解析出来,以便后续对音视频流进行解码、编码等操作。 在 Android 基于 FFmpeg 开发简易播放器中,我们可以使用 FFmpeg 提供的 API 来进行解封装。具体步骤如下: 1. 打开输入文件 使用 FFmpeg 的 avformat_open_input() 函数打开要解封装的音视频文件,该函数返回一个 AVFormatContext 结构体指针,该指针包含了输入文件的相关信息。 2. 寻找音视频流 使用 FFmpeg 的 avformat_find_stream_info() 函数读取输入文件的文件头信息,并寻找其中包含的音视频流。该函数会将每个音视频流的信息保存在 AVStream 结构体中。 3. 选择音视频流 根据需要播放的音视频流类型,在所有寻找到的音视频流中选择对应的流。可以通过判断 AVStream 结构体中的 codecpar->codec_type 来确定该流是音频流还是视频流。 4. 获取解码器 使用 FFmpeg 的 avcodec_find_decoder() 函数获取对应的解码器,并使用 avcodec_open2() 函数打开解码器。 5. 循环读取数据包 使用 FFmpeg 的 av_read_frame() 函数循环读取音视频数据包(AVPacket 结构体),并将数据包送到解码器进行解码。 6. 关闭解码器和输入文件 在播放完成后,需要使用 avcodec_free_context() 函数释放解码器占用的资源,并使用 avformat_close_input() 函数关闭输入文件。 以上就是基于 FFmpeg 进行解封装的大致步骤。当然,在实际开发中还有很多细节需要注意,比如错误处理、内存管理等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值