该节是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-C
与Swift
两种实现,为了方便说明,文章引用的是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硬解码上下文。