ビデオ表示
ディスプレイ上にビデオデータを表示させる。
画像表示、ビデオプレーヤ、インターネットストリーミング。
オペレーテイングシステムに依存し、専用の API 群が用意されている。
Windows | |
Win32 | Win32 API |
DirectDraw | DirectX ファミリ |
Linux | |
X11 | X11 API |
ほか |
以下は、一定周期毎にファイルからRGBデータを読出し、ディスプレイ表示させるプログラムである。一連の手順として、
表示デバイスの初期化 | |
タイムイベントとRGBデータのディスプレイ表示 | |
表示デバイスの終了処理 |
を基本とする。
Windows DirectDraw 版: DirectDraw 関数群の使用、リンクオプションに ddraw.lib を加える。
DirectDraw プログラムはC++で記述されるため、その他の部分をCで記述する場合は、CとC++を共存させるルールに従わなければならない。defs.h に書かれた #ifdef __cplusplus ... #endif の記述がこれに相当する。
drawDD() 関数に出てくるサーフェスのロック、アンロックとは、ロック期間中は他のプログラムからの書きこみを許さないと言う意味で、マルチスレッドの排他制御に相当する。なお、サーフェスとは、ビデオカードのビデオメモリに相当する。ddrawDD() 関数の最後の Blt() 関数が表示を実行する。
また、下記のプログラムでは、Win32 のSetTimer()、WM_TIMER の組合せによるタイムイベントを使っている。100ms毎にファイルからRGBデータを読みこみ、drawDD() 関数を呼び出して表示を行っている。
なお、下記のプログラムは24ビットフルカラー、および前回のビデオキャプチャで作成したRGBデータの形式しか正しく表示しないので注意すること。
main.c (GUIプログラム 参照)
#include <stdio.h> #include <windows.h> #include "defs.h" /************************************************************/ // 各種宣言 /************************************************************/ // RGB データ格納用バッファ unsigned char *pRed; unsigned char *pGreen; unsigned char *pBlue; // ファイルと制御フラグ FILE* fp; char* pFileName = "sample.rgb"; BOOL bWrite = FALSE; // 画像のサイズ (キャプチャ時の設定に合わせる) int nWidth = 176; int nHeight = 144; /************************************************************/ // ウィンドウプログラム /************************************************************/ // ------------------------------------------- // イベント処理 // ------------------------------------------- LRESULT APIENTRY WndProc (HWND hWnd, UINT msg, UINT wParam, LONG lParam) { BOOL ret; // イベントに応じて処理を実行 switch (msg) { case WM_CREATE: // メモリ領域の確保 pRed = (unsigned char *) malloc(nWidth * nHeight); pGreen = (unsigned char *) malloc(nWidth * nHeight); pBlue = (unsigned char *) malloc(nWidth * nHeight); if(pRed == NULL || pGreen == NULL || pBlue == NULL) { MessageBox(hWnd, "メモリの確保に失敗しました", "エラー", MB_OK); PostMessage(hWnd, WM_CLOSE, 0, 0); return 0; } // 開始 initDD(hWnd, nWidth, nHeight); fp = fopen(pFileName, "rb"); if(fp == NULL) { MessageBox(hWnd, "ファイルのオープンに失敗しました", "エラー", MB_OK); PostMessage(hWnd, WM_CLOSE, 0, 0); return 0; } SetTimer(hWnd, 1, 100, NULL); bWrite = TRUE; return 0; case WM_CLOSE: // 終了 bWrite = FALSE; fclose(fp); closeDD(); // メモリ領域の解放 free(pRed); free(pGreen); free(pBlue); DestroyWindow(hWnd); return 0; case WM_DESTROY: PostQuitMessage (0); break; case WM_TIMER: if(bWrite == TRUE) { if(feof(fp)) fseek(fp, 0, SEEK_SET); fread(pRed, 1, nWidth*nHeight, fp); fread(pGreen, 1, nWidth*nHeight, fp); fread(pBlue, 1, nWidth*nHeight, fp); drawDD(hWnd, nWidth, nHeight, pRed, pGreen, pBlue); } break; } return DefWindowProc (hWnd, msg, wParam, lParam); } // ------------------------------------------- // メイン制御部 // ------------------------------------------- int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hDummy, LPSTR lpStr, int nShowCmd) { WNDCLASS wc; MSG msg; HWND hWnd; // ウィンドウクラスの定義 wc.lpfnWndProc = WndProc; wc.hInstance = hInst; wc.hIcon = LoadIcon (NULL, IDI_APPLICATION); wc.hCursor = LoadCursor (NULL, IDC_ARROW); wc.lpszClassName = "Player"; wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.style = 0; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.lpszMenuName = 0; RegisterClass (&wc); // メインウィンドウの生成 hWnd = CreateWindow( wc.lpszClassName, "Video Player Sample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, nWidth, nHeight, 0, 0, hInst, 0 ); if (hWnd == NULL) ExitThread (1); ShowWindow (hWnd, SW_SHOWNOACTIVATE); UpdateWindow (hWnd); // 無限ループ (イベントが発生するたびに WndProc を呼び出す) while (GetMessage (&(msg), NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage (&msg); } return msg.wParam; } |
ddraw.cpp
#include <windows.h> #include <ddraw.h> #include "defs.h" // DirectDraw LPDIRECTDRAW lpDDraw; LPDIRECTDRAWCLIPPER lpClipper; LPDIRECTDRAWSURFACE lpPrimary; LPDIRECTDRAWSURFACE lpMain; //------------------------------------------- // 初期化 //------------------------------------------- BOOL initDD(HWND hWnd, int width, int height) { HRESULT ddreturn; DDSURFACEDESC ddsd; // DirectDraw オブジェクトの生成 ddreturn = DirectDrawCreate( NULL, &lpDDraw, NULL ); if ( ddreturn != DD_OK ) { MessageBox(hWnd, "DirectDrawオブジェクトの生成に失敗しました", "エラー", MB_OK); return FALSE; } // DirectDraw 協調レベルの設定 lpDDraw->SetCooperativeLevel( hWnd, DDSCL_NORMAL ); // DirectDraw クリッパーの生成 lpDDraw->CreateClipper(0, &lpClipper, NULL); lpClipper->SetHWnd(0, hWnd); // DirectDraw サーフェスの生成 (Primary) ddsd.dwSize = sizeof( ddsd ); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; lpDDraw->CreateSurface( &ddsd, &lpPrimary, NULL ); // クリッパ設定 lpPrimary->SetClipper(lpClipper); // DirectDraw サーフェスの生成 (Main) ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwHeight = height; ddsd.dwWidth = width; lpDDraw->CreateSurface ( &ddsd, &lpMain, NULL ); // ビデオカードのフォーマットの取得、設定 DDPIXELFORMAT pixelFmt; memset (&pixelFmt, 0, sizeof(pixelFmt)); pixelFmt.dwSize = sizeof(pixelFmt); lpPrimary->GetPixelFormat (&pixelFmt); if (pixelFmt.dwFlags & DDPF_RGB) { if (pixelFmt.dwRGBBitCount == 24) { if ((pixelFmt.dwRBitMask == 0xff0000) && (pixelFmt.dwGBitMask == 0x00ff00) && (pixelFmt.dwBBitMask == 0x0000ff)) { // OK: 24bitフルカラーモード } else { MessageBox(hWnd, "24bitフルカラーにしてください", "エラー", MB_OK); return FALSE; } } else { MessageBox(hWnd, "24bitフルカラーにしてください", "エラー", MB_OK); return FALSE; } } else { MessageBox(hWnd, "24bitフルカラーにしてください", "エラー", MB_OK); return FALSE; } return TRUE; } //------------------------------------------- // 終了処理 //------------------------------------------- BOOL closeDD() { HRESULT ddreturn; // DirectDraw オブジェクト開放 if ( lpMain != NULL ) { ddreturn = lpMain->Release(); lpMain = NULL; } if ( lpPrimary != NULL ) { ddreturn = lpPrimary->Release(); lpPrimary = NULL; } lpDDraw = NULL; return TRUE; } //------------------------------------------- // DirectDraw 表示 //------------------------------------------- BOOL restoreDD( void ) { lpPrimary->Restore(); lpMain->Restore(); return TRUE; } BOOL drawDD(HWND hWnd, int width, int height, unsigned char *red, unsigned char *green, unsigned char *blue) { HRESULT ddreturn; DDSURFACEDESC ddsd; RECT rect; RECT writeRect; POINT pt; int i, j; unsigned char r0, r1, r2, r3; unsigned char g0, g1, g2, g3; unsigned char b0, b1, b2, b3; unsigned char *pr, *pg, *pb; unsigned char *ds; unsigned int *ids; // サーフェスパラメータの設定 memset( &ddsd, 0, sizeof(ddsd) ); ddsd.dwSize = sizeof( ddsd ); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.dwWidth = width; ddsd.dwHeight = height; // サーフェスのロック lpMain->Lock(NULL, &ddsd, 0, NULL); // サーフェスへのRGBデータの書きこみ pr = red; pg = green; pb = blue; ds = (unsigned char*) ddsd.lpSurface; for (j=0; j<height; j++) { ids = (unsigned int *) ds; for (i=0; i<width; i+=4) { r0 = *(pr++); r1 = *(pr++); r2 = *(pr++); r3 = *(pr++); g0 = *(pg++); g1 = *(pg++); g2 = *(pg++); g3 = *(pg++); b0 = *(pb++); b1 = *(pb++); b2 = *(pb++); b3 = *(pb++); *(ids++) = b0 | (g0 << 8) | (r0 << 16) | (b1 << 24); *(ids++) = g1 | (r1 << 8) | (b2 << 16) | (g2 << 24); *(ids++) = r2 | (b3 << 8) | (g3 << 16) | (r3 << 24); } ds += ddsd.lPitch; } // サーフェスのアンロック lpMain->Unlock(NULL); // 書き出し位置の調整と表示 SetWindowPos(hWnd, NULL, 0, 0, width + 6, height + 25, SWP_NOZORDER | SWP_NOMOVE); GetClientRect(hWnd, &rect ); pt.x = pt.y = 0; ClientToScreen(hWnd, &pt ); SetRect (&writeRect, pt.x, pt.y, width + pt.x, height + pt.y); SetRect (&rect, 0, 0, width, height); ddreturn = lpPrimary->Blt(&writeRect, lpMain, &rect, DDBLT_ASYNC, NULL); if ( ddreturn == DDERR_SURFACELOST ) restoreDD(); return TRUE; } |
defs.h: CプログラムとC++プログラムの共存のために使用
#ifdef __cplusplus extern "C" { #endif // DirectDraw 関数 BOOL initDD(HWND hWnd, int width, int height); BOOL drawDD(HWND hWnd, int width, int height, unsigned char *r, unsigned char *g, unsigned char *b); BOOL closeDD(); #ifdef __cplusplus } #endif |
Windows Win32 版: 準備中
Linux X11 版: 準備中