1

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);あちこちでソーススレッドがマージスレッドに譲ることができ、問題は解決されたようです。

4

2 に答える 2

2

再生の完了には、ストリーム ソースからのストリーム終了通知の送信が内部的に含まれます。これは、ダウンストリーム フィルターによって中継され、レンダラーで収集され、結合されて、アプリケーションに報告されます。したがって、正常に完了するには、フィルタ グラフのすべての参加者が正しく機能する必要があります。

グラフのトポロジーを発見したので、異なるマシンでトポロジーを比較する必要があります。そこに違いが見られる場合は、どのフィルターが完了通知を失っている可能性があるかを示唆している可能性があります。

ただし、トポロジが正確に一致していても、一部のフィルターは他の理由で異なる動作をする可能性があります。特に、グラフに独自のカスタム フィルターを設定すると、通知が失われ、グラフが完了しない可能性が高くなります。データの処理を停止し、そこからアイドリングします (これは、チェックしたいもう 1 つのことです。CPU 消費がゼロに低下するか、何らかの処理がまだ行われているかどうか。この場合、問題をデッドロックに再認定できます)。

この問題にアプローチするために多かれ少なかれ簡単にできることは、グラフからフィルターを切り離して、どのフィルターが問題を引き起こしているかを正確に特定することです。これらのグラフを試すと、違反者が見つかる可能性があります。

File Source -> MPEG Demux -> MPEG4 Decoder -> Color Space Converter -> Null Render
File Source -> MPEG Demux -> MPEG4 Decoder -> Null Render
File Source -> MPEG Demux -> Null Render
于 2013-08-16T19:05:32.050 に答える