h264視頻
收到的純視頻或者音頻的數(shù)據(jù)應(yīng)該先保存到本地悍缠,用vlc先測試,如果能播放證明數(shù)據(jù)沒有問題耐量,才好進(jìn)行下一步解碼播放
關(guān)于VideoToolBox也有很多的東西飞蚓,接口和屬性的定義等,找到兩篇文章做了介紹
使用VideoToolbox硬解碼H.264
VideoToolbox解析
當(dāng)初自己注釋的代碼不小心刪了,現(xiàn)在對比著demo在捋一下流程decode demo
- 聲明用到的幾個成員
//sps 和 pps的內(nèi)存區(qū)以及大小
uint8_t *_sps;
NSInteger _spsSize;
uint8_t *_pps;
NSInteger _ppsSize;
//解碼會話的引用
VTDecompressionSessionRef _deocderSession;
//描述媒體數(shù)據(jù)和其他各樣的類型的引用
CMVideoFormatDescriptionRef _decoderFormatDescription;
- 解碼的入口
#pragma mark - 對外提供解碼接口
-(void) decodeNalu:(uint8_t *)frame withSize:(uint32_t)frameSize;
1.此函數(shù)中廊蜒,將前四個字節(jié)替換為數(shù)據(jù)幀的大小減去00 00 00 01四個字節(jié);這一步我記得有一個方法可以直接轉(zhuǎn)換的(CFSwapInt32HostToBig)著榴,現(xiàn)在是手動一個字節(jié)一個字節(jié)轉(zhuǎn)的。
2.判斷脑又,nalu類型锐借,如果是5代表關(guān)鍵幀初始化解碼器,7和8分別初始化sps和pps其他的就是數(shù)據(jù)幀調(diào)用解碼函數(shù)钞翔。
- 初始化解碼器
按流程倒著來:
為解碼視頻幀創(chuàng)建一個解碼會話严卖,VTDecompressionSessionCreate布轿,解碼的幀會通過回調(diào)函數(shù)發(fā)出。函數(shù)要傳遞一些參數(shù)
1.分配器疟呐,傳NULL使用默認(rèn)的即可
2.videoFormatDescription就是成員描述媒體數(shù)據(jù)的那個引用
3.指定一個專門的視頻解碼器东且,傳入NULL讓video toolbox選擇一個解碼器
4.想要輸出的圖像數(shù)據(jù)的屬性等
5.解碼后的回調(diào)函數(shù)
6.成員中的那個deocderSession來接收創(chuàng)建的這個解碼會話
然后可以為這個會話設(shè)置一些屬性
//kVTDecompressionPropertyKey_RealTime 解碼實時輸出珊泳,后面那個參數(shù)具體沒弄清呢
VTSessionSetProperty(_deocderSession, kVTDecompressionPropertyKey_RealTime, kCFBooleanTrue);
這樣的話拷沸,在initH264Decoder方法中最開始那些操作當(dāng)然就是為VTDecompressionSessionCreate這個做的一些準(zhǔn)備了⊙砹耍看看就懂了序无。
- 解碼
通過CMBlockBufferCreateWithMemoryBlock方法創(chuàng)建CMBlockBufferRef衡创,在用BlockBuffer通過CMSampleBufferCreateReady創(chuàng)建CMSampleBufferRef璃氢,然后使用VTDecompressionSessionDecodeFrame進(jìn)行解碼狮辽,解碼后會調(diào)用回調(diào)函數(shù)。在回調(diào)函數(shù)中喉脖,使用了代理傳出解碼后的數(shù)據(jù)树叽,進(jìn)行顯示。
在這個解碼方法中有個sourceFrameRefCon參數(shù)须误,傳入了一開始定義的CVPixelBufferRef outputPixelBuffer = NULL;這里這個參數(shù)跟回調(diào)函數(shù)中那個sourceFrameRefCon是一個仇轻。
- 顯示的方法:這里直接使用了apple寫好的一個AAPLEAGLLayer來顯示了,貌似還可以轉(zhuǎn)為圖片顯示哦
//先創(chuàng)建
-(void)createLayer{
_playLayer = [[AAPLEAGLLayer alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
_playLayer.backgroundColor = [UIColor blackColor].CGColor;
[self.layer addSublayer:_playLayer];
}
//代理
#pragma mark - 解碼回調(diào)
- (void)displayDecodedFrame:(CVImageBufferRef )imageBuffer{
if(imageBuffer)
{
_playLayer.pixelBuffer = imageBuffer;
CVPixelBufferRelease(imageBuffer);
}
return;
}
- 關(guān)于一些數(shù)據(jù)結(jié)構(gòu)定義
1祭椰、CVPixelBuffer:編碼前和解碼后的圖像數(shù)據(jù)結(jié)構(gòu)方淤;
2蹄殃、CMBlockBuffer:編碼后圖像的數(shù)據(jù)結(jié)構(gòu);
而CMSampleBuffer就相當(dāng)于一個容器诅岩,他存放上面兩種類型的一種以及cmtime等一些參數(shù)吩谦。供編解碼器使用。
我們還可以看到一些結(jié)構(gòu)如下:
typedef CVImageBufferRef CVPixelBufferRef;
typedef CVBufferRef CVImageBufferRef;
一開始納悶這是啥意思咐扭,這樣有啥用,后來看文檔說的很清楚:CVBuffer就像抽象基類一樣袜爪,他定義了如何與緩沖區(qū)的數(shù)據(jù)進(jìn)行交互穗慕。這個buffer可以包含視頻,音頻等怀各,像CVImageBuffer瓢对,CVPixelBuffer都是由它衍生出來的胰苏。這一點和CMVideoFormatDescriptionRef也類似,CMFormatDescriptions代表一些描述信息硕并,可以用來描述音頻視頻等類型,也是基類一樣埃仪,具體明確的description就有CMVideoFormatDescription和CMAudioFormatDescription陕赃。