QueryAccept (アップストリーム)
[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayer、IMFMediaEngine、Audio/Video Capture を使用することを強くお勧めします。 Microsoft は、レガシ API を使用する既存のコードを、可能であれば新しい API を使用するように書き換えるよう提案しています。]
このメカニズムにより、入力ピンはアップストリーム ピアへの形式変更を提案できます。 ダウンストリーム フィルターは、 IMemAllocator::GetBuffer の次の呼び出しでアップストリーム フィルターが取得するサンプルにメディアの種類をアタッチする必要があります。 ただし、これを行うには、ダウンストリーム フィルターで接続用のカスタム アロケーターを提供する必要があります。 このアロケーターは、ダウンストリーム フィルターが次のサンプルでメディアの種類を設定するために使用できるプライベート メソッドを実装する必要があります。
次の手順で行われます。
- ダウンストリーム フィルターは、ピン接続でフィルターのカスタム アロケーターを使用しているかどうかを確認します。 アップストリーム フィルターがアロケーターを所有している場合、ダウンストリーム フィルターは形式を変更できません。
- ダウンストリーム フィルターは、アップストリーム出力ピンで IPin::QueryAccept を呼び出します (図、手順 A を参照)。
- がS_OKを返す場合
QueryAccept
、ダウンストリーム フィルターはメディアの種類を設定するために、そのアロケーターでプライベート メソッドを呼び出します。 このプライベート メソッド内で、アロケーターは次に使用可能なサンプル (B) で IMediaSample::SetMediaType を呼び出します。 - アップストリーム フィルターは GetBuffer を 呼び出して、新しいサンプル (C) と IMediaSample::GetMediaType を取得してメディアの種類 (D) を取得します。
- アップストリーム フィルターがサンプルを配信する場合は、そのサンプルにメディアの種類をアタッチしたままにする必要があります。 そうすることで、ダウンストリーム フィルターはメディアの種類が変更されたことを確認できます (E)。
アップストリーム フィルターが形式の変更を受け入れる場合は、次の図に示すように、元のメディアの種類に切り替えることもできます。
この種類の形式変更のメイン例には、DirectShow ビデオ レンダラーが含まれます。
- 元の ビデオ レンダラー フィルターは、ストリーミング中に RGB と YUV の種類を切り替えることができます。 フィルターが接続するときは、現在の表示設定に一致する RGB 形式が必要です。 これにより、必要に応じて GDI にフォールバックできます。 ストリーミングが開始されると、DirectDraw が使用可能な場合、ビデオ レンダラーは YUV 型への形式変更を要求します。 その後、何らかの理由で DirectDraw サーフェスが失われると、RGB に戻る可能性があります。
- 新しいビデオ ミキシング レンダラー (VMR) フィルターは、YUV の種類を含め、グラフィックス ハードウェアでサポートされている任意の形式で接続されます。 ただし、グラフィックス ハードウェアは、パフォーマンスを最適化するために、基になる DirectDraw サーフェスのストライドを変更する可能性があります。 VMR フィルターは を使用
QueryAccept
して、BITMAPINFOHEADER 構造体の biWidth メンバーで指定された新しいストライドを報告します。 VIDEOINFOHEADER または VIDEOINFOHEADER2 構造体のソース四角形とターゲット四角形は、ビデオをデコードする領域を識別します。
実装に関する注意事項
これは主にビデオ レンダラーの機能であるため、アップストリーム形式の変更を要求する必要があるフィルターを記述することはほとんどありません。 ただし、ビデオ変換フィルターまたはビデオ デコーダーを作成する場合、フィルターはビデオ レンダラーからの要求に正しく応答する必要があります。
ビデオ レンダラーとデコーダーの間に配置されたトランスインプレース フィルターは、すべての呼び出しをアップストリームに渡す QueryAccept
必要があります。 新しい書式情報が到着したら保存します。
コピー変換フィルター (つまり、インプレース変換以外のフィルター) は、次のいずれかの動作を実装する必要があります。
- パス形式はアップストリームで変更され、新しい書式情報が到着したときに格納されます。 上流のサンプルに形式をアタッチできるように、フィルターでカスタム アロケーターを使用する必要があります。
- フィルター内で書式変換を実行します。 これは、形式変更をアップストリームに渡すよりも簡単です。 ただし、デコーダー フィルターを正しい形式にデコードするよりも効率が低い場合があります。
- 最後の手段として、単に形式の変更を拒否します。 (詳細については、DirectShow 基本クラス ライブラリの CTransInPlaceOutputPin::CheckMediaType メソッドのソース コードを参照してください)。ただし、フォーマット変更を拒否すると、ビデオ レンダラーで最も効率的な形式が使用できなくなるため、パフォーマンスが低下する可能性があります。
次の擬似コードは、YUV と RGB 出力の種類を切り替えることができるコピー変換フィルター ( CTransformFilter から派生) を実装する方法を示しています。 この例では、形式変更をアップストリームに渡すのではなく、フィルターが変換自体を実行することを前提としています。
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);
}
}