Utilizzo dell'indicizzatore per scrivere un nuovo indice
Questo argomento illustra come scrivere un indice per un file ASF (Advanced Systems Format).
Ecco la procedura generale per la creazione di un indice ASF:
- Inizializzare una nuova istanza dell'oggetto indicizzatore ASF, come descritto in Creazione e configurazione dell'indicizzatore.
- Facoltativamente, configurare l'indicizzatore.
- Inviare pacchetti di dati ASF all'indicizzatore.
- Eseguire il commit dell'indice.
- Ottenere l'indice completato dall'indicizzatore e scriverlo in un flusso.
Configurare l'indicizzatore
Per utilizzare l'indicizzatore per scrivere un nuovo oggetto index, l'oggetto indicizzatore deve avere il flag MFASF_INDEXER_WRITE_NEW_INDEX impostato con una chiamata a IMFASFIndexer::SetFlags prima di essere inizializzato con IMFASFIndexer::Initialize.
Quando l'indicizzatore è configurato per la scrittura di un indice, il chiamante sceglie i flussi da indicizzare. Per impostazione predefinita, l'indicizzatore tenta di creare un oggetto Index per tutti i flussi. L'intervallo di tempo predefinito è un secondo.
IMFASFIndexer::SetIndexStatus può essere usato per eseguire l'override della scelta predefinita dei flussi e dei tipi di indice dell'oggetto indicizzatore.
Il codice di esempio seguente illustra l'inizializzazione di un ASF_INDEX_DESCRIPTOR e un ASF_INDEX_IDENTIFIER prima di una chiamata a 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);
L'identificatore di indice deve avere il tipo di indice GUID impostato su GUID_NULL per indicare che il tipo di indice sarà basato sul tempo di presentazione. L'identificatore di indice deve essere inizializzato anche con il numero di flusso del flusso ASF da indicizzare. Dopo aver impostato l'identificatore di indice, usarlo per inizializzare il descrittore di indice.
La struttura del descrittore di indice include membri che devono essere impostati prima della chiamata a SetIndexStatus. L'identificatore è una struttura ASF_INDEX_IDENTIFIER che identifica il numero del flusso e il tipo di indice. cPerEntryBytes è il numero di byte usati per ogni voce di indice. Se il valore è MFASFINDEXER_PER_ENTRY_BYTES_DYNAMIC, le voci di indice hanno dimensioni variabili. dwInterval è l'intervallo di indicizzazione. Un valore di MFASFINDEXER_NO_FIXED_INTERVAL indica che non esiste un intervallo di indicizzazione fisso.
Inviare pacchetti di dati ASF all'indicizzatore
Poiché l'indicizzatore è un oggetto a livello WMContainer, deve essere usato insieme al multiplexer durante la generazione di pacchetti.
I pacchetti restituiti da GetNextPacket possono essere inviati all'oggetto indicizzatore tramite chiamate a GenerateIndexEntries in cui crea voci di indice per ogni pacchetto inviato.
Il codice seguente illustra come eseguire questa operazione:
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;
}
Per altre informazioni, vedere Generazione di nuovi pacchetti di dati ASF.
Eseguire il commit dell'indice
Dopo che l'ultimo pacchetto ha creato una voce di indice, è necessario eseguire il commit dell'indice. Questa operazione viene eseguita con una chiamata a IMFASFIndexer::CommitIndex. CommitIndex accetta un puntatore all'oggetto ContentInfo che descrive il contenuto del file ASF. Il commit dell'indice completa l'indicizzazione e aggiorna l'intestazione con nuove informazioni sulle dimensioni e la ricercabilità dei file.
Ottenere l'indice completato
Per ottenere l'indice completato dall'indicizzatore, seguire questa procedura:
- Chiamare IMFASFIndexer::GetIndexWriteSpace per ottenere le dimensioni dell'indice.
- Chiamare MFCreateMemoryBuffer per creare un buffer multimediale. È possibile allocare un buffer sufficientemente grande da contenere l'intero indice, allocare un buffer più piccolo e ottenere l'indice in blocchi.
- Chiamare IMFASFIndexer::GetCompletedIndex per ottenere i dati dell'indice. Nella prima chiamata impostare il parametro cbOffsetWithinIndex su zero. Se si ottiene l'indice in blocchi, incrementare cbOffsetWithinIndex ogni volta in base alle dimensioni dei dati della chiamata precedente.
- Chiamare IMFMediaBuffer::Lock per ottenere un puntatore ai dati dell'indice e alle dimensioni dei dati.
- Scrivere i dati dell'indice nel file ASF.
- Chiama IMFMediaBuffer::Unlock per sbloccare il buffer multimediale.
- Ripetere i passaggi da 3 a 6 fino a quando non è stato scritto l'intero indice.
Il codice seguente illustra questi passaggi:
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;
};
Argomenti correlati