实现原理
正如我们所知,编码数据仅用于传输,无法直接渲染到屏幕上,所以这里利用苹果原生框架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传出.