directshowでのTV(MPEG2の)フィルターの開発について

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 187

kokawa2003

score 152

Dierctshowでのフィルターを開発しています。
まず手始めになにもしないフィルターを開発しようと思いました。
ちょっと長いがソースです
HEADER

class MyTransformFilter :
    public CTransformFilter
{

public:
    MyTransformFilter();

    // Methods required for filters derived from CTransformFilter

        // Methods required for filters derived from CTransformFilter
    HRESULT CheckInputType(const CMediaType* mtIn);
    HRESULT GetMediaType(int iPosition, CMediaType* pMediaType);
    HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut);
    HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProp);
    HRESULT Transform(IMediaSample* pSource, IMediaSample* pDest);

};


本体

MyTransformFilter::MyTransformFilter():CTransformFilter(NAME("My Transform Filter"), 0,CLSID_MyTransformFilter) {

}


HRESULT MyTransformFilter::CheckInputType(const CMediaType* mtIn) {
    VIDEOINFOHEADER* pVih =
        reinterpret_cast<VIDEOINFOHEADER*>(mtIn->pbFormat);

    RPC_WSTR waString;
    UuidToString(&(mtIn->subtype), &waString);
    TRACE(L"okawa:");
    TRACE((WCHAR*)waString);
    TRACE(L"\n");
    RpcStringFree(&waString);

    if ((mtIn->majortype != MEDIATYPE_Video) ||
        (mtIn->subtype != MEDIASUBTYPE_RGB24) ||
        (mtIn->formattype != FORMAT_VideoInfo) ||
        (mtIn->cbFormat < sizeof(VIDEOINFOHEADER)) ||
        (pVih->bmiHeader.biPlanes != 1) ||
        (pVih->bmiHeader.biBitCount != 24) ||
        (pVih->bmiHeader.biCompression != BI_RGB))
    {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }

    return S_OK;
}
HRESULT MyTransformFilter::GetMediaType(int iPosition, CMediaType* pMediaType) {
    HRESULT hr;


    ASSERT(m_pInput->IsConnected());

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

    if (FAILED(hr = m_pInput->ConnectionMediaType(pMediaType))) return hr;

    ASSERT(pMediaType->formattype == FORMAT_VideoInfo);
    VIDEOINFOHEADER* pVih =
        reinterpret_cast<VIDEOINFOHEADER*>(pMediaType->pbFormat);
    pVih->bmiHeader.biCompression = BI_RGB;
    pVih->bmiHeader.biSizeImage = DIBSIZE(pVih->bmiHeader);
    pVih->bmiHeader.biPlanes = 1;
    pVih->bmiHeader.biBitCount = 24;
    pVih->bmiHeader.biCompression = BI_RGB;
    //pVih->bmiHeader.biWidth = pVih->bmiHeader.biWidth;
    //pVih->bmiHeader.biHeight = pVih->bmiHeader.biHeight;

    return S_OK;
}
HRESULT MyTransformFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) {
    // Check the major type.
    if ((mtOut->majortype != MEDIATYPE_Video) ||
        (mtOut->formattype != FORMAT_VideoInfo) ||
        (mtOut->cbFormat < sizeof(VIDEOINFOHEADER)))
    {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }

    // Compare the bitmap information against the input type.
    ASSERT(mtIn->formattype == FORMAT_VideoInfo);
    BITMAPINFOHEADER* pBmiOut = HEADER(mtOut->pbFormat);
    BITMAPINFOHEADER* pBmiIn = HEADER(mtIn->pbFormat);
    if ((pBmiOut->biPlanes != 1) ||
        (pBmiOut->biBitCount != 24) ||
        (pBmiOut->biCompression != BI_RGB) ||
        (pBmiOut->biWidth != pBmiIn->biWidth) ||
        (pBmiOut->biHeight != pBmiIn->biHeight))
    {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }

    // Compare source and target rectangles.
    RECT rcImg;
    SetRect(&rcImg, 0, 0, pBmiIn->biWidth, pBmiIn->biHeight);
    RECT* prcSrc = &((VIDEOINFOHEADER*)(mtIn->pbFormat))->rcSource;
    RECT* prcTarget = &((VIDEOINFOHEADER*)(mtOut->pbFormat))->rcTarget;
    if ((!IsRectEmpty(prcSrc) && !EqualRect(prcSrc, &rcImg)) ||
        (!IsRectEmpty(prcTarget) && !EqualRect(prcTarget, &rcImg)))
    {
        return VFW_E_INVALIDMEDIATYPE;
    }

    // Everything is good.
    return S_OK;
}
HRESULT MyTransformFilter::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProp) {
    AM_MEDIA_TYPE mt;
    HRESULT hr = m_pOutput->ConnectionMediaType(&mt);
    if (FAILED(hr))
    {
        return hr;
    }

    ASSERT(mt.formattype == FORMAT_VideoInfo);
    BITMAPINFOHEADER* pbmi = HEADER(mt.pbFormat);
    pProp->cbBuffer = DIBSIZE(*pbmi) ;
    if (pProp->cbAlign == 0) pProp->cbAlign = 1;
    if (pProp->cBuffers == 0) pProp->cBuffers = 1;

    // Release the format block.
    FreeMediaType(mt);

    // Set allocator properties.
    ALLOCATOR_PROPERTIES Actual;
    hr = pAlloc->SetProperties(pProp, &Actual);
    if (FAILED(hr)) return hr;

    // Even when it succeeds, check the actual result.
    if (pProp->cbBuffer > Actual.cbBuffer) return E_FAIL;

    return S_OK;
}



HRESULT MyTransformFilter::Transform(IMediaSample* pSource, IMediaSample* pDest) {


    BYTE* pBufferIn=NULL, * pBufferOut=NULL;
    HRESULT hr;

    // Get pointers to the underlying buffers.
    if (FAILED(hr = pSource->GetPointer(&pBufferIn))) return hr;
    if (FAILED(hr = pDest->GetPointer(&pBufferOut))) return hr;
    AM_MEDIA_TYPE mt;
    hr = m_pOutput->ConnectionMediaType(&mt);
    if (FAILED(hr))
    {
        return hr;
    }

    static int cnt = 0;
    cnt++;
    char filename[MAX_PATH];;
    sprintf(filename, "test%d.bmp", cnt);

    BITMAPINFOHEADER* pbmi = HEADER(mt.pbFormat);
    int width = pbmi->biWidth;
    int height = pbmi->biHeight;

    /*
    cv::Mat picYV12 = cv::Mat(height * 3 / 2, width, CV_8UC1, pBufferIn);
    cv::Mat picBGR;
    cv::cvtColor(picYV12, picBGR, cv::COLOR_YUV2BGR_YV12);
    cv::imwrite(filename, picBGR);*/

    //cv::Mat indata(height + height / 2, width, CV_8UC1, pBufferIn);
    //cv::imwrite(filename, indata);
    //long len2 = width * height * 3;
    long len = pSource->GetSize();
    memcpy(pBufferOut, pBufferIn, len);


    pDest->SetActualDataLength(pSource->GetActualDataLength());
    pDest->SetSyncPoint(TRUE);

    return S_OK;

}

これでテレビ(地デジ)画像をフィルターしようとして
動いているGRAPHのEnhancedVideoRenderの直前にこのフィルターを入れてみま
した。
幸いtransformが呼ばれているのは見ましたが実際の画像は緑がかったものでした。
イメージ説明
これYUV関係か?と思ったのでこのフィルターの後にCOLOR space converterをいれてみましたが状況は変わりませんでした。
そこで
CheckInputType(const CMediaType* mtIn)
をデバッグしてみましたが
MEDIASUBTYPE_RGB24のチェックはセーフで
でS_OKがかえってきているのは見ました。
なのに何故この画像がでるのか仕組みが全く分かりません。
お教えいただければ幸いです。
あと私が知っているのは、CheckInputTypeにSYSTEMがNV12,YV12,IYUV,RGB555,RGB8でもアクセスしてきているのは知っていますがこれらにやはりまじめに対応すべきか?とは考えています。でもどう対応するのかは全く分かりません

追記
https://groups.google.com/forum/#!topic/microsoft.public.win32.programmer.directx.video/EltvHpBjsQY
とかまじめに読んでいるとバッファの長さがまずい?とおもった。
んでとりあえず
DecideBufferSize

AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType();
VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pType->pbFormat;
ASSERT(pvi);
int cxImage = pvi->bmiHeader.biWidth;
int cyImage = pvi->bmiHeader.biHeight;
pProperties->cbBuffer = cxImage * cyImage * 2 * 10;
を追加したらよさげなのだが
cxImage * cyImage * 2 * 10;
の根拠がわからない。
掛ける係数は正確にこれなんだろうか?

ソース(全面的に無駄コードカット)

MyTransformFilter::MyTransformFilter():CTransformFilter(NAME("My Transform Filter"), 0,CLSID_MyTransformFilter) {

}


HRESULT MyTransformFilter::CheckInputType(const CMediaType* mtIn) {
    VIDEOINFOHEADER* pVih =
        reinterpret_cast<VIDEOINFOHEADER*>(mtIn->pbFormat);

    if (*mtIn->Type() != MEDIATYPE_Video ||
        *mtIn->Subtype() != MEDIASUBTYPE_RGB32 ||
        *mtIn->FormatType() != FORMAT_VideoInfo)
    {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }
    return S_OK;
}
HRESULT MyTransformFilter::GetMediaType(int iPosition, CMediaType* pMediaType) {
    if (iPosition < 0) {
        return E_INVALIDARG;
    }
    else if (iPosition > 0) {
        return VFW_S_NO_MORE_ITEMS;
    }
    // 優先出力タイプは 入力メディアタイプと同じとする
    // ※ データフォーマットを変換するフィルタ(encoder,decoderなど) は異なるメディアタイプになる.
    *pMediaType = m_pInput->CurrentMediaType();
    return S_OK;
}
HRESULT MyTransformFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) {
    if (*mtIn->Type() != MEDIATYPE_Video ||
        *mtIn->Subtype() != MEDIASUBTYPE_RGB32 ||
        *mtIn->FormatType() != FORMAT_VideoInfo)
    {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }
    if (*mtIn != *mtOut) {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }
    return S_OK;
}
HRESULT MyTransformFilter::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* ppropInputRequest) {
    if (m_pInput != NULL && m_pInput->IsConnected() == FALSE) {
        return E_FAIL;
    }
    // バッファサイズを取得し、アロケータプロパティに設定
    ppropInputRequest->cBuffers = 1;
    ppropInputRequest->cbBuffer = this->m_pInput->CurrentMediaType().GetSampleSize();
    if (ppropInputRequest->cbBuffer == 0) {
        AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType();
        VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pType->pbFormat;
        ASSERT(pvi);
        int cxImage = pvi->bmiHeader.biWidth;
        int cyImage = pvi->bmiHeader.biHeight;
        ppropInputRequest->cbBuffer = cxImage * cyImage * 2 * 10;

    }
    ASSERT(ppropInputRequest->cbBuffer);
    ALLOCATOR_PROPERTIES actual_prop;
    HRESULT hr = pAlloc->SetProperties(ppropInputRequest, &actual_prop);
    if (FAILED(hr)) {
        return hr;
    }
    // アロケータは要求に対して正確に一致できるとは限らないため、確保されたかチェックする
    if (ppropInputRequest->cBuffers > actual_prop.cBuffers ||
        ppropInputRequest->cbBuffer > actual_prop.cbBuffer)
    {
        return E_FAIL;
    }
    return S_OK;
}
HRESULT MyTransformFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) {
    LPDWORD pSrc, pDest;
    pIn->GetPointer((BYTE * *)& pSrc);
    pOut->GetPointer((BYTE * *)& pDest);
    const long act_size = pIn->GetActualDataLength();


    memcpy(pDest, pSrc, act_size);
    pOut->SetActualDataLength(act_size);
    pOut->SetSyncPoint(TRUE);

    OutputDebugString(L"transe\n");

    /*
    LONGLONG media_start, media_end;
    pIn->GetMediaTime(&media_start, &media_end);
    pOut->SetMediaTime(&media_start, &media_end);
    REFERENCE_TIME ref_start, ref_end;
    pIn->GetTime(&ref_start, &ref_end);
    pOut->SetTime(&ref_start, &ref_end);
    pOut->SetSyncPoint(TRUE);*/
    return S_OK;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

暫定修正
ただppropInputRequest->cbBuffer = cxImage * cyImage * 2 * 10;
がOKかどうかは不明。今のところOK

MyTransformFilter::MyTransformFilter():CTransformFilter(NAME("My Transform Filter"), 0,CLSID_MyTransformFilter) {

}

HRESULT MyTransformFilter::CheckInputType(const CMediaType* mtIn) {
VIDEOINFOHEADER* pVih =
reinterpret_cast<VIDEOINFOHEADER*>(mtIn->pbFormat);

if (*mtIn->Type() != MEDIATYPE_Video ||
*mtIn->Subtype() != MEDIASUBTYPE_RGB32 ||
*mtIn->FormatType() != FORMAT_VideoInfo)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
return S_OK;
}
HRESULT MyTransformFilter::GetMediaType(int iPosition, CMediaType* pMediaType) {
if (iPosition < 0) {
return E_INVALIDARG;
}
else if (iPosition > 0) {
return VFW_S_NO_MORE_ITEMS;
}
// 優先出力タイプは 入力メディアタイプと同じとする
// ※ データフォーマットを変換するフィルタ(encoder,decoderなど) は異なるメディアタイプになる.
*pMediaType = m_pInput->CurrentMediaType();
return S_OK;
}
HRESULT MyTransformFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) {
if (*mtIn->Type() != MEDIATYPE_Video ||
*mtIn->Subtype() != MEDIASUBTYPE_RGB32 ||
*mtIn->FormatType() != FORMAT_VideoInfo)
{
return VFW_E_TYPE_NOT_ACCEPTED;
}
if (*mtIn != *mtOut) {
return VFW_E_TYPE_NOT_ACCEPTED;
}
return S_OK;
}
HRESULT MyTransformFilter::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* ppropInputRequest) {
if (m_pInput != NULL && m_pInput->IsConnected() == FALSE) {
return E_FAIL;
}
// バッファサイズを取得し、アロケータプロパティに設定
ppropInputRequest->cBuffers = 1;
ppropInputRequest->cbBuffer = this->m_pInput->CurrentMediaType().GetSampleSize();
if (ppropInputRequest->cbBuffer == 0) {
AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType();
VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pType->pbFormat;
ASSERT(pvi);
int cxImage = pvi->bmiHeader.biWidth;
int cyImage = pvi->bmiHeader.biHeight;
ppropInputRequest->cbBuffer = cxImage * cyImage * 2 * 10;

}
ASSERT(ppropInputRequest->cbBuffer);
ALLOCATOR_PROPERTIES actual_prop;
HRESULT hr = pAlloc->SetProperties(ppropInputRequest, &actual_prop);
if (FAILED(hr)) {
return hr;
}
// アロケータは要求に対して正確に一致できるとは限らないため、確保されたかチェックする
if (ppropInputRequest->cBuffers > actual_prop.cBuffers ||
ppropInputRequest->cbBuffer > actual_prop.cbBuffer)
{
return E_FAIL;
}
return S_OK;
}
HRESULT MyTransformFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) {
LPDWORD pSrc, pDest;
pIn->GetPointer((BYTE * *)& pSrc);
pOut->GetPointer((BYTE * *)& pDest);
const long act_size = pIn->GetActualDataLength();

memcpy(pDest, pSrc, act_size);
pOut->SetActualDataLength(act_size);
pOut->SetSyncPoint(TRUE);

OutputDebugString(L"transe\n");

/*
LONGLONG media_start, media_end;
pIn->GetMediaTime(&media_start, &media_end);
pOut->SetMediaTime(&media_start, &media_end);
REFERENCE_TIME ref_start, ref_end;
pIn->GetTime(&ref_start, &ref_end);
pOut->SetTime(&ref_start, &ref_end);
pOut->SetSyncPoint(TRUE);*/
return S_OK;
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る