Freigeben über


Verwenden des Indexers zum Schreiben eines neuen Indexes

In diesem Thema wird gezeigt, wie Sie einen Index für eine ASF-Datei (Advanced Systems Format) schreiben.

Hier ist das allgemeine Verfahren zum Erstellen eines ASF-Indexes:

  1. Initialisieren Sie eine neue instance des ASF-Indexerobjekts, wie unter Erstellen und Konfigurieren des Indexers beschrieben.
  2. Optional können Sie den Indexer konfigurieren.
  3. Senden von ASF-Datenpaketen an den Indexer.
  4. Committen Sie den Index.
  5. Rufen Sie den vollständigen Index aus dem Indexer ab, und schreiben Sie ihn in einen Stream.

Konfigurieren des Indexers

Um den Indexer zum Schreiben eines neuen Indexobjekts zu verwenden, muss für das Indexerobjekt das Flag festgelegt MFASF_INDEXER_WRITE_NEW_INDEX, das mit einem Aufruf von IMFASFIndexer::SetFlags festgelegt wurde, bevor es mit IMFASFIndexer::Initialize initialisiert wird.

Wenn der Indexer für das Schreiben eines Index konfiguriert ist, wählt der Aufrufer die Datenströme aus, die indiziert werden sollen. Standardmäßig versucht der Indexer, ein Indexobjekt für alle Streams zu erstellen. Das Standardzeitintervall beträgt eine Sekunde.

IMFASFIndexer::SetIndexStatus kann verwendet werden, um die Standardauswahl von Streams und Indextypen des Indexerobjekts zu überschreiben.

Der folgende Beispielcode zeigt die Initialisierung eines ASF_INDEX_DESCRIPTOR und eines ASF_INDEX_IDENTIFIER vor einem Aufruf von 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);

Für den Indexbezeichner muss der GUID-Indextyp auf GUID_NULL festgelegt sein, um anzugeben, dass der Indextyp präsentationszeitbasiert ist. Der Indexbezeichner muss auch mit der Streamnummer des asf-Datenstroms initialisiert werden, der indiziert werden soll. Nachdem der Indexbezeichner festgelegt wurde, verwenden Sie ihn, um den Indexdeskriptor zu initialisieren.

Die Indexdeskriptorstruktur verfügt über Member, die vor dem Aufruf von SetIndexStatus festgelegt werden müssen. Der Bezeichner ist eine ASF_INDEX_IDENTIFIER Struktur, die die Datenstromnummer und den Indextyp identifiziert. cPerEntryBytes ist die Anzahl der Bytes, die für jeden Indexeintrag verwendet werden. Wenn der Wert MFASFINDEXER_PER_ENTRY_BYTES_DYNAMIC ist, haben die Indexeinträge eine variable Größe. dwInterval ist das Indizierungsintervall. Der Wert MFASFINDEXER_NO_FIXED_INTERVAL gibt an, dass kein festes Indizierungsintervall vorhanden ist.

Senden von ASF-Datenpaketen an den Indexer

Da der Indexer ein WMContainer-Objekt ist, muss er während der Paketgenerierung in Verbindung mit dem Multiplexer verwendet werden.

Von GetNextPacket zurückgegebene Pakete können über Aufrufe von GenerateIndexEntries an das Indexerobjekt gesendet werden, wo Indexeinträge für jedes gesendete Paket erstellt werden.

Der folgende Code veranschaulicht, wie dies geschehen kann:

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

Weitere Informationen finden Sie unter Generieren neuer ASF-Datenpakete.

Commit für den Index

Nachdem für das letzte Paket ein Indexeintrag erstellt wurde, muss ein Commit für den Index ausgeführt werden. Dies erfolgt durch einen Aufruf von IMFASFIndexer::CommitIndex. CommitIndex verwendet einen Zeiger auf das ContentInfo-Objekt, das den Inhalt der ASF-Datei beschreibt. Durch das Committen des Indexes wird die Indizierung abgeschlossen und der Header mit neuen Informationen zur Dateigröße und Suchbarkeit aktualisiert.

Abrufen des abgeschlossenen Indexes

Führen Sie die folgenden Schritte aus, um den vollständigen Index aus dem Indexer abzurufen:

  1. Rufen Sie IMFASFIndexer::GetIndexWriteSpace auf, um die Größe des Indexes abzurufen.
  2. Rufen Sie MFCreateMemoryBuffer auf, um einen Medienpuffer zu erstellen. Sie können entweder einen Puffer zuordnen, der groß genug ist, um den gesamten Index aufzunehmen, einen kleineren Puffer zuzuweisen und den Index in Blöcken abzurufen.
  3. Rufen Sie IMFASFIndexer::GetCompletedIndex auf, um die Indexdaten abzurufen. Legen Sie beim ersten Aufruf den CbOffsetWithinIndex-Parameter auf 0 (null) fest. Wenn Sie den Index in Blöcken abrufen, erhöhen Sie cbOffsetWithinIndex jedes Mal um die Größe der Daten aus dem vorherigen Aufruf.
  4. Rufen Sie IMFMediaBuffer::Lock auf, um einen Zeiger auf die Indexdaten und die Größe der Daten zu erhalten.
  5. Schreiben Sie die Indexdaten in die ASF-Datei.
  6. Rufen Sie IMFMediaBuffer::Unlock auf, um den Medienpuffer zu entsperren.
  7. Wiederholen Sie die Schritte 3 bis 6, bis Sie den gesamten Index geschrieben haben.

Diese Schritte sind im folgenden Code dargestellt:

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

ASF-Indexer