FFmpeg筆記(五)-- 編解碼函數(shù)詳解

1.libavformat

AVFormatContext可以進(jìn)行格式的封裝與解封裝淑趾,它的數(shù)據(jù)部分由底層提供待笑,底層使用了AVIOContext丽柿,這個(gè)AVIOContext實(shí)際上就是為普通的I/O增加了一層Buffer緩沖區(qū)飞袋,再往 底層就是URLContext恰聘,也就是到達(dá)了協(xié)議層句各。如圖:


libavformat

相關(guān)函數(shù)及結(jié)構(gòu)體:

av_register_all()

編譯FFmpeg的時(shí)候,做了一個(gè)configure的配置,configure的配置會(huì)生成兩個(gè)文件:config.mk與config.h晴叨。 config.mk實(shí)際上就是makefile文件需要包含進(jìn)去的子模塊凿宾,會(huì)作用在編譯階段,幫助開發(fā)者編譯出正確的庫;而config.h是作用在運(yùn)行階段兼蕊, 這一階段將確定需要注冊(cè)哪些容器以及編解碼格式到FFmpeg框架中初厚。 所以該函數(shù)的內(nèi)部實(shí)現(xiàn)會(huì)先調(diào)用avcodec_register_all來注冊(cè)所有config.h 里面開放的編解碼器,然后會(huì)注冊(cè)所有的Muxer和Demuxer(也就是封 裝格式)孙技,最后注冊(cè)所有的Protocol(即協(xié)議層的東西)产禾。

avformat_open_input()

avformat_open_input會(huì)根據(jù)所提供的文件路徑判斷文件的格式,其實(shí)就是通過這一步來決定使用的到底是哪一個(gè)Demuxer牵啦。

avformat_find_stream_info()

該方法的作用就是把所有Stream的MetaData信息填充好亚情。方法內(nèi)部會(huì)先查找對(duì)應(yīng)的解碼器,然后打開對(duì)應(yīng)的解碼器哈雏,緊接著會(huì)利用Demuxer中的 read_packet函數(shù)讀取一段數(shù)據(jù)進(jìn)行解碼楞件,當(dāng)然解碼的數(shù)據(jù)越多,分析出的流信息就會(huì)越準(zhǔn)確僧著,如果是本地資源履因,那么很快就可以得到非常準(zhǔn)確的信息了,但是對(duì)于網(wǎng)絡(luò)資源來說盹愚,則會(huì)比較慢,因此該函數(shù)有幾個(gè)參數(shù)可以控制讀取數(shù)據(jù)的長度站故,一個(gè)是probe size皆怕,一個(gè)是max_analyze_duration,還有一個(gè)是fps_probe_size西篓,這三個(gè)參數(shù)共同控制解碼數(shù)據(jù)的長度愈腾,當(dāng)然,如果配置這幾個(gè)參數(shù)的值越小岂津,那么這個(gè)函數(shù)執(zhí)行的時(shí)間就會(huì)越快虱黄,但是會(huì)導(dǎo)致AVStream結(jié)構(gòu)體里面一些信息(視頻的寬、高吮成、fps橱乱、編碼類型等)不準(zhǔn)確辜梳。

av_find_best_stream()

獲取各種流的索引。

av_read_frame()

使用該方法讀取出來的數(shù)據(jù)是AVPacket泳叠,在FFmpeg的早期版本中 開放給開發(fā)者的函數(shù)其實(shí)就是av_read_packet作瞄,但是需要開發(fā)者自己來處理AVPacket中的數(shù)據(jù)不能被解碼器完全處理完的情況,即需要把未處理完的壓縮數(shù)據(jù)緩存起來的問題危纫。所以到了新版本的FFmpeg中宗挥,其提供了該函數(shù),用于處理此狀況种蝶。該函數(shù)的實(shí)現(xiàn)首先會(huì)委托到Demuxer的 read_packet方法中去契耿,當(dāng)然read_packet通過解復(fù)用層和協(xié)議層的處理之后,會(huì)將數(shù)據(jù)返回到這里螃征,在該函數(shù)中進(jìn)行數(shù)據(jù)緩沖處理宵喂。為了保證每次讀取完整的一幀,讀取到的數(shù)據(jù)長度可能不一樣会傲。

2.libavcodec

對(duì)于開發(fā)者來說锅棕,這一層我們能接觸到的最頂層的結(jié)構(gòu)體就是 AVCodecContext,該結(jié)構(gòu)體包含的就是與實(shí)際的編解碼有關(guān)的部分淌山。首先裸燎,AVCodecContext是包含在一個(gè)AVStream里面的,即描述了這路流的編碼格式是什么泼疑,其中存放了具體的編碼格式信息德绿,根據(jù)Codec的信息可以打開編碼器或者解碼器,然后利用該編碼器或者解碼器進(jìn)行 AVPacket與AVFrame之間的轉(zhuǎn)換(實(shí)際上就是解碼或者編碼的過程)退渗, 這是FFmpeg中最重要的一部分移稳。結(jié)構(gòu)如圖:


libavformat

相關(guān)函數(shù)及結(jié)構(gòu)體:

avcodec_find_decoder()

根據(jù)上下文找到解碼器。

avcodec_open2()

打開解碼器会油。

av_frame_alloc()

AVFrame對(duì)象必須調(diào)用av_frame_alloc()在堆上分配个粱。

avcodec_decode_audio4()
參數(shù)1:avctx編解碼器上下文
參數(shù)2:frame用于存儲(chǔ)解碼音頻樣本的AVFrame
參數(shù)3:got_frame_ptr如果沒有幀可以解碼則為零,否則為非零
參數(shù)4:avpkt包含輸入緩沖區(qū)的輸入AVPacket
參數(shù)5:如果在解碼期間發(fā)生錯(cuò)誤翻翩,則返回否定錯(cuò)誤代碼都许,否則返回從輸入AVPacket消耗的字節(jié)數(shù)。
avcodec_send_packet():發(fā)送解碼未處理數(shù)據(jù)
avcodec_receive_frame():接收解碼后的數(shù)據(jù)
avcodec_send_frame:發(fā)送編碼未處理數(shù)據(jù)
avcodec_receive_packet():接收編碼后的數(shù)據(jù)

一個(gè)packet會(huì)被解碼出一個(gè)frame嫂冻,不過也存在一個(gè)packet被解碼出多個(gè)frame或者多個(gè)packet才能解碼出一個(gè)frame的情況胶征,甚至也有些解碼器在輸入以及輸出端上可能會(huì)有延遲。了解更多看這里

返回狀態(tài):

send 0        :send_packet返回值為0桨仿,正常狀態(tài)睛低,意味著輸入的packet被解碼器正常接收。
send EAGAIN   :send_packet返回值為EAGAIN,輸入的packet未被接收钱雷,需要輸出一個(gè)或多個(gè)的frame后才能重新輸入當(dāng)前packet骂铁。
send EOF      :send_packet返回值為EOF,當(dāng)send_packet輸入為NULL時(shí)才會(huì)觸發(fā)該狀態(tài)急波,用于通知解碼器輸入packet已結(jié)束从铲。
send EINVAL   :沒有打開×××,或者這是一個(gè)編碼器澄暮,或者要求刷新
receive 0     :receive_frame返回值為0名段,正常狀態(tài),意味著已經(jīng)輸出一幀泣懊。
receive EAGAIN:receive_frame返回值為EAGAIN伸辟,未能輸出frame,需要輸入更多的packet才能輸出當(dāng)前frame馍刮。
receive EOF   :receive_frame返回值為EOF信夫,當(dāng)處于send EOF狀態(tài)后,調(diào)用一次或者多次receive_frame后就能得到該狀態(tài)卡啰,表示所有的幀已經(jīng)被輸出静稻。
簡略流程:av_read_frame讀取一幀數(shù)據(jù),avcodec_send_packet發(fā)送數(shù)據(jù)匈辱,解碼后avcodec_receive_frame接收一個(gè)完整幀振湾,但因?yàn)橐恍┨厥庠騛vcodec_send_packet發(fā)送的不是一個(gè)完成幀,此時(shí)avcodec_receive_frame會(huì)返回

3.libavutil

av_image_get_buffer_size()

給緩沖區(qū)設(shè)置類型類型亡脸,得到Y(jié)UV420P緩沖區(qū)大小押搪。

參數(shù)一:視頻像素?cái)?shù)據(jù)格式類型->YUV420P格式
參數(shù)二:一幀視頻像素?cái)?shù)據(jù)寬 = 視頻寬
參數(shù)三:一幀視頻像素?cái)?shù)據(jù)高 = 視頻高
參數(shù)四:字節(jié)對(duì)齊方式->默認(rèn)是1
int buffer_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,
                                           videoCodecCtx->width,
                                           videoCodecCtx->height,
                                           1);
av_image_fill_arrays()

緩存區(qū)填充數(shù)據(jù)。

參數(shù)一:目標(biāo)->填充數(shù)據(jù)(avframe_yuv420p)
參數(shù)二:目標(biāo)->每一行大小
參數(shù)三:原始數(shù)據(jù)
參數(shù)四:目標(biāo)->格式類型
參數(shù)五:寬
參數(shù)六:高
參數(shù)七:字節(jié)對(duì)齊方式
av_image_fill_arrays(avframe_yuv420p->data,
                     avframe_yuv420p->linesize,
                     out_buffer,
                     AV_PIX_FMT_YUV420P,
                     videoCodecCtx->width,
                     videoCodecCtx->height,
                     1);

4.libswresample

音頻重采樣浅碾,就是改變音頻的采樣率大州、sample format、聲道數(shù)等參數(shù)垂谢,使之按照我們期望的參數(shù)輸出厦画。

SwrContext

音頻格式轉(zhuǎn)換上下文。

swr_alloc()

初始化上下文結(jié)構(gòu)體埂陆。

swr_alloc_set_opts()

設(shè)置重采樣參數(shù)苛白。

swr_init()

在swr_alloc_set_opts之后調(diào)用,將采樣參數(shù)設(shè)置到上下文焚虱。

參數(shù)1:重采樣上下文
參數(shù)2:輸出的layout, 如:5.1聲道…
參數(shù)3:輸出的樣本格式。Float, S16, S24
參數(shù)4:輸出的樣本率懂版【樵裕可以不變。
參數(shù)5:輸入的layout。
參數(shù)6:輸入的樣本格式民鼓。
參數(shù)7:輸入的樣本率薇芝。
參數(shù)8,參數(shù)9丰嘉,日志夯到,不用管,可直接傳0 */
av_samples_get_buffer_size()

使用av_sample_get_buffer_size來計(jì)算音頻占用的字節(jié)數(shù)饮亏。

參數(shù)1:linesize calculated linesize, may be NULL
參數(shù)2:nb_channels   聲道
參數(shù)3:nb_samples    單個(gè)通道中的樣本數(shù)
參數(shù)4:sample_fmt    采樣格式
參數(shù)5:align         對(duì)齊緩沖區(qū)大小對(duì)齊(0 =默認(rèn)耍贾,1 =無對(duì)齊)
swr_convert()

轉(zhuǎn)碼。使用avcodec_decode_audio4函數(shù)解碼音頻得到的數(shù)據(jù)類型為float 4bit路幸,而播放器播放的格式一般為S16(signed 16bit),這就需要對(duì)解碼得到的數(shù)據(jù)進(jìn)行轉(zhuǎn)換荐开。

參數(shù)1:音頻重采樣的上下文
參數(shù)2:輸出的指針。傳遞的輸出的數(shù)組
參數(shù)3:輸出的樣本數(shù)量简肴,不是字節(jié)數(shù)晃听。單通道的樣本數(shù)量。
參數(shù)4:輸入的數(shù)組砰识,AVFrame解碼出來的DATA
參數(shù)5:輸入的單通道的樣本數(shù)量能扒。

5.libswscale

SwsContext

視頻格式轉(zhuǎn)換上下文,編解碼中可能需要對(duì)視頻格式重新設(shè)置辫狼,就需要用到SwsContext初斑。

sws_getContext()

設(shè)置視頻轉(zhuǎn)換上下文。

參數(shù)一:源文件->原始視頻像素?cái)?shù)據(jù)格式寬
參數(shù)二:源文件->原始視頻像素?cái)?shù)據(jù)格式高
參數(shù)三:源文件->原始視頻像素?cái)?shù)據(jù)格式類型
參數(shù)四:目標(biāo)文件->目標(biāo)視頻像素?cái)?shù)據(jù)格式寬
參數(shù)五:目標(biāo)文件->目標(biāo)視頻像素?cái)?shù)據(jù)格式高
參數(shù)六:目標(biāo)文件->目標(biāo)視頻像素?cái)?shù)據(jù)格式類型
sws_getContext(videoCodecCtx->width,
               videoCodecCtx->height,
               videoCodecCtx->pix_fmt,
               videoCodecCtx->width,
               videoCodecCtx->height,
               AV_PIX_FMT_YUV420P,
               SWS_FAST_BILINEAR,
               NULL,
               NULL,
               NULL);
sws_scale()

視頻參數(shù)轉(zhuǎn)換予借。

參數(shù)一:視頻像素?cái)?shù)據(jù)格式上下文
參數(shù)二:原來的視頻像素?cái)?shù)據(jù)格式->輸入數(shù)據(jù)
參數(shù)三:原來的視頻像素?cái)?shù)據(jù)格式->輸入畫面每一行大小
參數(shù)四:原來的視頻像素?cái)?shù)據(jù)格式->輸入畫面每一行開始位置(填寫:0->表示從原點(diǎn)開始讀取)
參數(shù)五:原來的視頻像素?cái)?shù)據(jù)格式->輸入數(shù)據(jù)行數(shù)
參數(shù)六:轉(zhuǎn)換類型后視頻像素?cái)?shù)據(jù)格式->輸出數(shù)據(jù)
參數(shù)七:轉(zhuǎn)換類型后視頻像素?cái)?shù)據(jù)格式->輸出畫面每一行大小
sws_scale(swscontext,
          (const uint8_t *const *)avframe_in->data,
          avframe_in->linesize,
          0,
          avcodec_context->height,
          avframe_yuv420p->data,
          avframe_yuv420p->linesize);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末越平,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子灵迫,更是在濱河造成了極大的恐慌秦叛,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瀑粥,死亡現(xiàn)場(chǎng)離奇詭異挣跋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)狞换,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門避咆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人修噪,你說我怎么就攤上這事查库。” “怎么了黄琼?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵樊销,是天一觀的道長。 經(jīng)常有香客問我,道長围苫,這世上最難降的妖魔是什么裤园? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮剂府,結(jié)果婚禮上拧揽,老公的妹妹穿的比我還像新娘。我一直安慰自己腺占,他們只是感情好淤袜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著湾笛,像睡著了一般饮怯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嚎研,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天蓖墅,我揣著相機(jī)與錄音,去河邊找鬼临扮。 笑死论矾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的杆勇。 我是一名探鬼主播贪壳,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蚜退!你這毒婦竟也來了闰靴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤钻注,失蹤者是張志新(化名)和其女友劉穎蚂且,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體幅恋,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡杏死,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捆交。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淑翼。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖品追,靈堂內(nèi)的尸體忽然破棺而出玄括,到底是詐尸還是另有隱情,我是刑警寧澤肉瓦,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布惠豺,位于F島的核電站银还,受9級(jí)特大地震影響风宁,放射性物質(zhì)發(fā)生泄漏洁墙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一戒财、第九天 我趴在偏房一處隱蔽的房頂上張望热监。 院中可真熱鬧,春花似錦饮寞、人聲如沸孝扛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽苦始。三九已至,卻和暖如春慌申,著一層夾襖步出監(jiān)牢的瞬間陌选,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國打工蹄溉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留咨油,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓柒爵,卻偏偏與公主長得像役电,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子棉胀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355