共用方式為


使用索引子寫入新的索引

本主題說明如何撰寫進階系統格式 (ASF) 檔案的索引。

以下是建立 ASF 索引的一般程式:

  1. 初始化 ASF 索引子物件的新實例,如 索引子建立和組態中所述。
  2. 選擇性地設定索引子。
  3. 將 ASF 資料封包傳送至索引子。
  4. 認可索引。
  5. 從索引子取得已完成的索引,並將它寫入資料流程。

設定索引子

若要使用索引子來寫入新的索引物件,索引子物件必須具有旗標MFASF_INDEXER_WRITE_NEW_INDEX以呼叫 IMFASFIndexer::SetFlags 來 設定旗標,才能使用 IMFASFIndexer::Initialize 初始化

當索引子設定為寫入索引時,呼叫端會選擇要編制索引的資料流程。 根據預設,索引子會嘗試為所有資料流程建立 Index 物件。 預設時間間隔為一秒。

IMFASFIndexer::SetIndexStatus 可用來覆寫索引子物件的預設資料流程和索引類型選擇。

下列範例程式碼顯示呼叫 SetIndexStatus之前,ASF_INDEX_DESCRIPTOR和ASF_INDEX_IDENTIFIER的初始化。

ASF_INDEX_DESCRIPTOR IndexerType;
ZeroMemory(&IndexerType, sizeof(ASF_INDEX_DESCRIPTOR));

ASF_INDEX_IDENTIFIER IndexIdentifier;
ZeroMemory(&IndexIdentifier, sizeof(ASF_INDEX_IDENTIFIER));

IndexIdentifier.guidIndexType = GUID_NULL;
IndexIdentifier.wStreamNumber = 1;

IndexerType.Identifier = IndexIdentifier;
IndexerType.cPerEntryBytes  = MFASFINDEXER_PER_ENTRY_BYTES_DYNAMIC;
IndexerType.dwInterval  = MFASFINDEXER_NO_FIXED_INTERVAL;

hr = pIndexer->SetIndexStatus((BYTE*)&IndexerType, sizeof(ASF_INDEX_DESCRIPTOR), TRUE);

索引識別碼必須將其 GUID 索引類型設定為 GUID_Null,以指出索引類型將以時間為基礎。 索引識別碼也必須使用要編制索引的 ASF 資料流程資料流程編號進行初始化。 設定索引識別碼之後,請使用它來初始化索引描述元。

索引描述項結構具有必須在呼叫 SetIndexStatus之前設定的成員。 識別碼 是識別資料流程編號和索引類型的 ASF_INDEX_IDENTIFIER 結構。 cPerEntryBytes 是用於每個索引項目目的位元組數目。 如果值MFASFINDEXER_PER_ENTRY_BYTES_DYNAMIC,則索引項目目的大小會變動。 dwInterval 是索引間隔。 MFASFINDEXER_NO_FIXED_INTERVAL值表示沒有固定的索引編制間隔。

將 ASF 資料封包傳送至索引子

因為索引子是 WMContainer 層級物件,所以必須在封包產生期間與多工器搭配使用。

GetNextPacket 傳回的封包可以透過呼叫 GenerateIndexEntries 傳送至索引子物件,以建立每個傳送封包的索引項目目。

下列程式碼示範如何完成此作業:

HRESULT SendSampleToMux(
    IMFASFMultiplexer *pMux,
    IMFASFIndexer *pIndex,
    IMFSample *pSample,
    WORD wStream,
    IMFByteStream *pDestStream
    )
{
    IMFSample *pOutputSample = NULL;
    IMFMediaBuffer *pDataPacket = NULL;

    DWORD dwMuxStatus = ASF_STATUSFLAGS_INCOMPLETE;

    HRESULT hr = pMux->ProcessSample(wStream, pSample, 0);
    if (FAILED(hr))
    {
        goto done;
    }

    while (dwMuxStatus & ASF_STATUSFLAGS_INCOMPLETE)
    {
        hr = pMux->GetNextPacket(&dwMuxStatus, &pOutputSample);
        if (FAILED(hr))
        {
            goto done;
        }

        if (pOutputSample)
        {
            // Send the data packet to the indexer
            hr = pIndex->GenerateIndexEntries(pOutputSample);
            if (FAILED(hr))
            {
                goto done;
            }

            // Convert the sample to a contiguous buffer.
            hr = pOutputSample->ConvertToContiguousBuffer(&pDataPacket);
            if (FAILED(hr))
            {
                goto done;
            }

            // Write the buffer to the byte stream.
            hr = WriteBufferToByteStream(pDestStream, pDataPacket, NULL);
            if (FAILED(hr))
            {
                goto done;
            }
        }

        SafeRelease(&pOutputSample);
        SafeRelease(&pDataPacket);
    }

done:
    SafeRelease(&pOutputSample);
    SafeRelease(&pDataPacket);
    return hr;
}

如需詳細資訊,請參閱 產生新的 ASF 資料封包

認可索引

在最後一個封包已為其建立索引項目目之後,必須認可索引。 這是透過呼叫 IMFASFIndexer::CommitIndex來完成。 CommitIndex 會取得 ContentInfo 物件的指標,該物件描述 ASF 檔案的內容。 認可索引會完成編制索引,並使用檔案大小和可搜尋性的新資訊來更新標頭。

取得已完成的索引

若要從索引子取得已完成的索引,請執行下列步驟:

  1. 呼叫 IMFASFIndexer::GetIndexWriteSpace 以取得索引的大小。
  2. 呼叫 MFCreateMemoryBuffer 以建立媒體緩衝區。 您可以配置足以保存整個索引的緩衝區,以配置較小的緩衝區,並以區塊為單位取得索引。
  3. 呼叫 IMFASFIndexer::GetCompletedIndex 以取得索引資料。 在第一次呼叫時,將 cbOffsetWithinIndex 參數設定為零。 如果您以區塊為單位取得索引,則每次以上一次呼叫的資料大小來遞增 cbOffsetWithinIndex
  4. 呼叫 IMFMediaBuffer::Lock 以取得索引資料的指標和資料大小。
  5. 將索引資料寫入 ASF 檔案。
  6. 呼叫 IMFMediaBuffer::Unlock 以解除鎖定媒體緩衝區。
  7. 重複步驟 3-6,直到您寫入整個索引為止。

下列程式碼顯示這些步驟:

HRESULT WriteASFIndex(IMFASFIndexer *pIndex,IMFByteStream *pStream)
{
    const DWORD cbChunkSize = 4096;

    IMFMediaBuffer *pBuffer = NULL;

    QWORD cbIndex = 0;
    DWORD cbIndexWritten = 0;

    HRESULT hr = pIndex->GetIndexWriteSpace(&cbIndex);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = MFCreateMemoryBuffer(cbChunkSize, &pBuffer);
    if (FAILED(hr))
    {
        goto done;
    }

    while (cbIndexWritten < cbIndex)
    {
        BYTE *pData = NULL;
        DWORD cbData = 0;
        DWORD cbWritten = 0;

        hr = pIndex->GetCompletedIndex(pBuffer, cbIndexWritten);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pBuffer->Lock(&pData, NULL, &cbData);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pStream->Write(pData, cbData, &cbWritten);

        (void)pBuffer->Unlock();

        if (FAILED(hr))
        {
            goto done;
        }

        cbIndexWritten += cbData;
    }

done:
    SafeRelease(&pBuffer);
    return hr;
};

ASF 索引子