[MacOSX] SeeSaw改
SeeSaw
SeeSawは,QuickTimeを利用したDV経由のフレームキャプチャのソースコード.
DV経由はそのままの場合,YUV422で取得されるので,GL_YCBCR_422_APPLEの拡張を利用し,テクスチャを作成し,OpenGLで表示している.
ソースコードは,以下のサイトで入手できる.
SeeSaw
とりあえず.Cocoaで使えるようにしてみる
オリジナルのソースコードは,構造体でオブジェクト指向っぽく実装している.
Cocoaのクラスとして,まとめた方が使いやすそうだったので.クラスにまとめてみる.
以下が,メインのクラス.
以下は,NSLog APIを使うために,拡張子を.mに変更した.
コンパイルするために,Carbon,QuickTimeフレームワークを追加する.
クラス
tagVideoWindow構造体のメンバと,tagVideoWindow.cの関数をクラスにまとめた.
@interface CaptureObject : NSObject
{
// GLUT
long milliSecPerTimer;
// vdig grab data
VdigGrab* pVdg;
long milliSecPerFrame;
Fixed frameRate;
long bytesPerSecond;
ImageDescriptionHandle
vdImageDesc;
// Destination port (GWorld)
CGrafPtr dstPort;
Rect dstPortBounds;
Rect dstDisplayBounds;
void* pDstData;
long dstDataSize;
}
- (id) init;
- (void) dealloc;
- (OSErr) videoSetTimerPeriodFromVdig;
- (OSErr) videoInitOffscreenWidth:(int)width height:(int)height;
- (void) videoSetDisplayBoundsToCaptureBounds;
- (void) grabYUVFrameToThisPointor:(unsigned char*)targetAddress;
- (void) grabRGBFrameToThisPointor:(unsigned char*)targetAddress;
- (BOOL) onTimer;
- (float) milliSecPerTimer;
- (NSSize) getFrameSize;
@end
主に必要な機能をピックアップして,実装した.
カメラ絞りや色合い等を変更するダイアログを利用する場合は,vdigGrab.mのvdgRequestSettingsを編集する.
OSErr vdgRequestSettings(VdigGrab* pVdg)
{
OSErr err;
// Use the SG Dialog to allow the user to select device and compression settings
/* 2005 11/14 for delete setting dialog by sonson
if (err = RequestSGSettings( pVdg->seqGrab,
pVdg->sgchanVideo))
{
NSLog(@"RequestSGSettings err=%d?n", err);
goto endFunc;
}
*/
if (err = vdgGetSettings(pVdg))
{
NSLog(@"vdgGetSettings err=%d?n", err);
goto endFunc;
}
endFunc:
return err;
}
RequestSGSettings APIでカメラの設定ダイアログでセットする.
フレームの取得とYUV展開
CaptureObjectクラスの以下のメソッドでピクセルをメモリに取得する.
targetAddressには,保存先のポインタを入力する.
ただし,ポインタにはフレームのデータ分だけメモリを確保しておく必要がある.
今回は画像処理が目的であるため,ピクセル情報をメインメモリへ保存する必要がある.
この処理は,上のgrabRGBFrameToThisPointorメソッドにある.
QuickTime経由で取得できる1フレームごとの画像データは,YUV422で圧縮されている.
このため,QuickTime経由できる画像データは,以下の式に基づいて変換する必要がある.
Red = Y + 1.402*V Green = Y - 0.344*U - 0.714*V Blue = Y + 1.722*U
ただし,YUV形式の場合は,一般のRGB形式とは以下のように異なる.


RGBの場合,一般的に,Red-8bit,Green-8bit,Blue-8bitと,各ピクセルごとに24bitのRGBの情報が保存される.
YUVの場合は,ピクセルを2組ずつにしてピクセルの情報をセクタ毎に保存する.
このセクタには,二つのピクセルのそれぞれの明度,そして,二つのピクセル共通のY,Uの値が保存される.2ピクセルごとに32bitの情報が保存される.
このため,640x480の画像で,1行ごとに必要な情報量は,
となり,1枚の画像に必要な情報量は,
となる.まぁ,YUVに圧縮効果があることが簡単にわかる.
このため,YUVをRGBに変換する場合は,例えば,以下のように展開する必要がある.
for( i=0;i<width*height/2;i++){
u = *(pixel+i*4 )-128;
y0= *(pixel+i*4+1 );
v = *(pixel+i*4+2 )-128;
y1= *(pixel+i*4+3 );
//
red = y0 + 1.402*v;
green = y0 - 0.344 * u - 0.714*v;
blue = y0 + 1.722 * u ;
//
*(targetAddress+i*6 ) = normalizeTable[red+127];
*(targetAddress+i*6+1) = normalizeTable[green+127]
*(targetAddress+i*6+2) = normalizeTable[blue+127];
red = y1 + 1.402 * v;
green = y1 - 0.344 * u - 0.714 * v;
blue = y1 + 1.722 * u ;
//
*(targetAddress+i*6+3) = normalizeTable[red+127];
*(targetAddress+i*6+4) = normalizeTable[green+127];
*(targetAddress+i*6+5) = normalizeTable[blue+127];
}
YUVをそのまま利用する
ただし,画像処理が目的でなく,かつ単純にOpenGLのテクスチャとして表示する場合は,GL_YCBCR_422_APPLEというApple拡張が用意されているので,簡単に行うことができる.
それについては,OpenGLテクスチャを生成するときに以下のように行う.
glTexSubImage2D(pWnd->texEnum, // GLenum target, 0, // GLint level, pWnd->dstDisplayBounds.left, // GLint xoffset pWnd->dstDisplayBounds.top, // GLint yoffset pWnd->dstDisplayBounds.right-pWnd->dstDisplayBounds.left, // GLsizei width, pWnd->dstDisplayBounds.bottom-pWnd->dstDisplayBounds.top, //GLsizei height, GL_YCBCR_422_APPLE, //GL_BGR_EXT, //GL_BGRA_EXT, // GLenum format, GL_UNSIGNED_SHORT_8_8_REV_APPLE, //GL_BYTE, //GL_UNSIGNED_INT_8_8_8_8_REV, //GLenum type pData //const GLvoid *pixels );
SeeSawModify.zip