連載2 画像転送システム その2
キャプチャー処理はオフスクリーンのデバイスコンテキスト(ghOffDC)を一つ用意して、そこにデスクトップのデバイスコンテキスト(ghDC)から画像をブリットすることで行います。また、取り込んだ画像はコーデックに送る必要があるので、オフスクリーンにはDIBセクションをアタッチし、画像データへアクセスするためのアドレス(glpOff)を取得しておきます。
DIBセクションでは色数等を自由に設定できますが、コーデックが対応している色数にする必要があるので注意して下さい。AMV3コーデックの場合はRGB32かRGB24が使えます。また、デスクトップの色数も同じにしておくと、最も効率良く処理することが出来ます。と言うよりも色数が違うとGDIによる変換処理が加わりものすごく遅くなりますので、そういった使い方は意図的に出来ないようにしておいた方が良いでしょう。
最近はデスクトップの色数をRGB24にすることはマレ(若しくはできない?)なので、殆どの場合はRGB32がベストと言うことになります。
// GDI処理で使う変数 HDC ghDC = NULL; // デスクトップのデバイスコンテキスト HDC ghOffDC = NULL; // オフスクリーンのデバイスコンテキスト(ここにデスクトップ画像を取り込む) LPVOID glpOff = NULL; // オフスクリーンのアドレス HBITMAP ghOffBmp = NULL; // オフスクリーンのビットマップハンドル HBITMAP ghOffBmpOld = NULL; // ビットマップハンドルの控え(不要?) DWORD gdwSizeW = 0; // デスクトップの横サイズ DWORD gdwSizeH = 0; // デスクトップの縦サイズ // GDI処理の初期化 BOOL GDIInit( SOCKET sock ) { // デスクトップの画像サイズを取得 gdwSizeW = GetSystemMetrics( SM_CXSCREEN ); gdwSizeH = GetSystemMetrics( SM_CYSCREEN ); // デスクトップのデバイスコンテキスト取得 ghDC = GetDC( NULL ); // DIBSection作成 // ・コーデックはこのDIB(glpOff)を元に圧縮します。 BITMAPINFO bi; ZeroMemory( &bi, sizeof(bi) ); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biBitCount = 32; // RGB32なので32を設定する bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biWidth = gdwSizeW; // 画像サイズ bi.bmiHeader.biHeight = gdwSizeH; // 画像サイズ bi.bmiHeader.biSizeImage = gdwSizeW*gdwSizeH*4; // RGB32で計算、1画素あたり4バイト bi.bmiHeader.biCompression = BI_RGB; ghOffBmp = CreateDIBSection( NULL, &bi, DIB_RGB_COLORS, (void **)(&glpOff), NULL, 0); // デバイスコンテキストも取得しておく(キャプチャー処理で使います) ghOffDC = CreateCompatibleDC( ghDC ); ghOffBmpOld = (HBITMAP)SelectObject( ghOffDC, ghOffBmp ); return TRUE; } // GDI処理 BOOL GDIMain( void ) { // キャプチャー処理 BitBlt( ghOffDC, 0, 0, gdwSizeW, gdwSizeH, ghDC, 0, 0, SRCCOPY // CAPTUREBLT を加えると半透明ウインドウも一緒にキャプチャーします。 ); return TRUE; } |
基本的にキャプチャー処理はBitBlt()で行いますが、GDI処理の遅いパソコンの場合は一度で画面全体を取り込もうとするとゲームなどのfpsがガクッと落ちてしまいますので、画面を何分割かして少しずつ取り込むようにした方が好ましい場合もあります。
アマレココやファンタジーリモートの分散処理オプションがこれに相当します。原理はこちら。
- 関連記事
trackback
コメントの投稿