RTSP(H264/H265) to MP4の超低遅延ブラウザ再生(配信)
カメラ等で使われるRTSPストリームはブラウザとすこぶる相性が悪く、以前はFlashを使って親戚のRTMPが再生されたりしていましたが、もはや過去のお話。
最近は、分割した MPEG4 ファイルを連続再生する HLS や MPEG-DASH が主流です。しかし、すべてを数秒に分割する仕組みのため通信効率が悪くなってしまいますし、どうやっても遅延の問題が避けられません。
かと言って WebRTC はP2P用に設計されていて、ブラウザ間ビデオチャットには向いていますが、配信等の目的に使うことは難しく、そもそもUDPが使えない環境では動作もしません。
そこで超低遅延(1秒未満)のストリーミング再生(配信)システムを構築しました。
更新履歴
- 2022/09/05 WebCodecs正式版に対応。
- 2021/04/29 H.265/HEVCに対応。
- 2021/04/21 エラー内容をHTML上で表示するよう変更。
- 2021/02/22 初版。
デモ
rtsp:// で始まるURLを入力すると、RTSPをリアルタイムで変換を確認できます。残念ながら適当なフリーのRTSPソースがないため、各自ご用意ください(192.168.x.xxのアドレスで試す人が多いようですが、当然接続できません。グローバルIPを持ったRTSPサーバを指定してお試しください)。
- Chrome および Firefox が推奨です。
- 対応しているのは「H.264/avc1」か「H.265/hvc1(HEVC)」ストリームのみです。
- デモはセキュリティのため以下の制限を加えています。
- RTSPパスワード認証は使用不可に設定しています。
- RTSP接続ポートは 554 のみに制限されています。
- 再生時間は60秒に制限されています。
- 「WebSocket Server Down」と言われた場合は、変換サーバの起動忘れなので、コメント or ご連絡ください。
- デモですので、常識の範囲内でご利用ください*1。
仕組み
RTSPサーバに接続して、リアルタイムでmp4に変換しています。コンテナ(フォーマット)を変換していますが再圧縮しているわけではないので高速に動作します。ffmpegを使っても同様のことが可能ですが、ffmpegでは変換過程で数秒程度の遅延が発生します。
ffmpeg -rtsp_transport tcp -i rtsp://<ip_address>/path -c:v copy -an -movflags empty_moov+omit_tfhd_offset+frag_keyframe+default_base_moof -f mp4 pipe:1
mp4に変換されたデータを WebSocket 経由でブラウザに送信し、受け取ったデータを JavaScript で MediaSource に入力し、VIDEOタグで表示しています。
let sourceBuffer; const ms = new MediaSource(); ms.addEventListener('sourceopen', function(evt){ sourceBuffer= ms.addSourceBuffer('video/mp4; codecs=avc1.64001E'); }); const VIDEO = document.getElementById('video'); VIDEO.src = window.URL.createObjectURL(ms); const ws = new WebSocket('ws://example.com/'); ws.binaryType = "arraybuffer"; ws.onmessage = function(evt) { sourceBuffer.appendBuffer( evt.data ); }
実際はもう少し複雑ですが、フロントエンド(JavaScript)では難しいことはしていません。デモページ内のソースに、スクリプトが全部書かれていますので、興味のある方はご覧ください。
変換サーバは?
今のところ非公開です。興味のある方はメール等でご連絡ください。ライセンス等する予定です。
まとめ
- 映像が目的だったため、今のところオーディオには非対応です。
- H264の圧縮も伸張もしていないので、H264がらみの特許問題は起きないはずです。
- Windows Media ServerやReal Serverがそうだったように、将来的にはRTSPが廃れるか、ブラウザがRTSPやRTSPライクな何かをサポートして状況は変化するように思います。
参考文献
- html5_rtsp_player
- WebSocket経由でRTSPサーバにアクセスし、JavaScript側でRTSP通信をしながらmp4を再構成しています。原理的には似ていますが、サーバ/クライアントでの処理分担が異なります。サーバはNode.jsで書かれていますが、30行程度のスクリプトでサーバを自作することも可能でした。
- v4l2rtspserver
- V4L2を使用した、RTSPサーバ。H264で出力をするためには、カメラがH264エンコーダーを内蔵しているか、V4L2対応のH264ハードウェアエンコーダーが必要。
- fmp4streamer
- V4L2(H264)なソースから、ブラウザで再生可能なH264ストリームを生成するソフト。やってることは一緒。ただ作り込みが甘いのか、試した限りだとリアルタイム性がいまいち。多少書き換えれば改善するかもしれもい。
メモ
Video4Linuxとffmpegを使用して、カメラからリアルタイムH265を吐き出す方法。
ffmpeg -f video4linux2 -i /dev/video0 -s 640x360 -c libx265 -pix_fmt yuv420p -fflags nobuffer -tune zerolatency -f rawvideo
これをそのままWebSocketで送信できれば、上記デモと全く同じ仕組みで、ブラウザ上にリアルタイムカメラ画像を取得可能。