H.264格式,iOS硬編解碼 以及 iOS 11對HEVC硬編解碼的支持
1,H.264格式
網絡表示層NAL,如圖H.264流由一幀一幀的NALU組成;
SPS:序列參數集,作用於一系列連續的編碼圖像;
PPS:圖像參數集,作用於編碼視頻序列中一個或多個獨立的圖像;
這兩個幀也是獨立的NALU。
I-Frame:關鍵幀,幀內編碼后的幀,顯示比較完全的一幀;
P-Frame:參考前一幀,可能只是對比前一幀的運動估計的變化部分;
B-Frame:會參照前后的幀,其他類似P-Frame。B和P Frame均包含了 幀間編碼和幀內編碼。
每個NALU以 start code 分隔:00 00 01(3 bytes) 或 00 00 00 01(4 bytes)。
2,iOS對H.264硬編解碼
iOS 8以后通過VideoToolBox支持對H.264的硬編碼;
其中的CMSampleBufferRef結構很有意思,需要理解,如圖
CMVideoFormatDesc中含有SPS,PPS和其他有用信息;
- 編碼時,CVPixelBuffer—>CMSampleBufferRef(其中包含已壓縮的CMBlockBuffer);
- 解碼時,通過VTDecompressionSession來解碼, CMSampleBufferRef(內含CMBlockBuffer)—>CVImageBufferRef(解碼后的幀數據);
2.1 編碼
下圖參照WWDC 2014的PDF,從相機或讀取視頻文件輸出的CVPixelBuffer—>Encoder—>CMSampleBufferRef—>NALUs。
經典的編碼器 推薦直播推流的LFLiveKit,代碼結構良好,數據流向非常清晰,很適合閱讀;
https://github.com/LaiFengiOS/LFLiveKit/blob/master/LFLiveKit/coder/LFHardwareVideoEncoder.m
編碼步驟大致是:
- 1,VTCompressionSessionCreate 通過寬,高,codecType(kCMVideoCodecType_H264),編碼回調VTCompressionOutputCallback 等初始化VTCompressionSessionRef實例compressionSession;
- 2,VTSessionSetProperty設置比較重要的編碼屬性,如
kVTCompressionPropertyKey_MaxKeyFrameInterval,關鍵幀間隔
kVTCompressionPropertyKey_RealTime
kVTCompressionPropertyKey_AverageBitRate
kVTCompressionPropertyKey_ProfileLevel
kVTCompressionPropertyKey_AllowFrameReordering等;最后VTCompressionSessionPrepareToEncodeFrames; - 3,往 VTCompressionSessionEncodeFrame添加原始CVPixelBuffer和pts
根據frameCount 計算出的pts
CMTime presentationTimeStamp = CMTimeMake(frameCount, (int32_t)_configuration.videoFrameRate);
和是否I-Frame:
if (frameCount % (int32_t)_configuration.videoMaxKeyframeInterval == 0) { properties = @{(__bridge NSString *)kVTEncodeFrameOptionKey_ForceKeyFrame: @YES}; }
- 4,VTCompressionOutputCallback回調中通過解析 CMSampleBufferRef 分別處理SPS,PPS,I-Frame和非I-Frame,添加startcode: 00 00 00 01 然后通過RTMP推出去。
2.2 解碼
編碼的逆過程,通常在播放器等場景應用,NALU + SPS,PPS—>CMBlockBuffer—>CMSampleBufferRef,再將CMSampleBufferRef包裝的幀數據輸入到 VTDecompressionSessionDecodeFrame,通過回調中CVImageBufferRef 直接上傳OpenGL ES 顯示)。
我寫了一個簡單的iOS H.264 stream decoder:
https://github.com/edisongz/ffmpeg_codec_demo
3,iOS 11 對HEVC的支持
iOS 11 + A9芯片開始對HEVC的支持,系統控件AVPlayer,以及Safari瀏覽器的支持;HEVC相對於H.264壓縮效率高40%。
硬編碼需要iOS11 + A10芯片
硬解碼需要iOS 11 + A9芯片
iOS 11 新API
//decoder let hardwareDecodeSupported = VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC) //encoder let error = VTCompressionSessionCreate( kCFAllocatorDefault, 3840, 2160, kCMVideoCodecType_HEVC, encoderSpecification, nil, nil, nil, nil, // using VTCompressionSessionEncodeFrameWithOutputHandler &session); if error == kVTCouldNotFindVideoEncoderErr { // no HEVC encoder }
具體的HEVC的VideoToolBox的硬件編解碼還有待完善;后續完成會添加到這里:
https://github.com/edisongz/ffmpeg_codec_demo
小結
H.264 iOS環境下的硬編解碼都是比較老的WWDC的session了,今年的WWDC 2017,增加的硬編解碼HEVC代碼,還需要找一台機器測試下。
參考
LFLiveKit 中硬編碼部分
WWDC 2014 Direct Access to Video Encoding and Decoding
WWDC 2017 Working with HEIF and HEVC
Github 自己寫的H.264流式解碼