iOS系統(tǒng)中H264硬解及顯示說明
蘋果在iOS 8.0系統(tǒng)之前媳否,沒有開放系統(tǒng)的硬件編碼解碼功能誓沸,不過Mac OS系統(tǒng)一直有,被稱為Video ToolBox的框架來處理硬件的編碼和解碼,終于在iOS 8.0后,蘋果將該框架引入iOS系統(tǒng)。
一荧止、VideoToolbox基本數(shù)據(jù)結(jié)構(gòu):
1、CVPixelBuffer:編碼前和解碼后的圖像數(shù)據(jù)結(jié)構(gòu)阶剑;
2跃巡、CMTime、CMClock和CMTimebase:時間戳相關(guān)牧愁。時間以64-bit/32-bit的形式出現(xiàn)素邪;
3、CMBlockBuffer:編碼后猪半,結(jié)果圖像的數(shù)據(jù)結(jié)構(gòu)兔朦;
4、CMVideoFormatDescription:圖像存儲方式磨确,編解碼器等格式描述沽甥;
5、CMSampleBuffer:存放編解碼前后的視頻圖像的容器數(shù)據(jù)結(jié)構(gòu)乏奥。
下圖為H264解碼前后數(shù)據(jù)結(jié)構(gòu)示意圖:
二摆舟、硬解使用方法:
H264的碼流由NALU單元組成,NALU單元包含視頻圖像數(shù)據(jù)和H264的參數(shù)信息邓了。其中視頻圖像數(shù)據(jù)就是CMBlockBuffer盏檐,而H264的參數(shù)信息則可以組合成FormatDesc。具體來說參數(shù)信息包含SPS(Sequence Parameter Set)和PPS(Picture Parameter Set)驶悟。下圖顯示一個H264碼流的結(jié)構(gòu):
解碼方式一:(通過系統(tǒng)提供的AVSampleBufferDisplayLayer來解碼并顯示)
1、初始化H264硬解param:
1) 提取sps和pps生成format description;
//sps
_spsSize =format.getCsd_0_size()-4;_sps = (uint8_t *)malloc(_spsSize);memcpy(_sps,format.getCsd_0()+4, _spsSize);
//pps
_ppsSize =format.getCsd_1_size()-4;_pps = (uint8_t *)malloc(_ppsSize);memcpy(_pps,format.getCsd_1()+4, _ppsSize);
2) 使用CMVideoFormatDescriptionCreateFromH264ParameterSets函數(shù)來構(gòu)建CMVideoFormatDescriptionRef材失。
CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
2, //param count? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? parameterSetPointers,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? parameterSetSizes,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4, //nalstartcodesize&_decoderFormatDescription);
2痕鳍、將H264碼流轉(zhuǎn)換成解碼前的CMSampleBuffer:
? 1) 使用CMBlockBufferCreateWithMemoryBlock接口構(gòu)造CMBlockBufferRef;
CMBlockBufferRef blockBuffer=NULL;CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (void*)frame.bytes,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? frame.length,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? kCFAllocatorNull,NULL,0, frame.length,0,&blockBuffer);
? 2)根據(jù)上述得到CMVideoFormatDescriptionRef、CMBlockBufferRef和可選的時間信息,使用CMSampleBufferCreate接口得到CMSampleBuffer數(shù)據(jù)這個待解碼的原始的數(shù)據(jù)笼呆。
CMSampleBufferRef sampleBuffer =NULL;CMSampleBufferCreateReady(kCFAllocatorDefault,? ? ? ? ? ? ? ? ? ? ? ? ? blockBuffer,? ? ? ? ? ? ? ? ? ? ? ? ? _decoderFormatDescription,1,0,NULL,1, sampleSizeArray,? ? ? ? ? ? ? ? ? ? ? ? ? &sampleBuffer);
3熊响、硬解圖像顯示:
通過系統(tǒng)提供的AVSampleBufferDisplayLayer來解碼并顯示。
AVSampleBufferDisplayLayer是蘋果提供的一個專門顯示編碼后的H264數(shù)據(jù)的顯示層诗赌,它是CALayer的子類汗茄,因此使用方式和其它CALayer類似。該層內(nèi)置了硬件解碼功能铭若,將原始的CMSampleBuffer解碼后的圖像直接顯示在屏幕上面洪碳,非常的簡單方便。
CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer,YES);CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments,0);CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);if(status == kCMBlockBufferNoErr) {
if([_avslayer isReadyForMoreMediaData]) ? ? ? ? ? ??{dispatch_sync(dispatch_get_main_queue(),^{ ? ? ? ?
? ? [_avslayer enqueueSampleBuffer:sampleBuffer]; ? ? ?
? ? });? ?
? }? ??
CFRelease(sampleBuffer);
}
解碼方式二:(通過VTDecompression接口叼屠,將CMSampleBuffer解碼成圖像瞳腌,將圖像通過UIImageView或者OpenGL來顯示)
1、初始化H264硬解param:
在方式一的基礎(chǔ)上,使用VTDecompressionSessionCreate接口構(gòu)造VTDecompressionSessionRef;(初始化VTDecompressionSession镜雨,設(shè)置解碼器的相關(guān)信息)
VTDecompressionSessionRef _deocderSession;VTDecompressionSessionCreate(kCFAllocatorDefault,? ? ? ? ? ? ? ? ? ? ? ? ? ? _decoderFormatDescription,NULL, attrs,? ? ? ? ? ? ? ? ? ? ? ? ? ? &callBackRecord,? ? ? ? ? ? ? ? ? ? ? ? ? ? &_deocderSession);
2嫂侍、將H264碼流轉(zhuǎn)換成解碼前的CMSampleBuffer:
同方式一
3、將CMSampleBuffer數(shù)據(jù)使用VTDecompressionSessionDecodeFrame接口解碼成CVPixelBufferRef數(shù)據(jù):
CVPixelBufferRef outputPixelBuffer=NULL;
VTDecompressionSessionDecodeFrame(_deocderSession,
sampleBuffer,
flags,
&outputPixelBuffer,
&flagOut);
4荚坞、將CVPixelBufferRef數(shù)據(jù)轉(zhuǎn)換成UIImage并顯示:
CIImage*ciImage= [CIImage imageWithCVPixelBuffer:outputPixelBuffer];UIImage*uiImage= [UIImage imageWithCIImage:ciImage];
三挑宠、程序流程框圖:
解碼方式一
解碼方式二
四、兩種解碼方式比較:
解碼方式一:
優(yōu)點(diǎn): 該方式通過系統(tǒng)提供的AVSampleBufferDisplayLayer顯示層來解碼并顯示颓影。該層內(nèi)置了硬件解碼功能各淀,將原始的CMSampleBuffer解碼后的圖像直接顯示在屏幕上,非常的簡單方便,且執(zhí)行效率高瞭空,占用內(nèi)存相對較少揪阿。
缺點(diǎn): 從解碼的數(shù)據(jù)中不能直接獲取圖像數(shù)據(jù)并對其做相應(yīng)處理,解碼后的數(shù)據(jù)不能直接進(jìn)行其他方面的應(yīng)用(一般要做較復(fù)雜的轉(zhuǎn)換)咆畏。
解碼方式二:
優(yōu)點(diǎn): 該方式通過VTDecompressionSessionDecodeFrame接口南捂,得到CVPixelBufferRef數(shù)據(jù),我們可以直接從CVPixelBufferRef數(shù)據(jù)中獲取圖像數(shù)據(jù)并對其做相應(yīng)處理旧找,方便于其他應(yīng)用溺健。
缺點(diǎn): 解碼中執(zhí)行效率相對降低,占用的內(nèi)存也會相對較大钮蛛。
').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('
').text(i)); }; $numbering.fadeIn(1700); }); });
以上就介紹了iOS系統(tǒng)中H264硬解及顯示說明鞭缭,包括了方面的內(nèi)容,希望對IOS開發(fā)有興趣的朋友有所幫助魏颓。
加一條個人github上demo地址:h264硬解碼demo