Étape 5. Transformer l’image

[La fonctionnalité associée à cette page, DirectShow, est une fonctionnalité héritée. Il a été remplacé par MediaPlayer, IMFMediaEngine et Audio/Video Capture dans Media Foundation. Ces fonctionnalités ont été optimisées pour Windows 10 et Windows 11. Microsoft recommande vivement au nouveau code d’utiliser MediaPlayer, IMFMediaEngine et La capture audio/vidéo dans Media Foundation au lieu de DirectShow, lorsque cela est possible. Microsoft suggère que le code existant qui utilise les API héritées soit réécrit pour utiliser les nouvelles API si possible.]

Il s’agit de l’étape 5 du tutoriel Écriture de filtres de transformation.

Le filtre amont fournit des exemples multimédias au filtre de transformation en appelant la méthode IMemInputPin::Receive sur la broche d’entrée du filtre de transformation. Pour traiter les données, le filtre de transformation appelle la méthode Transform , qui est virtuelle pure. Les classes CTransformFilter et CTransInPlaceFilter utilisent deux versions différentes de cette méthode :

  • CTransformFilter::Transform prend un pointeur vers l’exemple d’entrée et un pointeur vers l’exemple de sortie. Avant d’appeler la méthode, le filtre copie les exemples de propriétés de l’exemple d’entrée vers l’exemple de sortie, y compris les horodatages.
  • CTransInPlaceFilter::Transform prend un pointeur vers l’exemple d’entrée. Le filtre modifie les données en place.

Si la méthode Transform retourne S_OK, le filtre remet l’exemple en aval. Pour ignorer un cadre, retournez S_FALSE. En cas d’erreur de diffusion en continu, retournez un code d’échec.

L’exemple suivant montre comment l’encodeur RLE peut implémenter cette méthode. Votre propre implémentation peut différer considérablement, en fonction de ce que fait votre filtre.

HRESULT CRleFilter::Transform(IMediaSample *pSource, IMediaSample *pDest)
{
    // Get pointers to the underlying buffers.
    BYTE *pBufferIn, *pBufferOut;
    hr = pSource->GetPointer(&pBufferIn);
    if (FAILED(hr))
    {
        return hr;
    }
    hr = pDest->GetPointer(&pBufferOut);
    if (FAILED(hr))
    {
        return hr;
    }
    // Process the data.
    DWORD cbDest = EncodeFrame(pBufferIn, pBufferOut);
    KASSERT((long)cbDest <= pDest->GetSize());

    pDest->SetActualDataLength(cbDest);
    pDest->SetSyncPoint(TRUE);
    return S_OK;
}

Cet exemple suppose qu’EncodeFrame est une méthode privée qui implémente l’encodage RLE. L’algorithme d’encodage lui-même n’est pas décrit ici ; Pour plus d’informations, consultez la rubrique « Compression bitmap » dans la documentation du Kit de développement logiciel (SDK) de plateforme.

Tout d’abord, l’exemple appelle IMediaSample::GetPointer pour récupérer les adresses des mémoires tampons sous-jacentes. Il les transmet à la méthode EncoderFrame privée. Ensuite, il appelle IMediaSample::SetActualDataLength pour spécifier la longueur des données encodées. Le filtre en aval a besoin de ces informations pour pouvoir gérer correctement la mémoire tampon. Enfin, la méthode appelle IMediaSample::SetSyncPoint pour définir l’indicateur de trame clé sur TRUE. L’encodage de longueur d’exécution n’utilise pas d’images delta, de sorte que chaque image est une image clé. Pour les images delta, définissez la valeur SUR FALSE.

Voici d’autres problèmes que vous devez prendre en compte :

  • Horodatages. La classe CTransformFilter horoda l’exemple de sortie avant d’appeler la méthode Transform . Il copie les valeurs d’horodatage de l’exemple d’entrée, sans les modifier. Si votre filtre doit modifier les horodatages, appelez IMediaSample::SetTime sur l’exemple de sortie.

  • Modifications de format. Le filtre amont peut modifier les formats mi-flux en attachant un type de média à l’exemple. Avant de le faire, il appelle IPin::QueryAccept sur la broche d’entrée de votre filtre. Dans la classe CTransformFilter , cela entraîne un appel à CheckInputType suivi de CheckTransform. Le filtre en aval peut également changer les types de médias, à l’aide du même mécanisme. Dans votre propre filtre, il y a deux choses à watch pour :

    • Assurez-vous que QueryAccept ne retourne pas de fausses acceptations.
    • Si votre filtre accepte les modifications de format, case activée à l’intérieur de la méthode Transform en appelant IMediaSample::GetMediaType. Si cette méthode retourne S_OK, votre filtre doit répondre au changement de format.

    Pour plus d’informations, consultez Modifications de format dynamique.

  • Fils. Dans CTransformFilter et CTransInPlaceFilter, le filtre de transformation fournit des exemples de sortie de manière synchrone à l’intérieur de la méthode Receive . Le filtre ne crée pas de threads de travail pour traiter les données. En règle générale, il n’y a aucune raison pour qu’un filtre de transformation crée des threads de travail.

Suivant : Étape 6. Ajouter la prise en charge de COM.

Écriture de filtres DirectShow