Share via


Verwenden des Indexers zum Suchen in einer ASF-Datei

Der ASF-Indexer ist eine WMContainer-Schichtkomponente, die zum Lesen oder Schreiben von Indexobjekten in einer ASF-Datei (Advanced Systems Format) verwendet wird. Dieses Thema enthält Informationen zur Verwendung des ASF-Indexers zum Suchen in einer ASF-Datei.

Informationen zur Struktur einer ASF-Datei finden Sie unter ASF-Dateistruktur.

Initialisieren des Indexers für die Suche

So initialisieren Sie den ASF-Indexer für die Suche:

  1. Rufen Sie MFCreateASFIndexer auf, um eine neue instance des ASF-Indexers zu erstellen.
  2. Rufen Sie IMFASFIndexer::Initialize auf, um den Indexer zu initialisieren. Diese Methode ruft Informationen aus dem ASF-Header ab, um zu bestimmen, welche ASF-Streams indiziert werden. Standardmäßig ist das Indexerobjekt für die Suche konfiguriert.
  3. Rufen Sie IMFASFIndexer::GetIndexPosition auf, um den Offset des Index in der ASF-Datei zu suchen.
  4. Rufen Sie die MFCreateASFIndexerByteStream-Funktion auf, um einen Bytestream zum Lesen des Indexes zu erstellen. Die Eingabe für diese Funktion ist ein Zeiger auf einen Bytedatenstrom, der die ASF-Datei und den Offset des Indexes (aus dem vorherigen Schritt) enthält.
  5. Rufen Sie IMFASFIndexer::SetIndexByteStreams auf, um den Indexbytestream für den Indexer festzulegen.

Diese Schritte sind im folgenden Code dargestellt:

HRESULT CreateASFIndexer(
    IMFByteStream *pContentByteStream,  // Pointer to the content byte stream
    IMFASFContentInfo *pContentInfo,
    IMFASFIndexer **ppIndexer
    )
{
    IMFASFIndexer *pIndexer = NULL;
    IMFByteStream *pIndexerByteStream = NULL;

    QWORD qwLength = 0, qwIndexOffset = 0, qwBytestreamLength = 0;

    // Create the indexer.
    HRESULT hr = MFCreateASFIndexer(&pIndexer);
    if (FAILED(hr))
    {
        goto done;
    }

    //Initialize the indexer to work with this ASF library
    hr =  pIndexer->Initialize(pContentInfo);
    if (FAILED(hr))
    {
        goto done;
    }

    //Check if the index exists. You can only do this after creating the indexer

    //Get byte stream length
    hr = pContentByteStream->GetLength(&qwLength);
    if (FAILED(hr))
    {
        goto done;
    }

    //Get index offset
    hr = pIndexer->GetIndexPosition(pContentInfo, &qwIndexOffset);
    if (FAILED(hr))
    {
        goto done;
    }

    if ( qwIndexOffset >= qwLength)
    {
        //index object does not exist, release the indexer
        goto done;
    }
    else
    {
        // initialize the indexer
        // Create a byte stream that the Indexer will use to read in
        // and parse the indexers.
         hr = MFCreateASFIndexerByteStream(
             pContentByteStream,
             qwIndexOffset,
             &pIndexerByteStream
             );

        if (FAILED(hr))
        {
            goto done;
        }
   }

    hr = pIndexer->SetIndexByteStreams(&pIndexerByteStream, 1);
    if (FAILED(hr))
    {
        goto done;
    }

    // Return the pointer to the caller.
    *ppIndexer = pIndexer;
    (*ppIndexer)->AddRef();

done:
    SafeRelease(&pIndexer);
    SafeRelease(&pIndexerByteStream);
    return hr;
}

Abrufen der Suchposition.

  1. Um herauszufinden, ob ein bestimmter Stream indiziert ist, rufen Sie IMFASFIndexer::GetIndexStatus auf. Wenn der Stream indiziert ist, empfängt der pfIsIndexed-Parameter den Wert TRUE. Andernfalls erhält er den Wert FALSE.
  2. Standardmäßig verwendet der Indexer die Vorwärtssuche. Rufen Sie für die umgekehrte Suche (d. h. suchen am Ende der Datei) IMFASFIndexer::SetFlags auf, und legen Sie das MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK-Flag fest. Überspringen Sie andernfalls diesen Schritt.
  3. Wenn der Stream indiziert ist, rufen Sie die Suchposition für eine angegebene Präsentationszeit ab, indem Sie IMFASFIndexer::GetSeekPositionForValue aufrufen. Diese Methode liest den ASF-Index und sucht den Indexeintrag, der dem angeforderten Zeitpunkt am nächsten ist. Die -Methode gibt den Byteoffset des Datenpakets zurück, das durch den Indexeintrag angegeben wird. Der Byteoffset ist relativ zum Anfang des ASF-Datenobjekts.

Die GetSeekPositionForValue-Methode verwendet einen Zeiger auf die ASF_INDEX_IDENTIFIER-Struktur . Diese Struktur gibt einen Indextyp und einen Streambezeichner an. Derzeit muss der Indextyp GUID_NULL sein, was die zeitbasierte Indizierung angibt.

Der folgende Code ruft eine Suchposition unter Berücksichtigung eines Streambezeichners und einer Zielpräsentationszeit ab. Wenn der Aufruf erfolgreich ist, werden der Datenoffset im parameter pcbDataOffset und die ungefähre tatsächliche Suchzeit in phnsApproxSeekTime zurückgegeben.

HRESULT GetSeekPositionWithIndexer(
    IMFASFIndexer *pIndexer,
    WORD          wStreamNumber,
    MFTIME        hnsSeekTime,          // Desired seek time, in 100-nsec.
    BOOL          bReverse,
    QWORD         *pcbDataOffset,       // Receives the offset in bytes.
    MFTIME        *phnsApproxSeekTime   // Receives the approximate seek time.
    )
{
    // Query whether the stream is indexed.

    ASF_INDEX_IDENTIFIER IndexIdentifier = { GUID_NULL, wStreamNumber };

    BOOL fIsIndexed = FALSE;

    ASF_INDEX_DESCRIPTOR descriptor;

    DWORD cbIndexDescriptor = sizeof(descriptor);

    HRESULT hr = pIndexer->GetIndexStatus(
        &IndexIdentifier,
        &fIsIndexed,
        (BYTE*)&descriptor,
        &cbIndexDescriptor
        );

    if (hr == MF_E_BUFFERTOOSMALL)
    {
        hr = S_OK;
    }
    else if (FAILED(hr))
    {
        goto done;
    }

    if (!fIsIndexed)
    {
        hr = MF_E_ASF_NOINDEX;
        goto done;
    }

    if (bReverse)
    {
        hr = pIndexer->SetFlags(MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK);
        if (FAILED(hr))
        {
            goto done;
        }
    }

    // Get the offset from the indexer.

    PROPVARIANT var;

    var.vt = VT_I8;
    var.hVal.QuadPart = hnsSeekTime;

    hr = pIndexer->GetSeekPositionForValue(
        &var,
        &IndexIdentifier,
        pcbDataOffset,
        phnsApproxSeekTime,
        0
        );

done:
    return hr;
}

ASF-Indexer