產生新的 ASF 資料封包
ASF 多工器 是 WMContainer 層元件,可與 ASF 資料物件 搭配運作,並讓應用程式能夠針對符合 ContentInfo 物件中所定義需求的資料流程產生 ASF 資料封包。
多工器有一個輸入和一個輸出。 它會接收包含數位媒體資料的資料流程範例,並產生一或多個可寫入 ASF 容器的資料封包。
下列清單摘要說明產生 ASF 資料封包的程式:
- 將輸入資料傳遞至 IMFASFMultiplexer::P rocessSample中的多工器。
- 在迴圈中呼叫 IMFASFMultiplexer::GetNextPacket 以收集資料封包,直到擷取所有完整的封包為止。
- 在輸入資料轉換成完整的封包之後,多工器中可能會有一些擱置的資料,但 GetNextPacket並未擷取。 呼叫 IMFASFMultiplexer::Flush 以封包化擱置中的樣本,並再次呼叫 GetNextPacket 從多工器收集它們。
- 藉由呼叫 IMFASFMultiplexer::End 來更新相關聯的 ASF 標頭物件,以反映多工器在資料封包產生期間所做的變更。
下圖說明透過多工器產生 ASF 檔案的資料封包。
ASF 資料封包建立
建立和初始化多工器之後,如 建立 Multiplexer 物件中所述,呼叫 IMFASFMultiplexer::P rocessSample ,以將輸入資料傳遞至多工器以處理資料封包。 指定的輸入必須位於媒體範例中, (IMFSample 介面) 可以有一或多個媒體緩衝區, (IMFMediaBuffer 介面) 包含資料流程的資料。 如果是 ASF 到 ASF 轉碼,可以從建立封包化資料流程樣本的分割器產生輸入媒體範例。 如需詳細資訊,請參閱 ASF 分隔器。
在呼叫 ProcessSample之前,請確定輸入媒體範例的時間戳記是有效的簡報時間;否則 ProcessSample 會失敗,並傳回MF_E_NO_SAMPLE_TIMESTAMP程式碼。
多工器可以透過 ProcessSample接受輸入為壓縮或未壓縮的媒體範例。 多工器會根據資料流程的頻寬使用量,指派傳送時間給這些樣本。 在此程式中,多工器會檢查流失值區參數 (位速率和緩衝區視窗使用率) ,並可拒絕不符合這些值的樣本。 輸入媒體範例可能會因為下列其中一個原因而失敗頻寬檢查:
- 如果輸入媒體範例延遲抵達,因為上次指派的傳送時間大於此媒體範例上的時間戳記。 ProcessSample 失敗,並傳回 MF_E_LATE_SAMPLE 錯誤碼。
- 如果輸入媒體範例上的時間戳記早于指派的傳送時間 (這表示緩衝區溢位) 。 如果多工器設定為在多工器初始化期間設定 MFASF_MULTIPLEXER_AUTOADJUST_BITRATE 旗標來調整位元速率,則多工器可以忽略這種情況。 For more information, see "Multiplexer Initialization and Leaky Bucket Settings" in Creating the Multiplexer Object. 如果未設定此旗標,且多工器遇到頻寬溢出, ProcessSample 會失敗並傳回 MF_E_BANDWIDTH_OVERRUN 錯誤碼。
多工器指派傳送時間之後,輸入媒體範例會新增至 傳送視窗,這是依傳送時間排序的輸入媒體範例清單,並準備好處理到資料封包中。 在資料封包建構期間,會剖析輸入媒體範例,並將相關資料寫入資料封包作為承載。 完整的資料封包可以包含來自一或多個輸入媒體範例的資料。
當新的輸入媒體範例抵達傳送視窗中時,它們會新增至佇列,直到有足夠的媒體範例形成一個完整的封包為止。 輸入媒體範例所包含的媒體緩衝區中的資料不會複製到產生的資料封包。 資料封包會保存輸入媒體緩衝區的參考,直到輸入媒體範例完全封包化,以及從多工器收集完整的封包為止。
當有完整的資料封包可用時,可以藉由呼叫 IMFASFMultiplexer::GetNextPacket來擷取。 如果您在有完整的封包可供擷取時呼叫 ProcessSample ,它會失敗並傳回 MF_E_NOTACCEPTING 錯誤碼。 這表示多工器無法接受更多輸入,而且您必須呼叫 GetNextPacket 來擷取等候的封包。 在理想情況下,每個 ProcessSample 呼叫都應該接著一或多個 GetNextPacket 呼叫,以取得完整的資料封包。 建立完整的資料封包可能需要一個以上的輸入媒體範例。 相反地,一個輸入媒體範例中的資料可能會跨越多個封包。 因此,並非所有 對 ProcessSample 的呼叫都會產生輸出媒體範例。
如果輸入媒體範例包含 由 MFSampleExtension_CleanPoint 屬性指示的主要畫面格,多工器會將 屬性複製到封包。
取得 ASF 資料封包
若要收集多工器所產生的完整資料封包輸出媒體範例,請在迴圈中呼叫 IMFASFMultiplexer::GetNextPacket ,直到封包沒有其他輸出媒體樣本為止。 下列列出成功案例:
- 如果有完整的資料封包可用,GetNextPacket會在pdwStatusFlags參數中收到ASF_STATUS_FLAGS_INCOMPLETE旗標;ppIPacket參數會收到第一個資料封包的指標。 只要收到這個旗標,您就必須呼叫這個方法。 每次反覆運算時, ppIPacket 會指向佇列中的下一個封包。
- 如果只有一個資料封包,ppIPacket會指向它,而且pdwStatusFlags中不會收到ASF_STATUS_FLAGS_INCOMPLETE旗標。
- 如果多工器仍在封包化和新增資料封包的過程中,GetNextPacket可以成功,而不會產生任何資料封包。 在此情況下, ppIPacket 會指向 Null。 若要繼續,您必須呼叫 ProcessSample,為多工器提供更多輸入媒體範例。
下列範例程式碼示範使用多工器產生資料封包的函式。 產生的資料封包內容會寫入呼叫端所配置的資料位元組資料流程。
//-------------------------------------------------------------------
// GenerateASFDataPackets
//
// Gets data packets from the mux. This function is called after
// calling IMFASFMultiplexer::ProcessSample.
//-------------------------------------------------------------------
HRESULT GenerateASFDataPackets(
IMFASFMultiplexer *pMux,
IMFByteStream *pDataStream
)
{
HRESULT hr = S_OK;
IMFSample *pOutputSample = NULL;
IMFMediaBuffer *pDataPacketBuffer = NULL;
DWORD dwMuxStatus = ASF_STATUSFLAGS_INCOMPLETE;
while (dwMuxStatus & ASF_STATUSFLAGS_INCOMPLETE)
{
hr = pMux->GetNextPacket(&dwMuxStatus, &pOutputSample);
if (FAILED(hr))
{
break;
}
if (pOutputSample)
{
//Convert to contiguous buffer
hr = pOutputSample->ConvertToContiguousBuffer(&pDataPacketBuffer);
if (FAILED(hr))
{
break;
}
//Write buffer to byte stream
hr = WriteBufferToByteStream(pDataStream, pDataPacketBuffer, NULL);
if (FAILED(hr))
{
break;
}
}
SafeRelease(&pDataPacketBuffer);
SafeRelease(&pOutputSample);
}
SafeRelease(&pOutputSample);
SafeRelease(&pDataPacketBuffer);
return hr;
}
函 WriteBufferToByteStream
式會顯示在 IMFByteStream::Write主題中。
若要查看使用此程式碼範例的完整應用程式,請參閱 教學課程:將 ASF 資料流程從一個檔案複製到另一個檔案。
張貼Packet-Generation呼叫
若要確定多工器中沒有等候的完整資料封包,請呼叫 IMFASFMultiplexer::Flush。 這會強制多工器封包處理進行中的所有媒體範例。 應用程式可以透過迴圈中的 GetNextPacket ,以媒體範例的形式收集這些封包,直到沒有剩餘的封包被擷取為止。
產生所有媒體範例之後,請呼叫 IMFASFMultiplexer::End 來更新與這些資料封包相關聯的 ASF 標頭物件。 標頭物件是藉由傳遞用來初始化多工器的 ContentInfo 物件來指定。 此呼叫會更新各種標頭物件,以反映多工器在資料封包產生期間所做的變更。 此資訊包括封包計數、傳送持續時間、播放持續時間,以及所有資料流程的資料流程號碼。 也會更新整體標頭大小。
您必須確定在擷取所有資料封包之後呼叫 End 。 如果在多工器中等候任何封包, End 將會失敗並傳回 MF_E_FLUSH_NEEDED 錯誤碼。 在此情況下,在迴圈中呼叫 Flush 和 GetNextPacket 以取得等候封包。
注意
針對 VBR 編碼,在呼叫 End之後,您必須在 ContentInfo 物件的編碼屬性中設定編碼統計資料。 For information about this process, see "Configuring the ContentInfo Object with Encoder Settings" in Setting Properties in the ContentInfo Object. 下列清單顯示要設定的特定屬性:
- MFPKEY_RAVG 是 VBR 內容的平均位元速率。
- MFPKEY_BAVG 是平均位元速率的緩衝區視窗。
- MFPKEY_RMAX 是 VBR 內容的尖峰位元速率。
- MFPKEY_BMAX 是尖峰緩衝區視窗。
相關主題