« 『立ち飲み やきや 中野店』で飲む! | トップページ | 『志の笛』でオフ会! »

2009年6月 5日 (金)

『Direct3D』と『DirectShow』の狭間で!

『Direct3D』でフルスクリーン表示をした時に
『DirectShow』での画像が表示されない事がある…。

ウインドウでは起きない…。

『DirectShow』のエラーも出ていない…。

何が悪いんだろう?

ちなみに現象が起きた条件。
・C++
・DirectX8
・Direct3D
・DirectShow
・フルスクリーン表示

一度画像が再生されないともう再生されないかと思ったら
そうでもない。

何かがハングとかしている訳ではなさそうだ…。

取り敢えず傾向を見るために100回ぐらい
ムービー再生のテストをしてみる…。

どうも二分の一の確立で表示されないようだ…。

これは、どういう事だろうか?

ムービーが表示される画面と表示されない画面があって
その二つの画面が高速に入れ替わっているように思える…。

そのタイミングによって表示されたり表示されなかったり…。

多分『Direct3D』が悪さをしているんだろう…。

ありあえるのは、フリップによるフロントサーフェスと
バックサーフェスの切り換えが影響していると
当たりを付けてみる。

ざっくり3D出力関連をこんな感じにコメントアウトしてみる。

#if 0
Device->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL | D3DCLEAR_ZBUFFER, 0, 1.0f, 0 )
Device->BeginScene( );
...
Device->EndScene( );
Device->Present( NULL, NULL, NULL, NULL );
#endif

問題無くムービーが再生される…。

どうやら「Clear/BeginScene/Present」のどれかが呼ばれると
フリップが起こり表示されなくなるようだ…。

ムービー再生中に『Present』を連続して呼び出すと再生される…。

無論、黒い画面が入ってパカル訳だが傾向は、得られたと思う。

結論、『Direct3D』が悪さしている!<と断定!

実際、ここまで来るのに数日間かけて結構試行錯誤…。(涙)

『DirectShow』は、ウインドウ周りでの処理で『HDC』を介して『BitBlt』
辺りでデスクトップに貼り付けているのではないだろうか?

と推測。

何らかの理由で『HDC』の出力先が切り替わっているのでは?

だったら必ず表示される方にしてムービーを再生すればOKじゃないのか?

どうやったら2つのサーフェスのどちらが表かを区別できるのだろう?

調べてみる…。

どうやら、そのような関数は、無いようだ…。

ヘルプには、「良い感じに切り換えている」とある…。

カウンターを付けてみたが単に傾向が何となく分かるだけで
間違いなくこっちと言えなさそうだ…。

もし、『DirectShow』が『HDC』経由で何処かに出力されているのなら
表示されなくても画像はあるだろう…。

と『HDC』経由で画像を引っ張り出してテクスチャーに張って
表示できるようにしたのだが…

メチャメチャ重い…。

それに表示されない時には、表示されない…。

まあ、何かミスってる可能性は、大だが…。

正直重過ぎて使い物にならないので没!

『HDC』での出力と『Direct3D』との出力で齟齬があれば
それを手掛かりに確認できるかも?

何処に出力されているのか分からないので『HDC』経由で
プット&ゲットしてみるが、同じ物が返ってくる…。

テストを行っていると不思議な現象を見付けた。

『HDC』経由で画面に出力したら即座に表示される時と
表示されない時がある。

もしかしたら、これが『HDC』と『Direct3D』の出力の齟齬!?

『HDC』でプットして『Direct3D』でゲットして異なれば正常とか…。

一条の希望の光を見えたような気がした…。

試してみた…。

『HDC』経由で画面に出力して即座に表示される時には、
『GetRenderTarget』で画像を得られない。

『HDC』経由で画面に出力しても即座に表示されない時には、
『GetRenderTarget』で画像を得られた!

これでムービーを確実に表示する方法を見付けたよ!

マジ祝杯もんス!

----------------------------------------
検証プログラムを作ろうかと思ったが…
メチャメチャ長くなるので…
チェック処理の所だけね。
説明少ないけど、足りない分は察して頂戴。
今回珍しく動作確認していなので間違いがあるかも…。(汗)
と言う訳でヒント程度に参考にして頂戴…。

処理の流れは、「WindowDC」で画像を出力し
「GetRenderTarget」で画像を取得し
比較すると言ったもの。
----------------------------------------
LPBYTE    Pixel;
----------------------------------------
void RenderTargetCopy( void )
{
    LPDIRECT3DSURFACE8    Render;
    LPDIRECT3DSURFACE8    Bitmap;
    D3DSURFACE_DESC    Desc;
    D3DLOCKED_RECT    Rect;

    Device->GetRenderTarget( &Render );
    Render->GetDesc( &Desc );
    Device->CreateImageSurface( Desc.Width, Desc.Height, D3DFMT_R8G8B8, &Bitmap );
    D3DXLoadSurfaceFromSurface( Bitmap, NULL, NULL, Render, NULL, NULL, D3DX_FILTER_NONE, 0 );
    Bitmap->LockRect( &Rect, NULL, D3DLOCK_READONLY );
    memcpy( Pixel, Rect.pBits, Desc.Height * Rect.Pitch );
    Bitmap->UnlockRect( );
    Bitmap->Release( );
    Render->Release( );
}
----------------------------------------
    // フルスクリーンならフロントサーフェスが後ろに行っていたら前に出します。
    if( FullScreenFlag )
    {
        for( i = 0 ; i < 10 ; i++ )
        {
            // 「BitmapDC」は、画面の大きさの真っ白な画像です。
            // 「WindowDC」は、ウインドウ作成時に取得しておきます。
            BitBlt( WindowDC, 0, 0, Width, Height, BitmapDC, 0, 0, SRCCOPY );

            // レンダリングターゲットの画像を取り出します。
            RenderTargetCopy( );

            // 画像情報が一致したら脱出します。
            if( ( *( LPDWORD )Pixel != 0xFFFFFFFF )
                break;

            // 「Direct3D」を使って画面をクリアします。
            // これでフロントサーフェスがフィリップされます。
            Device->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL | D3DCLEAR_ZBUFFER, 0, 1, 0 );
            Device->BeginScene( );
            Device->EndScene( );
            Device->Present( NULL, NULL, NULL, NULL );
        }
    }
    // 『DirectShow』のムービー再生処理へ
----------------------------------------

PS.

『HDC』は、バックサーフェスに関連付けられ
『DirectShow』は、フロントサーフェスに関連付けられ
それらの関連付けは、固定されているようです。

従ってバックサーフェスがレンダリングサーフェスの時、
『HDC』でのプットは、画面上に表示されません。
しかしレンダリングサーフェスから画像を得られます。

逆にフロントサーフェスがレンダリングサーフェスの時、
『HDC』でのプットは、画面上に表示されますが
レンダリングサーフェスから画像を得られません。

フィリップによってフロントサーフェスが
レンダリングサーフェスの時には、
『DirectShow』の画像が表示されなくなる
という事になるらしい…。

フィリップに関係無く『HDC』と『DirectShow』は、
画面に出力されるべきじゃない?

これって『Direct3D』の不具合だろう!

…と思うのだが…。

多分『Direct3D』を使っている奴等は、
『HDC』や『DirectShow』を使わないのかもしれない…。

…多分そうに違いない…。

|

« 『立ち飲み やきや 中野店』で飲む! | トップページ | 『志の笛』でオフ会! »

コメント

けいさん
コメント有難うございます。

ホントこいつに泣かされました…。
マイクロソフトが対策を公表すれば良いのに!
などと思いましたよ。

お役に立てれば何よりです♪

投稿: kouyou | 2009年6月18日 (木) 23時06分

おぉ。同じネタで苦しんでいる人発見。
すごいですね。この問題を解決できたなんて!
僕は解決できなかったんで、放置してましたよ。。。

投稿: けい | 2009年6月18日 (木) 22時39分

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: 『Direct3D』と『DirectShow』の狭間で!:

« 『立ち飲み やきや 中野店』で飲む! | トップページ | 『志の笛』でオフ会! »