Поделиться через


Использование индексатора для записи нового индекса

В этом разделе показано, как записать индекс для файла расширенного системного формата (ASF).

Ниже приведена общая процедура создания индекса ASF.

  1. Инициализируйте новый экземпляр объекта индексатора ASF, как описано в разделе Создание и настройка индексатора.
  2. При необходимости настройте индексатор.
  3. Отправка пакетов данных ASF в индексатор.
  4. Зафиксируйте индекс.
  5. Получите завершенный индекс из индексатора и запишите его в поток.

Настройка индексатора

Чтобы использовать индексатор для записи нового объекта индекса, перед его инициализацией с помощью 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. Фиксация индекса завершает индексирование и обновляет заголовок новыми сведениями о размере файла и возможности поиска.

Получение завершенного индекса

Чтобы получить полный индекс из индексатора, выполните следующие действия.

  1. Вызовите IMFASFIndexer::GetIndexWriteSpace , чтобы получить размер индекса.
  2. Вызовите MFCreateMemoryBuffer , чтобы создать буфер мультимедиа. Можно либо выделить буфер, достаточно большой для хранения всего индекса, либо выделить буфер меньшего размера и получить индекс блоками.
  3. Вызовите IMFASFIndexer::GetCompletedIndex , чтобы получить данные индекса. При первом вызове задайте для параметра cbOffsetWithinIndex значение 0. Если индекс получается фрагментами, увеличьте 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