画面をキャプチャするための様々な方法

プログラムで画面をキャプチャするためのテクニックを説明します。

前書き

いくつかの回では、我々はプログラムで画面全体の内容をキャプチャしたいです。以下は、それを行うことができる方法を説明します。一般的に、我々が持っている直接のオプションは、他の人の間で、使用しているGDIおよび/またはDirectXの検討する価値がある別のオプションはあるのWindows Media APIここでは、それらのそれぞれを考えると、彼らは私たちの目的のために使用することができる方法を見てしまいます。これらのそれぞれにおいて、我々は我々のアプリケーション定義されたメモリやビットマップにスクリーンショットを得れば、私たちは映画を生成する際にそれを使用することができ、近づきます。記事を参照してくださいHBITMAPからムービーを作成するプログラムで、ビットマップのシーケンスからムービーの作成の詳細については。

GDI道にそれをキャプチャ

パフォーマンスが問題ではなく、私たちが望むすべてのことをするときは、デスクトップの単なるスナップショットであるとき、私たちはGDIのオプションを検討することができます。それはウィンドウハンドル(持ちである-このメカニズムはデスクトップでも窓であるという単純な原理に基づいているHWND)と、デバイスコンテキスト(DC)を。私たちが撮影するデスクトップのデバイスコンテキストを取得することができれば、私達はちょうどすることができblit、当社のアプリケーションにそれらの内容は、通常の方法でデバイスコンテキストを定義しました。機能によって達成することができます-私たちはそのウィンドウハンドルを知っていれば、デスクトップのデバイスコンテキストを取得することは非常に簡単ですGetDesktopWindow()このように、必要な手順は以下のとおりです。

  1. 関数を使用して、デスクトップウィンドウハンドルを取得しGetDesktopWindow()
  2. 関数を使用して、デスクトップウィンドウのDCを取得しますGetDC()
  3. その互換性のDCに選択するために、デスクトップDCのための互換性のDCと互換性のあるビットマップを作成します。これらは、使用して行うことができるCreateCompatibleDC()CreateCompatibleBitmap()私たちのDCにビットマップを選択することで行うことができますSelectObject()
  4. あなたは、単に画面をキャプチャする準備ができているときは常にblitすべてです- -作成された互換性のDCへのデスクトップDCの内容、あなたが行われています。私たちは今、作成した互換性のあるビットマップは、キャプチャの瞬間に画面の内容が含まれています。
  5. 作業が完了したときにオブジェクトを解放することを忘れないでください。メモリは、(他のアプリケーションのための)貴重です。

ボイドCaptureScreen()
{ 
    int型nScreenWidth = GetSystemMetrics関数(SM_CXSCREEN)。
    INT nScreenHeight = GetSystemMetrics関数(SM_CYSCREEN)。
    HWND hDesktopWnd = GetDesktopWindow()。
    HDC hDesktopDC = GetDC(hDesktopWnd)。
    HDC hCaptureDC = CreateCompatibleDC(hDesktopDC)。
    HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hDesktopDC、
                            nScreenWidth、nScreenHeight)。
    SelectObject(hCaptureDC、hCaptureBitmap)。
    BitBlt(hCaptureDC、0,0、nScreenWidth、nScreenHeight、
           hDesktopDC、0,0、SRCCOPY | CAPTUREBLT)。
    SaveCapturedBitmap(hCaptureBitmap)。//プレースホルダは-あなたのコードを入れてください
                                //ここではディスクに撮影した画像を保存するために
    ReleaseDCの(hDesktopWnd、hDesktopDC)。 
    DeleteDC(hCaptureDC)。
    DeleteObjectの(hCaptureBitmap)。
}

上記のコードでは、関数は、GetSystemMetrics()で使用されるスクリーンの幅を返しSM_CXSCREEN、そしてで呼び出されたときに画面の高さを返しますSM_CYSCREENディスクとどのようにクリップボードに送信するにキャプチャビットマップを保存する方法の詳細については、付属のソースコードを参照してください。その非常に簡単。ソースコードは、実装規則的な間隔で画面の内容をキャプチャするための上記の技術を、撮像画像シーケンスのうちムービーを作成します。

そして、それを行うためのDirectXの道

DirectXのでスクリーンショットをキャプチャすることはとても簡単な作業です。DirectXは、これを行うためのきちんとした方法を提供しています。

すべてのDirectXアプリケーションは、我々は、そのアプリケーションに関連するビデオメモリの内容を保持するためのバッファ、または表面を呼んでいるものが含まれています。これは、アプリケーションのバックバッファと呼ばれています。一部のアプリケーションは、複数のバックバッファを持っているかもしれません。フロントバッファ - とすべてのアプリケーションがデフォルトでアクセスできることを別のバッファがあります。これは、フロントバッファは、デスクトップコンテンツに関連するビデオメモリを保持し、したがって本質的に画面イメージです。

私たちのDirectXアプリケーションからフロントバッファにアクセスすることにより、私たちはその瞬間に画面の内容をキャプチャすることができます。

DirectXのアプリケーションからフロントバッファにアクセスすることはとても簡単でわかりやすいです。インタフェースはIDirect3DDevice9提供GetFrontBufferData()取るメソッドIDirect3DSurface9オブジェクト・ポインタとその表面上にコピーするフロントバッファの内容を。IDirect3DSurfce9オブジェクトは、メソッドを使用して生成することができますIDirect3DDevice8::CreateOffscreenPlainSurface()スクリーンは、表面上に捕捉されたら、我々は機能を使用することができますD3DXSaveSurfaceToFile()ビットマップ形式でディスクに直接表面を保存します。したがって、次のように画面の外観をキャプチャするためのコード:

extern IDirect3DDevice9 * g_pd3dDevice。
ボイドCaptureScreen()
{ 
    IDirect3DSurface9 * pSurface。
    g_pd3dDevice-> CreateOffscreenPlainSurface(ScreenWidth、ScreenHeight、
        D3DFMT_A8R8G8B8、D3DPOOL_SCRATCH、&pSurface、NULL); 
    g_pd3dDevice-> GetFrontBufferData(0、pSurface)。
    D3DXSaveSurfaceToFile( "Desktop.bmp"、D3DXIFF_BMP、pSurface、NULL、NULL); 
    pSurface->リリース(); 
}

上記において、g_pd3dDeviceあるIDirect3DDevice9物体、及び適切に初期化されると仮定されています。このコードスニペットは、直接ディスクに撮影した画像を保存します。しかし、代わりに私たちは直接、画像のビットを操作したい場合は、ディスクへの保存の-私たちは、メソッドを使用して行うことができますIDirect3DSurface9::LockRect()本質的に撮影された画像のビットへのポインタである-これは、表面メモリへのポインタを与えます。私たちは、アプリケーション定義されたメモリにビットをコピーすることができますし、それらを操作することができます。表面内容は、当社のアプリケーション定義されたメモリにコピーする方法を次のコードスニペットのプレゼント:

extern void *型のpBits。
extern IDirect3DDevice9 * g_pd3dDevice。
IDirect3DSurface9 * pSurface。
g_pd3dDevice-> CreateOffscreenPlainSurface(ScreenWidth、ScreenHeight、
                                          D3DFMT_A8R8G8B8、D3DPOOL_SCRATCH、
                                          &pSurface、NULL); 
g_pd3dDevice-> GetFrontBufferData(0、pSurface)。
D3DLOCKED_RECT lockedRect; 
pSurface-> LockRect(&lockedRect、NULL、
                   D3DLOCK_NO_DIRTY_UPDATE | 
                   D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY))); 
以下のために(INT iが= 0; I <ScreenHeight; I ++)
{ 
    のmemcpy((BYTE *)pBits + I * ScreenWidth * BITSPERPIXEL / 8、
        (BYTE *)lockedRect.pBits + I * lockedRect.Pitch、 
        ScreenWidth * BITSPERPIXEL / 8)。
}
g_pSurface-> UnlockRect(); 
pSurface->リリース();

上記では、pBitsですvoid*我々はにコピーする前に十分なメモリが割り当てられていることを確認しますpBits以下のための典型的な値はBITSPERPIXELピクセル当たり32ビットです。しかし、それはあなたの現在のモニターの設定によって異なります。ここで注意すべき重要な点は、表面の幅は、キャプチャーされた画面イメージの幅と同じではないということです。なぜならメモリアライメントに関わる問題の表面は、それらが完全にワード境界に整列させるために各列の末尾に追加のものを追加している可能性があり、(ワード境界に整列するメモリ不整列メモリに比べて高速にアクセスされているものとします) 。lockedRect.Pitch私たちは二つの連続する行の開始点の間のバイト数を示します。つまり、次の行上の正しい位置に進めるために、我々は、事前べきでPitchないことにより、Width次を使用して、逆に表面のビットをコピーすることができます。

以下のために(INT iは= 0; I <ScreenHeight; I ++)
{ 
    のmemcpy((BYTE *)pBits +(ScreenHeight - I - 1)* 
        ScreenWidth * BITSPERPIXEL / 8、
        (BYTE *)lockedRect.pBits iはlockedRect.Pitchを* +、
        ScreenWidth * BITSPERPIXEL / 8); 
}

あなたは、トップダウンとボトムアップのビットマップの間で変換するとき、これは便利来るかもしれません。

上記の手法は、しばらくLockRect()の撮影した画像のコンテンツにアクセスするための一つの方法であるIDirect3DSurface9、我々はのために定義された別のより洗練された方法持っているIDirect3DSurface9GetDC()方法を。我々は使用することができIDirect3DSurface9::GetDC()、直接することが可能となるDirectXの像面、のためにGDI互換のデバイスコンテキストを取得する方法をblitDC定義された当社のアプリケーションに表面内容。関心のある読者は、この代替を探索することができます。

サンプルソースコードは、この記事の実装で一定の間隔で画面の内容を取得するため、ユーザー作成したビットマップにオフスクリーン無地表面の内容をコピーする技術が提供され、撮影された画像シーケンスからムービーを作成します。

しかし、画面キャプチャのためにこの技術を使用するときに注意するポイントの価値は、ドキュメントに記載された注意は次のとおりです。GetFrontBufferData()遅い操作で設計することにより、パフォーマンス・クリティカルなアプリケーションでの使用を考慮すべきではありません。したがって、GDIアプローチは、そのような場合にはDirectXのアプローチよりも好ましいです。

画面をキャプチャするためのWindows Media API

ウィンドウズメディア9.0サポートは、Windows Mediaエンコーダ9 APIを使用してキャプチャを選別します。これは、名前のコーデックが含まWindows Mediaビデオ9画面コーデック特別に画面キャプチャによって作成されたコンテンツを操作するように最適化されています。Windows MediaエンコーダAPIは、インタフェースを提供IWMEncoder2効率的に画面の内容をキャプチャするために使用することができます。

画面キャプチャ用のWindows MediaエンコーダのAPIでの作業は非常に簡単です。まず、我々はの作成を開始する必要がありますIWMEncoder2使用して、オブジェクトCoCreateInstance()の機能を。これは次のように行うことができます。

IWMEncoder2 * g_pEncoder = NULL; 
CoCreateInstance(CLSID_WMEncoder、NULL、CLSCTX_INPROC_SERVER、
        IID_IWMEncoder2、(無効**)&g_pEncoder)。

Encoderこのようにして作成されたオブジェクトは、キャプチャー画面データを操作するためのすべての操作が含まれています。しかし、適切に業務を遂行するために、エンコーダオブジェクトは、プロファイルと呼ばれるもので定義された設定に依存します。プロファイルには何もなく、エンコードの動作を制御するすべての設定を含むファイルではありません。また、キャプチャしたデータの性質に応じて、そのようなコーデックオプションなど、さまざまなカスタマイズされたオプションなどを使用して実行時にカスタムプロファイルを作成することができます。私たちのスクリーンキャプチャアプリケーションでプロファイルを使用するには、我々は、に基づいて、カスタムプロファイルの作成Windows Mediaビデオ9画面コーデックをカスタムプロファイルオブジェクトはインターフェイスでサポートされていますIWMEncProfile2私たちは、使用してカスタムプロファイルオブジェクトを作成することができますCoCreateInstance()としての機能を:

IWMEncProfile2 * g_pProfile = NULL; 
CoCreateInstance(CLSID_WMEncProfile2、NULL、CLSCTX_INPROC_SERVER、
        IID_IWMEncProfile2、(無効**)&g_pProfile)。

私たちは、プロファイル内のエンコーダのターゲットオーディエンスを指定する必要があります。各プロファイルは、インタフェースのオブジェクトである視聴者構成の多数を保持することができますIWMEncAudienceObjここでは、我々は我々のプロファイルの1つの観客オブジェクトを使用します。私たちは、この方法を使用して、当社のプロファイルの観客オブジェクトを作成IWMEncProfile::AddAudience()し、ポインタを返すことになる、IWMEncAudienceObjそのようなビデオコーデックの設定(ような構成のために使用することができるがIWMEncAudienceObj::put_VideoCodec()、)ビデオフレームサイズの設定を(IWMEncAudienceObj::put_VideoHeight()IWMEncAudienceObj::put_VideoWidth())などたとえば、私たちはビデオを設定します可能にするコーデックWindows Mediaビデオ9画面コーデックとして:

extern IWMEncAudienceObj * pAudience。
#define VIDEOCODEC MAKEFOURCC( 'M'、 'S'、 'S'、 '2')
    // MSS2コーデック画面用FOURCCある

=長いlCodecIndex -1。
g_pProfile-> GetCodecIndexFromFourCC(WMENC_VIDEO、VIDEOCODEC、
    &lCodecIndex)。//コーデックのインデックスを取得
pAudience-> put_VideoCodec(0、lCodecIndexを)。

FOURCCは、世界の各コーデックの一意の識別子の一種です。以下のためのFOURCC Windows Mediaビデオ9画面コーデックは MSS2です。IWMEncAudienceObj::put_VideoCodec()方法を使用することによって得ることができる-特定のプロファイルを認識するための入力としてプロファイルインデックスを受け付けますIWMEncProfile::GetCodecIndexFromFourCC()

私たちは、プロファイルオブジェクトの設定が完了したら、我々は方法使用して私たちのエンコーダにそのプロファイルを選択することができますIWMEncSourceGroup :: put_Profile()上で定義されたソースグループのエンコーダのオブジェクトを。ソースグループはの集まりであるソース各ソースは、各エンコーダオブジェクトは、それが入力されたデータを取得し、そこから多くのソースグループで作業することができますなどのビデオストリームまたはオーディオストリームまたはHTMLストリームであるかもしれません。私たちのスクリーンキャプチャアプリケーションのみがビデオストリームを使用するので、私たちのエンコーダオブジェクトの必要性は、その中に単一のソース、ビデオソース、と一つのソースグループを持っています。この使用するように構成する単一のビデオソースニーズスクリーン装置の方法を用いて行うことができる入力源としてIWMEncVideoSource2::SetInput(BSTR)とおり

extern IWMEncVideoSource2 * pSrcVid。
pSrcVid->はSetInput(CComBSTR( "SCREENCAP:// ScreenCapture1");

先の出力は、ビデオファイル(に保存するように構成することができるWMVムービー方法使用して)IWMEncFile::put_LocalFileName()必要とするIWMEncFileオブジェクト。このIWMEncFileオブジェクトは、メソッドを使用することによって得ることができるIWMEncoder::get_File()ように。

IWMEncFile * pOutFile = NULL; 
g_pEncoder-> GET_FILE(&pOutFile)。
pOutFile-> put_LocalFileName(CComBSTR(szOutputFileName)。

必要なすべての構成はエンコーダーオブジェクトに対して行われた後今、私たちは、この方法を使用することができIWMEncoder::Start()、画面のキャプチャを開始します。方法IWMEncoder::Stop()IWMEncoder::Pauseキャプチャを停止し、一時停止のために使用される可能性があります。

フルスクリーンキャプチャを使用してこの取引が、私たちは交互に入力された映像ソースストリームのプロパティを調整することにより、キャプチャの領域を選択することができます。このために、我々は、使用する必要があるIPropertyBagのインタフェースIWmEnVideoSource2としてのオブジェクトを:

#define WMSCRNCAP_WINDOWLEFT CComBSTR( "左")
の#define WMSCRNCAP_WINDOWTOP CComBSTR( "トップ")
の#define WMSCRNCAP_WINDOWRIGHT CComBSTR( "右")
の#define WMSCRNCAP_WINDOWBOTTOM CComBSTR( "ボトム")
の#define WMSCRNCAP_FLASHRECT CComBSTR( "FlashRect")
の#define WMSCRNCAP_ENTIRESCREEN CComBSTR( "スクリーン")
WMSCRNCAP_WINDOWTITLE CComBSTR( "WINDOWTITLE")の#define 
のextern IWMEncVideoSource2 * pSrcVid。
int型nLeft、nRight、NTOP、nBottom。
pSrcVid->のQueryInterface(IID_IPropertyBag、(無効**)&pPropertyBag)。
CComVariantをvarValueは偽=。
pPropertyBag->書き込み(WMSCRNCAP_ENTIRESCREEN、&をvarValue)。
varValue = nLeft。
pPropertyBag-> (WMSCRNCAP_WINDOWLEFT、&をvarValue)を書きます。
varValue = nRight。
pPropertyBag->書き込み(WMSCRNCAP_WINDOWRIGHT、&をvarValue)。
varValue = NTOP。
pPropertyBag->書き込み(WMSCRNCAP_WINDOWTOP、&をvarValue)。
varValue = nBottom。
pPropertyBag->書き込み(WMSCRNCAP_WINDOWBOTTOM、&をvarValue)。

同行のソースコードは、画面をキャプチャするため、この手法を実装しています。離れて生成された出力ムービーの素敵な品質から、面白いかもしれない一つのポイントは、この中には、マウスカーソルもキャプチャされていることです。(デフォルトでは、GDIとDirectXは、マウスカーソルをキャプチャすることはほとんどありません)。

お使いのシステムは、ウィンドウメディア9.0 APIを使用してアプリケーションを作成するためのWindows Media 9.0 SDKのコンポーネントと一緒にインストールする必要があることに注意してください。

アプリケーションを実行するには、エンドユーザーは、Windows Mediaエンコーダ9シリーズをインストールする必要があります。あなたはWindows MediaエンコーダSDKに基づいたアプリケーションを配布する場合、また、あなたのセットアップでWindows Mediaエンコーダを再分配することによって、またはWindows Mediaエンコーダ自分自身をインストールするには、ユーザーに要求することによってのいずれか、Windows Mediaエンコーダソフトウェアが含まれている必要があります。

Windows Mediaエンコーダ9.0は、次のサイトからダウンロードできます。

結論

画面の内容をキャプチャ - 技術の全ては様々な単一の目標を目指している上述しました。しかし、結果は、プログラムで使用される特定の技術に依存して変化する、容易に推測することができます。私たちが望むことをすべては時折ちょうどランダムなスナップショットである場合は、GDIのアプローチは、そのシンプルさを考えると、良い選択です。私たちは、より専門的な結果をしたい場合は、Windowsのメディアを使用することは、より良い選択肢だろう。注目にワンポイントの価値は、システムの設定に依存する場合がありますこれらのメカニズムによってキャプチャされたコンテンツの品質です。例えば、ハードウェアアクセラレーションを無効にする(デスクトッププロパティ|設定|詳細|トラブルシューティング)は大幅キャプチャアプリケーションの全体的な品質とパフォーマンスが向上する可能性があります

 

します。https://www.codeproject.com/Articles/5051/Various-methods-for-capturing-the-screen

 

おすすめ

転載: www.cnblogs.com/cnhk19/p/12017630.html