AAC、H264網(wǎng)絡(luò)流播放-H264硬解碼顯示

h264視頻

收到的純視頻或者音頻的數(shù)據(jù)應該先保存到本地,用vlc先測試,如果能播放證明數(shù)據(jù)沒有問題,才好進行下一步解碼播放

關(guān)于VideoToolBox也有很多的東西,接口和屬性的定義等,找到兩篇文章做了介紹
使用VideoToolbox硬解碼H.264
VideoToolbox解析

當初自己注釋的代碼不小心刪了,現(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使用默認的即可
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方法中最開始那些操作當然就是為VTDecompressionSessionCreate這個做的一些準備了??纯淳投恕?/p>

  • 解碼

通過CMBlockBufferCreateWithMemoryBlock方法創(chuàng)建CMBlockBufferRef,在用BlockBuffer通過CMSampleBufferCreateReady創(chuàng)建CMSampleBufferRef,然后使用VTDecompressionSessionDecodeFrame進行解碼,解碼后會調(diào)用回調(diào)函數(shù)。在回調(diào)函數(shù)中,使用了代理傳出解碼后的數(shù)據(jù),進行顯示。

在這個解碼方法中有個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就相當于一個容器,他存放上面兩種類型的一種以及cmtime等一些參數(shù)。供編解碼器使用。

我們還可以看到一些結(jié)構(gòu)如下:

typedef CVImageBufferRef CVPixelBufferRef;  
typedef CVBufferRef CVImageBufferRef;

一開始納悶這是啥意思,這樣有啥用,后來看文檔說的很清楚:CVBuffer就像抽象基類一樣,他定義了如何與緩沖區(qū)的數(shù)據(jù)進行交互。這個buffer可以包含視頻,音頻等,像CVImageBuffer,CVPixelBuffer都是由它衍生出來的。這一點和CMVideoFormatDescriptionRef也類似,CMFormatDescriptions代表一些描述信息,可以用來描述音頻視頻等類型,也是基類一樣,具體明確的description就有CMVideoFormatDescription和CMAudioFormatDescription。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容