2013年11月2日土曜日

hls用のmpegts作成プログラムが進んだのでメモしておきます。

はじめにぶっちゃけて置きますが、最近はffmpegが優秀になっているので、面倒なことしなくてもよかった気がします。
まぁ、勉強になって楽しかったですが・・・

---- まずは基本 ----

hls(HttpLiveStreaming)がなにか?
 appleのiPhone等、iOSでバイスで大きめの動画を再生させる場合、もしくはライブ映像を流す場合、httpLiveStreamingという方式を使うのが推奨されてます。
 一応mp4でも再生は可能なのですがmp4の場合はファイルの先頭部にmoovという再生時の位置情報やキーフレームがどのようにはいっているか等、いろいろな情報がいっきに詰まっています。1時間の動画とかになった場合は、これが大きすぎてダウンロードがうまくいかなかったり、動作しても再生までに時間がかかったりします。
 hlsを使うとテキストでできた再生用のリストファイルと再生の実体動画がわかれているので、必要な動画データからダウンロードさせることでサクッと動作します。
 最近では、androidやWiiUにも実装されている規格となります。

利点は?
 まずhttpのやり取りだけで成立するので、たいていの環境で動作します。
 サイズの大きいデータの場合は再生まで速いです。
 ライブ映像も扱うことが可能です。
 必要に応じて転送サイズを変更することも可能です。
 iOS6以降の場合はsubtitleを挿入したりすることも可能です。
欠点は?
 mpegtsベースなので転送データサイズが増えます。
 基本動作では、ファイルが大量にできるので、管理が大変です。

どうやって使うの?
 VODの場合はVLCプレーヤーでコンバートできたはずです。
 avconvを使う場合は出力タイプをhls、出力ファイル拡張子をm3u8にすれば作成されます。
例:$ avconv -i mario.flv -acodec copy -vcodec copy -f hls output.m3u8
として実行した場合、output[n].tsが大量にできて、output.m3u8が生成されます。
(与太話:最近のプログラムは優秀ですね。以前はrtmpdump + ffmpeg + segmenterとか組み合わせてつくっていました。精度もよくなかった・・・)

---- 続いて変わった使い方 ----

ファイルが大量にできるのはヤダ
 そういう人向けに1つのmpegtsファイルの部分アクセスを実行することで動作させることも可能になっています。
0byte〜
500byte〜
1000byte〜
みたいなアクセスを実行します。
httpの206アクセスが可能なサーバーでかつ、そこそこあたらしいiOS端末の場合は動作可能になります。
詳しくは仕様をみてください。

ライブを扱いたい
 ffmpegやavconvはpipelineでデータの入力を受け付けることが可能なので
rtmpdump -> ffmpegで出力したデータにhttp経由でアクセスする
みたいなことを実施すればライブ映像を扱うことができます。

回線速度に合わせて映像のクオリティーを前後させたい
 appleの提供しているsegmentCreatorを使えば確かできるはずです。が、使ったことはありません。
仕様によると
・重ねる映像の比率が一致すること(16:9と4:3をまぜるということは不可)
・音声データは一致すること
の2点を守ればOKとのことで、実際に作成したところ動作できました。
切り替えはシームレスで、あ、急に映像が悪くなった・・・というのがわかる感じでした。

subtitleをいれたい。
 本来はCEA608でしたっけ?mpegtsのデータにclosed captionを織り込む必要があったのですが、日本語は扱えませんでした。
ところがiOS6から(僕が確認したのはiOS7からですが・・・)webVttのm3u8をつくることで任意の言語のsubtitleを挿入することが可能になった模様です。
 詳しくはappleのドキュメントをみるか、僕にコンタクトとってください。そんなに難しいものではないです。
 なお、iphone4Sでデバッグしていますが、ちょっとバグがあるみたいです。

---- 本題 ----

さて、本題ですが最近このmpegtsの動作について研究していました。
というのもffmpegやavconvで吐くmpegtsデータの音声と映像の吐き方の部分で、いくつかの要件があったためです。
1:映像と音声の吐き方に関連性がないため、分割したときに、片方のデータが欠如することがあった。
2:分割したときに先頭に必要なトラック情報がなかったため、トラック情報のデータに当たるまで再生が開始されない問題があった。
3:nullパケットや無駄に挿入された追加情報があるためそれらのデータを削除したかった。

ちなみにできてからわかったのですが、1,2に関してはavconvにhls出力を実行させると解決したデータが吐き出されることがわかっています。

で、やってみてできたデータがこちらです。
http://49.212.39.17/mario2/index.m3u8
iphoneあたりでみてみると再生できます。

やっていることはデータを受け取ってからトラック情報、映像、音声にデータを分解
音声データは一番細かいフレームデータ(0.03秒ごと程度)に分解しておく。
映像のキーフレームからキーフレームの間隔にその間に配布べき音声データを適宜挿入しつつファイルの先頭にだけ、トラック情報をいれるようにしておく。

先頭にトラック情報と必要なキーフレームが必ずくるようになっているので、どこから再生してもスパット動作するという形になります。

---- 苦労した点 ----

mpegtsのフォーマット変換に苦労しました。
・まずpcrの取り扱いの問題、単にavconvに変換させると同期処理のためかpcrの値がtimestamp値よりちょっと遅れていることがあるみたいです。これを調整するのに苦労しました。
・bufferの問題。vlcとvlc互換のライブラリをつかっている場合ですが、音声用のpesが大きいと後ろの方のデータを無視するという仕様だかバグだかわからない動作がありました。
回避策として、中間フレームでも音声データ量が大きくなった場合は、ファイルに書き出すようにしました。
pesは60kByteほどのデータを持たせることが可能なんですが、4kByte強の粒度で挿入するようにしました。
なお、ffmpegではこの問題はない模様ですが、出力データの粒度は4kByte強になっているみたいです。
・pesのデータの取り扱いの資料がなかったので、いくつかパラメーターの意味を誤解していた部分があったところ。

---- で研究してなにしたいの? ----

まずはプログラムの精度をあげたい点
・ffmpegのrtmpdumpを利用している場合もしくは、rtmpdumpからpipeしてつかっている場合は、映像配信がunpublishされた場合にプロセスごと止まってしまう点がある件。
できたら、unpublishしたら待機しておいて、publish再開したときにすぐに動作再開してもらえばいい感じの動作になる。
・flashのrtmp配信では、soundLevelによる音声欠損や中途でのコーデック切り替えやサイズ切り替えが可能だが、きちんと対応したい。音声欠損は回復するまでコンバートがとまってしまう。映像切り替えはその後ffmpegがエラー吐いて動作しなくなる。

続いてちまたにあふれるmp4のデータをmpegtsで視聴できるようにするproxy servletを書きたい。
できたら高速アクセスできるようになるはず。

変換の高速化を図りたい。
・ffmpegで変換していると変換に3秒ほどかかる形になっているが、実は型に合わせるために、待っている時間が存在しているみたいです。実際にxuggleの変換部分だけ抜き出して動作させてやると変換はそこまで時間がかからない。
よって、自力でmpegts出力ができるようになっておくと高速コンバートが実装できる可能性が高い。

あとは、単なる趣味。

0 件のコメント:

コメントを投稿