次の方法で共有


手順 5. イメージを変換する

[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayerIMFMediaEngine、および Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayerIMFMediaEngineAudio/Video Capture を使用することを強くお勧めします。 Microsoft は、従来の API を使用する既存のコードを、可能であれば新しい API を使用するように書き直すよう提案しています。]

これは、 変換フィルターの作成に関するチュートリアルの手順 5 です。

アップストリーム フィルターは、変換フィルターの入力ピンで IMemInputPin::Receive メソッドを呼び出すことによって、変換フィルターにメディア サンプルを配信します。 データを処理するために、変換フィルターは純粋な仮想である Transform メソッドを呼び出します。 CTransformFilter クラスと CTransInPlaceFilter クラスは、このメソッドの 2 つの異なるバージョンを使用します。

  • CTransformFilter::Transform は、入力サンプルへのポインターと出力サンプルへのポインターを受け取ります。 フィルターが メソッドを呼び出す前に、入力サンプルから出力サンプル (タイム スタンプを含む) にサンプル プロパティをコピーします。
  • CTransInPlaceFilter::Transform は 、入力サンプルへのポインターを受け取ります。 フィルターは、データをインプレースで変更します。

Transform メソッドが S_OKを返す場合、フィルターはサンプルをダウンストリームに配信します。 フレームをスキップするには、S_FALSEを返します。 ストリーミング エラーが発生した場合は、エラー コードを返します。

次の例は、RLE エンコーダーがこのメソッドを実装する方法を示しています。 独自の実装は、フィルターの動作によって大きく異なる場合があります。

HRESULT CRleFilter::Transform(IMediaSample *pSource, IMediaSample *pDest)
{
    // Get pointers to the underlying buffers.
    BYTE *pBufferIn, *pBufferOut;
    hr = pSource->GetPointer(&pBufferIn);
    if (FAILED(hr))
    {
        return hr;
    }
    hr = pDest->GetPointer(&pBufferOut);
    if (FAILED(hr))
    {
        return hr;
    }
    // Process the data.
    DWORD cbDest = EncodeFrame(pBufferIn, pBufferOut);
    KASSERT((long)cbDest <= pDest->GetSize());

    pDest->SetActualDataLength(cbDest);
    pDest->SetSyncPoint(TRUE);
    return S_OK;
}

この例では、EncodeFrame が RLE エンコードを実装するプライベート メソッドであることを前提としています。 エンコード アルゴリズム自体については、ここでは説明しません。詳細については、プラットフォーム SDK のドキュメントのトピック「ビットマップ圧縮」を参照してください。

最初に、この例では IMediaSample::GetPointer を呼び出して、基になるバッファーのアドレスを取得します。 これらをプライベート EncoderFrame メソッドに渡します。 次に 、IMediaSample::SetActualDataLength を呼び出して、エンコードされたデータの長さを指定します。 ダウンストリーム フィルターでは、バッファーを適切に管理できるように、この情報が必要です。 最後に、メソッドは IMediaSample::SetSyncPoint を呼び出して、キー フレーム フラグを TRUE に設定 します。 実行長エンコードではデルタ フレームが使用されないため、すべてのフレームはキー フレームです。 デルタ フレームの場合は、値を FALSE に設定します。

考慮する必要があるその他の問題は次のとおりです。

  • タイム スタンプ。 CTransformFilter クラスは、Transform メソッドを呼び出す前に、出力サンプルのタイムスタンプを設定します。 入力サンプルからタイム スタンプ値を変更せずにコピーします。 フィルターでタイム スタンプを変更する必要がある場合は、出力サンプルで IMediaSample::SetTime を呼び出します。

  • 変更の書式を設定します。 アップストリーム フィルターでは、メディアの種類をサンプルにアタッチすることで、ストリームの途中で形式を変更できます。 その前に、フィルターの入力ピンで IPin::QueryAccept を呼び出します。 CTransformFilter クラスでは、CheckInputType の後に CheckTransform を呼び出します。 ダウンストリーム フィルターでは、同じメカニズムを使用してメディアの種類を変更することもできます。 独自のフィルターには、次の 2 つのwatchがあります。

    • QueryAccept が誤った受け入れを返していないことを確認します。
    • フィルターが書式の変更を受け入れる場合は、IMediaSample::GetMediaType を呼び出して Transform メソッド内でそれらに対してチェックします。 そのメソッドがS_OKを返す場合、フィルターは形式の変更に応答する必要があります。

    詳細については、「 動的書式の変更」を参照してください。

  • スレッド。 CTransformFilterCTransInPlaceFilter の両方で、変換フィルターは Receive メソッド内で出力サンプルを同期的に配信します。 フィルターでは、データを処理するワーカー スレッドは作成されません。 通常、変換フィルターがワーカー スレッドを作成する理由はありません。

次へ: 手順 6.COM のサポートを追加します。

DirectShow フィルターの作成