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 Instanz des ASF-Indexerobjekts, wie in indexer Creation and Configuration beschrieben.
  2. Konfigurieren Sie optional den Indexer.
  3. Senden Sie ASF-Datenpakete an den Indexer.
  4. Commit für den Index.
  5. Rufen Sie den abgeschlossenen Index vom Indexer ab, und schreiben Sie ihn in einen Datenstrom.

Konfigurieren des Indexers

Um den Indexer zum Schreiben eines neuen Indexobjekts zu verwenden, muss das Indexerobjekt das Flag MFASF_INDEXER_WRITE_NEW_INDEX durch einen Aufruf von IMFASFIndexer::SetFlags gesetzt haben, bevor es mit IMFASFIndexer::Initialize initialisiert wird.

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

IMFASFIndexer::SetIndexStatus kann verwendet werden, um die Standardauswahl des Indexerobjekts von Datenströmen und Indextypen außer Kraft zu setzen.

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

Der Indexbezeichner muss seinen GUID-Indextyp auf GUID_NULL festgelegt haben, um anzugeben, dass der Indextyp präsentationszeitbasiert ist. Der Indexbezeichner muss auch mit der Datenstromnummer des ASF-Datenstroms initialisiert werden, der indiziert werden soll. Sobald der Indexbezeichner festgelegt ist, 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, weisen die Indexeinträge eine variable Größe auf. dwInterval ist das Indizierungsintervall. Ein Wert von MFASFINDEXER_NO_FIXED_INTERVAL gibt an, dass kein festes Indizierungsintervall vorhanden ist.

Senden von ASF-Datenpaketen an den Indexer

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

Von GetNextPacket zurückgegebene Pakete können über Aufrufe von GenerateIndexEntries an das Indexerobjekt gesendet werden, wobei 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.

Index festschreiben

Nachdem das letzte Paket einen Indexeintrag erstellt hat, muss der Index zugesichert werden. Dies erfolgt mit einem Aufruf von IMFASFIndexer::CommitIndex. CommitIndex verwendet einen Zeiger auf das ContentInfo-Objekt, das den Inhalt der ASF-Datei beschreibt. Das Commit des Indexes beendet die Indizierung und aktualisiert den Header mit neuen Informationen zur Dateigröße und Suchbarkeit.

Fertiggestellten Index abrufen

Führen Sie die folgenden Schritte aus, um den abgeschlossenen 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 zuweisen, der groß genug ist, um den gesamten Index zu speichern, einen kleineren Puffer zuzuweisen und den Index in Blöcken abzurufen.
  3. Rufen Sie IMFASFIndexer::GetCompletedIndex auf, um die Indexdaten abzurufen. Legen Sie im ersten Aufruf den parameter cbOffsetWithinIndex auf 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 abzurufen.
  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