Usando o indexador para procurar dentro de um arquivo ASF

O indexador ASF é um componente de camada WMContainer usado para ler ou gravar objetos de índice em um arquivo ASF (Advanced Systems Format). Este tópico fornece informações sobre como usar o indexador ASF a ser buscado em um arquivo ASF.

Para obter informações sobre a estrutura de um arquivo ASF, consulte Estrutura de Arquivos ASF.

Inicializando o indexador para busca

Para inicializar o indexador ASF para buscar:

  1. Chame MFCreateASFIndexer para criar uma nova instância do indexador ASF.
  2. Chame IMFASFIndexer::Initialize para inicializar o indexador. Esse método obtém informações do cabeçalho ASF para determinar quais fluxos ASF são indexados. Por padrão, o objeto indexador é configurado para busca.
  3. Chame IMFASFIndexer::GetIndexPosition para localizar o deslocamento do índice dentro do arquivo ASF.
  4. Chame a função MFCreateASFIndexerByteStream para criar um fluxo de bytes para ler o índice. A entrada para essa função é um ponteiro para um fluxo de bytes que contém o arquivo ASF e o deslocamento do índice (da etapa anterior).
  5. Chame IMFASFIndexer::SetIndexByteStreams para definir o fluxo de bytes de índice no indexador.

O código a seguir mostra essas etapas:

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;
}

Obtendo a Posição de Busca.

  1. Para descobrir se um fluxo específico é indexado, chame IMFASFIndexer::GetIndexStatus. Se o fluxo for indexado, o parâmetro pfIsIndexed receberá o valor TRUE; caso contrário, ele receberá o valor FALSE.
  2. Por padrão, o indexador usa a busca de encaminhamento. Para a busca inversa (ou seja, buscando no final do arquivo), chame IMFASFIndexer::SetFlags e defina o sinalizador MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK . Caso contrário, pule essa etapa.
  3. Se o fluxo for indexado, obtenha a posição de busca para um horário de apresentação especificado chamando IMFASFIndexer::GetSeekPositionForValue. Esse método lê o índice ASF e localiza a entrada de índice mais próxima do tempo solicitado. O método retorna o deslocamento de bytes do pacote de dados especificado pela entrada de índice. O deslocamento de bytes é relativo ao início do objeto de dados ASF.

O método GetSeekPositionForValue usa um ponteiro para a estrutura ASF_INDEX_IDENTIFIER . Essa estrutura especifica um tipo de índice e um identificador de fluxo. Atualmente, o tipo de índice deve ser GUID_NULL, que especifica a indexação baseada em tempo.

O código a seguir obtém uma posição de busca, considerando um identificador de fluxo e o tempo de apresentação de destino. Se a chamada for bem-sucedida, ela retornará o deslocamento de dados no parâmetro pcbDataOffset e o tempo de busca real aproximado em 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;
}

Indexador ASF