使用索引子寫入新的索引
本主題說明如何撰寫進階系統格式 (ASF) 檔案的索引。
以下是建立 ASF 索引的一般程式:
- 初始化 ASF 索引子物件的新實例,如 索引子建立和組態中所述。
- 選擇性地設定索引子。
- 將 ASF 資料封包傳送至索引子。
- 認可索引。
- 從索引子取得已完成的索引,並將它寫入資料流程。
設定索引子
若要使用索引子來寫入新的索引物件,索引子物件必須具有旗標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 檔案的內容。 認可索引會完成編制索引,並使用檔案大小和可搜尋性的新資訊來更新標頭。
取得已完成的索引
若要從索引子取得已完成的索引,請執行下列步驟:
- 呼叫 IMFASFIndexer::GetIndexWriteSpace 以取得索引的大小。
- 呼叫 MFCreateMemoryBuffer 以建立媒體緩衝區。 您可以配置足以保存整個索引的緩衝區,以配置較小的緩衝區,並以區塊為單位取得索引。
- 呼叫 IMFASFIndexer::GetCompletedIndex 以取得索引資料。 在第一次呼叫時,將 cbOffsetWithinIndex 參數設定為零。 如果您以區塊為單位取得索引,則每次以上一次呼叫的資料大小來遞增 cbOffsetWithinIndex 。
- 呼叫 IMFMediaBuffer::Lock 以取得索引資料的指標和資料大小。
- 將索引資料寫入 ASF 檔案。
- 呼叫 IMFMediaBuffer::Unlock 以解除鎖定媒體緩衝區。
- 重複步驟 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;
};
相關主題