カスタム動画のレンダリング(iOS)

概要

このチュートリアルでは、OTPublisher オブジェクトで使用されるビデオレンダラーに軽微な変更を加える手順について解説します。同様の手法を用いて、OTSubscriber オブジェクトで使用されるビデオレンダラーを変更することも可能です(ただし、この例ではパブリッシャー用のカスタムレンダラーについてのみ説明しています)。

プロジェクトの設定

このセクションのコードは 基本的なビデオ・レンダラー のプロジェクトである。 opentok-ios-sdk-samples リポジトリもしまだなら、レポをローカル・ディレクトリにクローンする必要がある。 これはコマンドラインを使って実行できる:

git clone https://github.com/opentok/opentok-ios-sdk-samples.git

ディレクトリをBasic Video Rendererプロジェクトに変更します:

cd opentok-ios-sdk-samples/Basic-Video-Renderer

次に、OpenTokの依存関係をインストールします:

pod install

Xcodeでプロジェクトを開き、その通りに進めてください。

コードを詳しく見ていく

この例では、アプリはカスタムビデオレンダラを使用して、OTPublisherオブジェクトのビデオの白黒バージョンを表示しています。

メインのViewControllerでは、OTPublisherオブジェクトを初期化した後に videoRender プロパティは、OTKBasicVideoRenderのインスタンスに設定されます:

_publisher = [[OTPublisher alloc] initWithDelegate:self settings:settings];
_renderer = [[OTKBasicVideoRender alloc] init];
_publisher.videoRender = _renderer;

OTKBasicVideoRender は、OTVideoRender プロトコル(OpenTok iOS SDK で定義されている)を実装するカスタムクラスです。このプロトコルを使用すると、OpenTok のパブリッシャーまたはサブスクライバーが使用するカスタムビデオレンダラーを定義することができます。

について [OTKBasicVideoRender init:] メソッドは _renderView プロパティを UIView オブジェクトに追加します。これは、(パブリッシャーまたはサブスクライバーによって)レンダリングされるビューを含む UIView オブジェクトです。このサンプルでは、UIView オブジェクトは UIView を継承した OTKCustomRenderView クラスで定義されています:

- (id)init
{
    self = [super init];
    if (self) {
        _renderView = [[OTKCustomRenderView alloc] initWithFrame:CGRectZero];
    }
    return self;
}

OTKCustomRenderViewクラスには、ビデオフレームを白黒表現に変換するメソッド(後述)があります。

[OTVideoRender renderVideoFrame:] メソッドは、パブリッシャー(またはサブスクライバー)がビデオフレームをビデオレンダラーにレンダリングする際に呼び出されます。このフレームは OTVideoFrame オブジェクト(OpenTok iOS SDK で定義)です。 OTKCustomRenderView におけるこのメソッドの実装では、単にフレームを受け取り、それを [renderVideoFrame] メソッドを呼び出します:

- (void)renderVideoFrame:(OTVideoFrame*) frame
{
    [(OTKCustomRenderView*)self.renderView renderVideoFrame:frame];
}

について [OTKCustomRenderView renderVideoFrame] メソッドは、プレーン内のピクセルを繰り返し処理し、各ピクセルを白黒の値に調整し、その値をバッファに追加します。そして、バッファをビューの画像を表すCGImageRefに書き出し、次のように呼び出します。 [self setNeedsDisplay] で画像ビューをレンダリングする:

- (void)renderVideoFrame:(OTVideoFrame *)frame
{
    __block OTVideoFrame *frameToRender = frame;
    dispatch_sync(self.renderQueue, ^{
        if (_img != NULL) {
            CGImageRelease(_img);
            _img = NULL;
        }

        size_t bufferSize = frameToRender.format.imageHeight
          * frameToRender.format.imageWidth * 3;
        uint8_t *buffer = malloc(bufferSize);

        uint8_t *yplane = [frameToRender.planes pointerAtIndex:0];

        for (int i = 0; i < frameToRender.format.imageHeight; i++) {
            for (int j = 0; j < frameToRender.format.imageWidth; j++) {
                int starting = (i * frameToRender.format.imageWidth * 3) + (j * 3);
                uint8_t yvalue = yplane[(i * frameToRender.format.imageWidth) + j];
                // If in a RGB image we copy the same Y value for R, G and B
                // we will obtain a Black & White image
                buffer[starting] = yvalue;
                buffer[starting+1] = yvalue;
                buffer[starting+2] = yvalue;
            }
        }

        CGDataProviderRef imgProvider = CGDataProviderCreateWithData(NULL,
                                                                     buffer,
                                                                     bufferSize,
                                                                     release_frame);

        _img = CGImageCreate(frameToRender.format.imageWidth,
                             frameToRender.format.imageHeight,
                             8,
                             24,
                             3 * frameToRender.format.imageWidth,
                             CGColorSpaceCreateDeviceRGB(),
                             kCGBitmapByteOrder32Big | kCGImageAlphaNone,
                             imgProvider,
                             NULL,
                             false,
                             kCGRenderingIntentDefault);


        CGDataProviderRelease(imgProvider);
        dispatch_async(dispatch_get_main_queue(), ^{
            [self setNeedsDisplay];
        });
    });
}

おめでとうございます!iOS向け「カスタム動画レンダリング」チュートリアルを完了しました。
ここで作成したコードをさらに試したり調整したりすることもできますし、あるいは 次のステップ の下にある。

次のステップ

ここでの作業が終わったら、以下の役立つリソースを活用して、OpenTokアプリケーションの構築と機能強化を続けてください: