2014-09-28 87 views
5

在詳細回顧了WWDC2014 Session513之後,我嘗試在IOS8.0上編寫我的應用程序來解碼和顯示一個實時H.264流。首先,我成功構建了H264參數集。當我得到一個4位起始碼的幀時,就像「0x00 0x00 0x00 0x01 0x65 ...」,我把它放到一個CMblockBuffer中。然後我使用預覽CMBlockBuffer構造一個CMSampleBuffer。之後,我將CMSampleBuffer放入AVSampleBufferDisplayLayer中。一切正常(我檢查了返回的值),除了AVSampleBufferDisplayLayer不顯示任何視頻圖像。由於這些API對每個人來說都是相當新穎的,所以我找不到任何可以解決此問題的機構。將H.264 I幀放到AVSampleBufferDisplayLayer中,但沒有顯示視頻圖像

我給出的關鍵代碼如下,我真的很感激它,如果你能幫助找出爲什麼無法顯示視頻圖像。非常感謝。

(1)AVSampleBufferDisplayLayer初始化。 dsplayer是我的主視圖控制器的objc實例。

@property(nonatomic,strong)AVSampleBufferDisplayLayer *dspLayer; 

if(!_dspLayer) 
{ 
    _dspLayer = [[AVSampleBufferDisplayLayer alloc]init]; 
    [_dspLayer setFrame:CGRectMake(90,551,557,389)]; 
    _dspLayer.videoGravity = AVLayerVideoGravityResizeAspect; 
    _dspLayer.backgroundColor = [UIColor grayColor].CGColor; 
    CMTimebaseRef tmBase = nil; 
    CMTimebaseCreateWithMasterClock(NULL,CMClockGetHostTimeClock(),&tmBase); 
    _dspLayer.controlTimebase = tmBase; 
    CMTimebaseSetTime(_dspLayer.controlTimebase, kCMTimeZero); 
    CMTimebaseSetRate(_dspLayer.controlTimebase, 1.0); 

    [self.view.layer addSublayer:_dspLayer]; 

} 

(2)在另一個線程中,我得到一個H.264 I幀。 //構造H.264參數組確定

CMVideoFormatDescriptionRef formatDesc; 
    OSStatus formatCreateResult = 
    CMVideoFormatDescriptionCreateFromH264ParameterSets(NULL, ppsNum+1, props, sizes, 4, &formatDesc); 
    NSLog([NSString stringWithFormat:@"construct h264 param set:%ld",formatCreateResult]); 

//構造cmBlockbuffer。// databuf指向H.264數據。開始於 「0×00 0×00 0×00 0×01 0x65 ........」

CMBlockBufferRef blockBufferOut = nil; 
    CMBlockBufferCreateEmpty (0,0,kCMBlockBufferAlwaysCopyDataFlag, &blockBufferOut); 
    CMBlockBufferAppendMemoryBlock(blockBufferOut, 
            dataBuf, 
            dataLen, 
            NULL, 
            NULL, 
            0, 
            dataLen, 
            kCMBlockBufferAlwaysCopyDataFlag); 

//構建cmsamplebuffer確定

size_t sampleSizeArray[1] = {0}; 
    sampleSizeArray[0] = CMBlockBufferGetDataLength(blockBufferOut); 
    CMSampleTiminginfo tmInfos[1] = { 
     {CMTimeMake(5,1), CMTimeMake(5,1), CMTimeMake(5,1)} 
    }; 
    CMSampleBufferRef sampBuf = nil; 
    formatCreateResult = CMSampleBufferCreate(kCFAllocatorDefault, 
         blockBufferOut, 
         YES, 
         NULL, 
         NULL, 
         formatDesc, 
         1, 
         1, 
         tmInfos, 
         1, 
         sampleSizeArray, 
         &sampBuf); 

//投入AVSampleBufferdisplayLayer,只是一個框架。但我看不到任何視頻框架在我看來

if([self.dspLayer isReadyForMoreMediaData]) 
    { 
    [self.dspLayer enqueueSampleBuffer:sampBuf]; 
    } 
    [self.dspLayer setNeedsDisplay]; 
+0

Scythe42答案可能會解決你的問題。我也遇到了一些問題,使其工作。但最後我做到了。你應該[看看](http://stackoverflow.com/questions/25980070/how-to-use-avsamplebufferdisplaylayer-in-ios-8-for-rtp-h264-streams-with-gstream)。 – Zappel 2014-10-29 19:09:07

+0

也一樣。有一個vail&ready CMSampleBuffer,但它不會顯示在屏幕上...... :( – zaxy78 2017-11-01 14:15:19

回答

4

你NAL單元起始碼0×00 0×00 0×01或0×00 0×00 0×00 0×01需要由長度頭部被替換。

您在WWDC會議中已明確指出,附件B的開始代碼需要由AVCC符合標題替換。您基本上正在從這裏的附件B流格式轉換MP4文件格式(當然的簡化說明)。

您創建參數集時的呼叫對此是「4」,所以您需要以4字節長度的前綴爲您的VCL NAL單元加前綴。這就是爲什麼你將它指定爲AVCC格式,長度標題可以更短。

無論你放進CMSampleBuffer裏面什麼都沒問題,如果內容可以被解碼,就沒有理智檢查,只要你滿足了任意數據結合定時信息和參數集的必要參數。

基本上你輸入的數據表示VCL NAL單元長度爲1個字節。解碼器沒有得到完整的NAL單元,並在出現錯誤時解除。

還要確保在使用創建PPS/SPS沒有添加長度副本的參數集並且附件B開始代碼也被剝離時。

另外我建議不要使用AVSampleBufferDisplayLayer,但要經過一個VTDecompressionSession,因此您可以執行諸如顏色校正或像素着色器內所需的其他內容。

+2

注意NAL長度代碼需要以big-endian字節順序也很重要。 – Greg 2015-03-03 20:25:22

0

最初使用DecompressionSessionDecode Frame可能是一個想法,因爲這會給你一些關於解碼成功的反饋。如果解碼出現問題,AVSampleBufferDisplay圖層不會告訴您它只是不顯示任何內容。我可以給你一些代碼,以幫助如果需要,讓我知道你是如何得到的,因爲我正在嘗試同樣的事情:)