媒體接收
媒體接收 是接收媒體數據的管線物件。 媒體接收是一或多個媒體數據流的目的地。 媒體接收分為兩個一般類別:
轉譯器 是呈現播放數據的媒體接收。 增強式視訊轉譯器 (EVR) 會顯示視訊畫面,而音訊轉譯器會透過聲卡或其他音訊裝置播放音訊串流。
封存接收 是將數據寫入檔案或其他記憶體的媒體接收。
它們之間的主要差異在於封存接收不會以固定播放速率取用數據。 相反地,它會寫入儘快接收的數據。
媒體接收會公開IMFMediaSink介面。 每個媒體接收都包含一或多個 資料流接收,。 每個數據流接收都會從一個數據流接收數據。 數據流接收會公開 IMFStreamSink介面。 應用程式通常不會直接建立媒體接收。 相反地,應用程式會建立一或多個啟用對象,媒體會話會使用此物件來建立接收。 接收上所有其他作業都是由媒體會話處理,應用程式不會在媒體接收或任何數據流接收上呼叫任何方法。 如需啟用物件的詳細資訊,請參閱 Activation Objects。
如果您要撰寫自定義媒體接收,或想要直接不使用媒體會話來使用媒體接收,您應該閱讀本主題的其餘部分。
數據流接收
媒體接收可以有固定數目的數據流接收,也可以支援新增和移除數據流接收。 如果數據流接收數目固定,IMFMediaSink::GetCharacteristics 方法會傳回MEDIASINK_FIXED_STREAMS旗標。 否則,您可以新增和移除數據流接收。 若要新增資料流接收,請呼叫 IMFMediaSink::AddStreamSink。 若要移除資料流接收,請呼叫 IMFMediaSink::RemoveStreamSink。 MEDIASINK_FIXED_STREAMS旗標表示媒體接收不支援這兩種方法。 (它可能支援一些其他方式來設定數據流數目,例如在建立接收時設定初始化參數。數據流接收的清單已排序。 若要依索引值列舉它們,請呼叫 IMFMediaSink::GetStreamSinkByIndex 方法。
數據流接收也有標識碼。 數據流標識碼在媒體接收內是唯一的,但不需要連續。 視媒體接收而定,串流標識碼可能有一些與內容相關的意義。 例如,封存接收可能會將數據流標識碼寫入檔案標頭。 否則,它們是任意的。 若要依識別碼取得數據流接收,請呼叫 IMFMediaSink::GetStreamSinkById。
簡報時鐘
媒體接收取用樣本的速率是由 Presentation Clock所控制。 媒體會話會選取簡報時鐘,並藉由呼叫媒體接收 的 imfMediaSink::SetPresentationClock 方法,在媒體接收上設定它。 簡報時鐘必須在媒體接收上設定,才能開始串流。 每個媒體接收都需要執行簡報時鐘。 媒體接收會使用簡報時鐘進行兩個用途:
若要在串流啟動或停止時接收通知。 媒體接收會透過IMFClockStateSink介面接收這些通知,所有媒體接收都必須實作這些通知。
判斷何時應該轉譯樣本。 當媒體接收收到新的範例時,它會從範例取得時間戳,並嘗試在該簡報時間轉譯範例。
簡報時鐘會從另一個物件衍生其時鐘時間,稱為 簡報時間來源。 簡報時間來源會公開 IMFPresentationTimeSource介面。 某些媒體接收可以存取精確的時鐘,因此會公開此介面。 這表示媒體接收可能會根據自己的時鐘所提供的時間排程樣本。 不過,媒體接收無法假設這是這種情況。 無論簡報時鐘是由媒體接收本身,還是由其他時鐘驅動,它都必須使用簡報時鐘的時間。
如果媒體接收無法比對速率與時鐘以外的時鐘,GetCharacteristics 方法會傳回MEDIASINK_CANNOT_MATCH_CLOCK旗標。 如果此旗標存在,而且簡報時鐘使用不同的簡報時間來源,媒體接收可能會執行不佳。 例如,在播放期間可能會發生問題。
無速率 接收是媒體接收,會忽略樣本上的時間戳,並在每個樣本送達時立即取用數據。 無速率媒體接收會從 getCharacteristics方法傳回MEDIASINK_RATELESS 旗標。 此旗標通常適用於封存接收。 如果管線中的每個媒體接收都是無速率的,媒體會話會使用特殊的無速率簡報時鐘。 當接收取用樣本時,這個時鐘就會執行得一樣快。
數據流格式
在媒體接收可以接收範例之前,客戶端必須在數據流接收上設定媒體類型。 若要設定媒體類型,請呼叫數據流接收的 IMFStreamSink::GetMediaTypeHandler 方法。 這個方法會傳回 IMFMediaTypeHandler介面指標。 使用此介面可取得慣用媒體類型清單、取得目前的媒體類型,以及設定媒體類型。
若要取得慣用媒體類型的清單,請呼叫 IMFMediaTypeHandler::GetMediaTypeByIndex。 慣用型別應視為用戶端的提示。 清單可能不完整,或包含部分媒體類型。 部分媒體類型是沒有描述有效格式所需的所有屬性的媒體類型。 例如,部分視訊類型可能會指定色彩空間和位深度,但不能指定影像寬度或高度。 部分音訊類型可能會指定壓縮格式和取樣率,但不能指定音訊通道的數目。
若要取得數據流接收目前的媒體類型,請呼叫 IMFMediaTypeHandler::GetCurrentMediaType。 第一次建立數據流接收時,它可能已設定預設媒體類型,或用戶端設定一個媒體類型之前可能沒有媒體類型。
若要設定媒體類型,請呼叫 IMFMediaTypeHandler::SetCurrentMediaType。 某些數據流接收可能不支援在 設定 之後變更類型。 因此,在設定媒體類型之前,先測試媒體類型會很有用。 若要測試媒體接收是否接受媒體類型(未設定類型),請呼叫 IMFMediaTypeHandler::IsMediaTypeSupported。
數據流
媒體接收會使用 提取模型,這表示數據流接收會視需要要求數據。 用戶端應及時回應,以避免發生任何問題。
某些媒體接收支援 預先註冊。 預先註冊是在簡報時鐘開始之前將數據提供給媒體接收的程式。 如果媒體接收支持預先註冊,媒體接收會公開 IMFMediaSinkPreroll 介面,而 getCharacteristics方法會傳回MEDIASINK_CAN_PREROLL旗標。 預先註冊可確保媒體接收已準備好在簡報時鐘啟動時呈現第一個範例。 建議客戶端在媒體接收支援時一律預先註冊,因為它可以防止播放期間發生問題或間距。
資料流至媒體接收的運作方式如下:
- 用戶端會設定媒體類型和簡報時鐘。 媒體接收會向簡報時鍾註冊本身,以接收有關時鍾狀態變更的通知。
- 選擇性地,IMFMediaSinkPreroll 的客戶端查詢。 如果媒體接收公開此介面,用戶端會呼叫 IMFMediaSinkPreroll::NotifyPreroll。 否則,用戶端會跳至步驟 5。
- 每個數據流接收都會傳送一或多個 MEStreamSinkRequestSample 事件。 為了回應上述每個事件,用戶端會取得該數據流的下一個數據範例,並呼叫 IMFStreamSink::P rocessSample。
- 當每個數據流接收接收足夠的預先註冊數據時,它會傳送 MEStreamSinkPrerolled 事件。
- 用戶端會呼叫 IMFPresentationClock::Start 來啟動簡報時鐘。
- 簡報時鐘會呼叫IMFClockStateSink::OnClockStart,通知媒體接收時鐘正在啟動。
- 若要取得更多數據,每個數據流接收都會傳送 MEStreamSinkRequestSample 事件。 為了回應上述每個事件,用戶端會取得下一個範例,並呼叫 ProcessSample。 此步驟會重複執行,直到簡報結束為止。
大部分媒體接收會以異步方式處理範例,因此數據流接收一次可以傳送多個範例要求。
在串流期間,用戶端可以隨時呼叫 IMFStreamSink::P laceMarker,並 IMFStreamSink::Flush。 下一節會說明標記。 排清會導致數據流接收卸除任何已排入佇列但尚未轉譯的樣本。
標記
標記可讓用戶端指出數據流中的特定點。 標記包含下列資訊:
- 標記類型,定義為 MFSTREAMSINK_MARKER_TYPE 列舉的成員。
- 與標記相關聯的數據。 數據的意義取決於標記類型。 某些標記類型沒有數據。
- 用戶端自己使用的選擇性數據。
若要放置標記,用戶端會呼叫 IMFStreamSink::P laceMarker。 數據流接收會完成在 PlaceMarker 呼叫之前收到的任何範例,然後傳送 MEStreamSinkMarker 事件。
大部分的媒體接收會保留擱置中的樣本佇列,這些樣本會以異步方式處理。 標記事件必須以範例處理串行化,因此媒體接收應該將標記放在相同的佇列中。 例如,假設客戶端進行下列方法呼叫:
- ProcessSample (範例 #1)
- ProcessSample (範例 #2)
- PlaceMarker (標記 #1)
- ProcessSample (範例 #3)
- PlaceMarker (標記 #2)
在此範例中,數據流接收必須在處理範例 #2 之後,將 MEStreamSinkMarker 事件傳送給標記 #1,而標記的事件 #2 在處理範例之後 #3。
如果用戶端排清數據流接收,數據流接收會立即處理佇列中的任何標記。 它會將狀態代碼設定為在這些事件上E_ABORT。
某些標記包含與媒體接收相關的資訊:
- MFSTREAMSINK_MARKER_TICK:表示數據流中有一個間距。 下一個範例將是不連續的。
- MFSTREAMSINK_MARKER_ENDOFSEGMENT:表示線段的結尾或數據流的結尾。 下一個範例(如果有的話)可能是不連續的。
- MFSTREAMSINK_MARKER_EVENT:包含事件。 視事件類型和媒體接收的實作而定,媒體接收可能會處理事件或忽略它。
狀態變更
媒體接收會透過媒體接收 IMFClockStateSink 介面,在簡報時鐘中收到狀態變更的通知。 當客戶端設定簡報時鐘時,媒體接收會呼叫 IMFPresentationClock::AddClockStateSink 來註冊自己以取得時鐘的通知。 下表摘要說明媒體接收在回應時鐘狀態變更時的行為。
時鍾狀態變更 | 來樣加工 | 標記處理 |
---|---|---|
OnClockStart | 處理時間戳等於或晚於時鐘開始時間的範例。 | 處理標記之前收到的所有樣本時,傳送 MEStreamSinkMarker 事件。 |
OnClockPause | 暫停時,媒體接收可能會失敗 ProcessSample。 如果媒體接收在暫停時接受樣本,它必須排入佇列,直到時鐘重新啟動為止。 暫停時,請勿處理任何已排入佇列的樣本。 |
如果有已排入佇列的樣本,請將標記放在相同的佇列中。 當時鐘重新啟動時,傳送標記事件。 否則,請立即傳送標記事件。 |
OnClockRestart | 處理暫停時已排入佇列的任何範例,然後將 與 onClockStart相同。 | 針對佇列標記傳送 MEStreamSinkMarker 事件(使用範例處理串行化),然後將與 onClockStart相同。 |
OnClockStop | 卸除所有已排入佇列的範例。 ProcessSample 的進一步呼叫可能會失敗。 | 傳送佇列標記事件。 在後續呼叫 PlaceMarker時,立即傳送標記事件。 |
此外,數據流接收必須在完成狀態轉換時傳送下列事件:
- OnClockStart、OnClockRestart:MEStreamSinkStarted 事件
- OnClockPause:MEStreamSinkPaused 事件
- OnClockStop:MEStreamSinkStopped 事件
敲定
某些媒體接收在傳遞最後一個範例之後需要額外的處理步驟。 此需求通常適用於封存接收,而封存接收必須將標頭或索引寫入檔案中。 如果媒體接收需要任何最終處理,則會公開IMFFinalizableMediaSink介面。
用戶端傳遞最後一個範例之後,用戶端會查詢此介面。 如果媒體接收支援 介面,用戶端會呼叫 IMFFinalizableMediaSink::BeginFinalize 以異步方式執行最終處理。 此方法遵循標準媒體基礎異步模型,如 異步回呼方法中所述,。 媒體接收可以假設用戶端會呼叫 beginFinalize 。 呼叫 BeginFinalize 可能會導致撰寫錯誤的檔案。
關閉
當用戶端使用媒體接收完成時,用戶端會呼叫 IMFMediaSink::Shutdown。 在此方法內,媒體接收應該會中斷任何循環參考計數。 一般而言,媒體接收與數據流接收之間會有循環參考。
如果您使用事件佇列協助程式對象實作 IMFMediaEventGenerator,請在事件佇列上呼叫 IMFMediaEventQueue::Shutdown。 此方法會關閉事件佇列,併發出目前正在等候事件的任何呼叫端發出訊號。
關機之後,媒體接收上的所有方法都會傳回MF_E_SHUTDOWN,但IUnknown 方法 除外。
媒體接收介面
下表列出媒體接收可透過queryInterface 公開的標準介面。 媒體接收也可以公開自定義介面。
介面 | 描述 |
---|---|
IMFMediaSink | 媒體接收的主要介面。 (必要。) |
IMFClockStateSink | 用來在簡報時鐘變更狀態時通知媒體接收。 (必要。) |
IMFFinalizableMediaSink | 如果媒體接收必須執行最終處理步驟,請實作 。 (選擇性。) |
IMFGetService | 如果媒體接收公開任何服務介面,則實作 。 (選擇性。) |
IMFMediaEventGenerator | 如果媒體接收傳送任何事件,則實作 。 (選擇性。) |
IMFMediaSinkPreroll | 如果媒體接收支援預先註冊,請實作 。 (選擇性。) |
IMFPresentationTimeSource | 如果媒體接收可以提供簡報時鐘的時間來源,請實作 。 (選擇性。) |
IMFQualityAdvise | 如果媒體接收可以調整播放品質,請實作 。 (選擇性。) |
選擇性地,媒體接收可以實作下列介面即服務。
服務介面 | 描述 |
---|---|
IMFRateSupport | 報告支援的播放速率範圍。 |
如需服務介面和 IMFGetService的詳細資訊,請參閱 服務介面。
數據流接收介面
數據流接收必須透過 QueryInterface公開下列介面。
介面 | 描述 |
---|---|
IMFStreamSink | 數據流接收的主要介面。 (必要。) |
IMFMediaEventGenerator | 佇列事件。 IMFStreamSink介面會繼承這個介面。 (必要。) |
目前沒有針對數據流接收定義任何服務介面。
數據流接收事件
下表列出針對泛型數據流接收所定義的事件。 數據流接收也可以傳送此處未列出的自定義事件。
事件 | 描述 |
---|---|
MEStreamSinkFormatChanged | 數據流接收的媒體類型已不再有效。 (選擇性。) |
MEStreamSinkMarker | 已處理標記。 (必要。) |
MEStreamSinkPaused | 數據流接收已暫停。 (必要。) |
MEStreamSinkPrerolled | 預先標籤已完成。 (選擇性。) |
MEStreamSinkRateChanged | 數據流接收已變更播放速率。 (選擇性。) |
MEStreamSinkRequestSample | 要求新的範例。 (必要。) |
MEStreamSinkScrubSampleComplete | 清除要求已完成。 (選擇性。) |
MEStreamSinkStarted | 數據流接收已啟動。 (必要。) |
MEStreamSinkStopped | 數據流接收已停止。 (必要。) |
目前沒有針對媒體接收定義一般用途的事件。 某些媒體接收可能會傳送自定義事件。
相關主題