Utilisation de l’indexeur pour rechercher dans un fichier ASF

L’indexeur ASF est un composant de couche WMContainer utilisé pour lire ou écrire des objets index dans un fichier ASF (Advanced Systems Format). Cette rubrique fournit des informations sur l’utilisation de l’indexeur ASF à rechercher dans un fichier ASF.

Pour plus d’informations sur la structure d’un fichier ASF, consultez Structure de fichier ASF.

Initialisation de l’indexeur pour la recherche

Pour initialiser l’indexeur ASF pour rechercher :

  1. Appelez MFCreateASFIndexer pour créer un instance de l’indexeur ASF.
  2. Appelez IMFASFIndexer::Initialize pour initialiser l’indexeur. Cette méthode obtient des informations à partir de l’en-tête ASF pour déterminer quels flux ASF sont indexés. Par défaut, l’objet indexeur est configuré pour la recherche.
  3. Appelez IMFASFIndexer::GetIndexPosition pour rechercher le décalage de l’index dans le fichier ASF.
  4. Appelez la fonction MFCreateASFIndexerByteStream pour créer un flux d’octets pour la lecture de l’index. L’entrée de cette fonction est un pointeur vers un flux d’octets qui contient le fichier ASF et le décalage de l’index (de l’étape précédente).
  5. Appelez IMFASFIndexer::SetIndexByteStreams pour définir le flux d’octets d’index sur l’indexeur.

Le code suivant illustre ces étapes :

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

Obtention de la position de recherche.

  1. Pour savoir si un flux particulier est indexé, appelez IMFASFIndexer::GetIndexStatus. Si le flux est indexé, le paramètre pfIsIndexed reçoit la valeur TRUE ; sinon, elle reçoit la valeur FALSE.
  2. Par défaut, l’indexeur utilise la recherche vers l’avant. Pour la recherche inversée (c’est-à-dire la recherche à partir de la fin du fichier), appelez IMFASFIndexer::SetFlags et définissez l’indicateur MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK . Sinon, ignorez cette étape.
  3. Si le flux est indexé, obtenez la position de recherche pour une heure de présentation spécifiée en appelant IMFASFIndexer::GetSeekPositionForValue. Cette méthode lit l’index ASF et recherche l’entrée d’index la plus proche de l’heure demandée. La méthode retourne le décalage d’octets du paquet de données spécifié par l’entrée d’index. Le décalage d’octets est relatif au début de l’objet de données ASF.

La méthode GetSeekPositionForValue prend un pointeur vers la structure ASF_INDEX_IDENTIFIER . Cette structure spécifie un type d’index et un identificateur de flux. Actuellement, le type d’index doit être GUID_NULL, ce qui spécifie l’indexation basée sur le temps.

Le code suivant obtient une position de recherche, en fonction d’un identificateur de flux et de l’heure de présentation cible. Si l’appel réussit, il retourne le décalage des données dans le paramètre pcbDataOffset et le temps de recherche réel approximatif dans phnsApproxSeekTime.

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

Indexeur ASF