Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
[Funkce přidružená k této stránce DirectShow je starší funkce. Byla nahrazena MediaPlayer, MMFMediaEnginea Audio/Video Capture v Media Foundation. Tyto funkce jsou optimalizované pro Windows 10 a Windows 11. Microsoft důrazně doporučuje, aby nový kód používal MediaPlayer, MMFMediaEngine a Audio/Video Capture v Media Foundation místo DirectShow, pokud je to možné. Microsoft navrhuje, aby se stávající kód, který používá starší rozhraní API, přepsal, aby se nová rozhraní API používala, pokud je to možné.]
Tento mechanismus umožňuje vstupnímu kolíku navrhnout změnu formátu na nadřazený partnerský vztah. Podřízený filtr musí připojit typ média k ukázce, kterou upstreamový filtr získá v dalším volání IMemAllocator::GetBuffer. Aby to ale bylo možné provést, musí podřízený filtr poskytnout vlastní alokátor připojení. Tento alokátor musí implementovat privátní metodu, kterou může podřízený filtr použít k nastavení typu média v další ukázce.
K následujícím krokům dochází:
- Podřízený filtr zkontroluje, jestli připojení připnutí používá vlastní alokátor filtru. Pokud nadřazený filtr vlastní alokátor, podřízený filtr nemůže změnit formát.
- Podřízený filtr volá IPin::QueryAccept na upstreamovém výstupním kolíku (viz obrázek, krok A).
- Pokud
QueryAcceptvrátí S_OK, podřízený filtr zavolá privátní metodu na jeho alokátoru, aby nastavil typ média. V rámci této privátní metody alokátor volá IMediaSample::SetMediaType v další dostupné ukázce (B). - Upstreamový filtr volá GetBuffer získat novou ukázku (C) a IMediaSample::GetMediaType získat typ média (D).
- Když upstreamový filtr doručí ukázku, měl by ponechat typ média připojený k této ukázce. Tímto způsobem může podřízený filtr potvrdit, že se typ média změnil (E).
Pokud upstreamový filtr přijme změnu formátu, musí být také schopný přepnout zpět na původní typ média, jak je znázorněno v následujícím diagramu.
queryaccept (upstream)
Mezi hlavní příklady této změny formátu patří renderery videa DirectShow.
- Původní Video Renderer filtr může během streamování přepínat mezi typy RGB a YUV. Když se filtr připojí, vyžaduje formát RGB, který odpovídá aktuálnímu nastavení zobrazení. To zaručuje, že se může vrátit na GDI, pokud potřebuje. Po zahájení streamování, pokud je directDraw k dispozici, Video Renderer požádá o změnu formátu na typ YUV. Později se může přepnout zpět na RGB, pokud z nějakého důvodu ztratí plochu DirectDraw.
- Novější filtr Video Mixing Renderer (VMR) se připojí k libovolnému formátu podporovanému grafickým hardwarem, včetně typů YUV. Grafický hardware ale může změnit krok podkladové plochy DirectDraw, aby se optimalizoval výkon. Filtr VMR používá
QueryAcceptk hlášení nového kroku, který je zadán v biWidth člen BITMAPINFOHEADER struktury. Zdrojové a cílové obdélníky v VIDEOINFOHEADER nebo VIDEOINFOHEADER2 strukturu identifikují oblast, ve které má být video dekódováno.
Poznámky k implementaci
Je nepravděpodobné, že napíšete filtr, který potřebuje požadovat změny nadřazeného formátu, protože se jedná hlavně o funkci rendererů videa. Pokud ale napíšete filtr transformace videa nebo dekodér videa, musí filtr správně reagovat na požadavky z rendereru videa.
Trans-in-place filtr, který se nachází mezi video rendererem a dekodérem, by měl předat všechny QueryAccept volání upstream. Nové informace o formátu uložte, až dorazí.
Filtr transformace kopírování (to znamená netransformní místní filtr) by měl implementovat jedno z následujících chování:
- Předejte změny formátu upstreamu a uložte nové informace o formátu, jakmile dorazí. Filtr musí používat vlastní alokátor, aby mohl připojit formát k nadřazené ukázce.
- Proveďte převod formátu uvnitř filtru. To je pravděpodobně jednodušší než předání změny formátu upstream. Může ale být méně efektivní než nechat dekódovat dekódovací filtr do správného formátu.
- Jako poslední možnost jednoduše zamítnout změnu formátu. (Další informace naleznete ve zdrojovém kódu pro CTransInPlaceOutputPin::CheckMediaType metoda v knihovně základních tříd DirectShow.) Odmítnutí změny formátu ale může snížit výkon, protože brání rendereru videa v použití nejúčinnějšího formátu.
Následující pseudokód ukazuje, jak můžete implementovat filtr copy-transform (odvozený z CTransformFilter), který může přepínat mezi typy výstupu YUV a RGB. Tento příklad předpokládá, že filtr provede převod sám, místo předání změny formátu 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);
}
}