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


Использование индексатора для поиска в ASF-файле

Индексатор ASF — это компонент уровня WMContainer, который используется для чтения или записи объектов индекса в файле ASF. В этом разделе содержатся сведения об использовании индексатора ASF для поиска в ASF-файле.

Сведения о структуре ASF-файла см. в разделе Структура файлов ASF.

Инициализация индексатора для поиска

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

  1. Вызовите MFCreateASFIndexer , чтобы создать новый экземпляр индексатора ASF.
  2. Вызовите IMFASFIndexer::Initialize , чтобы инициализировать индексатор. Этот метод получает сведения из заголовка ASF, чтобы определить, какие потоки ASF индексируются. По умолчанию объект индексатора настроен для поиска.
  3. Вызовите IMFASFIndexer::GetIndexPosition , чтобы найти смещение индекса в ASF-файле.
  4. Вызовите функцию MFCreateASFIndexerByteStream , чтобы создать поток байтов для чтения индекса. Входными данными для этой функции является указатель на поток байтов, содержащий ASF-файл, и смещение индекса (из предыдущего шага).
  5. Вызовите IMFASFIndexer::SetIndexByteStreams , чтобы задать индексный поток байтов в индексаторе.

Следующий код показывает эти действия.

HRESULT CreateASFIndexer(
    IMFByteStream *pContentByteStream,  // Pointer to the content byte stream
    IMFASFContentInfo *pContentInfo,
    IMFASFIndexer **ppIndexer
    )
{
    IMFASFIndexer *pIndexer = NULL;
    IMFByteStream *pIndexerByteStream = NULL;

    QWORD qwLength = 0, qwIndexOffset = 0, qwBytestreamLength = 0;

    // Create the indexer.
    HRESULT hr = MFCreateASFIndexer(&pIndexer);
    if (FAILED(hr))
    {
        goto done;
    }

    //Initialize the indexer to work with this ASF library
    hr =  pIndexer->Initialize(pContentInfo);
    if (FAILED(hr))
    {
        goto done;
    }

    //Check if the index exists. You can only do this after creating the indexer

    //Get byte stream length
    hr = pContentByteStream->GetLength(&qwLength);
    if (FAILED(hr))
    {
        goto done;
    }

    //Get index offset
    hr = pIndexer->GetIndexPosition(pContentInfo, &qwIndexOffset);
    if (FAILED(hr))
    {
        goto done;
    }

    if ( qwIndexOffset >= qwLength)
    {
        //index object does not exist, release the indexer
        goto done;
    }
    else
    {
        // initialize the indexer
        // Create a byte stream that the Indexer will use to read in
        // and parse the indexers.
         hr = MFCreateASFIndexerByteStream(
             pContentByteStream,
             qwIndexOffset,
             &pIndexerByteStream
             );

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

    hr = pIndexer->SetIndexByteStreams(&pIndexerByteStream, 1);
    if (FAILED(hr))
    {
        goto done;
    }

    // Return the pointer to the caller.
    *ppIndexer = pIndexer;
    (*ppIndexer)->AddRef();

done:
    SafeRelease(&pIndexer);
    SafeRelease(&pIndexerByteStream);
    return hr;
}

Получение позиции поиска.

  1. Чтобы узнать, индексируется ли определенный поток, вызовите IMFASFIndexer::GetIndexStatus. Если поток индексируется, параметр pfIsIndexed получает значение TRUE; в противном случае он получает значение FALSE.
  2. По умолчанию индексатор использует поиск вперед. Для обратного поиска (т. е. поиска в конце файла) вызовите IMFASFIndexer::SetFlags и установите флаг MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK . В противном случае пропустите этот шаг.
  3. Если поток индексирован, получите позицию поиска для указанного времени презентации, вызвав IMFASFIndexer::GetSeekPositionForValue. Этот метод считывает индекс ASF и находит запись индекса, которая ближе всего к требуемому времени. Метод возвращает смещение в байтах пакета данных, указанного в записи индекса. Смещение в байтах относительно начала объекта данных ASF.

Метод GetSeekPositionForValue принимает указатель на структуру ASF_INDEX_IDENTIFIER . Эта структура задает тип индекса и идентификатор потока. В настоящее время тип индекса должен быть GUID_NULL, что указывает индексирование на основе времени.

Следующий код получает позицию поиска с учетом идентификатора потока и целевого времени презентации. Если вызов выполнен успешно, он возвращает смещение данных в параметре pcbDataOffset и приблизительное фактическое время поиска в phnsApproxSeekTime.

HRESULT GetSeekPositionWithIndexer(
    IMFASFIndexer *pIndexer,
    WORD          wStreamNumber,
    MFTIME        hnsSeekTime,          // Desired seek time, in 100-nsec.
    BOOL          bReverse,
    QWORD         *pcbDataOffset,       // Receives the offset in bytes.
    MFTIME        *phnsApproxSeekTime   // Receives the approximate seek time.
    )
{
    // Query whether the stream is indexed.

    ASF_INDEX_IDENTIFIER IndexIdentifier = { GUID_NULL, wStreamNumber };

    BOOL fIsIndexed = FALSE;

    ASF_INDEX_DESCRIPTOR descriptor;

    DWORD cbIndexDescriptor = sizeof(descriptor);

    HRESULT hr = pIndexer->GetIndexStatus(
        &IndexIdentifier,
        &fIsIndexed,
        (BYTE*)&descriptor,
        &cbIndexDescriptor
        );

    if (hr == MF_E_BUFFERTOOSMALL)
    {
        hr = S_OK;
    }
    else if (FAILED(hr))
    {
        goto done;
    }

    if (!fIsIndexed)
    {
        hr = MF_E_ASF_NOINDEX;
        goto done;
    }

    if (bReverse)
    {
        hr = pIndexer->SetFlags(MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK);
        if (FAILED(hr))
        {
            goto done;
        }
    }

    // Get the offset from the indexer.

    PROPVARIANT var;

    var.vt = VT_I8;
    var.hVal.QuadPart = hnsSeekTime;

    hr = pIndexer->GetSeekPositionForValue(
        &var,
        &IndexIdentifier,
        pcbDataOffset,
        phnsApproxSeekTime,
        0
        );

done:
    return hr;
}

Индексатор ASF