2012-04-23 3 views
1

実際には技術の野生のミックスですが、私の質問に対する答えはDirect3D 9.私は任意のD3D9アプリケーションに接続しています。ほとんどの場合、それはゲームであり、EndScene関数の動作を擬似的にするための独自のコードを注入します。バックバッファは、プッシュソースDirectShowフィルタのビットマップを指すように設定されたサーフェスにコピーされます。フィルタは25fpsでビットマップをサンプリングし、ビデオを.aviファイルにストリームします。ゲームのキャプチャを停止するはずのホットキーの組み合わせについてユーザーに知らせるテキストオーバーレイがゲームの画面全体に表示されますが、このオーバーレイは記録されたビデオには表示されません。 1つの迷惑な事実を除いて、すべてが素早く美しく動作します。ランダムな機会に、テキストオーバーリーのフレームが記録されたビデオの中に入り込みます。これは実際に望まれる人為的なものではなく、エンドユーザは自分のゲームプレイをビデオで見るだけで何もしたくない。私は誰もがなぜこれが起こっているのアイデアを共有することができます聞くことを望むだろう。ここでEndSceneフックのソースコードは次のとおりです。誰もが興味を持っている場合ゲームプレイビデオをキャプチャするIDirect3DDevice9 :: EndSceneメソッドをフックする:記録されたビデオのテキストオーバーレイを取り除くことはできません

using System; 
using SlimDX; 
using SlimDX.Direct3D9; 
using System.Diagnostics; 
using DirectShowLib; 
using System.Runtime.InteropServices; 

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
[System.Security.SuppressUnmanagedCodeSecurity] 
[Guid("EA2829B9-F644-4341-B3CF-82FF92FD7C20")] 

public interface IScene 
{ 
    unsafe int PassMemoryPtr(void* ptr, bool noheaders); 
    int SetBITMAPINFO([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]byte[] ptr, bool noheaders); 
} 

public class Class1 
{ 
    object _lockRenderTarget = new object(); 
    public string StatusMess { get; set; } 
    Surface _renderTarget; 
    //points to image bytes 
    unsafe void* bytesptr; 
    //used to store headers AND image bytes 
    byte[] bytes; 
    IFilterGraph2 ifg2; 
    ICaptureGraphBuilder2 icgb2; 
    IBaseFilter push; 
    IBaseFilter compressor; 
    IScene scene; 
    IBaseFilter mux; 
    IFileSinkFilter sink; 
    IMediaControl media; 
    bool NeedRunGraphInit = true; 
    bool NeedRunGraphClean = true; 
    DataStream s; 
    DataRectangle dr; 

    unsafe int EndSceneHook(IntPtr devicePtr) 
    { 
     int hr; 

     using (Device device = Device.FromPointer(devicePtr)) 
      { 
      try 
      { 
       lock (_lockRenderTarget) 
       { 

        bool TimeToGrabFrame = false; 

        //.... 
        //logic based on elapsed milliseconds deciding if it is time to grab another frame 

        if (TimeToGrabFrame) 
        { 

         //First ensure we have a Surface to render target data into 
         //called only once 
         if (_renderTarget == null) 
         { 

          //Create offscreen surface to use as copy of render target data 
          using (SwapChain sc = device.GetSwapChain(0)) 
          { 

           //Att: created in system memory, not in video memory 
           _renderTarget = Surface.CreateOffscreenPlain(device, sc.PresentParameters.BackBufferWidth, sc.PresentParameters.BackBufferHeight, sc.PresentParameters.BackBufferFormat, Pool.SystemMemory); 

          } //end using 
         } // end if 

         using (Surface backBuffer = device.GetBackBuffer(0, 0)) 
         { 
          //The following line is where main action takes place: 
          //Direct3D 9 back buffer gets copied to Surface _renderTarget, 
          //which has been connected by references to DirectShow's 
          //bitmap capture filter 
          //Inside the filter (code not shown in this listing) the bitmap is periodically 
          //scanned to create a streaming video. 
          device.GetRenderTargetData(backBuffer, _renderTarget); 

          if (NeedRunGraphInit) //ran only once 
          { 
           ifg2 = (IFilterGraph2)new FilterGraph(); 
           icgb2 = (ICaptureGraphBuilder2)new CaptureGraphBuilder2(); 
           icgb2.SetFiltergraph(ifg2); 
           push = (IBaseFilter) new PushSourceFilter(); 
           scene = (IScene)push; 

           //this way we get bitmapfile and bitmapinfo headers 
           //ToStream is slow, but run it only once to get the headers 
           s = Surface.ToStream(_renderTarget, ImageFileFormat.Bmp); 
           bytes = new byte[s.Length]; 

           s.Read(bytes, 0, (int)s.Length); 
           hr = scene.SetBITMAPINFO(bytes, false); 

           //we just supplied the header to the PushSource 
           //filter. Let's pass reference to 
           //just image bytes from LockRectangle 

           dr = _renderTarget.LockRectangle(LockFlags.None); 
           s = dr.Data; 
           Result r = _renderTarget.UnlockRectangle(); 
           bytesptr = s.DataPointer.ToPointer(); 
           hr = scene.PassMemoryPtr(bytesptr, true); 

           //continue building graph 
           ifg2.AddFilter(push, "MyPushSource"); 

           icgb2.SetOutputFileName(MediaSubType.Avi, "C:\foo.avi", out mux, out sink); 

           icgb2.RenderStream(null, null, push, null, mux); 

           media = (IMediaControl)ifg2; 

           media.Run(); 

           NeedRunGraphInit = false; 
           NeedRunGraphClean = true; 

           StatusMess = "now capturing, press shift-F11 to stop"; 

          } //end if 

         } // end using backbuffer 
        } // end if Time to grab frame 

       } //end lock 
      } // end try 

      //It is usually thrown when the user makes game window inactive 
      //or it is thrown deliberately when time is up, or the user pressed F11 and 
      //it resulted in stopping a capture. 
      //If it is thrown for another reason, it is still a good 
      //idea to stop recording and free the graph 
      catch (Exception ex) 
      { 
       //.. 
       //stop the DirectShow graph and cleanup 

      } // end catch 

      //draw overlay 
      using (SlimDX.Direct3D9.Font font = new SlimDX.Direct3D9.Font(device, new System.Drawing.Font("Times New Roman", 26.0f, FontStyle.Bold))) 
      { 
       font.DrawString(null, StatusMess, 20, 100, System.Drawing.Color.FromArgb(255, 255, 255, 255)); 
      } 

      return device.EndScene().Code; 

     } // end using device 

    } //end EndSceneHook 

答えて

0

それは時々起こるように、私は最終的に、この質問に対する答えを自分自身を発見しました。一部のDirect3D9アプリケーションでは、フックされたEndSceneが呼び出されるたびに必ずしもリフレッシュされるわけではありません。そのため、前のEndSceneフック呼び出しからのテキストオーバーレイを持つバックバッファが、入力フレームを収集するDirectShowソースフィルタに渡されることがありました。私は、フレームをDirectShowフィルターに渡す前に、既知のRGB値を持つ小さな3ピクセルのオーバーレイを各フレームにスタンプし、このダミーオーバーレイがまだ存在していたかどうかをチェックし始めました。オーバーレイがあった場合は、現在のフレームの代わりに以前にキャッシュされたフレームが渡されました。このアプローチは、DirectShowグラフに記録されたビデオからテキストオーバーレイを効果的に削除しました。

関連する問題