音視頻知識梳理

一、整體播放策略

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

二、VideoToolBox硬解

CMSampleBuffer = CMTime + FormatDesc(sps,pps) + CMBlockBuffer
CMBlockBuffer:編碼的圖像數(shù)據(jù)結構
CVPixelBuffer:解碼后的圖像數(shù)據(jù)結構

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中取到YUV數(shù)據(jù)(這里的是非交叉的)
Y:
AVFrame->data[0] 存Y數(shù)據(jù)的buffer
AVFrame->linesize[0] Y數(shù)據(jù)一段的長度,一般等于像素width。有幾段呢,就得看height

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

AVFrame->data[2] 存V數(shù)據(jù)的buffer
AVFrame->linesize[2] V數(shù)據(jù)一段的長度,一般等于像素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作為取值累積量,這樣才不會出現(xiàn)越界或者取錯數(shù)據(jù)

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

四、ffmpeg其他一些重要信息

(1)主要結構體
AVFormatContext:文件信息上下文,其中就包含了流信息結構AVStream

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

AVCodecContext:具體的音視頻格式信息。要解碼音視頻,需要從這里拿到相關信息,比如AVCodecID

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

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

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

- AVCC
extradata+NAL長度+NAL+NAL長度+NAL。。。
NAL長度所占字節(jié)、SPS與PPS等包含在extradata中

(3)extradata
解碼AVCC需要與視頻合成都需要extradata,如何構造extradata
- extradata(Annex-B)
- extradata(AVCC)
- extradata(Annex-B) 轉換為 extradata(AVCC)

(4)timebase
ffmpeg中的一種時間單位,包含了與秒的對應關系,都可以轉換為秒。
- pts,dts,duration
pts * timebase = 以秒為單位的值

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

(6)編碼流程
- 生成AVCodecContext,要設置分辨率,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)建視頻流
- 構造AVCodecContext,賦值給AVStream->codecpar
- 設置timebase,AVStream->time_base
- avio_open打開輸出文件
- avformat_write_header寫入頭
- av_interleaved_write_frame 寫入packet
- av_write_trailer 寫入結尾

五、OpenGL

簡單說就是直接操作GPU進行圖片的渲染。OpenGL有自己的渲染管線,提供給外部修改的有頂點處理和片元處理。
頂點處理:我們可以為OpenGL提供頂點,相當于構建了圖片的外部框架(頂點坐標)
片元處理:提供圖片紋理填充剛才構建的外部框架的內(nèi)容 (通過紋理坐標可以控制圖片的方向)
然后OpenGL就幫我們寫入到幀緩沖區(qū):glDraw

幀緩沖區(qū)不能直接顯示,還得關聯(lián)一個渲染緩沖區(qū),渲染緩沖區(qū)又與某個CAEAGLLayer對應。這樣就可以顯示出來:presentRenderbuffer

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

OpenGL是通過shader語言操作的,通過shader語音來操控頂點與片元

六、ijkPlayer的整體流程

三個線程 讀線程+解碼線程+顯示線程
讀線程:不斷從視頻文件通過ffmpeg讀取到AVPacket,存到videoq隊列里面
解碼線程:從videoq拿出AVPacket,通過ffmpeg解碼得到AVFrame,然后轉化為Frame結構體,存到picq隊列
顯示線程:不斷從picq取出Frame,然后通過OpenGL渲染

七、音頻相關

每個采樣都得用一個數(shù)據(jù)類型來存儲,可以是float、uint16等。這個會決定音頻的大小
1、音頻解碼

  • ffmpeg軟解
    需要參數(shù):sample_rate(采樣率)、channels(聲道數(shù))、sample_fmt(AV_SAMPLE_FMT_S16,存儲采樣的數(shù)據(jù)格式)、channel_layout(類似channels,兩個常量:單聲道、立體聲)

nb_samples:一包(幀)acc的一個channel有多少采樣。解碼成pcm之后,就是通過這些采樣來計算buf大小,用來存解碼后的pcm數(shù)據(jù)(av_samples_get_buffer_size)注:一般1024個pcm數(shù)據(jù)作為ACC的一幀,一個(一幀frame)pcm就是一個采樣(非交錯存儲)

一般解碼后的pcm可能需要重采樣,比如sample_fmt是16或32等,或者采樣,聲道不一致,需要通過swr_convert轉換

非交錯的存儲方式:NonInterleaved,一個frame只存一個channel,所以frame的大小等于一個channel的采樣大小
交錯的存儲方式:Interleaved,一個frame存多個channel的數(shù)據(jù),所以frame = sampleSize * channel

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

2、音頻編碼

  • ffmpeg軟編:軟解的逆過程

  • AudioToolBox硬編碼:硬解碼的逆過程

3、音頻播放

  • AudioSession
  • AudioQueue
  • AudioUnit
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

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