VideoToolbox实现视频硬解码

482 阅读1分钟

实现原理

正如我们所知,编码数据仅用于传输,无法直接渲染到屏幕上,所以这里利用苹果原生框架VideoToolbox解析文件中的编码的视频流,并将压缩视频数据(h264/h265)解码为指定格式(yuv,RGB)的视频原始数据,以渲染到屏幕上.

总体架构

总体思想即将FFmpeg parse到的数据装到CMBlockBuffer中,将extra data分离出的vps,sps,pps装到CMVideoFormatDesc中,将计算好的时间戳装到CMTime中,最后即可拼成完成的CMSampleBuffer以用来提供给解码器.

简易流程

FFmpeg parse流程

  • 创建format context: avformat_alloc_context
  • 打开文件流: avformat_open_input
  • 寻找流信息: avformat_find_stream_info
  • 获取音视频流的索引值: formatContext->streams[i]->codecpar->codec_type == (isVideoStream ? AVMEDIA_TYPE_VIDEO : AVMEDIA_TYPE_AUDIO)
  • 获取音视频流: m_formatContext->streams[m_audioStreamIndex]
  • 解析音视频数据帧: av_read_frame
  • 获取extra data: av_bitstream_filter_filter

VideoToolbox decode流程

  • 比较上一次的extra data,如果数据更新需要重新创建解码器
  • 分离并保存FFmpeg parse到的extra data中分离vps, sps, pps等关键信息 (比较NALU头)
  • 通过CMVideoFormatDescriptionCreateFromH264ParameterSets,CMVideoFormatDescriptionCreateFromHEVCParameterSets装载vps,sps,pps等NALU header信息.
  • 指定解码器回调函数与解码后视频数据类型(yuv,RGB...)
  • 创建解码器VTDecompressionSessionCreate
  • 生成CMBlockBufferRef装载解码前数据,再将其转为CMSampleBufferRef以提供给解码器.
  • 开始解码VTDecompressionSessionDecodeFrame
  • 在回调函数中CVImageBufferRef即为解码后的数据,可转为CMSampleBufferRef传出.