Dela via


QueryAccept (uppströms)

[Funktionen som är associerad med den här sidan, DirectShow, är en äldre funktion. Det har ersatts av MediaPlayer, IMFMediaEngineoch Audio / Video Capture i Media Foundation. Dessa funktioner har optimerats för Windows 10 och Windows 11. Microsoft rekommenderar starkt att ny kod använder MediaPlayer, IMFMediaEngine och Audio/Video Capture i Media Foundation i stället för DirectShow, när det är möjligt. Microsoft föreslår att befintlig kod som använder äldre API:er skrivs om för att använda de nya API:erna om möjligt.]

Den här mekanismen gör det möjligt för en pin-kod för indata att föreslå en formatändring av dess överordnade peer. Det underordnade filtret måste koppla en medietyp till exemplet som det överordnade filtret hämtar i nästa anrop till IMemAllocator::GetBuffer. För att kunna göra detta måste dock det underordnade filtret tillhandahålla en anpassad allokeringsfaktor för anslutningen. Den här allokeraren måste implementera en privat metod som det underordnade filtret kan använda för att ange medietypen i nästa exempel.

Följande steg utförs:

  1. Det underordnade filtret kontrollerar om pin-anslutningen använder filtrets anpassade allokering. Om det överordnade filtret äger allokeraren kan inte det underordnade filtret ändra formatet.
  2. Det underordnade filtret anropar IPin::QueryAccept på den överordnade utdatastiftet (se bild, steg A).
  3. Om QueryAccept returnerar S_OK anropar det underordnade filtret den privata metoden på dess allokerare för att ange medietypen. I den här privata metoden anropar allokeraren IMediaSample::SetMediaType i nästa tillgängliga exempel (B).
  4. Det överordnade filtret anropar GetBuffer för att hämta ett nytt exempel (C) och IMediaSample::GetMediaType för att hämta medietypen (D).
  5. När det överordnade filtret levererar exemplet bör det lämna medietypen kopplad till exemplet. På så sätt kan det underordnade filtret bekräfta att medietypen har ändrats (E).

Om det överordnade filtret accepterar formatändringen måste det också kunna växla tillbaka till den ursprungliga medietypen, som visas i följande diagram.

queryaccept (uppströms)

De viktigaste exemplen på den här typen av formatändring omfattar DirectShow-videoåtergivningarna.

  • Det ursprungliga Video Renderer-filtret kan växla mellan RGB- och YUV-typer under strömning. När filtret ansluter krävs ett RGB-format som matchar de aktuella visningsinställningarna. Detta garanterar att det kan falla tillbaka på GDI om det behöver. Om DirectDraw är tillgängligt när strömningen har påbörjats begär videoåtergivningen en formatändring till en YUV-typ. Senare kan den växla tillbaka till RGB om den förlorar DirectDraw-ytan av någon anledning.
  • Det nyare VMR-filtret (Video Mixing Renderer) ansluter med alla format som stöds av grafikmaskinvaran, inklusive YUV-typer. Grafikmaskinvaran kan dock ändra steget för den underliggande DirectDraw-ytan för att optimera prestanda. VMR-filtret använder QueryAccept för att rapportera det nya steget, som anges i biWidth medlem i BITMAPINFOHEADER- struktur. Käll- och målrektanglarna i VIDEOINFOHEADER- eller VIDEOINFOHEADER2 struktur identifierar den region där videon ska avkodas.

Implementeringsanteckning

Det är osannolikt att du kommer att skriva ett filter som behöver begära ändringar i uppströmsformatet, eftersom detta främst är en funktion i videoåtergivningarna. Men om du skriver ett videotransformeringsfilter eller en videodekodare måste filtret svara korrekt på begäranden från videoåtergivningen.

Ett trans-in-place-filter som finns mellan videoåtergivningen och avkodaren bör skicka alla QueryAccept anrop uppströms. Lagra den nya formatinformationen när den kommer.

Ett filter för kopieringstransformering (d.ex. ett filter som inte är trans-in-place) bör implementera något av följande beteende:

  • Pass-format ändras uppströms och lagrar den nya formatinformationen när den tas emot. Filtret måste använda en anpassad allokerare så att det kan koppla formatet till det överordnade exemplet.
  • Utför formatkonverteringen i filtret. Detta är förmodligen enklare än att skicka formatändringen uppströms. Det kan dock vara mindre effektivt än att låta avkodaren filtrera avkoda i rätt format.
  • Som en sista utväg avvisar du helt enkelt formatändringen. (Mer information finns i källkoden för CTransInPlaceOutputPin::CheckMediaType-metoden i DirectShow-basklassbiblioteket.) Att avvisa en formatändring kan dock minska prestandan, eftersom det hindrar videoåtergivningen från att använda det mest effektiva formatet.

Följande pseudokod visar hur du kan implementera ett copy-transform-filter (härlett från CTransformFilter) som kan växla mellan YUV- och RGB-utdatatyper. Det här exemplet förutsätter att filtret utför själva konverteringen i stället för att skicka formatändringen uppströms.

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