IMediaSample
ビデオ ファイルから取得する DirectShow フィルター グラフに取り組んでいます。しばらく前に契約開発者から元の実装を受け取りましたが、このコードが私の開発マシンでは機能しているのに、他の 2 つのテスト サーバーでは機能していない理由を突き止めようとして頭を悩ませていました。
フィルター グラフが「壊れた」マシンで完了することは決してないことがわかります。私はいつも電話E_ABORT
から受け取りIMediaEvent->WaitForCompletion()
ます。ただし、「動作している」マシンでは、この呼び出しは通常S_OK
、約 2 回ループした後に戻ります。
更新: DirectShow Spyが機能していないようです。おそらくそれは、チェーンで(<-- 示唆されているように、メッセージ ポンピングによってこれが解決されます)CTransInPlaceFilter
収集するための未登録の習慣があるためでしょうか?IMediaSample
エラーはありませんが、リモート グラフに接続しようとすると、GraphEdit と GraphStudio の両方がハングします。
GraphStudioを使用して、に接続する MPEG-4 Decoder からメディア サブタイプを取得できましたCTransInPlaceFilter
。私のマシンではそうMEDIASUBTYPE_YV12
ですが、「壊れた」マシンではMEDIASUBTYPE_IYUV
. 私たちのCheckInputType
方法では、グラフに 1 つ以上の「魔法のフィルター」が挿入されていると思われるものCTransInPlaceFilter
だけを受け入れます。MEDIASUBTYPE_RGB24
更新: Roman R のおかげで、DirectShow Spyを動作させることができました。少なくとも「壊れた」マシンでは。「稼働中」のマシンでアクセス違反が発生しますが、フィルター グラフが高速で実行され、破棄されるため、接続するのが困難です。
MEDIASUBTYPE_IYUV
また、in outを処理できる色空間コンバーターがあることもわかりましMEDIASUBTYPE_RGB24
た。それをグラフに追加したところ、今は正しいはずです。
DirectShow Spyはこれをフィルター グラフとして表示します (私には完全に見えます)。
ファイル ソース -> MPEG Demux -> MPEG4 Decoder -> Color Space Converter -> CTransInPlaceFilter -> Null Render
ただし、IMediaEvent->WaitForCompletion()
呼び出しが返されることはなくS_OK
、フィルター グラフは永久に実行されます。だから今、私は何が起こっているのか困惑しています。エラー状態などをチェックする必要があるものは他にありますか?
更新:ループを変更して、グラフ内のフィルターを列挙し、その状態をクエリします。
char debugString[512];
int count = 0;
long EvCode;
mediaFilter->SetSyncSource(NULL);
hr = mediaControl->Run();
sprintf(debugString, "mediaControl->Run() %d", hr);
DebugLog(debugString);
while (!m_ThreadKill)
{
hr = mediaEvent->WaitForCompletion(200, &EvCode);
sprintf(debugString, "mediaEvent->WaitForCompletion() %d, %d", hr, count);
DebugLog(debugString);
count++;
IEnumFilters *pEnum = NULL;
IBaseFilter *pFilter;
ULONG cFetched;
graphBuilder->EnumFilters(&pEnum);
while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
{
FILTER_INFO FilterInfo;
FILTER_STATE FilterState;
char szName[256];
pFilter->GetState(200, &FilterState);
pFilter->QueryFilterInfo(&FilterInfo);
WideCharToMultiByte(CP_ACP, 0, FilterInfo.achName, -1, szName, 256, 0, 0);
sprintf(debugString, "Filter: %s, %d", szName, FilterState);
DebugLog(debugString);
SAFE_RELEASE(FilterInfo.pGraph);
SAFE_RELEASE(pFilter);
}
SAFE_RELEASE(pEnum);
if (hr == S_OK)
{
break;
}
}
sprintf(debugString, "mediaControl->Stop()");
DebugLog(debugString);
mediaControl->Stop();
それらはすべて「実行中」の状態です。では、フィルターが正しく接続されていて、すべてのフィルターが実行されている場合、「壊れた」マシンでグラフが完成しないのはなぜでしょうか?
更新: Roman R によって提案されたようCTransInPlaceFilter
に、壊れたマシンのフィルター グラフから私たちを削除し、グラフは正常に完了しました。をCTransInPlaceFilter
接続すると、CPU 使用率がゼロになります。したがって、次のコードが一部のマシンでは機能するのに、他のマシンでは機能しない理由がわかりません。CTransInPlaceFilter
何が起こっているか (または起こっていないか) を把握するために、いくつかのデバッグ ログを に追加し始めます。
解決策: Roman R が示唆したように (私は自分自身を繰り返しているように感じます:P) 問題は最終的にデッドロックになりました。壊れたマシンにはすべて単一の CPU/コアがありましたが、動作中のマシンには複数の CPU/コアがありました。アプリケーションは、ソース ビデオごとのスレッド、マージ スレッド、および宛先スレッドで構成されます。
ソース スレッドはフィルタ グラフを実行し (フィルタ グラフも独自のスレッドで実行されると仮定します)、 からデータを取得してIMediaSample
に配置しCQueue<BYTE*>
ます。
マージ スレッドはソースをループし、ソースからサンプル データを取得しCQueue<BYTE*>
、フレームを 1 つの画像にマージしてCQueue<BYTE*>
、宛先スレッドが消費する に送信します。
宛先スレッドは、ビデオ/オーディオをエンコードするために別のフィルター グラフを実行します。
CQueue<BYTE*>
空き領域ができるまで Putのブロック。マージ スレッドがアイテムを削除しているため、通常はこれで問題ありません。ただし、シングル CPU/コア マシンでは、マージ スレッドがソース スレッドによってブロックされていました。
簡単に言えば、Sleep(0);
あちこちでソーススレッドがマージスレッドに譲ることができ、問題は解決されたようです。