Partilhar via


Usando o indexador para gravar um novo índice

Este tópico mostra como gravar um índice para um arquivo ASF (Formato de Sistemas Avançados).

Este é o procedimento geral para criar um índice ASF:

  1. Inicialize uma nova instância do objeto indexador ASF, conforme descrito em Criação e Configuração do Indexador.
  2. Opcionalmente, configure o indexador.
  3. Envie pacotes de dados ASF para o indexador.
  4. Confirme o índice.
  5. Obtenha o índice concluído do indexador e escreva-o em um fluxo.

Configurar o Indexador

Para usar o indexador para gravar um novo objeto de índice, o objeto indexador deve ter o sinalizador MFASF_INDEXER_WRITE_NEW_INDEX definido com uma chamada para IMFASFIndexer::SetFlags antes de ser inicializado com IMFASFIndexer::Initialize.

Quando o indexador é configurado para gravar um índice, o chamador escolhe os fluxos a serem indexados. Por padrão, o indexador tenta criar um objeto Index para todos os fluxos. O intervalo de tempo padrão é de um segundo.

IMFASFIndexer::SetIndexStatus pode ser usado para substituir a escolha padrão do objeto indexador de fluxos e tipos de índice.

O código de exemplo a seguir mostra a inicialização de um ASF_INDEX_DESCRIPTOR e um ASF_INDEX_IDENTIFIER antes de uma chamada para 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);

O identificador de índice deve ter seu tipo de índice GUID definido como GUID_NULL para indicar que o tipo de índice será baseado em tempo de apresentação. O identificador de índice também deve ser inicializado com o número de fluxo do fluxo ASF a ser indexado. Depois que o identificador de índice for definido, use-o para inicializar o descritor de índice.

A estrutura do descritor de índice tem membros que devem ser definidos antes da chamada para SetIndexStatus. Identificador é uma estrutura ASF_INDEX_IDENTIFIER que identifica o número do fluxo e o tipo de índice. cPerEntryBytes é o número de bytes usados para cada entrada de índice. Se o valor for MFASFINDEXER_PER_ENTRY_BYTES_DYNAMIC, as entradas de índice terão tamanho variável. dwInterval é o intervalo de indexação. Um valor de MFASFINDEXER_NO_FIXED_INTERVAL indica que não há intervalo de indexação fixo.

Enviar pacotes de dados ASF para o indexador

Como o indexador é um objeto de nível WMContainer, ele deve ser usado em conjunto com o multiplexer durante a geração de pacotes.

Os pacotes retornados de GetNextPacket podem ser enviados para o objeto indexador por meio de chamadas para GenerateIndexEntries , onde ele cria entradas de índice para cada pacote enviado.

O código a seguir demonstra como isso pode ser feito:

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

Para obter mais informações, consulte Gerando novos pacotes de dados ASF.

Confirmar o índice

Depois que o último pacote tiver uma entrada de índice criada para ele, o índice deverá ser confirmado. Isso é feito com uma chamada para IMFASFIndexer::CommitIndex. CommitIndex usa um ponteiro para o objeto ContentInfo que descreve o conteúdo do arquivo ASF. A confirmação do índice conclui a indexação e atualiza o cabeçalho com novas informações sobre o tamanho do arquivo e a buscabilidade.

Obter o índice concluído

Para obter o índice concluído do indexador, execute as seguintes etapas:

  1. Chame IMFASFIndexer::GetIndexWriteSpace para obter o tamanho do índice.
  2. Chame MFCreateMemoryBuffer para criar um buffer de mídia. Você pode alocar um buffer grande o suficiente para manter todo o índice, de alocar um buffer menor e obter o índice em partes.
  3. Chame IMFASFIndexer::GetCompletedIndex para obter os dados do índice. Na primeira chamada, defina o parâmetro cbOffsetWithinIndex como zero. Se você receber o índice em partes, incremente cbOffsetWithinIndex cada vez pelo tamanho dos dados da chamada anterior.
  4. Chame IMFMediaBuffer::Lock para obter um ponteiro para os dados de índice e o tamanho dos dados.
  5. Escreva os dados de índice no arquivo ASF.
  6. Chame IMFMediaBuffer::Unlock para desbloquear o buffer de mídia.
  7. Repita as etapas 3 a 6 até que você tenha gravado todo o índice.

O código a seguir mostra essas etapas:

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

Indexador ASF