基于iOS11的HEVC(H.265)硬編碼/硬解碼功能開發指南

蘋果于北京時間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.264與H.265的壓縮效果對比.png

需要注意的是,H.265的硬編/解功能,并不是ios的所有設備升級到新系統上都可以使用,目前蘋果公布可使用HEVC編/解碼的移動設備要求如下:

iOS 11 HEVC Encode

H.265硬編.png

iOS 11 HEVC Decode

H.265硬解.png

二、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的為兩個字節,其結構如下:

H265 nalu header

所以,H.265編碼格式的NALU類型判斷方式如下,code為NALU Header的第一個字節:

int type = (code & 0x7E)>>1;

其中type類型為32、33、34的NALU分別為VPSSPSPPS,其他類型參見H.265規范《T-REC-H.265-201304-I!!PDF-E》。

3.2 HEVCDecoderConfigurationRecord

使用ffmpeg讀取MP4文件后,視頻的AVCodecContext結構的extradata存儲的即為包含有SPSPPS信息的數據結構。

對于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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。