MyStreamer – iOS, OS X, Android, VLC (OS X, Linux, Windows) にストリーミングするシステム

NO IMAGE

1 種類のサーバを実装するだけで,iOS, OS X, Android, VLC media player (OS X, Linux, Windows) という多岐に渡るプラットフォームに向けてストリーミングを行うことができるようなサーバを製作しました.
ワンソース・マルチクライアントなストリーミングサーバです.
MyStreamer と名付けてみました.

俯瞰的には下図のようになります.

streaming

目次

MyStreamer の概要

今回製作したアプリケーションサーバ MyStreamer の概要図です.

mystreamer

サーバは,任意のビデオ入力を MPEG2-TS にトランスコードし,さらに分割してウェブサーバに配置します.
分割した MPEG2-TS を暗号化することも可能です.
サーバは,ウェブサーバに配置された MPEG2-TS の URI を記述したプレイリストを生成,更新します.
クライアントは定期的にそのプレイリストを取得し,その中に記述されている MPEG2-TS をダウンロードして再生します.
つまり,HTTP 上でストリーミングを行います.
このようなストリーミングの仕組みが IETF ドラフトとして提案されています.
iOS, OS X, Android, VLC 等が対応しています.

MyStreamer のデモ

iPad をクライアントとして,MyStreamer のデモを行なってみます.

USB カメラの映像と USB カメラ付属のマイクの音声をリアルタイムにライブストリーミング

ウェブアプリを起動し,USB カメラによるストリーミングを選択し,キャプチャ解像度,ストリーミング解像度,ビットレート,暗号化の有無を設定し,サーバに設定情報を送信します.
サーバは受け取った設定情報通りに処理を開始し,リアルタイムなトランスコーディング,セグメント化,暗号化を行い,さらに動的なプレイリスト生成を行います.
iPad では,サーバに設定情報を送信した 12 秒後にストリーミングが開始されます.
サーバ側ではリアルタイムに,FFmpeg (トランスコード),Segmenter (MPEG2-TS 分割),Encrypter (MPEG2-TS 暗号化),Playlister (プレイリスト生成) が動いています.

サーバ内の任意のビデオファイルをストリーミング

ウェブアプリを起動し,サーバ内のビデオファイルによるストリーミングを選択し,ストリーミング解像度,ビデオビットレート,オーディオビットレート,暗号化の有無を設定し,サーバに設定情報を送信します.
サーバは受け取った設定情報通りに処理を開始し,ビデオファイルをトランスコーディングしながら,セグメント化,暗号化を行い,さらに動的なプレイリスト生成を行います.
iPad では,サーバに設定情報を送信した 9 秒後にストリーミングが開始されます.
遅延を 1 桁台に収めました.
サーバ側ではリアルタイムに,FFmpeg (トランスコード),Segmenter (MPEG2-TS 分割),Encrypter (MPEG2-TS 暗号化),Playlister (プレイリスト生成) が動いています.

なお,デモ中でストリーミングしているビデオファイルは,クリエイティブコモンズ (CC BY) のものを使用しています.
(c) copyright 2008, Blender Foundation / www.bigbuckbunny.org

ストリーミングしながらウェブブラウジング

せっかくの表示情報量の多いタブレットを有効に活用しようということで,結構手間はかかりますが,ネイティブアプリ上に再生プレーヤを実装することで,再生プレーヤと WebView を一緒に並べて,ストリーミングしながらウェブブラウジングを行うこともできます.
下の画像は,iOS SDK で AVPlayerView と UIWebView を上下に配置したネイティブアプリを iPad で実行しているものです.

mystreamer_native

Adaptive Bitrate Streaming

このシステムで使用している Adaptive Bitrate Streaming についての説明を.

平たく説明すると,複数条件のビットレートのファイルを準備し,それを分割的にダウンロードすることで,どんなネットワーク環境下でもストリーミング再生を途切れにくくする,というものになります.(他にもたくさんの機能がありますが)

ストリーミング再生を途切れにくくする,ということは,つまりは,ネットワークの帯域変動に柔軟に対応するストリーミングになります.
再生クライアントの動作としては,ネットワークが安定して速度が出ているときは高いビットレートのストリームを取りに行き,ネットワークが不安定で速度があまり出ないときは低いビットレートのストリームを取りに行きます.
それにより,ネットワークが不安定な場合 (特に無線) であってもストリーミング再生が止まることなく,できる限り継続されることが期待されます.
高品位なストリーミングでありながら再生が途切れない,という要求における一つの落とし所といえます.

このような仕組みは,いくつか提案されているようです.
そして,これらの総称として,Adaptive Bitrate Streaming という名称が付けられています.
Wikipedia に,とてもわかりやすい絵で紹介されています.

Adaptive bitrate streaming
http://en.wikipedia.org/wiki/Adaptive_bitrate_streaming

HTTP Live Streaming に関する参考情報

2012-05-05 時点,プロトコル仕様のリビジョンは 10,プロトコルバージョンは 5 となっています.
HTTP Live Streaming に対応するサーバは,ウェブ上に一般的に公開されている内容のみで実装することが可能です.

プロトコル仕様
http://tools.ietf.org/html/draft-pantos-http-live-streaming

技術情報 (詳細) :
https://developer.apple.com/resources/http-streaming/

技術情報 (概要) :
https://developer.apple.com/jp/devcenter/ios/library/documentation/StreamingMediaGuide.pdf

Wikipedia : HTTP Live Streaming
http://en.wikipedia.org/wiki/HTTP_Live_Streaming

MPEG2-TS に関する仕様
ISO/IEC 13818-1
Information technology — Generic coding of moving pictures and associated audio information: Systems

メリット

一般的なポートを使用できる

HTTP でストリーミングするので特殊なポート番号を使用しません.
そのため,ファイアウォールを気にすることが少なくなります.

ストリーミングが途切れにくい (モバイルにもやさしい)

マルチスレッドで同時に複数条件のビットレートのストリームを作成した場合,サーバには高ビットレートから低ビットレートのストリームが存在します.
ネットワークに余裕がある場合は高ビットレートの高品位なストリーミングを行い,ネットワークの速度が低下した場合は低ビットレートのストリーミングに切り替わります.
そのため,モバイル (LTE/3G) のような,有線と比べて比較的不安定なネットワーク環境下でも,ストリーミング再生がなるべく途切れることなく継続されるようになります.

なお,再生するビットレートの切り替え判断はクライアント側で行われるので,サーバ側は複数条件のビットレートを置いておくだけでよいです.

クライアント側の実装がほとんど必要ない

iOS, Android の場合,HTTP Live Streaming プロトコルは,HTML5 の video タグで再生することができるため,クライアント側のアプリを実装する必要がありません.
Safari や Chrome で再生できます.
そのため,iOS Developer Program に参加する必要もありませんし,Android SDK も必要ありません.
世間一般に既に普及しているモバイルデバイスとの相性は良いといえます.

一方で,iOS SDK, Android SDK には HTTP Live Streaming 向けの API も準備されているので,HTTP Live Streaming プロトコルを再生するネイティブアプリを作製することもできます.

Linux や Windows の場合,HTML5 の video タグに対応したブラウザであっても,そもそも HTTP Live Streaming プロトコルに対応していないので,VLC media player を使用するのが良いでしょう.

その他参考情報

さすが Adobe さん

PCとモバイルの両方で妥協しないマルチデバイス映像配信の最適解:Adobe Media Server & Adobe Access DRM
http://www.slideshare.net/otachan/pcadobe-media-server-adobe-access-drm

iOSを含めた全方位ビデオ配信の最適解:Adobe Flash Media Server
http://www.slideshare.net/otachan/iosadobe-flash-media-server

MyStreamer の特徴

以下,特徴をつらつらと.

サーバ実装

MPEG2-TS (H.264/AAC-LC) へのトランスコーダとしては,FFmpeg (x264/libfaac) を使用しています.
それ以外の部分,MPEG2-TS の分割,MPEG2-TS の暗号化,プレイリストの動的生成・更新は,Java でプログラムを書いています.
Java のアプリケーションサーバとして,Jetty を使用しています.

ストリーミング機能

ライブ

USB カメラの映像とマイク音声をリアルタイムにストリーミングすることができます.
iPhone や iPad,Android を使用して,外出先で自宅の様子を確認することができ,監視カメラ的に使用できます.

高価なネットワークカメラを購入せずとも UVC 対応の USB カメラで事足りる,という利点となりますが,プログラム開発,検証の手間を考えると,どちらが良いのやらです.

シェア

任意のビデオファイルをトランスコードしながらストリーミングするので,iPhone や iPad,Android 向けに事前にエンコードしておく手間が必要ありません.
サーバにファイルを置いておくだけでよいです.
NAS にファイルを置いている場合は,ストリーミングサーバに NFS マウントしてやります.
例えば,ビデオカメラで撮影したファイルを置いておいて,遠く離れた帰省先等へとストリーミングすることも可能です.

フリーなロケーション

キャプチャデバイスが Video4Linux2,あるいは,標準出力に対応している場合,その出力を FFmpeg でリアルタイムにトランスコードしながらストリーミングすることができます.
キャプチャデバイスの出力を,いつでも,どこでもストリーミングできます.

メディアフォーマット

ファイルコンテナはプロトコル仕様に従い,MPEG2-TS です.
コーデックについてはプロトコル仕様では特に規定されていませんが,iOS, OS X, Android, VLC で再生できるように,ビデオコーデックは H.264,オーディオコーデックは AAC-LC としています.
システム的には,オーディオコーデックは HE-AAC, HE-AACv2, MP3 にも対応可能です.
また,ビデオの解像度やビデオ,オーディオのビットレート等は任意に設定することが可能です.
1920×1080 解像度を iPhone 5 や iPad 3rd で再生できることを確認しています.

メリット

HTTP Live Streaming プロトコルを使用しているので,前述の HTTP Live Streaming メリットを受けています.

その他には,iOS 標準のストリーミング方式なので、iOS では非常に再生が安定しています.
ストリーミングなのでクライアント機器のストレージを圧迫しません.(特にストレージの小さいモバイル機器)
トランスコードしながらストリーミングするため,事前に,機器ごと向けにエンコード/トランスコードしておく必要がありません.

デメリット

サーバ・クライアント型のストリーミングなので,ネットワーク圏外だと再生できません.

高ビットレートでストリーミングすると,データ通信量が非常に大きくなり,データ通信料等を気に掛ける必要があります.

H.264 トランスコードしているので,それなりのサーバスペックが必要になります.

1 人で開発しているのでバグ満載です.

制限事項

リアルタイムなトランスコード出力を分割し,その URL をプレイリストに記述してストリーミングをしている関係上,遅延を無視することができません.
ドキュメントによると 30 秒程度の遅れは発生するだろう,とのことです.
ハードウェアのスペック,プログラミングでのチューニングである程度改善できますが,MyStream では 9 秒の遅延が発生します.
つまり,プロトコル仕様上,1方向における高品位なビデオ,オーディオのストリーミングに向いており,リアルタイムな双方向通信には向いていません.
双方向コミュニケーションについては,WebSocket や WebRTC に期待しましょう.

MyStreamer では,ビットレートを 3 種類設定することができます.
CPU の処理速度,ストレージの転送速度,クライアントで再生するのに現実的なビットレート,無線速度などいろいろ考慮すると,変動させるビットレートは,自分の環境では 3 種類くらいが妥当だろうというところです.
ハードウェアの性能を上げたり,プログラムをチューニングすればもっとたくさん同時に処理できるかとは思いますが.

MyStreamer の詳細

以下,詳細情報をつらつらと.

サーバスペック

OS とソフトウェア

Ubuntu 13.04 (3.8.0-19-generic) 64bit
Oracle JDK 7u21
Jetty 9.0.2
FFmpeg 1.2 と FFmpeg 0.11.2

ハードウェア

Intel Core i7-2600K
Scythe SCMG-3100
ASUS P8H67-M EVO
Corsair CMX8GX3M2A1333C9 DIMM DDR3 Synchronous 1333 MHz 4GB x 2
Intel SSDSC2CT12 120GB
Intel Gigabit CT Desktop Adapter EXPI9301CT
Logicool HD Pro Webcam C910

再生クライアント

自宅にある再生可能な機器

iPhone 5 (iOS 6.1.3)
iPad 3rd (iOS 6.1.3)
Nexus 7 (Android 4.2.2)
MacBook Pro (Retina, 13-inch, Late 2012) (OS X 10.8.3)
Mac mini Mid 2011 (OS X 10.8.3)
自作の Linux PC 上の VLC (Ubuntu 13.04 (64bit))
自作の Windows PC 上の VLC (Windows 7 SP1 (64bit))

ストリーミングサーバがやること

1. ソースを取り込み,リアルタイムなエンコード,トランスコード

このシステムでは,取り込むソースにより,3 つの形態に分けられます.
なお,何れの場合も,エンコーダ&トランスコーダとしては FFmpeg を使用します.
その出力は,コンテナとしては MPEG2-TS であり,ビデオコーデックは H.264,オーディオコーデックは AAC-LC とします.

エンコードの際の設定としては,iOS については下記の通りのようです.
H.264 Baseline profile 3.0, Baseline profile 3.1, or Main profile 3.1
iPad のような大きな画面だと Main profile 推奨とのこと.

1-1. USB カメラの映像と音声

Video4Linux2 で USB カメラが撮影している映像をリアルタイムエンコードします.
USB カメラにマイクが内蔵されている場合,音声も含めてエンコードします.
外出先から自宅の中を確認したり,簡易的な監視カメラなどの用途に使用できます.
リアルタイムなライブストリーミングといえます.
USB カメラは UVC 対応が前提です.

理由があって,FFmpeg 0.11.2 を使用しています.

1-2. 既にあるファイル

サーバ内に既に存在しているファイル (自分で撮影したビデオなど) をトランスコードします.
FFmpeg でトランスコードできるフォーマットのファイルであることが前提です.

2013-50-05 時点で最新の FFmpeg 1.2 を使用しています.
あるいは,Git で得られる開発版でも動作します.

1-3. キャプチャデバイスで生成しているファイル

FFmpeg は,他のプログラムが標準出力として出力したものを標準入力とすることができます.
よって,その標準入力の内容をリアルタイムにトランスコードすることもできます.
リアルタイムなライブストリーミングといえます.
キャプチャデバイスから標準出力を得ることができることが前提です.

2013-50-05 時点で最新の FFmpeg 1.2 を使用しています.
あるいは,Git で得られる開発版でも動作します.

2. MPEG2-TS の分割

1 で生成された MPEG2-TS を任意の秒単位で分割します.
リアルタイムなライブストリーミングを実現させるために,リアルタイムにエンコード,トランスコードされているものをリアルタイムに分割していきます.
分割するポイントは,TS における PAT,PMT の位置と,TS パケットヘッダにおける PCR の値を参考にします.

3. MPEG2-TS の暗号化

2 で分割された MPEG2-TS を暗号化します.
HTTP Live Streaming の仕様では,MPEG2-TS を暗号化する際には AES(AES-128)/CBC/PKCS7Padding を使用するように記述されています.
しかし,Java の標準の Cipher クラスでは AES/CBC/PKCS7Padding には対応していません.
そのため,http://www.bouncycastle.org/latest_releases.html を使用しました.
暗号化の際の鍵は,HTTPS で提供するのが良いでしょう.

なお,Java の標準 Cipher クラスでは AES/CBC/PKCS5Padding には対応しており,この条件で暗号化した MPEG2-TS を iOS で再生できました.

4. プレイリストの作成

3 で生成された 「分割 MPEG2-TS」 の URI と再生時間,その他必要な情報を記述したプレイリストを生成します.
リアルタイムなライブストリーミングなので,次から次と 「分割 MPEG2-TS」 が新規に作成されます.
そのため,プレイリストの内容はストリーミング中は常に定期的に更新される必要があります.

5. その他

プレイリストの拡張子 .m3u8, MPEG2-TS の拡張子 .ts に対して,適切な MIME Type を設定します.

m3u8 - application/vnd.apple.mpegurl
ts - video/MP2T
key - application/octet-stream

5. 各クラス

クライアントでの再生方法 1 -クライアント側実装不必要-

クライアントでの再生方法については,クライアントユーザとして,実装が不必要なものと必要なものがあります.
まず,前者として,HTML5 の video タグでの再生,プロトコルに対応したプレーヤでの再生が挙げられます.

再生側のクライアントは,iOS, Android を搭載したモバイル機器,OS X を搭載した Mac,VLC をインストールした PC となります.
iOS,OS X,Android の場合,HTML5 の video タグで再生することができます.

<video src = "hoge.m3u8" controls autoplay ></video>

QuickTime,VLC の場合,プレイリストの URL を開くことで再生します.

以下,具体例です.

iOS では,

ウェブブラウザでプレイリストの URI に直接アクセスした場合,iPhone ではメディアプレーヤが起動し再生し,iPad ではウェブブラウザ内で再生されます.
ウェブブラウザで video タグを使用して再生した場合,iPhone ではメディアプレーヤが起動し再生し,iPad ではウェブブラウザ内で再生されます.
iOS SDK の AVPlayer を使用して再生することもできます.

一番手っ取り早いのは,ウェブブラウザでプレイリストの URI に直接アクセスして再生する方法です.
これだとクライアント側は何も実装する必要がありません.

iPhone 5 (iOS 6.1.2) での再生

iphone5_hls1

再生中に画面をタップすると,

iphone5_hls2

iPad 3rd (iOS 6.1.2) での再生

ipad3_hls1

再生中に画面をタップすると,

ipad3_hls2

Android では,

ウェブブラウザでプレイリストの URI に直接アクセスした場合,メディアプレーヤが起動し再生します.
ウェブブラウザで video タグを使用して再生した場合,メディアプレーヤが起動し再生します.
Android SDK の VideoView を使用して再生することもできます.

Nexus 7 (Android 4.2.2) での再生

Screenshot_2013-02-26-02-50-09

再生中に画面をタップすると,

Screenshot_2013-02-26-02-50-45

OS X では,

ウェブブラウザでプレイリストの URI に直接アクセスした場合,プレイリストがダウンロードされるので,ダウンロードしたプレイリストを QuickTime で開いて再生します.
ウェブブラウザで video タグを使用して再生した場合,ウェブブラウザ内で再生します.
QuickTime でプレイリストの URI に直接アクセスして再生することもできます.

OS X にインストールした QuickTime での再生例

mystreamer_osx_qt

VLC をインストールした OS X, Linux, Windows では,

プレイリストの URI を指定して,VLC でネットワークストリームを開きます.

Windows 7 にインストールした VLC での再生例

streaming_vlc

クライアントでの再生方法 2 -クライアント側実装必要-

クライアントでの再生方法については,クライアントユーザとして,実装が不必要なものと必要なものがあります.
次に後者として,iOS SDK,Android SDK を使用した再生が挙げられます.

iOS SDK についてはこちら.
Android SDK についてはこちら.

再生時にクライアントがやること

複数の再生方法について記述しましたが,何れの場合も,クライアントの挙動としては,下記 1 から 3 のようになります.

1. プレイリストの取得

プレイリストを取得し,その内容を解析します.

2. 「分割 MPEG2-TS」 の取得

1 で取得したプレイリスト中に記述されている 「分割 MPEG2-TS」 の URI にアクセスし,「分割 MPEG2-TS」 をダウンロードします.

3. 再生

2 で取得した 「分割 MPEG2-TS」 を再生します.

1 から 3 を繰り返し,サーバが定期的に更新するプレイリスト,及びその中に記述されている 「分割 MPEG2-TS」 を取得することで,連続的なストリーミング再生が実現されます.

1 から 3 の繰り返しはクライアント機器に最初から実装されているので,一度プレイリストを取得しさえすれば,後はクライアント機器が勝手にやってくれます.
よって,この部分についてはクライアント側として実装の必要性はありません.
クライアント側としては,初回のプレイリスト取得のトリガ (GET リクエスト) をかけてやるのみです.

クライアント側の制限

HTTP Live Streaming の再生については,iOS,Andorid,QuickTime,VLC において,各々バージョン制限があります.
詳細は未まとめ.

未整理

オープンソースなサーバ

VLC が HTTP Live Streaming サーバ機能も持っているようです.

Documentation:Streaming HowTo
http://wiki.videolan.org/Documentation:Streaming_HowTo

Documentation:Streaming HowTo/Streaming for the iPhone
http://wiki.videolan.org/Documentation:Streaming_HowTo/Streaming_for_the_iPhone

オープンソースなセグメンタ

FFmpeg が HTTP Live Streaming に対応した MPEG2-TS 分割機能とプレイリスト生成機能を持っている模様.
詳細は未調査.

Variant Playlist における CODECS の値の定義

Video type parameters
http://wiki.whatwg.org/wiki/Video_type_parameters

How to add resolution and codec metadata to iOS streams
http://www.wowza.com/forums/content.php?210-How-to-add-resolution-and-codec-metadata-to-iOS-streams

HTML5 videoのcodecsの書き方
http://amaitorte.jp/diary/?id=541

RFC 6381
The ‘Codecs’ and ‘Profiles’ Parameters for “Bucket” Media Types

Androidカテゴリの最新記事