文鎮iPhone救出計画 〜ネットワークカメラ化〜

家で余っているiPhoneをネットワークカメラにしてみました。ネットワークカメラを買うまでも無いけどちょっとしたときに使いたい。作業をしながら鍋の煮え具合を見たいときに使えます。配信用のサーバーを用意する必要もないので便利です。

iOSの画面をキャプチャして配信することもできるので社内でのUIテストとかいいかも知れないですね。ネットワークは社内や家庭内LANでの運用を想定しています。

動作イメージ

iPhoneでの配信画面
f:id:shogo4405:20160429064330j:plain

Safari(OS X)で視聴したところ
f:id:shogo4405:20160429064159p:plain

ソースコード

アプリ自体の公開の予定はありませんが、github(https://github.com/shogo4405/lf.swift/tree/master/lf )上でソースコードを公開しています。スニペットはこちら、

// Cocoapodを使う場合のインストール
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!

pod 'lf', '~> 0.2'
// frameworkのインポート
import lf

final class LiveViewController: UIViewController {
    var httpService:HTTPService!
    var httpStream:HTTPStream!

    override func viewDidLoad() {
        super.viewDidLoad()

        httpStream = HTTPStream()
  // attachCameraの代わりにスクリーンキャプチャーして送ることができるよ
        //httpStream.attachScreen(ScreenCaptureSession())
        httpStream.syncOrientation = true
        httpStream.attachCamera(AVMixer.deviceWithPosition(.Back))

        // helloを指定するとhttp://ip.addr:8080/hello/playlist.m3u8 としてアクセスできるようになる。
        httpStream.publish("hello")

        httpService = HTTPService(domain: "", type: "_http._tcp", name: "lf", port: 8080)
        httpService.startRunning()
        httpService.addHTTPStream(httpStream)

        view.addSubview(httpStream.view)
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        httpStream.view.frame = view.frame
    }
}

技術的なお話

ネットワークカメラ化にあたっては、HLS(HTTP Live Streaming)の配信環境を自前で構築することで実現しています。

  1. NSNetServiceクラスを利用したHTTPサーバーの実装
  2. カメラ映像をH264エンコードして.tsファイルを作成する
  3. HTTPサーバー経由での.tsを配信する

HLSの仕組みを利用することでHLS対応ブラウザー(Microsoft Edge, Safari, モバイChromeなど)で映像の視聴が可能になります。

NSNetServiceクラスを利用したHTTPサーバーの実装

NSNetServiceクラスを利用します。publishWithOptionsメソッドにNSNetServiceOptions.ListenForConnections指定することでサービスとして機能します。

// ポート番号: 8080, TCPとしてリスンする
var service:NSNetService = NSNetService(domain: "", type: "_http._tcp", name: "", port: 8080)
service.delegate = self
service.publishWithOptions(NSNetServiceOptions.ListenForConnections)

NSNetServiceDelegateプロトコルのnetService(sender: NSNetService, didAcceptConnectionWithInputStream inputStream: NSInputStream, outputStream: NSOutputStream)メソッドで、inputStreamとoutputStreamというソケット通信に利用するインスタントの組み合わせが得られるので初期化していきます。

カメラ映像をH264エンコードして.tsファイルを作成する

主にこのようなことをやって.tsファイルを作成していきます。ライブラリー公開先のAVMixerクラス, AVCEncoderクラス, TSWriterクラスで分担して処理を行っています。

  1. AVCaptureSessionを利用してCMSampleBufferを取得する
  2. VTCompressionSessionを利用して生の映像をH264エンコード処理する
  3. H264データをPacketizedElementaryStream化の後TransportStreamに変換して.tsとして書き出す

HTTPサーバー経由での.tsを配信する

HTTPリクエストに併せて.tsを返すコードを書き出すことでHLSの視聴が可能になります。 HLSのRFCを参考にしました。draft-pantos-http-live-streaming-06 - HTTP Live Streaming