2012年6月26日火曜日

flvにいれることが可能なmp3フォーマット

flashのflvにはsound formatの定義としてmp3を取り込むことができるようになっています。

http://osflash.org/flv
こちらのFLV Tag 0x08: AUDIOの部分には2がmp3を示してsoundRateとしては5.5kHz 11kHz 22kHz 44kHzの4段階がつかえると書いてあります。

ん?

mp3のサンプリングレートって、この4つ以外にもあったような・・・
というわけで、MP3Formatのデータも紐解いてみますと

http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
Fの項目にサンプリングレートのインデックス定義があります。
44.1kHz以外にも、48kHzとか32kHzとか

こういう場合はどうなるんだろう?ということで、ffmpegでflv出力をやってみました。

44.1kHzならコンバート可能。
それ以外の場合はCould not write header for output file とでました。
扱うことができないというわけですね。

1つ勉強になりました。

mp3をflashに読み込んでflvに直しつつnetStream.appendBytesで再生してみようかと思っていましたが、仮につくってもmp3の状態によっては、flv化できないということですか・・・
ちょっと残念。

ちなみにflashそのものでは、扱うこと事態は可能みたいですね。
http://sothis.blog.so-net.ne.jp/2006-06-18-1
こちらのブログにあがっているflashプレーヤーに48kHzのmp3をあてがってみたらきちんと動作しました。

ほぅ・・・って感じですね。

しっかし、今日はことごとくやろうと思ったことができない日だな。

2012年6月25日月曜日

wonderflで別でつくったswfの内部クラスを呼び出せないかやってみた。

wonderflはjsdo.itに似てますが別でつくったコードを読み込むといった処理はできません。
(いやあるのかもしれませんけど。)
でもswfファイルって別につくったswfが同じdomain内にあるか、crossdomainで解決しておけば読み込んで内部のクラスを使うことができたはず・・・というわけでやってみました。

読み込み対象のクラスはこちら。
http://wonderfl.net/c/diwZ

読み込む側のクラスはこちら。
http://wonderfl.net/c/kueD

loadするswfのurlがすごいことになってますが、動作しますねw。いろんなユーティリティをつくっておけば、それを組み合わせていろいろやるということができるかもしれませんね。


さて、余談ですが・・・
やれるかやれないかは別にしてやってみたいこと箇条書きにしておきます。
1:mp3をflvになおしつつ、netStream.appendBytesをつかって再生させること。
2:flashでflazr同様のプログラムを書いて、flashからファイルをrtmpにpublishさせてみる。
3:チャットまわりをつくってhttp://wonderfl.net/c/wzCpこのtakStreamingのプレーヤーにコメント機能も実装しちゃう。

このあたりやりたいですね。

それ以前にしばらくは、wonderfl上に動作ライブラリをいくつかつくるのが先決かな・・・

2012年6月22日金曜日

wonderflにHttpTakStreamingのプレーヤーつくりました。

前からおいておきたいな・・・とおもっていたwonderflにHttpTakStreamingのプレーヤーを設置しました。

http://wonderfl.net/c/9VnJ
んで、youtubeのFinalFantasy9のBGMでも流しながら実験していたのですが、どうも音がとぎれることがあった・・・
おかしいなと思って調べてみたところ、どうやら原因はリストファイルへのアクセスを頻繁に実行しすぎるためみたいでした。
もともと0.5秒に1度データを取得しにいく形だったのですが、これを1.2秒ごとに変更したところなんとかなったっぽいです。

いくつかわかったことがあるので、書いておきます。
1:Flashからダウンロード要求を発行しすぎると、詰まることがありえる。

chromeのNetWorkをみてて気づいたのですが、メディアデータをDL後にindexファイルのDLが詰まっていました。どうやら、タイマーの間隔をつめすぎていたみたいです。0.5秒は無茶だったという。
もしくは処理完了してから、indexファイルの読み込みを要求するように書き換えないとだめですね。
とりあえず。0.5秒→1.2秒にしたらなんとかなった模様です。
この設定ちょっとまずいんですけどね。

2:FlashMediaLiveEncoderの出力データのキーフレーム間隔が非常に広いみたいです。

各mediaデータの生成タイミングは、設定間隔以上で動画のキーフレームがきたら・・・という条件にしてあります。
で、出力データをしらべてみたところ、200フレーム以上はなれてkeyFrameがくるようになっていました。
14秒ごとくらいの間隔?設定間隔を1.2秒にしていたので、もっと小さなデータがながれてくることを期待していたんですが・・・
ちなみに先ほどのちょっとまずいという件は、もし、キーフレームの密度が高い放送をやってしまうと、メディアデータの間隔が、ちょうど1.2秒になります。
タイマーも1.2秒だと、下手すると、ファイルをうまく受け取れない可能性が・・・

というわけで、リアルタイム性を押し出そうとおもったら、ちょっとエンコードして、キーフレームの間隔狭めておかないとだめですね。

com.ttProject.xuggle.out.flvのパッケージのクラス準備しなきゃだめかもw。
とはいえ、変換をかませるとそれだけで遅延の原因にもなりかねないし・・・どうなんだろう。


とりあえず、やらないといけないことは・・・
1:エンコード間隔を3秒程度に変換しておく。
2:HttpTakStreamingを生データから作成ではなく、xuggle変換後の出力にする?(リアルタイムに近づけるなら。)
それか、innerFrameのところで切っても問題なく再生できるような仕組みを考える。
3:Flash側の取得動作まわりのもろもろの対策
このあたりでしょうか・・・

昨日からFlashモードになってるから、1、3やって2は天啓がおりてくるまで待機かなw
ではでは〜

2012年6月18日月曜日

jpegmp3ストリーミングについて考えてみた。

jpegmp3のストリーミングをつくって、iPhoneなのに、フルスクリーンではない再生をやってみたいと思っています。
というわけでいろいろ考えてみた。

いまのところわかっていること。
・mp3のストリームはm3u8準拠でできるみたいなので、この再生positionをベースに画像を入れ替えていこうと思う。
・画像は1枚ずつ別の画像にしてしまうと、転送データが大きくなりすぎる懸念があるので、1枚の画像に複数のシーンを書き込んだ画像を準備しようと思う。(160x120の画像を縦に10個、1秒分描くみたいな感じ。)
・mp3のストリームはtsやtakみたいに間近の2、3パケットだけ送ればよいというわけにはいかないみたい。(再生時間がはじめてからの時間になってしまい、jpegとの同期がとれないみたい。)

というわけで現時点での案は次のような感じ。
・mp3の18375000パケットごとにセグメントをループさせる。(ちょうど1分の長さ)
要は1分20秒の画像と3分20秒の画像のindexは同じになる。
・jpeg用のインデックス定義ファイルはjplという拡張子にしておく。jpegListファイル内容は次のとおり。
#JPL-X-MEDIA-SEQUENCE:xx
冒頭の情報が何番目のセグメントであるか定義する。
#JPLINF:1111001111:[jpegファイルへのURL]という形で各要素は定義しておく。
1はフレームが存在する。0はフレームが存在しない(jpegの形式だと黒になる。)
1フレームがちょうど0.1秒分になるので、あとはjavascriptで画像をいれかえていけばOK

例としてはこんな感じ
index.jplの内容例
#JPL-X-MEDIA-SEQUENCE:120
#JPLINF:1110110111:http://49.212.39.17/stest/jpeg/test/120.jpg
#JPLINF:1111111101:http://49.212.39.17/stest/jpeg/test/121.jpg
#JPLINF:1111111111:http://49.212.39.17/stest/jpeg/test/122.jpg
#JPLINF:1011111111:http://49.212.39.17/stest/jpeg/test/123.jpg
#JPLINF:1111100111:http://49.212.39.17/stest/jpeg/test/124.jpg
#JPLINF:0111110111:http://49.212.39.17/stest/jpeg/test/125.jpg

こんなもんで構築できるかな

実際にプログラムをつくったら利用するファイルは以下
m3u8(mp3のストリーム定義)
mp3(mp3のデータ本体)
jpl(jpegのストリーム定義)
jpg(jpegのデータ本体)

mp3のストリームの再生位置を取得しつつjpegデータをcanvasにjavascriptで描きまくるみたいな動作になる予定

また帰宅後にぼちぼちプログラムをしていこうと思う。


おまけ、HttpTakStreamingの今回つくったファイル、ftl fth ftmファイルについて
■ftlファイル(FlvTakListファイル)
#FTH:[fthファイルのアドレス]

ヘッダファイルの定義


#FTM-X-MEDIA-SEQUENCE:xx
開始場所が何番目のシーケンスかの定義
xxは数値この数値と内容リストから、ファイルの結合順を導きだす。

#FTMINF:[ftmファイルのアドレス]
メディアファイルのデータ

■fthファイル(FlvTakHeaderファイル)
バイナリファイルで内容はflvの冒頭定義 + 映像の先頭パケット(AVCのみ) + 音声の先頭パケット(AACのみ)で構築されたファイル

■ftmファイル(FlvTakMediaファイル)
バイナリファイルで内容はflvの各メディアパケット(ただしタイムスタンプに細工あり)

ぶっちゃけると、先頭からファイルを入手すればcat結合でFLVファイルに復元することが可能。

$ cat index.fth > data.flv

$ cat 0.ftm >> data.flv
$ cat 1.ftm >> data.flv
$ cat 2.ftm >> data.flv
$ cat 3.ftm >> data.flv
$ cat 4.ftm >> data.flv
$ cat 5.ftm >> data.flv
$ cat 6.ftm >> data.flv
...
でdata.flvがちゃんとしたflvファイルになる。
これをnetStream.appendByteにむかってやってるのが、HttpTakStreamingになります。

ちなみに転送媒体をファイルではなくrtmfpのノード間通信にしたのが過去の記事のやつです。(p2pで高画質配信したいというやつ。)netGroupでは無理でしたが、netStreamでの転送なら動作可能です。

では、本日の由なしごとでした。

2012年6月17日日曜日

mediastreamingのデモができました。

最近いろいろやっていたmediastreamingのデモができました。

いまのところ次のような状況です。

■構成:
rtmpの配信クライアント→FlashMediaServer4→Flazrベースのjavaクライアント→セグメント用ファイル→クライアント


■対応セグメント:
HttpTakStreaming(Flash用)のftl、fth、ftm
HttpLiveStreaming(apple用)のts、m3u8
Mp3Streaming(apple用)のmp3、m3u8
(jpegMp3Streaming:将来つくる予定)

■デモ概要:
49.212.39.17のsakuraのvps上にFlashMediaServer 4.5をインストールし、Flazrのプログラムでストリームを監視しています。
適当な配信プログラムで次の放送を実施します。
rtmpアドレス:rtmp://49.212.39.17/test
ストリーム名:test

しばらくすると必要なコンバートがはじまるので、各セグメントにアクセスしてデータを視聴します。
Flashで見る場合
http://49.212.39.17/stest/player/HttpTakStreamingPlayer.htmlにアクセスします。
playボタンを押せば視聴がはじまります。

iOSデバイスで見る場合(HttpLiveStreaming)
MobileSafariで
http://49.212.39.17/stest/ts/test/index.m3u8
にアクセスすればOK

iOSでバイスで聴く場合(Mp3Streaming)
MobileSafariで
http://49.212.39.17/stest/mp3/test/index.m3u8
にアクセスすればOK

■いまのところわかっているバグ_
h264WebStreamerのデモで配信すると動作が芳しくない。
・FlashMediaLiveEncoderのAACを使うとhttpLiveStreamingで音飛びが発生する?
・たまにmpegtsのデータがおかしくなる。(音声の同期がくずれる?)

■今後やりたいこと
・とりあえず、安定化。
・適当な放送プレーヤーと視聴プレーヤーをwonderflあたりに作りたい。
・jpegmp3ストリーミングの構築
・iphone用の適当な視聴プレーヤーをjsdo.itあたりに作りたい。
・無料webスペースにセグメントファイルを配布する実験。
・amazonS3あたりにsegmentを配置して大規模配信のテストやってみたい。

とりあえず、早急には地に足がついた感じの安定感がほしいですね。
まだまだネタレベル。

以下追記

いまのところキーフレームベースで切り分けするようにしているので、時間ベースで均等にわけるようにすれば、もっと安定するかな・・・開始動作が安定しそうにないけどw。

□デモを試してみたい方おりましたら
red5のpublisherか、FlashMediaLiveEncoderあたりで、rtmp://49.212.39.17/test向けにtestという配信やってみてください。
ただし一般的に問題のある配信(アダルトとか違法なものとか)はご遠慮ください。

なんか問題があったり飽きたりした場合は撤去しますので、あしからず。

□ソースコード他
Flazrまわりの変換動作のソースコード
https://github.com/taktod/streaming/tree/mediastreaming
HttpTakStreamingのソースコード(主にFlash)
https://github.com/taktod/HttpTakStreaming
HttpLiveStreamingのmp3化はこのブログをひっくり返してもらえばでてくると思います。
HttpLiveStreamingそのものはgoogle.comあたりで検索してもらえればいろいろ情報がでてくるかと思います。

2012年6月15日金曜日

FlashMediaServerのメモ

SakuraのvpsにFlashMediaServerをいれました。
いれたといってもDevelop版ですけどね。

今回いろいろなsegmentをつくるプログラムを書いてるわけですが、元になるサーバーをFlashMediaServerにしたいと思います。

理由はこんな感じ
1:小規模solutionに展開していいらしい。
え?小規模ソリューションの展開にご使用していいの?

2:Flazr経由でのFlashMediaServerのデータのダウンロードができる件。
Red5のRtmpClientでは無理だったんですが、Flazrなら接続もデータのダウンロードも可能です。もちろんxuggleのffmpegのつなぐことも可能でした。まぁ、ちょっと謎解きが必要ですけど。なお、H.263のDisposable InnerFrameの件もRed5じゃなければ問題なく扱えるみたいです。

3:堂々とFlashMediaLiveEncoderが使える件。
Adobeが提供している無料で高画質配信できるアレです。
ライセンスにたしか、FlashMediaServerにしか流しちゃだめよというのがあったかと思います。
これですね。Flash Media Serverには流してよし、このソフトをつかってサーバーや実行ファイルをつくったり、他のプログラム(ストリームをやりとりする系)に流すのはだめって書いてあります。

まぁ、FlashMediaServerのライセンスにFlash以外の3rdパーティーのクライアントでつないじゃダメといった条項はなさそうだし、今回やりたいことはオッケーであろうと判断しました。

まぁ、単なる言い訳ですね。


さて、サーバーに導入するにあたってRed5のときと同じく、特定のアプリだけにしかアクセスできなくしたいと思います。

[fms]/applicationsの中にある邪魔なプログラムをすべて撤去します。(liveとかvodとか)
で、アプリ用のディレクトリを作ります。
今回はtestというディレクトリにしました。(あとで多分変更する。)
[fms]/applications/test/
これだけでアプリケーションとして有効になるので
rtmp://[ドメイン]/test
でアクセスできるようになるわけですが、これだけだと、任意のRoomアクセスできるし、ストリームも流し放題になります。

そこで次のようにやりました。
[fms]/applications/test/main.ascを準備して以下のコードを書きました。

application.onPublish = function(client, stream) {
        if(stream.name != "test") {
                this.disconnect(client);
        }
}
if(application.name != "test/_definst_") {
        application.shutdown();
}

test/_definst_以外のアプリケーションは生成させない。(room)を禁止する。
testという名前以外で放送開始したら、クライアントを切断させる。

ついでに[fms]/applications/test/streams/のディレクトリの所有者をrootに変えました。
これでrecordで放送されてもファイルはできません。

以上で特定のアプリのみRoom禁止、放送もできるけど放送可能なストリーム名は固定され、かつ録画もできない

という状況をつくりました。

2012年6月8日金曜日

mpegtsによるiphoneのHttpLiveStreaming成功しました。

最近がんばっていた。mpegtsを切り分けたデータによるHttpLiveStreamingの動作がうまく動作しました。
iPhone4Sでばっちり視聴もできました。

https://github.com/taktod/streaming/commit/58c30b481cdea460f2d66344a78fd0a317833463

いままで実験で再生がコンバートにおいついてプチってきれていたんですが、原因は出力ファイルリストの中にコンバート中のファイルがはいっていたからでした。
サーバーのスペック不足とかでなくてよかったです。

実験やってみたところ、遅れはだいたい10秒程度でした。

いまのところ、生成ファイルのdurationがだいたい5秒ごとくらいになっています。これは変換パラメーターをいじれば2〜3秒くらいにできるかと思うので、生成中ファイルのことも念頭にいれると、遅延はやっぱりできて5秒程度かなと思います。

「変換や伝送経路の問題1秒」+「生成中のファイル3秒」+「DLや開始のずれ2秒」

なので会社でたたき出した遅延5秒は超えられそうにないですね。ちょっと厳しすぎる。

今日は他にも試してみました。

■コンバート用のパケットを自力で作る件。
github側にあがっているxuggleをつかってリアルタイムflvデータコンバート処理をやってみようと思ったのですが・・・

コンバート用のパケットをIContainer経由以外でつくろうとしたところ、いまのところ正しいメディアデータと判定されませんでした。
とりあえず試したのは
1:IBufferの生成からはじめて、IPacket.make(IBuffer)でつくってみる。
2:IPacket.make()でつくってから
streamIndex、data、timeBase、timestamp、pts、position等をいれてみたのですが変換可能なデータと見なされませんでした。

仕方ないので別のアプローチということで次のことも試してみました。
timestampの入れ替えがない状態のflvとしてデータを流す。
結果としては、これも失敗しました。やっぱり、ストリームを取得していると急に数Mbyteくらいの読み込みが要求されて、壊れました。
今回ためした動作では、disposable innerFrameを追記していたので、これをはずしてもどうしようもなかったら、ちょっとお手上げです。

■FTPをつかって、リアルタイムに別のサーバーにあげる件。

jakartaのプロジェクト commons netにはjavaでftpアップロードを実施するクラスが実装されています。
それをつかって、ファイルの生成されてからアップロードではなく、変換されたbyteデータをそのままftp経由でリモートサーバーに書き込んじゃえということをやってみました。

やってみたところ、意味不明なファイルが大量にできました。たぶん、ftpで経由での書き込みに遅延があるのに、mpegtsの書き込みが殺到するから、こわれたのかな・・・

とりあえず今週末は、jpegmp3ストリーム、httpLiveStreaming、rtmpのストリーミングこの3つが連携できるような状況にもっていって、それなりの動作するプログラムを作り上げたいところ。

2012年6月7日木曜日

flvのffmpegコンバートできない件対策

どうやら古いffmpegでしか発生しないみたいですが、

Application provided invalid, non monotonically 
increasing dts to muxer in stream 0: 数値 < 数値
というエラーがでて、動作しないことがあるらしい。
なにかというと、データ内部のパケットが順番にきちんと並んでいない場合に発生するエラーらしいです。


というわけで、さくっと対策してみた、
以前のhttpTakStreamingをつくったときにわかっていたことなんですが、rtmpで流れてくるデータはたまにaudioとvideoのデータの順番いれかわっていることがあります。

とりあえず、この順番の入れ替えを直せばきちんと動作するか試したかったのでaudioデータは順番にqueueにいったんいれ、videoデータをうけとった瞬間にvideoデータのタイムスタンプまでaudioデータをいれるという方法を実施し、整列させました。

21:14:06 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - videoTimestamp:10390
21:14:06 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - audioTimestamp:10402
21:14:06 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - audioTimestamp:10449
21:14:06 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - queueSize:0
21:14:06 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - videoTimestamp:10490
21:14:06 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - audioTimestamp:10495
21:14:06 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - queueSize:0
21:14:06 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - videoTimestamp:10521
21:14:07 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - audioTimestamp:10542
21:14:07 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - audioTimestamp:10588
21:14:07 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - queueSize:1
21:14:07 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - videoTimestamp:10590
21:14:07 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - audioTimestamp:10634
21:14:07 [New I/O client worker #1-1] INFO  com.ttProject.flazr.StdoutWriter - audioTimestamp:10681

queueSizeが0でないところでは、データが入れ替わっていたところになります。
で、ためしたところ、ffmpegの動作ができました。

まぁ、冒頭にも書きましたが、新しいffmpegの場合きちんと解釈して動作してくれるのでわざわざこんなことする必要はないです。

ffmpegでコンバートしてて、冒頭のエラーをみかけたら、タイムスタンプの順番が狂ってる?と思えばいいかなと思います。

ではでは〜


2012年6月6日水曜日

xuggleのコンテナ経由せずに動画データを取り込めないか?その1

xuggleの変換はやりやすいのですが、どうもバグがあるみたいで、無理矢理いれた最新のgitバージョンから起こしたプログラムでは、ffmpegから要求されるデータ量が数MByteになってしまったり、bad pictureのエラーがでてとまったりしてしまいます。
(google codeにあがっている方ではいまのところこの問題は発生していません・・・*1)

ですが、やっぱり最新版ので動作させたいと思いますので対抗策を考えてみました。

一番手っ取り早そうなのはIContainerの読み込み部分の動作を解析して問題点を暴くことですが、さすがにそこまでマニアックなことはできないので、もっと簡単なところからせめて見たいと思います。

そこで今回は入力Containerの読み込み前と後でなにがかわるか確認してみました。
基本知識として、FLVファイルは
[ヘッダ(タイプ + データ量 + タイムスタンプ + トラック番号)(11バイト)] + [パケット情報(コーデックその他)(物による)] + [データ本体(任意)] + [末尾データ量]という形になっています。

ですから、データ本体とタイムスタンプ、コーデック情報あたりがセットになったオブジェクトになってるんじゃね?と思った次第で調べてみました。

まずはデータ本体
FLVデータの構造はググったら、調べることができるので、青マーカーで入力されたデータのうちメディアデータ本体がどこにあるか調べてみました。もののみごとに対応していますね。

つづいてタイムスタンプ
青マーカーで同じくかこったところがタイムスタンプの指定です、生データ側では、16進数になっていますが
0x0514 -> 1300
0x0543 -> 1347
とうまく対応しています。

というわけで、別にIContainerを経由しなくてもつくれそうな気がしてきました。

戯れ言*1
このブログの記事そのものも不確定要素満載の戯れ言ですが、その中での戯れ言。
google codeにあがっているxuggleとgithubにあがっているxuggleの違いについてなんですが、いまのところ次のような疑惑があります。
1:flv読み込み動作の安定性の件
githubのコードの場合、読み込みをつづけていると急に6Mくらいの大きなデータの読み込み要求がでて、変換がとまってしまう上に、読み込みきったらxuggleのcppで書かれた部分がデコードミスを起こして壊れてしまう。
google code側では、問題はでず。github側では、問題が発生する。

2:flvで中途でトラックが追加されたときの動作の件
flvフォーマットは、このタイムスタンプから、このメディアデータを再生するようにという定義になっています。なので、映像データは連続してくるのに、音声データはとびとびにとんでくるという状況が発生します。(マイクのループバック回避のために、microphoneにslience設定をいれていたりすると発生します。)
このときに後から追加されたトラックを無視してしまうみたいです。
google code側では問題なく動作する。github側では、問題が発生する。

3:対応フォーマットが違う。
一番大きいのは、vp8が対応している点、あとで余力があったらwebMのストリーミングのセグメント作成もさせてみたいので、できたらgithub版を使いたい。
google code側vpxは読み込みのみ、github版出力もOK
等々

そんなわけで、なんとかして、github版で安定動作させたいなと思っております。
ではでは〜

flazrからxuggleにデータを送る。

前回のエントリーにも書きましたが、xuggleの動作そのものは、flvフォーマット形式のデータをきちんとつくってやって、それをIURLProtocolHandlerのreadメソッドの要求に従って渡してやればOKということなので、そういうflazrのプログラムを書いてみました。

ソースはここ
https://github.com/taktod/streaming/commit/bb326b8f553c5b0b81edb7483f893cec862208e0

要は、com.ttProject.red5.Red5TranscodeManagerの設定処理と同じようなことをして、inputDataQueueにダウンロードしてきたRtmpデータをFlvの形式になおして、いれまくる。
それだけです。

Red5のときには、red5-web.xmlの記述に変換だの、各セグメントCreatorの定義を書き込めるようにしたのですが、今回は適当な方法が思い浮かばなかったので、とりあえずソースに直に書き込みました。
なので、com.ttProject.flazr.FlvWriterのコンストラクタが偉いことになってしまいました^^;

これで、eclipse上で簡単に実行できるようになったので、他の動作をつくるときにちっとはやりやすくなったかな。

ではでは〜

2012年6月4日月曜日

red5 + xuggleでhttpLiveStreamingをやってみた。

最近いろいろやってみた結果。

ソースコードはここ。
https://github.com/taktod/streaming/tree/mediastreaming

とりあえずmpegtsの動作はできたんですが、利用しているsakuraのvpsだとスペック的にたりないのか、リアルタイム視聴がうまくできなかった。再生が追いついてしまい、次のsegmentがダウンロードされるまでとびが発生しました。

いくつか覚え書き:
1:基本的にFlvDataQueueにflvとして成立するデータをいれてやって、FlvDataHandlerがそのデータを適宜正しく応答すれば、ffmpegのどんなコンバートでも実行可能っぽい。
(なので、flazrのダウンロードを入力ベースにすることも可能なはず。まだつくってないけど。)

2:ただしh.263のdisposable innerframeは解釈できないっぽいので、StreamListenerの動作で捨てている。
(無理矢理innerframeに変更したデータを作ってみましたが、やはり解釈できませんでした。最新のxuggleなら対処できるのかもしれない。)

3:変換は次のフローで実行している。
1:inputContainerからパケットを取り出す。
2:デコードする。
3:入力と出力の形式が違う場合はリサンプリングを実行する。
4:エンコードする。
5:outputContainerに渡す。
(1が済んだ時点で、ファイルに付いている拡張命令は取り除かれ、4が済んだ時点では、ファイルの形式になっていない生データが応答される。
映像の場合はデコードがおわったタイミングで画像になる。(BufferedImageとして扱うことが可能なので、このタイミングでモノクロにしたり画像に適当なものを書き込んだりできます。))

4:mpegtsをセグメントに分けるときには、映像のキーフレームを先頭にしてわけてやるといい感じの動作になるようです。
(キーフレームを無視して、フレームだけの解釈で実行すると、場所によっては、なかなか再生がはじまらなかったり、映像が始めに乱れることがありました。なお、以前紹介したcで書かれたsegmenterでは、単純に切り分けただけではないみたいです。)


xuggleのインストールがすこぶる面倒だし、ffmpegの変換パラメーターの吟味がややこしかったのに、いまさらリアルタイムに動作できないなんて・・・ひどすぎる。
まぁ、でも同じサーバーでやろうとしたら、並列処理がうまくいかないだけなので、別のサーバーにアップロードして、そこでユーザーに映像をながす・・・というやり方ならまだ希望があるかも。

ちなみにとびとびではありましたが、最速で7秒程度の遅延(単に動画が追いついただけですが)にすることはできた。

追記:red5の外部ツール対応が微妙っぽいので、FlashMediaLiveEncoderとかXSplitとかつかったら、またいろいろと問題がでるかもしれない。