カクタスソフトウェア
カクタスソフトウェア
サウンド MIDI マルチメディア アプリケーション

変換フィルター

変換フィルターは入力データを加工したものを出力用バッファにコピーします。サンプリング周波数変換など、入出力でデータサイズが異なる場合や、圧縮・解凍などメディアタイプそのものが変わる用途に用います。変換フィルターはCTransformFilterクラスから派生させます。

class CMyFilter : public CTransformFilter
{
...

CTransformFilterクラスを用いる場合、以下の関数をオーバーライドする必要があります。

以下に変換フィルターで必要な関数を紹介します。

CreateInstance

フィルターのインスタンスを生成する関数です。

CUnknown* WINAPI CMyFilter::CreateInstance(
    LPUNKNOWN       punk,
    HRESULT         *phr)
{
    ASSERT(phr);
    CMyFilter *pNewObject = new CMyFilter(punk, phr);

    if (pNewObject == NULL)
    {
        *phr = E_OUTOFMEMORY;
    }
    return pNewObject;
}

コンストラクター

CMyFilter::CMyFilter(LPUNKNOWN punk, HRESULT *phr)
    : CTransformFilter(NAME("MyFilter"), punk, CLSID_MY_FILTER)
{
    // TODO:
}

CMyFilter::~CMyFilter()
{
    // TODO:
}

CheckInputType

このフィルターが指定されたメディアタイプを支援しているかどうかを知らせます。支援していればS_OKを、そうでなければVFW_E_TYPE_NOT_ACCEPTEDを戻します。

HRESULT CMyFilter::CheckInputType(const CMediaType *mtIn)
{
    if (支援)           return S_OK;
    else                return VFW_E_TYPE_NOT_ACCEPTED;
}

CheckTransform

このフィルターがフォーマット変換を行うかどうかを知らせます。入力のメディアタイプがフォーマット変換によって異なるメディアタイプとして出力される場合、VFW_E_TYPE_NOT_ACCEPTEDを戻します。出力が入力と同種の(互換性のある)メディアタイプであればS_OKを戻します。

HRESULT CMyFilter::CheckTransform(
    const CMediaType    *mtIn,
    const CMediaType    *mtOut)
{
    if (互換性あり)     return S_OK;
    else                return VFW_E_TYPE_NOT_ACCEPTED;
}

どういう条件が整えば互換性ありと判断できるかは、フィルターの仕様によって異なります。以下にいくつかチェック方法を示します。

少なくとも入力が支援しているフォーマットである必要があります。

    if(*mtIn->FormatType() != 支援してるフォーマット)
    {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }

サブタイプが同じか?

    if (*mtIn->Subtype() != *mtOut->Subtype())
    {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }

入出力とも同じメディアタイプか?(これは簡易で最も厳密なチェック方法です。)

    if(*mtIn != *mtOut)
    {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }

DecideBufferSize

出力ピンのアロケータに必要なバッファサイズを知らせます。この関数の実行時には入力ピンが接続されている必要があります。

HRESULT CMyFilter::DecideBufferSize(
    IMemAllocator           *pAlloc,
    ALLOCATOR_PROPERTIES    *pProperties)
{
    if (m_pInput->IsConnected() == FALSE)
    {
        return E_UNEXPECTED;
    }
    pProperties->cBuffers = バッファの枚数;
    pProperties->cbBuffer = バッファサイズ;

    ALLOCATOR_PROPERTIES Actual;
    HRESULT hr = pAlloc->SetProperties(pProperties, &Actual);
    if (FAILED(hr))
    {
        return hr;
    }
    if (Actual.cbBuffer < pProperties->cbBuffer)
    {
        return E_FAIL;
    }
    return NOERROR;
}

以下の2つの変数にバッファサイズとバッファの数をセットします。

    pProperties->cBuffers = バッファの枚数;
    pProperties->cbBuffer = バッファサイズ;

IMemAllocator::SetProperties()関数の第1引数にリクエストしたいサイズをセットすると、第2引数に実際にアロケートされるサイズが戻ります。

    ALLOCATOR_PROPERTIES Actual;
    HRESULT hr = pAlloc->SetProperties(pProperties, &Actual);

割り当てられたバッファサイズが必要量を満たしているかチェックします。

    if ((Actual.cBuffers < pProperties->cBuffers) ||
        (Actual.cbBuffer < pProperties->cbBuffer))
    {
        return E_FAIL;
    }

バッファサイズの決め方はメディアタイプによって異なります。

オーディオ

例えば、ウェーブデータを0.1秒収納できるサイズを5つ、等とします。

    CMediaType *pMediaType = 出力ピンのメディアタイプ;
    WAVEFORMATEX *pwfx = (WAVEFORMATEX *)pMediaType->Format();

    int nBitsPerSample = pwfx->wBitsPerSample;
    int nSamplesPerSec = pwfx->nSamplesPerSec;
    int nChannels      = pwfx->nChannels;

    pProperties->cBuffers = 5;
    pProperties->cbBuffer = (nChannels * nSamplesPerSec * nBitsPerSample) / (8 * 10);

ビデオ

ビットマップ1枚分のサイズを設定します。

    CMediaType *pMediaType = 出力ピンのメディアタイプ;
    VIDEOINFOHEADER *pvih = (VIDEOINFOHEADER *)pMediaType->Format();

    pProperties->cBuffers = 1;
    pProperties->cbBuffer = GetBitmapSize(&pvih->bmiHeader);

入力ピンのメディアタイプから設定を取得します。

    CMediaType mediaTypeIn = m_pInput->CurrentMediaType();

    pProperties->cBuffers = 1;
    pProperties->cbBuffer = mediaTypeIn.GetSampleSize();

GetMediaType

出力ピンのメディアタイプを取得する関数です。

HRESULT CMyFilter::GetMediaType(
    int             iPosition,
    CMediaType      *pMediaType)
{
    if(iPosition < 0)       return E_INVALIDARG;
    if(iPosition > 0)       return VFW_S_NO_MORE_ITEMS;

    *pMediaType = m_pInput->CurrentMediaType();
    return S_OK;
}

出力ピンは1つしかないので、ピン番号”iPosition”はゼロ以外をエラーとします。

    if(iPosition < 0)       return E_INVALIDARG;
    if(iPosition > 0)       return VFW_S_NO_MORE_ITEMS;

入出力とも同じメディアタイプであれば、入力ピンのメディアタイプをpMediaTypeに代入します。

    *pMediaType = m_pInput->CurrentMediaType();

異なる場合には出力用のメディアタイプをpMediaTypeに代入します。

Transform

ここに実際のフィルター処理を記述します。

正常に出力用データを用意できた時は、S_OKを戻します。何らかのエラーにより出力用データを用意できなかった時は、S_FALSEを戻します。

HRESULT CMyFilter::Transform(
    IMediaSample    *pIn,
    IMediaSample    *pOut)
{
    // TODO:
    return S_OK;
}

以下にバッファの内容を何も変更せずに転送する例を示します。実際にはここに変換プログラムを書きます。

    LPBYTE  pSrce;
    LPBYTE  pDest;
    pIn->GetPointer(&pSrce);
    pOut->GetPointer(&pDest);
    long lSizeIn = pIn->GetActualDataLength();
    CopyMemory(pDest, pSrce, lSizeIn);
    pOut->SetActualDataLength(lSizeIn);

以下の情報を入力ピンから出力ピンへ転送します。

タイムスタンプ

    REFERENCE_TIME  tStart;
    REFERENCE_TIME  tEnd;
    if (SUCCEEDED(pIn->GetTime(&tStart, &tEnd)))
        pOut->SetTime(&tStart, &tEnd);

    LONGLONG    mStart;
    LONGLONG    mEnd;
    if (SUCCEEDED(pIn->GetMediaTime(&mStart, &mEnd)))
        pOut->SetMediaTime(&mStart, &mEnd);

同期ポイント

    HRESULT hr = pIn->IsSyncPoint();
    if (hr == S_OK)             pOut->SetSyncPoint(TRUE);
    else if (hr == S_FALSE)     pOut->SetSyncPoint(FALSE);
    else                        return E_UNEXPECTED;

連続性

    hr = pIn->IsDiscontinuity();
    if (hr == S_OK)             pOut->SetDiscontinuity(TRUE);
    else if (hr == S_FALSE)     pOut->SetDiscontinuity(FALSE);
    else                        return E_UNEXPECTED;

メディアタイプ

    AM_MEDIA_TYPE *mt;
    pIn->GetMediaType(&mt);
    pOut->SetMediaType(mt);
    DeleteMediaType(mt);

ドキュメントの先頭へ

カクタスソフトウェア 技術協力 資料室 資料室の広場 SourceForge.jp お問い合わせ