Использование индексатора для записи нового индекса
В этом разделе показано, как записать индекс для файла расширенного системного формата (ASF).
Ниже приведена общая процедура создания индекса ASF.
- Инициализируйте новый экземпляр объекта индексатора ASF, как описано в разделе Создание и настройка индексатора.
- При необходимости настройте индексатор.
- Отправка пакетов данных ASF в индексатор.
- Зафиксируйте индекс.
- Получите завершенный индекс из индексатора и запишите его в поток.
Настройка индексатора
Чтобы использовать индексатор для записи нового объекта индекса, перед его инициализацией с помощью IMFASFIndexer::SetFlags должен быть установлен флаг MFASF_INDEXER_WRITE_NEW_INDEX с вызовом IMFASFIndexer ::Initialize.
Когда индексатор настроен для записи индекса, вызывающий объект выбирает потоки для индексирования. По умолчанию индексатор пытается создать объект индекса для всех потоков. Интервал времени по умолчанию — одна секунда.
IMFASFIndexer::SetIndexStatus можно использовать для переопределения выбранного по умолчанию объекта индексатора потоков и типов индексов.
В следующем примере кода показана инициализация ASF_INDEX_DESCRIPTOR и ASF_INDEX_IDENTIFIER перед вызовом SetIndexStatus.
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 значение 0. Если индекс получается фрагментами, увеличьте 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;
};
Связанные темы