Condividi tramite


QueryAccept (Upstream)

[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, IMFMediaEnginee Acquisizione audio/video in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente di usare un nuovo codice MediaPlayer, IMFMediaEngine e Acquisizione audio/video in Media Foundation anziché DirectShow, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.

Questo meccanismo consente a un pin di input di proporre una modifica del formato al peer upstream. Il filtro downstream deve collegare un tipo di supporto all'esempio che il filtro upstream otterrà nella chiamata successiva a IMemAllocator::GetBuffer. A tale scopo, tuttavia, il filtro downstream deve fornire un allocatore personalizzato per la connessione. Questo allocatore deve implementare un metodo privato che il filtro downstream può usare per impostare il tipo di supporto nell'esempio successivo.

Si verificano i passaggi seguenti:

  1. Il filtro downstream controlla se la connessione pin usa l'allocatore personalizzato del filtro. Se il filtro upstream è proprietario dell'allocatore, il filtro downstream non può modificare il formato.
  2. Il filtro downstream chiama IPin::QueryAccept sul pin di output upstream (vedere figura, passaggio A).
  3. Se QueryAccept restituisce S_OK, il filtro downstream chiama il metodo privato sul relativo allocatore per impostare il tipo di supporto. All'interno di questo metodo privato, l'allocatore chiama IMediaSample::SetMediaType nell'esempio disponibile successivo (B).
  4. Il filtro upstream chiama GetBuffer per ottenere un nuovo esempio (C) e IMediaSample::GetMediaType per ottenere il tipo di supporto (D).
  5. Quando il filtro upstream fornisce l'esempio, deve lasciare il tipo di supporto associato a tale esempio. In questo modo, il filtro downstream può confermare che il tipo di supporto è stato modificato (E).

Se il filtro upstream accetta la modifica del formato, deve anche essere in grado di tornare al tipo di supporto originale, come illustrato nel diagramma seguente.

Gli esempi principali di questo tipo di modifica del formato coinvolgono i renderer video DirectShow.

  • Il filtro renderer video originale può passare tra i tipi RGB e YUV durante lo streaming. Quando il filtro si connette, richiede un formato RGB che corrisponda alle impostazioni di visualizzazione correnti. Ciò garantisce che possa eseguire il fallback su GDI, se necessario. Dopo l'avvio dello streaming, se DirectDraw è disponibile, il Renderer video richiede una modifica del formato a un tipo YUV. In seguito, potrebbe tornare a RGB se perde la superficie DirectDraw per qualsiasi motivo.
  • Il filtro VMR (Video Mixing Renderer) più recente si connetterà a qualsiasi formato supportato dall'hardware grafico, inclusi i tipi YUV. Tuttavia, l'hardware grafico potrebbe modificare lo stride della superficie DirectDraw sottostante per ottimizzare le prestazioni. Il filtro VMR usa QueryAccept per segnalare il nuovo stride, specificato nel membro biWidth della struttura BITMAPINFOHEADER. I rettangoli di origine e di destinazione nella struttura VIDEOINFOHEADER o VIDEOINFOHEADER2 identificano l'area in cui deve essere decodificato il video.

nota sull'implementazione

È improbabile che si scriva un filtro che debba richiedere modifiche al formato upstream, poiché si tratta principalmente di una funzionalità dei renderer video. Tuttavia, se si scrive un filtro di trasformazione video o un decodificatore video, il filtro deve rispondere correttamente alle richieste del renderer video.

Un filtro sul posto trans-in-place che si trova tra il renderer video e il decodificatore deve passare tutte le chiamate QueryAccept upstream. Archiviare le nuove informazioni sul formato all'arrivo.

Un filtro copy-transform (ovvero un filtro non trans-sul posto) deve implementare uno dei comportamenti seguenti:

  • Il passaggio modifica il formato upstream e archivia le nuove informazioni di formato all'arrivo. Il filtro deve usare un allocatore personalizzato in modo che possa collegare il formato all'esempio upstream.
  • Eseguire la conversione del formato all'interno del filtro. Questo è probabilmente più semplice rispetto al passaggio della modifica del formato upstream. Tuttavia, potrebbe essere meno efficiente rispetto a consentire al decodificatore di decodificare di decodificare nel formato corretto.
  • Come ultima risorsa, è sufficiente rifiutare la modifica del formato. Per altre informazioni, vedere il codice sorgente per il metodo CTransInPlaceOutputPin::CheckMediaType nella libreria di classi di base DirectShow. Il rifiuto di una modifica del formato può tuttavia ridurre le prestazioni, perché impedisce al renderer video di usare il formato più efficiente.

Lo pseudocodice seguente illustra come implementare un filtro copy-transform (derivato da CTransformFilter) in grado di passare tra i tipi di output YUV e RGB. In questo esempio si presuppone che il filtro esemplifichi la conversione stessa, anziché passare la modifica del formato upstream.

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