一、videoToolbox的基本數(shù)據(jù)
Video Toolbox視頻編解碼前后需要應(yīng)用的數(shù)據(jù)結(jié)構(gòu)進(jìn)行說(shuō)明。
CVPixelBuffer:編碼前和解碼后的圖像數(shù)據(jù)結(jié)構(gòu)。此內(nèi)容包含一系列的CVPixelBufferPool內(nèi)容
CMTime、CMClock和CMTimebase:時(shí)間戳相關(guān)。時(shí)間以64-bit/32-bit的形式出現(xiàn)。
pixelBufferAttributes:字典設(shè)置.可能包括Width/height、pixel format type、Compatibility (e.g., OpenGL ES, Core Animation)
CMBlockBuffer:編碼后,結(jié)果圖像的數(shù)據(jù)結(jié)構(gòu)。
CMVideoFormatDescription:圖像存儲(chǔ)方式,編解碼器等格式描述。
CMTimebase: 關(guān)于CMClock的一個(gè)控制視圖,包含CMClock、時(shí)間映射(Time mapping)、速率控制(Rate control)
CMSampleBuffer:存放編解碼前后的視頻圖像的容器數(shù)據(jù)結(jié)構(gòu)。
編碼前后的視頻圖像都封裝在 CMSampleBuffer中,編碼前以 CVPixelBuffer 進(jìn)行存儲(chǔ);編碼后以 CMBlockBuffer進(jìn)行存儲(chǔ)。除此之外兩者都括 CMTim 、 CMVideoFormatDesc。

二、硬解碼基本流程
1、由sps和pps創(chuàng)建CMVideoFormatDescription,每次重新來(lái)sps和pps都要重新創(chuàng)建。
const uint8_t* parameterSetPointers[2] = {mSPS, mPPS};
const size_t parameterSetSizes[2] = {mSPSSize, mPPSSize};
OSStatus status =
CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault,
2, //param count
parameterSetPointers,
parameterSetSizes,
4, //nal start code size
&mFormatDescription);
2、由CMVideoFormatDescription創(chuàng)建mDecodeSession,以及指定獲取解碼數(shù)據(jù)的回調(diào)函數(shù)。創(chuàng)建解碼會(huì)話需要提供回調(diào)函數(shù)以便系統(tǒng)解碼完成時(shí)將解碼數(shù)據(jù)、狀態(tài)等信息返回給用戶。
CFDictionaryRef attrs = NULL;
const void *keys[] = { kCVPixelBufferPixelFormatTypeKey };
// kCVPixelFormatType_420YpCbCr8Planar is YUV420
// kCVPixelFormatType_420YpCbCr8BiPlanarFullRange is NV12
uint32_t v = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;
const void *values[] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &v) };
attrs = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
VTDecompressionOutputCallbackRecord callBackRecord;
callBackRecord.decompressionOutputCallback = didDecompress;
callBackRecord.decompressionOutputRefCon = NULL;
//這個(gè)是用來(lái)做異步解碼實(shí)現(xiàn)的,decompressionOutputRefCon 為需要指定的對(duì)象,即自己。didDecompress則為回調(diào)函數(shù)。
status = VTDecompressionSessionCreate(kCFAllocatorDefault,
mFormatDescription,
NULL, attrs,
&callBackRecord,
&mDecodeSession);
CFRelease(attrs);
3、由編碼的數(shù)據(jù)(I、P、B幀數(shù)據(jù))創(chuàng)建CMBlockBuffer。
CMBlockBufferRef blockBuffer = NULL;
OSStatus status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,
(void*)packetBuffer, packetSize,
kCFAllocatorNull,
NULL, 0, packetSize,
0, &blockBuffer);
4、由CMBlockBuffer和CMVideoFormatDescription創(chuàng)建CMSampleBuffer
CMSampleBufferRef sampleBuffer = NULL;
const size_t sampleSizeArray[] = {packetSize};
status = CMSampleBufferCreateReady(kCFAllocatorDefault,
blockBuffer,
mFormatDescription,
1, 0, NULL, 1, sampleSizeArray,
&sampleBuffer);
5、解碼
VideoToolbox支持同、異步解碼,由VTDecodeFrameFlags指定,VTDecodeFrameFlags flags = kVTDecodeFrame_EnableAsynchronousDecompression; ,默認(rèn)為同步解碼。
同步解碼時(shí),調(diào)用解碼函數(shù) VTDecompressionSessionDecodeFrame 后系統(tǒng)回調(diào)我們提供的回調(diào)函數(shù),然后解碼函數(shù)才結(jié)束調(diào)用。異步解碼則回調(diào)順序不確定,故需要自行整理幀序。
VTDecodeFrameFlags flags = 0;
VTDecodeInfoFlags flagOut = 0;
// 默認(rèn)是同步操作。
// 調(diào)用didDecompress,返回后再回調(diào)
OSStatus decodeStatus = VTDecompressionSessionDecodeFrame(mDecodeSession,
sampleBuffer,
flags,
&outputPixelBuffer,//輸出解碼數(shù)據(jù)
&flagOut);
6、異步解碼回調(diào),調(diào)用解碼函數(shù)后回掉函數(shù)didDecompress,用來(lái)獲取解碼出的數(shù)據(jù)。
void didDecompress(void *decompressionOutputRefCon, void *sourceFrameRefCon,
OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef pixelBuffer,
CMTime presentationTimeStamp, CMTime presentationDuration ){
CVPixelBufferRef *outputPixelBuffer = (CVPixelBufferRef *)sourceFrameRefCon;
*outputPixelBuffer = CVPixelBufferRetain(pixelBuffer);
}