1. 程式人生 > >手機直播系統偶爾會需要到的:Windows 下視訊採集技術

手機直播系統偶爾會需要到的:Windows 下視訊採集技術

 

Windows下視訊採集的方法

在 Windows 下主要有兩種方法來採集視訊: 一種是通過 Media Foundation,另一種是通過 DirectShow。

Meida Foundation 是 Windows 從 vista 之後推出的一套全新的 多媒體SDK,簡單方便,從 Win7 開始成熟起來。

另一種是 DirectShow,它主要用於 win7 之前的採集視訊。使用 DirectShow 編寫程式碼比較麻煩,主要是因為 Windows 工程師按照邏輯電路的思維方式設計了 DirectsShow 的開發介面,引入了什麼 filter, pin之類的概念。這些老掉牙的東西現在估計沒幾個人能搞明白,除非你是從那個時代過來的,哈哈。

這也解釋了為啥現在很少有人學習 Windows 程式開發了,就是因為跟不上時代。你看人家 Android/iOS做視訊採集多簡單,你整的這麼麻煩,誰還願意學!

Media Foundation的一些概念

DirectShow 方案我們放到以後再分析,今天我們主要講下 MediaFoundation 如何進行視訊採集。

在講之前,我們先要補充一些基本概念。這些概念大家可以從Media Foundation Programming Guide 找到。下面的文字基本是翻譯的 Windows 的官方文件。

MF(MediaFoundation)的整體結構圖如下:

MF 提供了兩種不同的程式設計模型。第一種是上圖的左半部分,媒體資料通過端到端的管道傳遞。Application首先初始化管道,然後呼叫相應方法控制管道中的流。第二種如上圖的右半部分,Application可以從 Source Reader拉資料,也可以向 Sink Writer 推資料。這種模型對於處理資料非常有用。

Primitives 和 Platfrom

圖底部的 Primitives 是一些輔助API:

  • Attributes: 相當於一個 Map, 由 key/value 組成。
  • Media Type: 描述媒體資料流的格式。
  • Media Buffers: 存放一段媒體資料。
  • Media Samples: 存放 Media Buffers 的容器,相當於一個 Buffter List。

MF Platform 提供了一些核心功能的API。例如非同步呼叫、工作佇列。

Media Pipeline

Media Pipeline 包括三種類型物件:Media Sources、MFTs(Media Foundation Transfors)、Media Sink。

  • Media Sources: 將資料引入到管道里。資料可以來自本地檔案,網路流或都是硬體裝置。
  • MFTs: 處理流資料。在 MFTs 裡實現了編解碼器。
  • Media Sink: 消費資料。顯示視訊到顯示屏上,播放聲音或寫資料到媒體檔案。

Media Session 通過管道控制資料流。如質量控制,音訊/視訊同步,格式的改變。

Source Reader 和 Sink Writer

Source Reader 和 Sink Writer提供了使用 Media Foundation 的另一種方法(相較於 media source, transforms, media sink)。

  • Source Reader 控制著 media source 和 多個解碼器。
  • Sink Writer 控制著 media sink 和 多個編碼器。

你可以使用 Source Reader 從 media source 獲取到壓縮或未壓縮的資料,並使用 Sinker Writer 編碼資料併發送給 media sink。

下面我們就來看看 MF 是如何採集視訊資料的。

採集視訊資料

通過上面的介紹,我們基本可以知道 MF 採用 從源採集資料,編解碼,輸出渲染這種架構來處理多媒體。這種方式通俗易懂,使用起來非常方便。

MF採集視訊的基本步驟

MF採集資料使用的是架構中的第二種程式設計模型,其步驟如下:

  • 初始化 COM 元件。
  • 獲取視訊裝置列表。
  • 啟用某個視訊裝置,獲取該裝置的 Media Source。
  • 根據請求命令和 Media Source 建立 Source Reader。
  • 為 Source Reader 設定 Media Type。
  • 通過 Source Reader 從裝置中讀取 Media Type 格式的視訊資料。

以上就是 MF 從視訊裝置採集數所的基本步驟,下面我們來詳細介紹每一步。

詳細分析

由於每一步的程式碼都實分簡單,我這裡就不做過多的文字描述了,通過下面的程式碼及其註釋大家很容易理解其中的每一步。

初始化 COM 元件並啟動 MF

...
CoInitializeEx(NULL, COINIT_APARTMENTTHREAD | COINIT_DISABLE_OLEDDE)
MFStartup(MF_VERSION)
...

獲取所有的視訊裝置

IMFAttributes *videoCmd = NULL; 
IMFActivate **videoDevices = NULL;
UINT32 videoDeviceCount = 0;
...
//設定獲取視訊裝置的命令
MFCreateAttributes(videoCmd, 1/*表示只分配一項*/);
videoCmd->setGUID(
                MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,  //key
                MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID); //value
//獲取視訊裝置列表  
MFEnumDeviceSources(
                videoCmd,
                &videoDevices, //這裡是裝置列表
                &videoDeviceCount); //這裡存放的是裝置的個數
...

啟用某個視訊裝置

IMFMediaSource *mediaSource = NULL;
...
//啟用第一個視訊裝置,併為該設定備生成邏輯上的媒體源(Media Source)
videoDevices[0]->ActivateObject(IID_PPV_ARGS(&mediaSource));
...

建立 Source Reader

IMFSourceReader *soureReader = NULL;
...
//通過媒體源和請求命令,可以獲取source reader。(第二種開發模型)
MFCreateSourceReaderFromMediaSource(
                mediaSource,
                videoCmd,
                &sourceReader);
...

設定 Media Type

IMFMediaType *mediaType = NULL;
...
MFCreateMediaType(&mediaType);
//設定媒體為視訊
mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
//YUV格式為 I420
mediaType->SetGUID(MF_MT_SUBTYPE, WMMEDIASUBTYPE_I420); 
//每個視訊幀的大小為 640 * 480
MFSetAttributeSize(mediaType, MF_MT_FRAME_SIZE, 640, 480);
sourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                         NULL,
                         mediaType);

讀取資料

IMFSample *sample = NULL;
DWORD index, flags;
LONGLONG llVideoTs;
...
while(runing){
    sourceReader->ReadSample(
                    MF_SOURCE_READER_FIRST_VIDEO_STREAM,
                    0,
                    &index, //實際流的index
                    &flags, //staus flags
                    &llVideoTs, //時間戳
                    &sample); //存放採集到的視訊資料
}

通過上面簡單的幾步,就可以輕鬆的從視訊裝置裡取到視訊資料了。MF相對於 DirectShow真是簡單太多了。

上面介紹的是使用同步方式使用MF採集視訊資料,MF還提供了效率更高的非同步方式獲取視訊資料,有興趣的朋友可以以本篇文章為基礎去學習它的非同步方式。

小結

今天向大家介紹了在 Windows下使用 MF 如何採集視訊的方法。通過以下 6 步即可做到:

  • 初始化 COM 元件。
  • 獲取視訊裝置列表。
  • 啟用某個視訊裝置,獲取該裝置的 Media Source。
  • 根據請求命令和 Media Source 建立 Source Reader。
  • 為 Source Reader 設定 Media Type。
  • 通過 Source Reader 從裝置中讀取 Media Type 格式的視訊資料。

另外, MF 的採集方案只適用於 Win7 以後的系統,對於之前的系統還是要使用 DirectShow 方案。我也會在後面再為大家介紹如何使用 DirectShow 採集視訊。