共用方式為


產生新的 ASF 數據封包

ASF 多任務器 是 WMContainer 層元件,可與 ASF 資料物件 搭配運作,並讓應用程式能夠針對符合 ContentInfo 物件中所定義需求的數據流產生 ASF 數據封包。

多任務器有一個輸入和輸出。 它會接收包含數位媒體數據的數據流範例,併產生一或多個可寫入 ASF 容器的數據封包。

下列清單摘要說明產生 ASF 資料封包的程式:

  1. 將輸入數據傳遞至 IMFASFMultiplexer::ProcessSample中的多工器。
  2. 在迴圈中呼叫 IMFASFMultiplexer::GetNextPacket,以收集數據封包,直到擷取所有完整封包為止。
  3. 將輸入數據轉換成完整的封包之後,多工器中可能會有一些尚未被 GetNextPacket取出的數據。 呼叫 IMFASFMultiplexer::Flush 以封包化待處理的樣本,然後再次呼叫 GetNextPacket 從多工器收集它們。
  4. 藉由呼叫 IMFASFMultiplexer::End 來反映多任務器在數據封包產生期間所做的變更,以更新相關聯的 ASF 標頭物件。

下圖說明透過多任務器產生 ASF 檔案的數據封包。

圖表,顯示 asf 檔案的數據封包產生

ASF 資料包創建

建立和初始化多任務器之後,如 建立多任務器物件所述,請呼叫 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 旗標來調整比特率,則多任務器可以忽略這種情況。 如需詳細資訊,請參閱 建立 Multiplexer 物件中的「多工器初始化和漏桶設定」。 如果未設定此旗標,而且多任務器遇到頻寬滿溢,ProcessSample 會失敗,並傳回 MF_E_BANDWIDTH_OVERRUN 錯誤碼。

多任務器指派傳送時間之後,輸入媒體範例會新增至 傳送視窗,這是依傳送時間排序的輸入媒體範例清單,並準備處理到數據封包中。 在數據封包建構期間,會剖析輸入媒體範例,並將相關數據寫入數據封包作為承載。 完整的數據封包可以包含來自一或多個輸入媒體範例的數據。

當新的輸入媒體範例抵達傳送視窗中時,它們會新增至佇列,直到有足夠的媒體範例形成一個完整的封包為止。 輸入媒體範例所包含的媒體緩衝區中的數據不會複製到產生的數據封包。 資料封包會保留輸入媒體緩衝區的參考,直到輸入媒體樣本已完全封裝化,且完整的封包已從多工器中收集完成。

當有完整的數據封包可用時,可以呼叫 IMFASFMultiplexer::GetNextPacket來擷取。 如果您在有完整的封包可供擷取時呼叫 ProcessSample,則會失敗並傳回 MF_E_NOTACCEPTING 錯誤碼。 這表示多任務器無法接受更多輸入,而且您必須呼叫 getNextPacket 來擷取等候的封包。 在理想情況下,每個 ProcessSample 呼叫都應該接著一或多個 GetNextPacket 呼叫,以取得完整的數據封包。 建立完整的數據封包可能需要多個輸入媒體範例。 相反地,一個輸入媒體範例中的數據可能會跨越多個封包。 因此,並非所有呼叫 ProcessSample 都會產生輸出媒體範例。

如果輸入媒體範例包含由 MFSampleExtension_CleanPoint 屬性指示的關鍵幀,多工器將屬性複製到封包。

取得 ASF 資料封包

若要收集多任務器所產生完整數據封包的輸出媒體範例,請在迴圈中呼叫 IMFASFMultiplexer::GetNextPacket,直到封包沒有剩餘的輸出媒體範例為止。 下列列出成功案例:

  • 如果有完整的數據封包可用,GetNextPacketpdwStatusFlags 參數中接收 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 GetNextPacket,以媒體範例的形式收集這些封包,直到沒有剩餘封包可供擷取為止。

產生所有媒體範例之後,請呼叫 IMFASFMultiplexer::End,以更新與這些數據封包相關聯的 ASF 標頭物件。 標頭物件是藉由傳遞用來初始化多工器的 ContentInfo 物件來指定。 此呼叫會更新各種標頭物件,以反映多任務器在數據封包產生期間所做的變更。 這項資訊包括封包計數、傳送持續時間、播放持續時間,以及所有數據流的數據流編號。 也會更新整體標頭大小。

您必須確定在擷取所有數據封包之後,會呼叫 End。 如果多工器中有任何封包等候,End 將會失敗,並返回 MF_E_FLUSH_NEEDED 錯誤碼。 在此情況下,在迴圈中呼叫 FlushGetNextPacket,以取得等候封包。

注意

針對 VBR 編碼,在呼叫 End之後,您必須在 ContentInfo 對象的編碼屬性中設定編碼統計數據。 如需此程式的相關信息,請參閱 ContentInfo 物件 中的設定屬性中的<使用編碼器設定來設定 ContentInfo 物件>。 下列清單顯示要設定的特定屬性:

 

ASF 多任務器

教學課程:將 ASF 數據流從一個檔案複製到另一個檔案

教學課程:使用 CBR 編碼撰寫 WMA 檔案