Partager via


QueryAccept (amont)

[La fonctionnalité associée à cette page, DirectShow, est une fonctionnalité héritée. Il a été remplacé par MediaPlayer, IMFMediaEngineet audio/vidéo capture dans Media Foundation. Ces fonctionnalités ont été optimisées pour Windows 10 et Windows 11. Microsoft recommande vivement que le nouveau code utilise MediaPlayer, IMFMediaEngine et 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 en amont. Le filtre en aval doit attacher un type de média à l’exemple que le filtre en amont obtiendra dans 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 d’épingle utilise l’allocateur personnalisé du filtre. Si le filtre en amont possè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 en amont (voir l’illustration, l’é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 disponible suivant (B).
  4. Le filtre en amont appelle GetBuffer pour obtenir un nouvel exemple (C) et IMediaSample ::GetMediaType pour obtenir le type de média (D).
  5. Lorsque le filtre en amont remet l’exemple, il doit laisser le type de média attaché à cet exemple. Ainsi, le filtre en aval peut confirmer que le type de média a changé (E).

Si le filtre en amont accepte la modification 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 principaux exemples de ce type de modification 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 revenir sur GDI s’il en a besoin. Une fois la diffusion en continu commencé, si DirectDraw est disponible, video Renderer demande une modification de format à un type YUV. Plus tard, il peut revenir au RVB s’il perd la surface DirectDraw pour une raison quelconque.
  • Le nouveau filtre Video Mixing Renderer (VMR) 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 progression de la surface DirectDraw sous-jacente afin d’optimiser les performances. Le filtre VMR utilise QueryAccept pour signaler la nouvelle progression, spécifiée dans le membre biWidth de la structure BITMAPINFOHEADER. Les rectangles source et cible de la structure VIDEOINFOHEADER ou VIDEOINFOHEADER2 identifient la région dans laquelle la vidéo doit être décodée.

Note de mise en œuvre

Il est peu probable que vous écriviez un filtre qui doit demander des modifications de format en amont, car il s’agit principalement d’une fonctionnalité de renderers 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 renderer vidéo.

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

Un filtre de transformation de copie (autrement dit, un filtre non trans-sur place) doit implémenter l’un des comportements suivants :

  • Passez les modifications de format en 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 en amont.
  • Effectuez la conversion de format à l’intérieur du filtre. Cela est probablement plus facile que de passer le changement de format en amont. Toutefois, il peut être moins efficace que de laisser le filtre de décodage du décodeur dans le format correct.
  • En dernier recours, il 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 il empêche le renderer vidéo d’utiliser le format le plus efficace.

Le pseudo-code suivant montre comment implémenter un filtre de transformation de copie (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 elle-même, plutôt que de passer la modification du format en 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);
    }
}