天天看點

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

0. 前言

  我在前兩篇文章中寫了DirectShow捕獲音視訊然後生成avi,再進行264編碼的方法。那種方法有一些局限性,不适合實時性質的應用,如:視訊會議、視訊聊天、視訊監控等。本文所使用的技術,适用于這種實時性的應用,通過處理采集出來的音視訊的每一幀,實作實時編碼,實時輸出。這是我做直播系列應用的一部分,目前的情況是輸入端采用DirectShow技術捕獲音視訊,然後對視訊進行h.264編碼,對音頻進行aac編碼,輸出端則是生成檔案,接下來還要進一步擴充輸入端和輸出端,以支援檔案、桌面輸入,RTSP、RTMP、HTTP等流式協定輸出。

1. 簡單介紹

  首先是捕獲,這裡采用了DirectShow的方式,對它進行了一定程度的封裝,包括音視訊。好處是直接使用native api,你可以做想做的任何修改,壞處是,不能跨平台,采集音視訊這種應用,linux平台也是需要滴呀。有跨平台的做法,對視訊,可以使用OpenCV,對音頻,可以使用OpenAL或PortAudio等,這樣就行了。

  編碼可以選擇的餘地比較大,對視訊來講,有H264, MPEG-4, WebM/VP8, Theora等,音頻有Speex, AAC, Ogg/Vorbis等,它們都有相應的開源項目方案,我采用的是x264進行H264編碼,libfaac進行aac編碼,之後是否更改編碼方案,等具體項目需求再說了。這裡提一下WebM,Google牽頭的項目,完全開放和自由,使用VP8和Vorbis編碼,webm(mkv)封裝,有多家巨頭支援,目的是想要取代目前的H264視訊編碼,号稱比後者更加優秀,我沒有測試過實際效果。不過有商業公司牽頭就是不一樣,各項支援都很全面,有時間了關注一下。

2. 邏輯和流程

  基本的思想是實作dshow ISampleGrabberCB接口,通過回調來儲存每一個buffer。除了界面線程和dshow自己的線程之外,我們啟動了兩個線程,AudioEncoderThread和VideoEncoderThread,分别從SampleGrabber中取出資料,調用編碼器進行編碼,編碼後的檔案可以直接輸出。看圖:

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

  程式是用VS2010建構的,看張工程截圖:

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

  Base下面的是對系統API的一些簡單封裝,主要是線程和鎖。我這裡簡單也封裝的了一下dshow的捕獲過程,包括graph builder的建立,filter的連接配接等。directshow是出了名的難用,沒辦法,難用也得用。因為是VS2010,調用的Windows SDK 7.1中的dshow,沒有qedit.h這個檔案,而它正式定義ISampleGrabberCB的。不急,系統中還是有qedit.dll的,我們要做的就是從Windows SDK 6.0中,把它拷過來,然後在stdafx.h中加入這幾行代碼,就可以了

3. 音視訊編碼

  相關檔案:

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

  Encoder下就是音視訊編碼相關的代碼。X264Encoder封裝了調用x264編碼器的操作,FAACEncoder封裝了調用libfaac編碼器的操作,VideoEncoderThread和AudioEncoderThread負責主要的流程。下面我把關鍵代碼貼出來,大家可以參考一下。

  A. 視訊編碼線程

  主要流程是首先初始化x264編碼器,然後開始循環調用DSVideoGraph,從SampleGrabber中取出視訊幀,調用x264進行編碼,流程比較簡單,調用的頻率就是你想要擷取的視訊幀率。要注意的一點是,x264進行編碼比較耗時,在計算線程Sleep時間時,要把這個過程消耗的時間算上,以免采集的視訊幀率錯誤。

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

  B. 音頻編碼線程

  主要流程和視訊編碼線程相同,也是初始化FAAC編碼器,然後循環調用DSAudioGraph,從SampleGrabber中取出視訊幀,調用faac進行編碼。和視訊不同的是,音頻的sample的頻率是非常快的,是以幾乎要不斷的進行采集,但前提是SampleGrabber中捕獲到新資料了才行,不然你的程式cpu就100%了,下面代碼中IsBufferAvailaber()就是做這個檢測的。

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

  調用faac進行編碼的時候,有點需要注意,大家特别注意下,不然編碼出來的音頻會很不正常,搞不好的話會很頭疼的。先看下faac.h的相關接口

  faacEncEncode第三個參數指的是傳入的sample的個數,這個值要和調用faacEncOpen傳回的inputSamples相等。要做到這點,就要在dshow中設定好buffsize,公式是:

4. 程式界面

  運作中

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

  捕獲完成後生成aac 和 264檔案

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

  生成的aac檔案用MediaInfo讀出來的編碼格式

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

  生成的264檔案用MediaInfo讀出來的編碼格式

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼

  用mp4box封裝一下,把264和aac存放到mp4容器檔案中,就可以在播放器中播放了

采集音頻和攝像頭視訊并實時H264編碼及AAC編碼
下一篇: vi 指令 用法

繼續閱讀