1小時學會:最簡單的iOS直播推流(五)yuv贡蓖、pcm數(shù)據(jù)的介紹和獲取

最簡單的iOS 推流代碼曹鸠,視頻捕獲,軟編碼(faac斥铺,x264)彻桃,硬編碼(aac,h264)晾蜘,美顏邻眷,flv編碼眠屎,rtmp協(xié)議,陸續(xù)更新代碼解析肆饶,你想學的知識這里都有改衩,愿意懂直播技術(shù)的同學快來看!驯镊!

源代碼:https://github.com/hardman/AWLive

前面介紹了如何通過相機實時獲取音視頻數(shù)據(jù)葫督。

我們接下來就需要了解獲取到的數(shù)據(jù)到底是什么樣的。

使用系統(tǒng)提供的接口獲取到的音視頻數(shù)據(jù)都保存在CMSampleBufferRef中板惑。

使用GPUImamge獲取到的音頻數(shù)據(jù)為CMSampleBufferRef橄镜,獲取到的視頻格式為BGRA格式的二進制數(shù)據(jù)。

CMSampleBufferRef介紹

這個結(jié)構(gòu)在iOS中表示一幀音頻/視頻數(shù)據(jù)冯乘。

它里面包含了這一幀數(shù)據(jù)的內(nèi)容和格式洽胶。

我們可以把它的內(nèi)容取出來,提取出/轉(zhuǎn)換成 我們想要的數(shù)據(jù)裆馒。

代表視頻的CMSampleBufferRef中保存的數(shù)據(jù)是yuv420格式的視頻幀(因為我們在視頻輸出設(shè)置中將輸出格式設(shè)為:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)姊氓。

代表音頻的CMSampleBufferRef中保存的數(shù)據(jù)是PCM格式的音頻幀。

yuv是什么喷好?NV12又是什么他膳?

視頻是由一幀一幀的數(shù)據(jù)連接而成,而一幀視頻數(shù)據(jù)其實就是一張圖片绒窑。

yuv是一種圖片儲存格式棕孙,跟RGB格式類似。

RGB格式的圖片很好理解些膨,計算機中的大多數(shù)圖片蟀俊,都是以RGB格式存儲的。

yuv中订雾,y表示亮度肢预,單獨只有y數(shù)據(jù)就可以形成一張圖片,只不過這張圖片是灰色的洼哎。u和v表示色差(u和v也被稱為:Cb-藍色差烫映,Cr-紅色差),

為什么要yuv噩峦?

有一定歷史原因锭沟,最早的電視信號,為了兼容黑白電視识补,采用的就是yuv格式族淮。

一張yuv的圖像,去掉uv,只保留y祝辣,這張圖片就是黑白的贴妻。

而且yuv可以通過拋棄色差來進行帶寬優(yōu)化。

比如yuv420格式圖像相比RGB來說蝙斜,要節(jié)省一半的字節(jié)大小名惩,拋棄相鄰的色差對于人眼來說,差別不大孕荠。

一張yuv格式的圖像娩鹉,占用字節(jié)數(shù)為 (width * height + (width * height) / 4 + (width * height) / 4) = (width * height) * 3 / 2
一張RGB格式的圖像扛伍,占用字節(jié)數(shù)為(width * height) * 3

在傳輸上到推,yuv格式的視頻也更靈活(yuv3種數(shù)據(jù)可分別傳輸)。

很多視頻編碼器最初是不支持rgb格式的。但是所有的視頻編碼器都支持yuv格式槐瑞。

綜合來講,我們選擇使用yuv格式阁苞,所以我們編碼之前困檩,首先將視頻數(shù)據(jù)轉(zhuǎn)成yuv格式。

我們這里使用的就是yuv420格式的視頻那槽。

yuv420也包含不同的數(shù)據(jù)排列格式:I420悼沿,NV12,NV21.

其格式分別如下骚灸,
I420格式:y,u,v 3個部分分別存儲:Y0,Y1...Yn,U0,U1...Un/2,V0,V1...Vn/2
NV12格式:y和uv 2個部分分別存儲:Y0,Y1...Yn,U0,V0,U1,V1...Un/2,Vn/2
NV21格式:同NV12糟趾,只是U和V的順序相反。

綜合來說甚牲,除了存儲順序不同之外义郑,上述格式對于顯示來說沒有任何區(qū)別。

使用哪種視頻的格式丈钙,取決于初始化相機時設(shè)置的視頻輸出格式非驮。
設(shè)置為kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange時,表示輸出的視頻格式為NV12雏赦;
設(shè)置為kCVPixelFormatType_420YpCbCr8Planar時劫笙,表示使用I420。

GPUImage設(shè)置相機輸出數(shù)據(jù)時星岗,使用的就是NV12.

為了一致填大,我們這里也選擇NV12格式輸出視頻。

PCM是什么俏橘?

脈沖編碼調(diào)制栋盹,其實是將不規(guī)則的模擬信號轉(zhuǎn)換成數(shù)字信號,這樣就可以通過物理介質(zhì)存儲起來。

而聲音也是一種特定頻率(20-20000HZ)的模擬信號例获,也可以通過這種技術(shù)轉(zhuǎn)換成數(shù)字信號汉额,從而保存下來。

PCM格式榨汤,就是錄制聲音時蠕搜,保存的最原始的聲音數(shù)據(jù)格式。

相信你應該聽說過wav格式的音頻收壕,它其實就是給PCM數(shù)據(jù)流加上一段header數(shù)據(jù)妓灌,就成為了wav格式。

而wav格式有時候之所以被稱為無損格式蜜宪,就是因為他保存的是原始pcm數(shù)據(jù)(也跟采樣率和比特率有關(guān))虫埂。

像我們耳熟能詳?shù)哪切┮纛l格式,mp3圃验,aac等等掉伏,都是有損壓縮,為了節(jié)約占用空間澳窑,在很少損失音效的基礎(chǔ)上斧散,進行最大程度的壓縮。

所有的音頻編碼器摊聋,都支持pcm編碼鸡捐,而且錄制的聲音,默認也是PCM格式麻裁,所以我們下一步就是要獲取錄制的PCM數(shù)據(jù)箍镜。

從CMSampleBufferRef中提取yuv數(shù)據(jù)

在前面的文章(使用系統(tǒng)接口捕獲視頻)中,初始化輸出設(shè)備時煎源,我們將輸出的數(shù)據(jù)設(shè)置為kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange色迂。
因此在CMSampleBufferRef中保存的是yuv420(NV12)格式數(shù)據(jù)。
通過下面的方法將CMSampleBufferRef轉(zhuǎn)為yuv420(NV12)薪夕。

// AWVideoEncoder.m文件
-(NSData *) convertVideoSmapleBufferToYuvData:(CMSampleBufferRef) videoSample{
    // 獲取yuv數(shù)據(jù)
    // 通過CMSampleBufferGetImageBuffer方法脚草,獲得CVImageBufferRef。
    // 這里面就包含了yuv420(NV12)數(shù)據(jù)的指針
    CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(videoSample);
    
    //表示開始操作數(shù)據(jù)
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    
    //圖像寬度(像素)
    size_t pixelWidth = CVPixelBufferGetWidth(pixelBuffer);
    //圖像高度(像素)
    size_t pixelHeight = CVPixelBufferGetHeight(pixelBuffer);
    //yuv中的y所占字節(jié)數(shù)
    size_t y_size = pixelWidth * pixelHeight;
    //yuv中的uv所占的字節(jié)數(shù)
    size_t uv_size = y_size / 2;
    
    uint8_t *yuv_frame = aw_alloc(uv_size + y_size);
    
    //獲取CVImageBufferRef中的y數(shù)據(jù)
    uint8_t *y_frame = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
    memcpy(yuv_frame, y_frame, y_size);
    
    //獲取CMVImageBufferRef中的uv數(shù)據(jù)
    uint8_t *uv_frame = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
    memcpy(yuv_frame + y_size, uv_frame, uv_size);
    
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
    
    //返回數(shù)據(jù)
    return [NSData dataWithBytesNoCopy:yuv_frame length:y_size + uv_size];
}

將GPUImage獲取到的BGRA格式的圖片轉(zhuǎn)成yuv(NV12)格式

//AWGPUImageAVCapture.m文件
-(void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex{
    [super newFrameReadyAtTime:frameTime atIndex:textureIndex];
    if(!self.capture || !self.capture.isCapturing){
        return;
    }
    //將bgra轉(zhuǎn)為yuv
    //圖像寬度
    int width = imageSize.width;
    //圖像高度
    int height = imageSize.height;
    //寬*高
    int w_x_h = width * height;
    //yuv數(shù)據(jù)長度 = (寬 * 高) * 3 / 2
    int yuv_len = w_x_h * 3 / 2;
    
    //yuv數(shù)據(jù)
    uint8_t *yuv_bytes = malloc(yuv_len);
    
    //ARGBToNV12這個函數(shù)是libyuv這個第三方庫提供的一個將bgra圖片轉(zhuǎn)為yuv420格式的一個函數(shù)原献。
    //libyuv是google提供的高性能的圖片轉(zhuǎn)碼操作馏慨。支持大量關(guān)于圖片的各種高效操作,是視頻推流不可缺少的重要組件姑隅,你值得擁有写隶。
    [self lockFramebufferForReading];
    ARGBToNV12(self.rawBytesForImage, width * 4, yuv_bytes, width, yuv_bytes + w_x_h, width, width, height);
    [self unlockFramebufferAfterReading];
    
    NSData *yuvData = [NSData dataWithBytesNoCopy:yuv_bytes length:yuv_len];
    
    [self.capture sendVideoYuvData:yuvData];
}

從CMSampleBufferRef中提取PCM數(shù)據(jù)

// AWAudioEncoder.m 文件
-(NSData *) convertAudioSmapleBufferToPcmData:(CMSampleBufferRef) audioSample{
    //獲取pcm數(shù)據(jù)大小
    NSInteger audioDataSize = CMSampleBufferGetTotalSampleSize(audioSample);
    
    //分配空間
    int8_t *audio_data = aw_alloc((int32_t)audioDataSize);
    
    //獲取CMBlockBufferRef
    //這個結(jié)構(gòu)里面就保存了 PCM數(shù)據(jù)
    CMBlockBufferRef dataBuffer = CMSampleBufferGetDataBuffer(audioSample);
    //直接將數(shù)據(jù)copy至我們自己分配的內(nèi)存中
    CMBlockBufferCopyDataBytes(dataBuffer, 0, audioDataSize, audio_data);
    
    //返回數(shù)據(jù)
    return [NSData dataWithBytesNoCopy:audio_data length:audioDataSize];
}

至此我們已經(jīng)將捕獲的視頻數(shù)據(jù)轉(zhuǎn)為了yuv420格式,將音頻數(shù)據(jù)轉(zhuǎn)為了pcm格式讲仰。

接下來就可以對這些數(shù)據(jù)進行各種編碼了慕趴。編碼完成后,就可以將數(shù)據(jù)發(fā)送給服務(wù)器了。

文章列表

  1. 1小時學會:最簡單的iOS直播推流(一)項目介紹
  2. 1小時學會:最簡單的iOS直播推流(二)代碼架構(gòu)概述
  3. 1小時學會:最簡單的iOS直播推流(三)使用系統(tǒng)接口捕獲音視頻
  4. 1小時學會:最簡單的iOS直播推流(四)如何使用GPUImage冕房,如何美顏
  5. 1小時學會:最簡單的iOS直播推流(五)yuv躏啰、pcm數(shù)據(jù)的介紹和獲取
  6. 1小時學會:最簡單的iOS直播推流(六)h264、aac耙册、flv介紹
  7. 1小時學會:最簡單的iOS直播推流(七)h264/aac 硬編碼
  8. 1小時學會:最簡單的iOS直播推流(八)h264/aac 軟編碼
  9. 1小時學會:最簡單的iOS直播推流(九)flv 編碼與音視頻時間戳同步
  10. 1小時學會:最簡單的iOS直播推流(十)librtmp使用介紹
  11. 1小時學會:最簡單的iOS直播推流(十一)sps&pps和AudioSpecificConfig介紹(完結(jié))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末给僵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子详拙,更是在濱河造成了極大的恐慌帝际,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饶辙,死亡現(xiàn)場離奇詭異蹲诀,居然都是意外死亡,警方通過查閱死者的電腦和手機弃揽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門脯爪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蹋宦,你說我怎么就攤上這事披粟≈涠停” “怎么了冷冗?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長惑艇。 經(jīng)常有香客問我蒿辙,道長,這世上最難降的妖魔是什么滨巴? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任思灌,我火速辦了婚禮,結(jié)果婚禮上恭取,老公的妹妹穿的比我還像新娘泰偿。我一直安慰自己,他們只是感情好蜈垮,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布耗跛。 她就那樣靜靜地躺著,像睡著了一般攒发。 火紅的嫁衣襯著肌膚如雪调塌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天惠猿,我揣著相機與錄音羔砾,去河邊找鬼。 笑死,一個胖子當著我的面吹牛姜凄,可吹牛的內(nèi)容都是我干的政溃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼态秧,長吁一口氣:“原來是場噩夢啊……” “哼玩祟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起屿聋,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤空扎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后润讥,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體转锈,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年楚殿,在試婚紗的時候發(fā)現(xiàn)自己被綠了撮慨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡脆粥,死狀恐怖砌溺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情变隔,我是刑警寧澤规伐,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站匣缘,受9級特大地震影響猖闪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肌厨,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一培慌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柑爸,春花似錦吵护、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至进胯,卻和暖如春用爪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胁镐。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工偎血, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诸衔,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓颇玷,卻偏偏與公主長得像笨农,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子帖渠,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容