質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

Q&A

解決済

1回答

740閲覧

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

kokawa2003

総合スコア217

DirectX

DirectX(ダイレクトエックス)は、 マイクロソフトが開発したゲーム・マルチメディア処理用のAPIの集合です。

0グッド

0クリップ

投稿2019/05/29 07:07

編集2023/08/18 22:47

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

C++

1class MyTransformFilter : 2 public CTransformFilter 3{ 4 5public: 6 MyTransformFilter(); 7 8 // Methods required for filters derived from CTransformFilter 9 10 // Methods required for filters derived from CTransformFilter 11 HRESULT CheckInputType(const CMediaType* mtIn); 12 HRESULT GetMediaType(int iPosition, CMediaType* pMediaType); 13 HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut); 14 HRESULT DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProp); 15 HRESULT Transform(IMediaSample* pSource, IMediaSample* pDest); 16 17};

本体

C++

1MyTransformFilter::MyTransformFilter():CTransformFilter(NAME("My Transform Filter"), 0,CLSID_MyTransformFilter) { 2 3} 4 5 6HRESULT MyTransformFilter::CheckInputType(const CMediaType* mtIn) { 7 VIDEOINFOHEADER* pVih = 8 reinterpret_cast<VIDEOINFOHEADER*>(mtIn->pbFormat); 9 10 RPC_WSTR waString; 11 UuidToString(&(mtIn->subtype), &waString); 12 TRACE(L"okawa:"); 13 TRACE((WCHAR*)waString); 14 TRACE(L"\n"); 15 RpcStringFree(&waString); 16 17 if ((mtIn->majortype != MEDIATYPE_Video) || 18 (mtIn->subtype != MEDIASUBTYPE_RGB24) || 19 (mtIn->formattype != FORMAT_VideoInfo) || 20 (mtIn->cbFormat < sizeof(VIDEOINFOHEADER)) || 21 (pVih->bmiHeader.biPlanes != 1) || 22 (pVih->bmiHeader.biBitCount != 24) || 23 (pVih->bmiHeader.biCompression != BI_RGB)) 24 { 25 return VFW_E_TYPE_NOT_ACCEPTED; 26 } 27 28 return S_OK; 29} 30HRESULT MyTransformFilter::GetMediaType(int iPosition, CMediaType* pMediaType) { 31 HRESULT hr; 32 33 34 ASSERT(m_pInput->IsConnected()); 35 36 if (iPosition < 0) return E_INVALIDARG; 37 if (iPosition > 0) return VFW_S_NO_MORE_ITEMS; 38 39 if (FAILED(hr = m_pInput->ConnectionMediaType(pMediaType))) return hr; 40 41 ASSERT(pMediaType->formattype == FORMAT_VideoInfo); 42 VIDEOINFOHEADER* pVih = 43 reinterpret_cast<VIDEOINFOHEADER*>(pMediaType->pbFormat); 44 pVih->bmiHeader.biCompression = BI_RGB; 45 pVih->bmiHeader.biSizeImage = DIBSIZE(pVih->bmiHeader); 46 pVih->bmiHeader.biPlanes = 1; 47 pVih->bmiHeader.biBitCount = 24; 48 pVih->bmiHeader.biCompression = BI_RGB; 49 //pVih->bmiHeader.biWidth = pVih->bmiHeader.biWidth; 50 //pVih->bmiHeader.biHeight = pVih->bmiHeader.biHeight; 51 52 return S_OK; 53} 54HRESULT MyTransformFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) { 55 // Check the major type. 56 if ((mtOut->majortype != MEDIATYPE_Video) || 57 (mtOut->formattype != FORMAT_VideoInfo) || 58 (mtOut->cbFormat < sizeof(VIDEOINFOHEADER))) 59 { 60 return VFW_E_TYPE_NOT_ACCEPTED; 61 } 62 63 // Compare the bitmap information against the input type. 64 ASSERT(mtIn->formattype == FORMAT_VideoInfo); 65 BITMAPINFOHEADER* pBmiOut = HEADER(mtOut->pbFormat); 66 BITMAPINFOHEADER* pBmiIn = HEADER(mtIn->pbFormat); 67 if ((pBmiOut->biPlanes != 1) || 68 (pBmiOut->biBitCount != 24) || 69 (pBmiOut->biCompression != BI_RGB) || 70 (pBmiOut->biWidth != pBmiIn->biWidth) || 71 (pBmiOut->biHeight != pBmiIn->biHeight)) 72 { 73 return VFW_E_TYPE_NOT_ACCEPTED; 74 } 75 76 // Compare source and target rectangles. 77 RECT rcImg; 78 SetRect(&rcImg, 0, 0, pBmiIn->biWidth, pBmiIn->biHeight); 79 RECT* prcSrc = &((VIDEOINFOHEADER*)(mtIn->pbFormat))->rcSource; 80 RECT* prcTarget = &((VIDEOINFOHEADER*)(mtOut->pbFormat))->rcTarget; 81 if ((!IsRectEmpty(prcSrc) && !EqualRect(prcSrc, &rcImg)) || 82 (!IsRectEmpty(prcTarget) && !EqualRect(prcTarget, &rcImg))) 83 { 84 return VFW_E_INVALIDMEDIATYPE; 85 } 86 87 // Everything is good. 88 return S_OK; 89} 90HRESULT MyTransformFilter::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProp) { 91 AM_MEDIA_TYPE mt; 92 HRESULT hr = m_pOutput->ConnectionMediaType(&mt); 93 if (FAILED(hr)) 94 { 95 return hr; 96 } 97 98 ASSERT(mt.formattype == FORMAT_VideoInfo); 99 BITMAPINFOHEADER* pbmi = HEADER(mt.pbFormat); 100 pProp->cbBuffer = DIBSIZE(*pbmi) ; 101 if (pProp->cbAlign == 0) pProp->cbAlign = 1; 102 if (pProp->cBuffers == 0) pProp->cBuffers = 1; 103 104 // Release the format block. 105 FreeMediaType(mt); 106 107 // Set allocator properties. 108 ALLOCATOR_PROPERTIES Actual; 109 hr = pAlloc->SetProperties(pProp, &Actual); 110 if (FAILED(hr)) return hr; 111 112 // Even when it succeeds, check the actual result. 113 if (pProp->cbBuffer > Actual.cbBuffer) return E_FAIL; 114 115 return S_OK; 116} 117 118 119 120HRESULT MyTransformFilter::Transform(IMediaSample* pSource, IMediaSample* pDest) { 121 122 123 BYTE* pBufferIn=NULL, * pBufferOut=NULL; 124 HRESULT hr; 125 126 // Get pointers to the underlying buffers. 127 if (FAILED(hr = pSource->GetPointer(&pBufferIn))) return hr; 128 if (FAILED(hr = pDest->GetPointer(&pBufferOut))) return hr; 129 AM_MEDIA_TYPE mt; 130 hr = m_pOutput->ConnectionMediaType(&mt); 131 if (FAILED(hr)) 132 { 133 return hr; 134 } 135 136 static int cnt = 0; 137 cnt++; 138 char filename[MAX_PATH];; 139 sprintf(filename, "test%d.bmp", cnt); 140 141 BITMAPINFOHEADER* pbmi = HEADER(mt.pbFormat); 142 int width = pbmi->biWidth; 143 int height = pbmi->biHeight; 144 145 /* 146 cv::Mat picYV12 = cv::Mat(height * 3 / 2, width, CV_8UC1, pBufferIn); 147 cv::Mat picBGR; 148 cv::cvtColor(picYV12, picBGR, cv::COLOR_YUV2BGR_YV12); 149 cv::imwrite(filename, picBGR);*/ 150 151 //cv::Mat indata(height + height / 2, width, CV_8UC1, pBufferIn); 152 //cv::imwrite(filename, indata); 153 //long len2 = width * height * 3; 154 long len = pSource->GetSize(); 155 memcpy(pBufferOut, pBufferIn, len); 156 157 158 pDest->SetActualDataLength(pSource->GetActualDataLength()); 159 pDest->SetSyncPoint(TRUE); 160 161 return S_OK; 162 163}

これでテレビ(地デジ)画像をフィルターしようとして
動いている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;
の根拠がわからない。
掛ける係数は正確にこれなんだろうか?

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

cpp

1MyTransformFilter::MyTransformFilter():CTransformFilter(NAME("My Transform Filter"), 0,CLSID_MyTransformFilter) { 2 3} 4 5 6HRESULT MyTransformFilter::CheckInputType(const CMediaType* mtIn) { 7 VIDEOINFOHEADER* pVih = 8 reinterpret_cast<VIDEOINFOHEADER*>(mtIn->pbFormat); 9 10 if (*mtIn->Type() != MEDIATYPE_Video || 11 *mtIn->Subtype() != MEDIASUBTYPE_RGB32 || 12 *mtIn->FormatType() != FORMAT_VideoInfo) 13 { 14 return VFW_E_TYPE_NOT_ACCEPTED; 15 } 16 return S_OK; 17} 18HRESULT MyTransformFilter::GetMediaType(int iPosition, CMediaType* pMediaType) { 19 if (iPosition < 0) { 20 return E_INVALIDARG; 21 } 22 else if (iPosition > 0) { 23 return VFW_S_NO_MORE_ITEMS; 24 } 25 // 優先出力タイプは 入力メディアタイプと同じとする 26 // ※ データフォーマットを変換するフィルタ(encoder,decoderなど) は異なるメディアタイプになる. 27 *pMediaType = m_pInput->CurrentMediaType(); 28 return S_OK; 29} 30HRESULT MyTransformFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) { 31 if (*mtIn->Type() != MEDIATYPE_Video || 32 *mtIn->Subtype() != MEDIASUBTYPE_RGB32 || 33 *mtIn->FormatType() != FORMAT_VideoInfo) 34 { 35 return VFW_E_TYPE_NOT_ACCEPTED; 36 } 37 if (*mtIn != *mtOut) { 38 return VFW_E_TYPE_NOT_ACCEPTED; 39 } 40 return S_OK; 41} 42HRESULT MyTransformFilter::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* ppropInputRequest) { 43 if (m_pInput != NULL && m_pInput->IsConnected() == FALSE) { 44 return E_FAIL; 45 } 46 // バッファサイズを取得し、アロケータプロパティに設定 47 ppropInputRequest->cBuffers = 1; 48 ppropInputRequest->cbBuffer = this->m_pInput->CurrentMediaType().GetSampleSize(); 49 if (ppropInputRequest->cbBuffer == 0) { 50 AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType(); 51 VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pType->pbFormat; 52 ASSERT(pvi); 53 int cxImage = pvi->bmiHeader.biWidth; 54 int cyImage = pvi->bmiHeader.biHeight; 55 ppropInputRequest->cbBuffer = cxImage * cyImage * 2 * 10; 56 57 } 58 ASSERT(ppropInputRequest->cbBuffer); 59 ALLOCATOR_PROPERTIES actual_prop; 60 HRESULT hr = pAlloc->SetProperties(ppropInputRequest, &actual_prop); 61 if (FAILED(hr)) { 62 return hr; 63 } 64 // アロケータは要求に対して正確に一致できるとは限らないため、確保されたかチェックする 65 if (ppropInputRequest->cBuffers > actual_prop.cBuffers || 66 ppropInputRequest->cbBuffer > actual_prop.cbBuffer) 67 { 68 return E_FAIL; 69 } 70 return S_OK; 71} 72HRESULT MyTransformFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) { 73 LPDWORD pSrc, pDest; 74 pIn->GetPointer((BYTE * *)& pSrc); 75 pOut->GetPointer((BYTE * *)& pDest); 76 const long act_size = pIn->GetActualDataLength(); 77 78 79 memcpy(pDest, pSrc, act_size); 80 pOut->SetActualDataLength(act_size); 81 pOut->SetSyncPoint(TRUE); 82 83 OutputDebugString(L"transe\n"); 84 85 /* 86 LONGLONG media_start, media_end; 87 pIn->GetMediaTime(&media_start, &media_end); 88 pOut->SetMediaTime(&media_start, &media_end); 89 REFERENCE_TIME ref_start, ref_end; 90 pIn->GetTime(&ref_start, &ref_end); 91 pOut->SetTime(&ref_start, &ref_end); 92 pOut->SetSyncPoint(TRUE);*/ 93 return S_OK; 94}

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

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;

}

投稿2019/05/29 09:48

編集2019/05/29 09:51
kokawa2003

総合スコア217

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問