2012年5月9日水曜日

Core Video Task (5)

Core Video の役割は次の三つ.
1) Obtaing Frames Using the Display Link
2) Manipulationg Frames
3) Using Core Image Filtering With Core Video

今回は 2) Manipulationg Frames です.

これまで Display link を使ってフレームを得るまでの流れを見てきました.この後どのように料理するかは皆様方それぞれの一存で決まります.OpenGL texture として取得すれば,OpenGL の呼び出し(コール)を使って操作できます. Listing 2-7 では NSView の drawRect メソッドをオーバーライドしてそのビューに OpenGL を描画する方法を示しています.

Listing 2-7  Displaying OpenGL in a rectangle
- (void)drawRect:(NSRect)theRect
{
    [lock lock];    // 1
    NSRect      frame = [self frame];
    NSRect      bounds = [self bounds];
 
    [[self openGLContext] makeCurrentContext];// 2
    if(needsReshape)// 3
    {
        GLfloat     minX, minY, maxX, maxY;
 
        minX = NSMinX(bounds);
        minY = NSMinY(bounds);
        maxX = NSMaxX(bounds);
        maxY = NSMaxY(bounds);
 
        [self update];
 
        if(NSIsEmptyRect([self visibleRect])) // 4
        {
            glViewport(0, 0, 1, 1);
        } else {
            glViewport(0, 0,  frame.size.width ,frame.size.height);
        }
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(minX, maxX, minY, maxY, -1.0, 1.0);
 
        needsReshape = NO;
    }
 
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
 
    if(!currentFrame)// 5
        [self updateCurrentFrame];
    [self renderCurrentFrame];      // 6
    glFlush();// 7
    [lock unlock];// 8
}
では,説明をしていきます.

  1. スレッドをロックします. OpenGL はスレッドセーフではないため1スレッドです.
  2. レンダリングのために OpenGL をコンテキストにセットする.
  3. 描画領域のリサイズ時に, OpenGL コンテキストの更新を行う.
  4. ビューがビジブルなら, OpenGL コンテキストを新たなビュー領域に表す.インビジブルなら表さない.
  5. 現在のフレームが無ければ,再度フレームを取得する.これはリサイズ時に呼び出されることになる.
  6. 現在のフレームを OpenGL コンテキストに描画する. renderCurrentFrame メソッドはカスタムフレームコード(次参照)を保持します.
  7. Flush します.これでフレームは適切なタイミングでスクリーンに表示されます.
  8. スレッドをアンロックします.
renderCurrentFrame は皆様がフレームに対して行いたい処理を含められます. Listing 2-8 は簡単なサンプルで,どのように実装したらよいかを示しています.この例では, Core Image を使って OpenGL のコンテキストに描いています.
Listing 2-8  Drawing a frame
- (void)renderCurrentFrame
{
    NSRect      frame = [self frame];
 
    if(currentFrame)
    {
        CGRect      imageRect;
        CIImage     *inputImage;
 
        inputImage = [CIImage imageWithCVImageBuffer:currentFrame];// 1
 
        imageRect = [inputImage extent];// 2
        [ciContext drawImage:inputImage // 3
                atPoint:CGPointMake(
                (int)((frame.size.width - imageRect.size.width) * 0.5),
                (int)((frame.size.height - imageRect.size.height) * 0.5))
                fromRect:imageRect];
 
    }
    QTVisualContextTask(qtVisualContext);// 4
}
このコードは,以下のような手順です.

  1. 現在のフレームから Core Image 画像を作成します. Core Image のメソッド ImageWithCVImageBuffer はどんなイメージバッファタイプ(ピクセルバッファ, OpenGL バッファ, OpenGL コンテキスト)からも Core Image 画像を作り出します.
  2. その画像の境界矩形を取得します.
  3. Core Image コンテキストにその画像を描画します.drawImage:atPoint:fromRect メソッドは特定の場所の特定の visual コンテキストにそのフレームを描きます.
    描く前に, OpenGL コンテキストと同じ領域を参照する Core Image コンテキストを作成する必要があります.そうすることで Core Image API でその領域に描け,そして OpenGL を使ってそれを表示できます.例えば, Listing 2-3 の OpenGL コンテキスト作成後に次のコードを追加します.
    /* Create CGColorSpaceRef */
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
     
    /* Create CIContext */
    ciContext = [[CIContext contextWithCGLContext:
                    (CGLContextObj)[[self openGLContext] CGLContextObj]
                    pixelFormat:(CGLPixelFormatObj)
                    [[self pixelFormat] CGLPixelFormatObj]
                    options:[NSDictionary dictionaryWithObjectsAndKeys:
                    (id)colorSpace,kCIContextOutputColorSpace,
                    (id)colorSpace,kCIContextWorkingColorSpace,nil]] retain];
    CGColorSpaceRelease(colorSpace);
    Core Image に関しては, Core Image Programming Guide をご覧下さい.
  4. うまく行くように時間を与えます.描画メソッドを通すたびに, QTVisualContextTask を呼ばなければならないようです.

少々長かったですが, Core Video で取得した画像に対して, Core Image を効果的に用いられる術が分かりました.次回は, Core Image のフィルタを使った表現になります.



0 件のコメント:

コメントを投稿