QueryAccept (amont)

[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.]

Ce mécanisme permet à une broche d’entrée de proposer une modification de format à son homologue amont. Le filtre en aval doit attacher un type de média à l’exemple que le filtre amont obtiendra lors de son prochain appel à IMemAllocator::GetBuffer. Pour ce faire, toutefois, le filtre en aval doit fournir un allocateur personnalisé pour la connexion. Cet allocateur doit implémenter une méthode privée que le filtre en aval peut utiliser pour définir le type de média sur l’exemple suivant.

Les étapes suivantes se produisent :

  1. Le filtre en aval vérifie si la connexion de broche utilise l’allocateur personnalisé du filtre. Si le filtre amont est propriétaire de l’allocateur, le filtre en aval ne peut pas modifier le format.
  2. Le filtre en aval appelle IPin::QueryAccept sur la broche de sortie amont (voir l’illustration, étape A).
  3. Si QueryAccept retourne S_OK, le filtre en aval appelle la méthode privée sur son allocateur afin de définir le type de média. Dans cette méthode privée, l’allocateur appelle IMediaSample::SetMediaType sur l’exemple suivant disponible (B).
  4. Le filtre amont appelle GetBuffer pour obtenir un nouvel exemple (C) et IMediaSample::GetMediaType pour obtenir le type de média (D).
  5. Lorsque le filtre amont remet l’exemple, il doit laisser le type de média attaché à cet exemple. De cette façon, le filtre en aval peut confirmer que le type de média a changé (E).

Si le filtre amont accepte le changement de format, il doit également être en mesure de revenir au type de média d’origine, comme illustré dans le diagramme suivant.

queryaccept (amont)

Les main exemples de ce type de changement de format impliquent les convertisseurs vidéo DirectShow.

  • Le filtre Video Renderer d’origine peut basculer entre les types RVB et YUV pendant la diffusion en continu. Lorsque le filtre se connecte, il nécessite un format RVB qui correspond aux paramètres d’affichage actuels. Cela garantit qu’il peut se rabattre sur GDI s’il le faut. Une fois la diffusion en continu commencée, si DirectDraw est disponible, le convertisseur vidéo demande un changement de format en un type YUV. Plus tard, il peut revenir à RVB s’il perd la surface DirectDraw pour une raison quelconque.
  • Le filtre VMR (Video Mix Renderer) plus récent se connecte à n’importe quel format pris en charge par le matériel graphique, y compris les types YUV. Toutefois, le matériel graphique peut modifier la foulée de la surface DirectDraw sous-jacente afin d’optimiser les performances. Le filtre VMR utilise QueryAccept pour signaler la nouvelle foulée, qui est spécifiée dans le membre biWidth de la structure BITMAPINFOHEADER . Les rectangles source et cible dans la structure VIDEOINFOHEADER ou VIDEOINFOHEADER2 identifient la région dans laquelle la vidéo doit être décodée.

Note d’implémentation

Il est peu probable que vous écriviez un filtre qui doit demander des modifications de format amont, car il s’agit principalement d’une fonctionnalité des convertisseurs vidéo. Toutefois, si vous écrivez un filtre de transformation vidéo ou un décodeur vidéo, votre filtre doit répondre correctement aux demandes du convertisseur vidéo.

Un filtre trans-in-place qui se trouve entre le convertisseur vidéo et le décodeur doit passer tous les QueryAccept appels amont. Stockez les nouvelles informations de format lorsqu’elles arrivent.

Un filtre de transformation de copie (c’est-à-dire un filtre non trans-in-place) doit implémenter l’un des comportements suivants :

  • Passez les modifications de format amont et stockez les nouvelles informations de format lorsqu’elles arrivent. Votre filtre doit utiliser un allocateur personnalisé afin qu’il puisse attacher le format à l’exemple amont.
  • Effectuez la conversion de format à l’intérieur du filtre. C’est probablement plus facile que de passer le changement de format amont. Toutefois, il peut être moins efficace que de laisser le décodeur filtrer le décodage dans le format correct.
  • En dernier recours, il vous suffit de rejeter le changement de format. (Pour plus d’informations, reportez-vous au code source de la méthode CTransInPlaceOutputPin::CheckMediaType dans la bibliothèque de classes de base DirectShow.) Le rejet d’une modification de format peut toutefois réduire les performances, car cela empêche le convertisseur vidéo d’utiliser le format le plus efficace.

Le pseudo-code suivant montre comment implémenter un filtre de copie-transformation (dérivé de CTransformFilter) qui peut basculer entre les types de sortie YUV et RVB. Cet exemple part du principe que le filtre effectue la conversion lui-même, plutôt que de transmettre le changement de format amont.

HRESULT CMyTransform::CheckInputType(const CMediaType *pmt)
{
    if (pmt is a YUV type that you support) {
        return S_OK;
    }
    else {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }
}

HRESULT CMyTransform::CheckTransform(
    const CMediaType *mtIn, const CMediaType *mtOut)
{
    if (mtOut is a YUV or RGB type that you support)
    {
        if ((mtIn has the same video dimensions as mtOut) &&
            (you support the mtIn-to-mtOut transform))
        {
            return S_OK;
        }
    }
    // otherwise
    return VFW_E_TYPE_NOT_ACCEPTED;
}

// GetMediaType: Return a preferred output type.
HRESULT CMyTransform::GetMediaType(int iPosition, CMediaType *pMediaType)
{
    if (iPosition < 0) {
        return E_INVALIDARG;
    }
    switch (iPosition)
    {
    case 0:
        Copy the input type (YUV) to pMediaType
        return S_OK;
    case 1:
        Construct an RGB type that matches the input type.
        return S_OK;
    default:
        return VFW_S_NO_MORE_ITEMS;
    }
}

// SetMediaType: Override from CTransformFilter. 
HRESULT CMyTransform::SetMediaType(
    PIN_DIRECTION direction, const CMediaType *pmt)
{
    // Capture this information...
    if (direction == PINDIR_OUTPUT)
    {
       m_bYuv = (pmt->subtype == MEDIASUBTYPE_UYVY);
    }
    return S_OK;
}

HRESULT CMyTransform::Transform(
    IMediaSample *pSource, IMediaSample *pDest)
{
    // Look for format changes from downstream.
    CMediaType *pMT = NULL;
    HRESULT hr = pDest->GetMediaType((AM_MEDIA_TYPE**)&pMT);
    if (hr == S_OK)
    {
        hr = m_pOutput->CheckMediaType(pMT);
        if(FAILED(hr))
        {
            DeleteMediaType(pMT);
            return E_FAIL;
        }
        // Notify our own output pin about the new type.
        m_pOutput->SetMediaType(pMT);
        DeleteMediaType(pMT);
    }
    // Process the buffers
    if (m_bYuv) {
        return ProcessFrameYUV(pSource, pDest);
    }
    else {
        return ProcessFrameRGB(pSource, pDest);
    }
}