蘋果于北京時間2017年6月6日凌晨召開WWDC 2017大會,在此次發布會上按照慣例推出了iOS 11系統,同時也帶來了許多新鮮特性,如錄屏功能、相冊查看gif圖片、Siri支持翻譯等。作為音視頻開發者,我們更著重關注的是此次蘋果為iPhone為推出了兩種全新的媒體格式"HEVC和HEIF":視頻方面使用HEVC來代替H.264,而圖片則是用HEIF來代替JPG。這兩種格式號稱可以在保證畫質的情況下,大大減少視頻、照片的大小,經常因為容量不足而頭疼的朋友將成為最大受益者。
由此可見,如果在直播過程中使用H.265的視頻編碼格式,可使用較少的帶寬,得到更優的畫質。在iOS系統推出H.265的硬編硬解功能之前,我們在iphone手機上使用的H.265編解碼功能,均為軟件編解碼,其缺點是cpu占用高,手機發熱量大,無法支撐高分辨、高幀率的實時場景。相信此次iOS11的發布,會推動H.265在直播市場的發展。
本文我們會著重介紹如果在iOS11上使用系統API進行265硬編硬解功能,讀者需要有使用VideoToolBox進行H.264硬編/解碼的相關經驗。
一、什么是HEVC(H.265)
HEVC全稱High Efficiency Video Coding(高效率視頻編碼),是比H.264更加優秀的一種視頻壓縮標準(也稱為H.265)。HEVC在低碼率視頻壓縮上,提升質量、減少容量和節省帶寬方面都有突出表現,因此除了拍攝占用的容量減少外,在視頻通話時也能更加流暢清晰。據9to5Mac的測試結果,原來的H.264標準需要需要60MB才能達到的畫質,HEVC僅需要33MB。從下圖的壓縮效果可以看出,HEVC的壓縮算法更加智能,雖然圖片細節丟失的情況更高,但是卻不會嚴重影響視頻的畫質。
需要注意的是,H.265的硬編/解功能,并不是ios的所有設備升級到新系統上都可以使用,目前蘋果公布可使用HEVC編/解碼的移動設備要求如下:
iOS 11 HEVC Encode
iOS 11 HEVC Decode
二、VideoToolBox編碼
使用VideoToolBox進行H.264和H.265編碼的流程完全相同,只在創建和配置編碼器上存在少量差異,下面以VideoToolBox的編碼流程為線索,說明使用兩種編碼格式時的區別。
1. 創建VTCompressionSession
VT_EXPORT OSStatus
VTCompressionSessionCreate(
CM_NULLABLE CFAllocatorRef allocator,
int32_t width,
int32_t height,
CMVideoCodecType codecType,
CM_NULLABLE CFDictionaryRef encoderSpecification,
CM_NULLABLE CFDictionaryRef sourceImageBufferAttributes,
CM_NULLABLE CFAllocatorRef compressedDataAllocator,
CM_NULLABLE VTCompressionOutputCallback outputCallback,
void * CM_NULLABLE outputCallbackRefCon,
CM_RETURNS_RETAINED_PARAMETER CM_NULLABLE VTCompressionSessionRef * CM_NONNULL compressionSessionOut) API_AVAILABLE(macosx(10.8), ios(8.0), tvos(10.2));
- 如果使用H.264編碼功能,參數
codecType
需要設置為kCMVideoCodecType_H264
; - 如果使用H.265編碼功能,參數
codecType
需要設置為kCMVideoCodecType_HEVC
;
其他參數在使用兩種編碼格式時沒有區別。
2. 設置編碼相關參數
VT_EXPORT OSStatus
VTSessionSetProperty(
CM_NONNULL VTSessionRef session,
CM_NONNULL CFStringRef propertyKey,
CM_NULLABLE CFTypeRef propertyValue ) API_AVAILABLE(macosx(10.8), ios(8.0), tvos(10.2));
其中在配置kVTCompressionPropertyKey_ProfileLevel
屬性時,H.264和H.265有各自不同的ProfileLevel定義,與H.265相關的只有兩個,如下所示:
VT_EXPORT const CFStringRef kVTProfileLevel_HEVC_Main_AutoLevel API_AVAILABLE(macosx(10.13), ios(11.0), tvos(11.0));
VT_EXPORT const CFStringRef kVTProfileLevel_HEVC_Main10_AutoLevel API_AVAILABLE(macosx(10.13), ios(11.0), tvos(11.0));
3. 啟動編碼
VT_EXPORT OSStatus
VTCompressionSessionPrepareToEncodeFrames( CM_NONNULL VTCompressionSessionRef session ) API_AVAILABLE(macosx(10.9), ios(8.0), tvos(10.2));
4. 循環輸入源數據(yuv類型)
VT_EXPORT OSStatus
VTCompressionSessionEncodeFrame(
CM_NONNULL VTCompressionSessionRef session,
CM_NONNULL CVImageBufferRef imageBuffer,
CMTime presentationTimeStamp,
CMTime duration, // may be kCMTimeInvalid
CM_NULLABLE CFDictionaryRef frameProperties,
void * CM_NULLABLE sourceFrameRefCon,
VTEncodeInfoFlags * CM_NULLABLE infoFlagsOut ) API_AVAILABLE(macosx(10.8), ios(8.0), tvos(10.2));
5. 獲取編碼后的數據
通過在創建VTCompressionSession
傳入回調函數,獲取編碼后的數據。
typedef void (*VTCompressionOutputCallback)(
void * CM_NULLABLE outputCallbackRefCon,
void * CM_NULLABLE sourceFrameRefCon,
OSStatus status,
VTEncodeInfoFlags infoFlags,
CM_NULLABLE CMSampleBufferRef sampleBuffer );
至此針對使用VideoToolBox進行H.264/H.265編碼的基本流程已經介紹完畢。
三、VideoToolBox解碼
VideoToolBox的解碼主要涉及以下幾個函數:
VTDecompressionSessionCreate 創建解碼session
VTDecompressionSessionDecodeFrame 解碼一個frame
VTDecompressionSessionInvalidate 銷毀解碼session
其中VTDecompressionSessionCreate
創建session時需要CMVideoFormatDescriptionRef
類型的視頻格式描述,而對于CMVideoFormatDescriptionRef
,VideoToolBox中提供了多個方法可以創建:
CMVideoFormatDescriptionCreate
CMVideoFormatDescriptionCreateForImageBuffer
CMVideoFormatDescriptionCreateFromH264ParameterSets
在iOS11中新增了一個方法:
CMVideoFormatDescriptionCreateFromHEVCParameterSets
用以創建H.265視頻格式的描述。
對于H.264和H.265的解碼,在VideoToolBox層面的操作完全一致,唯一不同的就是視頻格式的描述類型不同。最常使用也最容易理解的為后兩個通過ParameterSets來創建的函數,前兩個函數的創建方式未作詳細了解。
至此,對使用VideoToolBox解碼H.265視頻的重點就放在如何獲取ParameterSets(即VPS、SPS和PPS)上。
3.1 H.265 NALU類型
同H.264一樣,H.265數據也是以NALU
的形式組織起來,區別在于H.264的NALU Header為一個字節,而H.265的為兩個字節,其結構如下:
所以,H.265編碼格式的NALU
類型判斷方式如下,code為NALU Header
的第一個字節:
int type = (code & 0x7E)>>1;
其中type類型為32、33、34的NALU分別為VPS
、SPS
和PPS
,其他類型參見H.265規范《T-REC-H.265-201304-I!!PDF-E》。
3.2 HEVCDecoderConfigurationRecord
使用ffmpeg讀取MP4文件后,視頻的AVCodecContext
結構的extradata
存儲的即為包含有SPS
、PPS
信息的數據結構。
對于H.264格式的視頻來說,為AVCDecoderConfigurationRecord
,該結構在標準文檔《ISO-14496-15 AVC file format》中有詳細說明。
對于H.265格式的視頻來說,為HEVCDecoderConfigurationRecord
,此結構的定義目前未找到官方的定義,參考 https://lists.matroska.org/pipermail/matroska-devel/2013-September/004567.html 及ffmpeg中hevc.c文件中的實現,該結構詳細如下:
// The CodecPrivate syntax shall follow the
// syntax of HEVCDecoderConfigurationRecord
// defined in ISO/IEC 14496-15.
//
// The number zero (0) shall be written to
// the configurationVersion variable until
// official finalization of 14496-15, 3rd ed.
//
// After its finalization, this field and the
// following CodecPrivate structure shall
// follow the definition of the
// HEVCDecoderConfigurationRecord in 14496-15.
unsigned int(8) configurationVersion;
unsigned int(2) general_profile_space;
unsigned int(1) general_tier_flag;
unsigned int(5) general_profile_idc;
unsigned int(32) general_profile_compatibility_flags;
unsigned int(48) general_constraint_indicator_flags;
unsigned int(8) general_level_idc;
bit(4) reserved = ‘1111’b;
unsigned int(12) min_spatial_segmentation_idc;
bit(6) reserved = ‘111111’b;
unsigned int(2) parallelismType;
bit(6) reserved = ‘111111’b;
unsigned int(2) chromaFormat;
bit(5) reserved = ‘11111’b;
unsigned int(3) bitDepthLumaMinus8;
bit(5) reserved = ‘11111’b;
unsigned int(3) bitDepthChromaMinus8;
bit(16) avgFrameRate;
bit(2) constantFrameRate;
bit(3) numTemporalLayers;
bit(1) temporalIdNested;
unsigned int(2) lengthSizeMinusOne;
unsigned int(8) numOfArrays;
for (j=0; j < numOfArrays; j++) {
bit(1) array_completeness;
unsigned int(1) reserved = 0;
unsigned int(6) NAL_unit_type;
unsigned int(16) numNalus;
for (i=0; i< numNalus; i++) {
unsigned int(16) nalUnitLength;
bit(8*nalUnitLength) nalUnit;
}
}
其中最后的nalUnit存儲的即為VPS、SPS和PPS信息。
獲取到VPS、SPS和PPS之后,就可以通過
CMVideoFormatDescriptionCreateFromHEVCParameterSets
來創建H.265視頻格式的描述信息,再創建解碼session即可使用VideoToolBox進行解碼。
3.3 說明
iOS 11 beta2的版本中
VTDecompressionSessionWaitForAsynchronousFrames
此函數調用會失敗,目前不確定是beta系統的問題還是什么其他原因,在該版本的iOS系統上使用ijkplayer VideoToolBox解碼會發現播放卡頓,就是因為該函數的問題導致,留待后續版本觀察(7月10日已經推出beta3版本,還未確認)
四、結束語
本文僅僅簡單介紹了在iOS11系統上如何使用VideoTooBox進行HEVC硬編/硬解功能,目前我們的SDK中已經支持該功能,但是由于iOS11系統還未正式發布,所以該功能暫時未上線。如果您想嘗鮮使用,可以通過下面的聯系方式向我們獲取。iOS11系統發布后,我們會第一時間上線該功能。
轉載請注明:
作者金山視頻云,首發簡書 Jianshu.com
也歡迎大家使用我們的直播/短視頻SDK,支持高效H.265軟編,同時也適配了iOS 11 HEVC系統編解碼能力:
iOS直播版(推流 + 播放):https://github.com/ksvc/KSYLive_iOS
iOS播放 :https://github.com/ksvc/KSYMediaPlayer_iOS
有關音視頻的更多精彩內容,請參考https://github.com/ksvc
金山云SDK相關的QQ交流群:
- 視頻云技術交流群:574179720
- 視頻云iOS技術交流:621137661