プロ生ちゃんと一緒にiPhoneから生放送!

iOS向けのライブ配信ライブラリーを書いてみた - Thousand Yearsで制作したRTMPなライブラリーGitHub - shogo4405/lf.swift: iOS用のライブ配信ライブラリーに映像効果を適用する機能をつけたので紹介します。
映像効果に利用するのは、プログラミング生放送でお馴染みのプロ生ちゃん(プロ生ちゃん(暮井 慧) | プログラミング生放送)です。プロ生ちゃんのpngとカメラ映像を合成して一緒に生放送できるようになります。
f:id:shogo4405:20160426124853p:plain

映像効果用クラスの作成

自作の映像効果を適用するためのVisualEffectクラスを継承したクラスを用意します。画像ファイルとカメラ映像を合成するための、主なポイントは以下の通り。

  1. CISourceOverCompositingのCIFilterの用意。ライブラリーの処理上CIImageになっているのでこちらのアプローチによる画像の合成を行います。
  2. カメラ画像(CIImageのextent)情報をもとにしてカメラ画像と同解像度の画像を作成する。この処理で出来た画像にプロ生ちゃん(合成したい画像)を描画しておく。
  3. プロ生ちゃんの画像をinputImage。カメラ映像をinputBackgroundImageとしてCIFilterを適用する
final class PronamaEffect: VisualEffect {
    // 1. CISourceOverCompositingなフィルターの準備
    let filter:CIFilter? = CIFilter(name: "CISourceOverCompositing")

    // 2. カメラ映像と同解像度の画像の作成
    var extent:CGRect = CGRectZero {
        didSet {
            if (extent == oldValue) {
                return
            }
            UIGraphicsBeginImageContext(extent.size)
            let image:UIImage = UIImage(named: "Icon.png")!
            image.drawAtPoint(CGPointMake(50, 50))
            pronama = CIImage(image: UIGraphicsGetImageFromCurrentImageContext(), options: nil)
            UIGraphicsEndImageContext()
        }
    }
    var pronama:CIImage?

    override init() {
        super.init()
    }
    // 3. フィルターの適用
    override func execute(image: CIImage) -> CIImage {
        guard let filter:CIFilter = filter else {
            return image
        }
        extent = image.extent
        filter.setValue(pronama!, forKey: "inputImage")
        filter.setValue(image, forKey: "inputBackgroundImage")
        return filter.outputImage!
    }
}

映像効果の適用

自作した映像効果を適用するコード

var effect:VisualEffect = VisualEffect()
var rtmpConnection:RTMPConnection = RTMPConnection()
var rtmpStream:RTMPStream = RTMPStream(rtmpConnection: rtmpConnection)
//  カメラソースの追加
rtmpStream.attachCamera(AVMixer.deviceWithPosition(.Back))

// -- エフェクトの登録
rtmpStream.registerEffect(effect)
// -- エフェクトの解除
// rtmpStream.unregisterEffect(effect)


// プレビュー映像の表示(映像効果が適用された状態で表示する)
view.addSubview(rtmpStream.view)

配信開始

// イベントハンドラの登録。接続が確立したことを確認するためにハンドラ内で行う
rtmpConnection.addEventListener(Event.RTMP_STATUS, selector:#selector(HogeController.rtmpStatusHandler(_:)), observer: self)

// サーバーへの接続
rtmpConnection.connect("rtmp://path/to/server")

func rtmpStatusHandler(notification:NSNotification) {
    let e:Event = Event.from(notification)
    if let data:ASObject = e.data as? ASObject , code:String = data["code"] as? String {
        switch code {
        case RTMPConnection.Code.ConnectSuccess.rawValue:
             // 配信開始!
             rtmpStream!.publish("streamName")
        default:
             break
        }
    }
}

ソースコード

説明のために端折って書いています。ソースコードの全部はこちらで参照できます。
lf.swift/LiveViewController.swift at master · shogo4405/lf.swift · GitHub