使用索引器写入新索引
本主题演示如何为高级系统格式 (ASF) 文件编写索引。
下面是创建 ASF 索引的一般过程:
- 初始化 ASF 索引器对象的新实例,如 索引器创建和配置中所述。
- (可选)配置索引器。
- 将 ASF 数据包发送到索引器。
- 提交索引。
- 从索引器获取已完成的索引,并将其写入流。
配置索引器
若要使用索引器编写新的索引对象,索引器对象必须具有标志MFASF_INDEXER_WRITE_NEW_INDEX设置,并调用 IMFASFIndexer::SetFlags ,然后才能使用 IMFASFIndexer::Initialize 初始化它。
当索引器配置为写入索引时,调用方将选择要编制索引的流。 默认情况下,索引器会尝试为所有流创建索引对象。 默认时间间隔为一秒。
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;
};
相关主题