ffmpeg編解碼詳細(xì)過程

ffmpeg編解碼詳細(xì)過程

Snip20160531_2.png
  1. 注冊(cè)所有容器格式和CODEC:av_register_all()

  2. 打開文件:av_open_input_file()

  3. 從文件中提取流信息:av_find_stream_info()

  4. 窮舉所有的流辖所,查找其中種類為CODEC_TYPE_VIDEO

  5. 查找對(duì)應(yīng)的解碼器:avcodec_find_decoder()

  6. 打開編解碼器:avcodec_open()

  7. 為解碼幀分配內(nèi)存:avcodec_alloc_frame()

  8. 不停地從碼流中提取出幀數(shù)據(jù):av_read_frame()

  9. 判斷幀的類型镣衡,對(duì)于視頻幀調(diào)用:avcodec_decode_video()

  10. 解碼完后,釋放解碼器:avcodec_close()

  11. 關(guān)閉輸入文件:av_close_input_file()

首先第一件事情就是開一個(gè)視頻文件并從中得到流。我們要做的第一件事情就是使用av_register_all();來初始化libavformat/libavcodec:

這一步注冊(cè)庫中含有的所有可用的文件格式和編碼器,這樣當(dāng)打開一個(gè)文件時(shí),它們才能夠自動(dòng)選擇相應(yīng)的文件格式和編碼器。av_register_all()只需調(diào)用一次,所以技扼,要放在初始化代碼中。也可以僅僅注冊(cè)個(gè)人的文件格式和編碼嫩痰。

下一步剿吻,打開文件:

AVFormatContext *pFormatCtx;
const char *filename="myvideo.mpg";
av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL); // 打開視頻文件
最后三個(gè)參數(shù)描述了文件格式始赎,緩沖區(qū)大泻统取(size)和格式參數(shù);我們通過簡(jiǎn)單地指明NULL或0告訴 libavformat 去自動(dòng)探測(cè)文件格式并且使用默認(rèn)的緩沖區(qū)大小造垛。這里的格式參數(shù)指的是視頻輸出參數(shù)魔招,比如寬高的坐標(biāo)。

下一步五辽,我們需要取出包含在文件中的流信息:
av_find_stream_info(pFormatCtx)办斑; // 取出流信息

AVFormatContext 結(jié)構(gòu)體

dump_format(pFormatCtx, 0, filename, false);//我們可以使用這個(gè)函數(shù)把獲取到得參數(shù)全部輸出。

for(i=0; i<pFormatCtx->nb_streams; i++) //區(qū)分視頻流和音頻流
if(pFormatCtx->streams->codec.codec_type==CODEC_TYPE_VIDEO) //找到視頻流杆逗,這里也可以換成音頻
{
videoStream=i;
break;
}

接下來就需要尋找解碼器

AVCodec *pCodec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);

avcodec_open(pCodecCtx, pCodec)乡翅; // 打開解碼器
給視頻幀分配空間以便存儲(chǔ)解碼后的圖片:

AVFrame *pFrame;
pFrame=avcodec_alloc_frame();

/////////////////////////////////////////開始解碼///////////////////////////////////////////

第一步當(dāng)然是讀數(shù)據(jù):

我們將要做的是通過讀取包來讀取整個(gè)視頻流,然后把它解碼成幀罪郊,最后轉(zhuǎn)換格式并且保存蠕蚜。

while(av_read_frame(pFormatCtx, &packet)>=0) { //讀數(shù)據(jù)

if(packet.stream_index==videoStream){ //判斷是否視頻流

avcodec_decode_video(pCodecCtx,pFrame, &frameFinished,

packet.data, packet.size); //解碼

if(frameFinished) {

img_convert((AVPicture )pFrameRGB, PIX_FMT_RGB24,(AVPicture)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width,pCodecCtx->height);//轉(zhuǎn)換 }

SaveFrame(pFrameRGB, pCodecCtx->width,pCodecCtx->height, i); //保存數(shù)據(jù)

av_free_packet(&packet); //釋放

av_read_frame()讀取一個(gè)包并且把它保存到AVPacket結(jié)構(gòu)體中。這些數(shù)據(jù)可以在后面通過av_free_packet()來釋放悔橄。函數(shù)avcodec_decode_video()把包轉(zhuǎn)換為幀靶累。然而當(dāng)解碼一個(gè)包的時(shí)候,我們可能沒有得到我們需要的關(guān)于幀的信息癣疟。因此挣柬,當(dāng)我們得到下一幀的時(shí)候,avcodec_decode_video()為我們?cè)O(shè)置了幀結(jié)束標(biāo)志frameFinished睛挚。最后邪蛔,我們使用 img_convert()函數(shù)來把幀從原始格式(pCodecCtx->pix_fmt)轉(zhuǎn)換成為RGB格式。要記住扎狱,你可以把一個(gè) AVFrame結(jié)構(gòu)體的指針轉(zhuǎn)換為AVPicture結(jié)構(gòu)體的指針侧到。最后勃教,我們把幀和高度寬度信息傳遞給我們的SaveFrame函數(shù)。

到此解碼完畢床牧,顯示過程使用SDL完成考慮到我們以后會(huì)使用firmware進(jìn)行顯示操作荣回,SDL忽略不講。

音視頻同步

DTS(解碼時(shí)間戳)和PTS(顯示時(shí)間戳)

當(dāng)我們調(diào)用av_read_frame()得到一個(gè)包的時(shí)候戈咳,PTS和DTS的信息也會(huì)保存在包中。但是我們真正想要的PTS是我們剛剛解碼出來的原始幀的PTS壕吹,這樣我們才能知道什么時(shí)候來顯示它著蛙。然而,我們從avcodec_decode_video()函數(shù)中得到的幀只是一個(gè)AVFrame耳贬,其中并沒有包含有用的PTS值(注意:AVFrame并沒有包含時(shí)間戳信息踏堡,但當(dāng)我們等到幀的時(shí)候并不是我們想要的樣子)。咒劲。我們保存一幀的第一個(gè)包的PTS:這將作為整個(gè)這一幀的PTS顷蟆。我們可以通過函數(shù)avcodec_decode_video()來計(jì)算出哪個(gè)包是一幀的第一個(gè)包。怎樣實(shí)現(xiàn)呢腐魂?任何時(shí)候當(dāng)一個(gè)包開始一幀的時(shí)候帐偎,avcodec_decode_video()將調(diào)用一個(gè)函數(shù)來為一幀申請(qǐng)一個(gè)緩沖。當(dāng)然蛔屹,ffmpeg允許我們重新定義那個(gè)分配內(nèi)存的函數(shù)削樊。計(jì)算前一幀和現(xiàn)在這一幀的時(shí)間戳來預(yù)測(cè)出下一個(gè)時(shí)間戳的時(shí)間。同時(shí)兔毒,我們需要同步視頻到音頻漫贞。我們將設(shè)置一個(gè)音頻時(shí)間audioclock;一個(gè)內(nèi)部值記錄了我們正在播放的音頻的位置育叁。就像從任意的mp3播放器中讀出來的數(shù)字一樣迅脐。既然我們把視頻同步到音頻,視頻線程使用這個(gè)值來算出是否太快還是太慢豪嗽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谴蔑,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子昵骤,更是在濱河造成了極大的恐慌树碱,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件变秦,死亡現(xiàn)場(chǎng)離奇詭異成榜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蹦玫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門赎婚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刘绣,“玉大人,你說我怎么就攤上這事挣输∥撤铮” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵撩嚼,是天一觀的道長(zhǎng)停士。 經(jīng)常有香客問我,道長(zhǎng)完丽,這世上最難降的妖魔是什么恋技? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮逻族,結(jié)果婚禮上蜻底,老公的妹妹穿的比我還像新娘。我一直安慰自己聘鳞,他們只是感情好薄辅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著抠璃,像睡著了一般站楚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸡典,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天源请,我揣著相機(jī)與錄音,去河邊找鬼彻况。 笑死谁尸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的纽甘。 我是一名探鬼主播良蛮,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼悍赢!你這毒婦竟也來了决瞳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤左权,失蹤者是張志新(化名)和其女友劉穎皮胡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赏迟,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屡贺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甩栈。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡泻仙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出量没,到底是詐尸還是另有隱情玉转,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布殴蹄,位于F島的核電站究抓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏袭灯。R本人自食惡果不足惜漩蟆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望妓蛮。 院中可真熱鬧,春花似錦圾叼、人聲如沸蛤克。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽构挤。三九已至,卻和暖如春惕鼓,著一層夾襖步出監(jiān)牢的瞬間筋现,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工箱歧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留矾飞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓呀邢,卻偏偏與公主長(zhǎng)得像洒沦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子价淌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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