在很多語音視頻軟件系統中,經常有將實時的音頻或視頻錄制為文件保存到磁盤的需求,比如,視頻監控系統中錄制監控到的視頻、視頻會議系統中錄制整個會議的過程、語音通話系統中錄制完整的對話內容、等等。
一.緣起
最近正在做的一個網絡招聘平臺的項目,其中有一個模塊是這樣的,應聘者可以通過該系統的客戶端錄制自己的視頻(自我介紹)上傳到服務器,而后,招聘者會在合適的時候瀏覽這些應聘者的視頻。該模塊涉及到的主要技術就是語音視頻錄制技術,它需要把從麥克風采集到的語音數據和從攝像頭采集到的視頻數據編碼并寫到.mp4文件中。要完成這些功能,具體來說,需要解決如下幾個技術問題:
(1)麥克風數據采集
(2)攝像頭數據采集
(3)音頻數據編碼
(4)視頻數據編碼
(5)將編碼后的數據按.mp4文件格式寫入到文件容器中。
(6)保證音頻視頻播放的同步。
二.Demo實現
如果要從頭開始一步步解決這些問題,將是非常艱難的挑戰。幸運的是,我們可以通過已有組件的組合來實現這些功能,語音視頻數據的采集我們可以借助 OMCS 框架完成,后續的語音視頻編碼并生成mp4文件,我們可以借助 MFile 組件完成。為了更方便地講解,這里我們將給出一個具體的demo,它可以錄制從本地攝像頭和本地麥克風采集的數據并生成mp4文件。demo運行的截圖如下所示:
接下來,我們來說說在這個demo中是如何一個個解決上述問題的。
1.語音數據采集
我們可以使用OMCS的MicrophoneConnector組件連接到自己的麥克風設備,這樣,揚聲器就會播放采集到的語音,而且,我們可以通過通過IMultimediaManager暴露的AudioPlayed事件,來捕獲正在播放的語音數據。
2.視頻數據采集
同樣的,我們可以使用CameraConnector控件連接到自己的攝像頭設備,然后,定時器每隔100ms(假設幀頻為10fps)調用其GetCurrentImage方法獲得正在繪制的Bitmap。
3.后續步驟
后續的4步都可以交由MFile組件搞定,我們大概看一下MFile組件中VideoFileMaker類的簽名,就知道怎么做了:
public
class
VideoFileMaker
:
IDisposable
{
///
<summary>
///
初始化視頻文件。
///
</summary>
///
<param name="filePath">
文件路徑
</param>
///
<param name="videoCodec">
視頻編碼格式
</param>
///
<param name="videoWidth">
視頻寬度
</param>
///
<param name="videoHeight">
視頻高度
</param>
///
<param name="videoFrameRate">
幀頻
</param>
///
<param name="audioCodec">
音頻編碼格式
</param>
///
<param name="audioSampleRate">
音頻采樣率。【注:采樣位數必須為16位】
</param>
///
<param name="audioChannelCount">
聲道數
</param>
///
<param name="autoSyncToAudio">
如果是實時錄制,則可傳入true,以音頻為基準進行同步。
</param>
void
Initialize(
string
filePath,
VideoCodecType
videoCodec,
int
videoWidth,
int
videoHeight,
int
videoFrameRate,
AudioCodecType
audioCodec,
int
audioSampleRate,
int
audioChannelCount,
bool
autoSyncToAudio);
///
<summary>
///
添加音頻幀。
///
</summary>
void
AddAudioFrame(
byte
[] audioframe);
///
<summary>
///
添加視頻幀。如果autoSyncToAudio開啟,則自動同步到音頻。
///
</summary>
void
AddVideoFrame(
Bitmap
frame);
///
<summary>
///
添加視頻幀。
///
</summary>
///
<param name="frame">
視頻幀
</param>
///
<param name="timeStamp">
離開始時的時間長度
</param>
void
AddVideoFrame(
Bitmap
frame, TimeSpan timeStamp);
///
<summary>
///
關閉視頻文件。
///
</summary>
///
<param name="waitFinished">
如果還有幀等待寫入文件,是否等待它們全部寫入文件。
</param>
void
Close(
bool
waitFinished); }
首先調用Initialize方法完成初始化,然后,循環調用AddAudioFrame和AddVideoFrame方法,當完成視頻錄制時,則調用Close方法,即可。很簡單,不是嗎?
4.主要代碼
首先,我們以aa01用戶登錄到OMCS服務器,然后,在拖拽一個CameraConnector控件和一個MicrophoneConnector組件到主窗體上,然后,讓它們都連到自己的攝像頭和麥克風。
this
.multimediaManager =
MultimediaManagerFactory
.GetSingleton();
this
.multimediaManager.Initialize(
"
aa01
"
,
""
,
"
127.0.0.1
"
,
9900
);
this
.cameraConnector1.BeginConnect(
"
aa01
"
);
this
.microphoneConnector1.BeginConnect(
"
aa01
"
);
接下來,我們初始化VideoFileMaker組件:
this .videoFileMaker.Initialize( " test.mp4 " , VideoCodecType .H264, this .multimediaManager.CameraVideoSize.Width, this .multimediaManager.CameraVideoSize.Height, 10 , AudioCodecType .AAC, 16000 , 1 , true ); this .timer = new System.Threading.Timer( new System.Threading. TimerCallback ( this .Callback), null , 0 , 100 ); this .multimediaManager.AudioPlayed += new ESBasic. CbGeneric < byte []>(multimediaManager_AudioPlayed);
參數中設定,使用h.264對視頻進行編碼,使用aac對音頻進行編碼,并生成mp4格式的文件。然后,我們可以通過OMCS獲取實時的音頻數據和視頻數據,并將它們寫到文件中。
void
multimediaManager_AudioPlayed(
byte
[] audio) {
this
.videoFileMaker.AddAudioFrame(audio); }
private
void
Callback(
object
state) {
Bitmap
bm
=
this
.cameraConnector1.GetCurrentImage();
this
.videoFileMaker.AddVideoFrame(bm); }
當想結束錄制時,則調用Close方法:
this
.videoFileMaker.Close(
true
);
這樣錄制生成的test.mp4文件就可以直接用我們的QQ影音或暴風影音來播放了。
更多細節,請查看demo源碼。
三.Demo下載
Demo源碼: VideoRecordDemo.rar
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
