音視頻知識(shí)梳理

一墓臭、整體播放策略

(1)iOS自帶的播放控件
- AVPlayer蘸鲸、AVQueuePlayer
只能通過(guò)路徑播放妖谴,可以播放本地視頻與云視頻
- AVSampleBufferDisplayLayer
可以實(shí)現(xiàn)按幀播放
(2)第三方
- ijkPlayer
默認(rèn)只支持按路徑播放窿锉,可以通過(guò)IO管道的方式,改為按幀播放方式
(3)組合方式
系統(tǒng)硬解VideoToolBox/ffmpeg軟解 + OpenGL顯示

二膝舅、VideoToolBox硬解

CMSampleBuffer = CMTime + FormatDesc(sps嗡载,pps) + CMBlockBuffer
CMBlockBuffer:編碼的圖像數(shù)據(jù)結(jié)構(gòu)
CVPixelBuffer:解碼后的圖像數(shù)據(jù)結(jié)構(gòu)

VTDecompressionSessionRef decodeSession

(CMSampleBuffer+decodeSession)—>VTDecompressionSessionDecodeFrame—>CVPixelBuffer

三、ffmpeg解碼

AVPacket—>AVFrame
1仍稀、創(chuàng)建AVCodec codec = avcodec_find_decoder(AV_CODEC_ID_H264)
2洼滚、創(chuàng)建AVCodecContext codecCtx = avcodec_alloc_context3(codec);
3、avcodec_open2(codecCtx, codec, NULL)
4技潘、視頻幀組裝成 AVPacket
5遥巴、avcodec_send_packet(codecCtx, &packet)
6、avcodec_receive_frame(codecCtx, AVFrame)

(1)AVFrame中取到Y(jié)UV數(shù)據(jù)(這里的是非交叉的)
Y:
AVFrame->data[0] 存Y數(shù)據(jù)的buffer
AVFrame->linesize[0] Y數(shù)據(jù)一段的長(zhǎng)度享幽,一般等于像素width铲掐。有幾段呢,就得看height

AVFrame->data[1] 存U數(shù)據(jù)的buffer
AVFrame->linesize[1] U數(shù)據(jù)一段的長(zhǎng)度值桩,一般等于像素width/2摆霉。有幾段呢,就得看height/2

AVFrame->data[2] 存V數(shù)據(jù)的buffer
AVFrame->linesize[2] V數(shù)據(jù)一段的長(zhǎng)度奔坟,一般等于像素width/2携栋。有幾段呢,就得看height/2

比如存到NDData里面:
width = MIN(linesize, width);
NSMutableData *md = [NSMutableData dataWithLength: width * height];
Byte *dst = (Byte *)md.mutableBytes;
for (NSUInteger i = 0; i < height; ++i) {
memcpy(dst, src, width);
dst += width;
src += linesize;
}
return md;

AVFrame->data只能以linesize作為取值累積量咳秉,這樣才不會(huì)出現(xiàn)越界或者取錯(cuò)數(shù)據(jù)

(2)IOS硬解得到的CVImageBufferRef婉支,其中的YUV是交叉存儲(chǔ)的
CVImageBufferRef imageBuffer =CMSampleBufferGetImageBuffer(sampleBuffer);

四、ffmpeg其他一些重要信息

(1)主要結(jié)構(gòu)體
AVFormatContext:文件信息上下文澜建,其中就包含了流信息結(jié)構(gòu)AVStream

AVStream:流信息磅摹,其中就包含具體的音視頻格式信息上下文AVCodecContext

AVCodecContext:具體的音視頻格式信息滋迈。要解碼音視頻,需要從這里拿到相關(guān)信息户誓,比如AVCodecID

AVPacket:未解碼的音視頻內(nèi)容饼灿。比如視頻的每一幀數(shù)據(jù),就體現(xiàn)在一個(gè)packet中

AVFrame:解碼后的音視頻內(nèi)容

(2)H264的兩種格式 Annex-B與AVCC
- Annex-B
0000000167(SPS)+0000000168(PPS)+0000000165(IDR)+其他幀

- AVCC
extradata+NAL長(zhǎng)度+NAL+NAL長(zhǎng)度+NAL帝美。碍彭。。
NAL長(zhǎng)度所占字節(jié)悼潭、SPS與PPS等包含在extradata中

(3)extradata
解碼AVCC需要與視頻合成都需要extradata庇忌,如何構(gòu)造extradata
- extradata(Annex-B)
- extradata(AVCC)
- extradata(Annex-B) 轉(zhuǎn)換為 extradata(AVCC)

(4)timebase
ffmpeg中的一種時(shí)間單位,包含了與秒的對(duì)應(yīng)關(guān)系舰褪,都可以轉(zhuǎn)換為秒皆疹。
- pts,dts占拍,duration
pts * timebase = 以秒為單位的值

(5)解碼流程
- 解Annex-B的H264
- 解AVCC的H264

(6)編碼流程
- 生成AVCodecContext略就,要設(shè)置分辨率,pix_fmt等參數(shù)
- avcodec_open2(codecCtx, codec, NULL)
- avcodec_send_frame(codecCtx, frame);
- avcodec_receive_packet(codecCtx, pkt);

(7)H264 合成mp4流程
- avformat_alloc_output_context2 創(chuàng)建輸出的文件
- avformat_new_stream 創(chuàng)建視頻流
- 構(gòu)造AVCodecContext晃酒,賦值給AVStream->codecpar
- 設(shè)置timebase表牢,AVStream->time_base
- avio_open打開(kāi)輸出文件
- avformat_write_header寫入頭
- av_interleaved_write_frame 寫入packet
- av_write_trailer 寫入結(jié)尾

五、OpenGL

簡(jiǎn)單說(shuō)就是直接操作GPU進(jìn)行圖片的渲染贝次。OpenGL有自己的渲染管線崔兴,提供給外部修改的有頂點(diǎn)處理和片元處理。
頂點(diǎn)處理:我們可以為OpenGL提供頂點(diǎn)蛔翅,相當(dāng)于構(gòu)建了圖片的外部框架(頂點(diǎn)坐標(biāo))
片元處理:提供圖片紋理填充剛才構(gòu)建的外部框架的內(nèi)容 (通過(guò)紋理坐標(biāo)可以控制圖片的方向)
然后OpenGL就幫我們寫入到幀緩沖區(qū):glDraw

幀緩沖區(qū)不能直接顯示敲茄,還得關(guān)聯(lián)一個(gè)渲染緩沖區(qū),渲染緩沖區(qū)又與某個(gè)CAEAGLLayer對(duì)應(yīng)山析。這樣就可以顯示出來(lái):presentRenderbuffer

傳值:CPU的值堰燎,先傳到GPU,GPU再傳給OpenGL繪制

OpenGL是通過(guò)shader語(yǔ)言操作的盖腿,通過(guò)shader語(yǔ)音來(lái)操控頂點(diǎn)與片元

六爽待、ijkPlayer的整體流程

三個(gè)線程 讀線程+解碼線程+顯示線程
讀線程:不斷從視頻文件通過(guò)ffmpeg讀取到AVPacket嫂沉,存到videoq隊(duì)列里面
解碼線程:從videoq拿出AVPacket谍咆,通過(guò)ffmpeg解碼得到AVFrame,然后轉(zhuǎn)化為Frame結(jié)構(gòu)體灌具,存到picq隊(duì)列
顯示線程:不斷從picq取出Frame茂卦,然后通過(guò)OpenGL渲染

七何什、音頻相關(guān)

每個(gè)采樣都得用一個(gè)數(shù)據(jù)類型來(lái)存儲(chǔ),可以是float等龙、uint16等处渣。這個(gè)會(huì)決定音頻的大小
1伶贰、音頻解碼

  • ffmpeg軟解
    需要參數(shù):sample_rate(采樣率)、channels(聲道數(shù))罐栈、sample_fmt(AV_SAMPLE_FMT_S16黍衙,存儲(chǔ)采樣的數(shù)據(jù)格式)、channel_layout(類似channels荠诬,兩個(gè)常量:?jiǎn)温暤览欧⒘Ⅲw聲)

nb_samples:一包(幀)acc的一個(gè)channel有多少采樣。解碼成pcm之后柑贞,就是通過(guò)這些采樣來(lái)計(jì)算buf大小方椎,用來(lái)存解碼后的pcm數(shù)據(jù)(av_samples_get_buffer_size)注:一般1024個(gè)pcm數(shù)據(jù)作為ACC的一幀,一個(gè)(一幀frame)pcm就是一個(gè)采樣(非交錯(cuò)存儲(chǔ))

一般解碼后的pcm可能需要重采樣钧嘶,比如sample_fmt是16或32等棠众,或者采樣,聲道不一致有决,需要通過(guò)swr_convert轉(zhuǎn)換

非交錯(cuò)的存儲(chǔ)方式:NonInterleaved闸拿,一個(gè)frame只存一個(gè)channel,所以frame的大小等于一個(gè)channel的采樣大小
交錯(cuò)的存儲(chǔ)方式:Interleaved疮薇,一個(gè)frame存多個(gè)channel的數(shù)據(jù)胸墙,所以frame = sampleSize * channel

  • AudioToolBox硬解
    inPutDescription(aac)—>outPutDescription(pcm)
    解碼器描述符(Description)我注,告訴系統(tǒng)使用哪個(gè)解碼器
    AudioConverterFillComplexBuffer 進(jìn)行解碼按咒,input和output的數(shù)據(jù)都是通過(guò)AudioBufferList進(jìn)行傳遞
  • 直接用aac庫(kù)

2、音頻編碼

  • ffmpeg軟編:軟解的逆過(guò)程

  • AudioToolBox硬編碼:硬解碼的逆過(guò)程

3但骨、音頻播放

  • AudioSession
  • AudioQueue
  • AudioUnit
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末励七,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子奔缠,更是在濱河造成了極大的恐慌掠抬,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件校哎,死亡現(xiàn)場(chǎng)離奇詭異两波,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)闷哆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門腰奋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人抱怔,你說(shuō)我怎么就攤上這事劣坊。” “怎么了屈留?”我有些...
    開(kāi)封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵局冰,是天一觀的道長(zhǎng)测蘑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)康二,這世上最難降的妖魔是什么碳胳? 我笑而不...
    開(kāi)封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮沫勿,結(jié)果婚禮上固逗,老公的妹妹穿的比我還像新娘。我一直安慰自己藕帜,他們只是感情好烫罩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著洽故,像睡著了一般贝攒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上时甚,一...
    開(kāi)封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天隘弊,我揣著相機(jī)與錄音,去河邊找鬼荒适。 笑死梨熙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的刀诬。 我是一名探鬼主播咽扇,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼陕壹!你這毒婦竟也來(lái)了质欲?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤糠馆,失蹤者是張志新(化名)和其女友劉穎嘶伟,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體又碌,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡九昧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了毕匀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铸鹰。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖期揪,靈堂內(nèi)的尸體忽然破棺而出掉奄,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布姓建,位于F島的核電站诞仓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏速兔。R本人自食惡果不足惜墅拭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涣狗。 院中可真熱鬧谍婉,春花似錦、人聲如沸镀钓。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)丁溅。三九已至唤蔗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間窟赏,已是汗流浹背妓柜。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涯穷,地道東北人棍掐。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拷况,于是被迫代替她去往敵國(guó)和親作煌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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