標籤:media foundation windows dshow mf 媒體播放
跳過第二章對工具TopoEdit的介紹,直接進行媒體播放的學習。
媒體播放這章,介紹了個檔案播放的例子,想起當初學習dshow的時候,一開始也是個檔案播放例子,不過那個例子比較簡單,沒多少代碼,nnd,而這個demo徹底瞎了,就一個簡單的檔案播放就這麼多代碼,哎。
這章的第一要義是說MF廣泛使用COM技術但又不是真正的COM介面,也就是MF混合了COM和正常的對象,使用COM的話很明顯得初始化COM。
以下按照播放一個檔案的流程,介紹使用到的MF相關概念:
1. 初始化COM,初始化MF。(特別說明:MF的API只有unicode版本沒有ASCII版本)
2. 引入一個重要的概念Media Session,相當於dshow的graph builder,Media Session主要用來控制媒體管道。就這個檔案播放的例子來說Media Session在內部從source採樣(取資料),然後給MFTs(transform component,解碼組件),最後再渲染;在外部則是控制播放暫停並且傳遞MF的內部事件等一系列功能,跟dshow的graph非常相似啊。
a)建立Media Session:MFCreateMediaSession(NULL, &m_pSession);第一個參數預設,第二個參數即新建立的指向media session的指標
b)設定media session的非同步事件回調:m_pSession->BeginGetEvent((IMFAsyncCallback*)this, NULL); 第一個參數為指定的回調對象,需要繼承至IMFAsyncCallback;非同步事件會回調給IMFAsyncCallback介面的Invoke函數,在IMFAsyncCallback中Invoke函數為純虛函數,需要繼承者實現。
3.引入概念topology,網路釋義拓撲結構,在該demo中是建立檔案播放的拓撲結構,所謂拓撲結構就是解析出需要的component,以便建立最終的媒體管道。以下分析topology的構建過程:
a)建立MF source:MF有個內建的組件名為source resolve,它根據檔案URL(也可以是流媒體)解析出相應的容器和資料格式,並建立對應的source component。
一. 建立source resolve:MFCreateSourceResolver(&pSourceResolver);
二. 建立MF source:
// Use the synchronous source resolver to create the media source. hr = pSourceResolver->CreateObjectFromURL( sURL, // URL of the source. MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE, // indicate that we want a source object, and // pass in optional source search parameters NULL, // Optional property store for extra parameters &objectType, // Receives the created object type. &pSource // Receives a pointer to the media source. ); 英文注釋很詳細,這裡再說明下第二個參數,它是用flag標記來指示如何建立並尋找匹配的MF source,MF_RESOLUTION_MEDIASOURCE:建立一個media source;MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE:該標記指示媒體源的匹配除了根據副檔名和MIME type外,如果失敗,還會去匹配其它登入的媒體源。這樣media source有了。
(還需說明的是上述方法是以同步方式來構建MF source,還有非同步方式,非同步方式主要是針對網路流媒體或是其它需要一定時間才能訪問到的資料來源)
b)構建topology:首先說明的是該例子的topology是partial,部分的,它只是構建source和sink,沒有加入transform。以下簡化該例子構建topology的步驟:
一. 得到MF source包含的流描述符,描述符裡包含有檔案(source)的媒體流資訊,例如流數目,以及相關屬性例如是音頻還是視頻,等等屬性
二.分別針對每股流建立source node,節點,相當於dshow的pin腳,作為component的代表,然後再分別針對相應的流類型(音頻或者視頻)建立sink node,這裡的sink用來render(渲染)
三. 串連source node和sink node,這裡就有個問題,那就是說source出來的資料sink不一定能直接用,例如編碼的資料是不能用來直接渲染的,而是應該在這之間加入MFTs,所以說這個topology是partial,not all ,Oh yeah! 截個例子中的代碼看看,注釋很銷魂:
// Connect the source node to the sink node. The resolver will find the // intermediate nodes needed to convert media types. hr = pSourceNode->ConnectOutput(0, pOutputNode, 0);
以上還需說明的是node的串連不代表真實對象(組件)的串連,node只是表示component有這樣的屬性,實際組件的串連(真實pipeline的形成)還需要靠media session來完成,just hint!
c)解析上面的partial topology使其形成真正的media pipeline:這個工作由media seesion來完成 ,上面的描述其實忽略了一個步驟,就是把topology綁定到media session裡,就是調用一個函數:SetTopology,該函數的說明可以參考msdn。解析這個部分topology其實就是啟用topology裡面的組件,並插入必要的用來轉換媒體類型的組件,哎,不知道有沒有說清楚,分兩步把:
一.啟用topology裡的node所描述的組件,b裡建立了sink node但還沒有執行個體化對應的audio render/video render,為了節省資源只有在真正需要的時候(just here)才執行個體化使其可用;(書裡這麼描述,實際只有看源碼才知道,)
二.插入適當的MFTs,使source出來的媒體類型能轉化為sink(render)可接受的媒體類型,也就是用來做媒體資料類型的轉換,完成整個pipeline的協商,使其能真正地去play。這是media session為我們做的事情,可以說是把partial topology變為真正的media pipeline。
ok,that‘s all. 該文沒怎麼描述API,可以參考msdn,很詳細,只是對流程做了記錄。
Windows Media Foundation學習筆記3——媒體播放