手機直播系統偶爾會需要到的: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 采集視頻。
手機直播系統偶爾會需要到的:Windows 下視頻采集技術