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:
- Inicialize uma nova instância do objeto indexador ASF, conforme descrito em Criação e Configuração do Indexador.
- Opcionalmente, configure o indexador.
- Envie pacotes de dados ASF para o indexador.
- Confirme o índice.
- 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:
- Chame IMFASFIndexer::GetIndexWriteSpace para obter o tamanho do índice.
- 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.
- 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.
- Chame IMFMediaBuffer::Lock para obter um ponteiro para os dados de índice e o tamanho dos dados.
- Escreva os dados de índice no arquivo ASF.
- Chame IMFMediaBuffer::Unlock para desbloquear o buffer de mídia.
- 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;
};
Tópicos relacionados