\(^o^)/\(^o^)/
Android端末にUSBで繋いだUVCカメラからの映像をライブストリーミングした〜いと思って悪戦苦闘してたんだけど、ようやくUStreamへもちゃんと送れるようになりました\(^o^)/ いやぁ〜予定してたよりも大幅に時間がかかってしまった。FFmpeg使うのは以前お仕事で作ったから簡単に出来るのは判ってたんやけどブラックボックスに丸投げって嫌やん?
とりあえず、ベランダのミニトマトの葉っぱが風に揺れるのを蛇かメラじゃなかったヘビカメラで映したのが流れとります。トマトの代わりにきゅうりかゴーヤかナスの葉っぱって事もあるかも(笑)
まぁ見ても何の面白みもないけどリンクはここ。StreamingWithUVCCamOnAndroid
テスト用に作ったチャネルだから不定期に流れたり止まったりします。家に居て空いている端末が有って端末の電池があって昼間のみでアプリのテスト中かまったくテストしてない時・・・とか。流れてないからって留守って訳じゃないから悪い事しに来ないようにね。
ヘビカメラには一応LEDライトが付いてるんだけど外で夜映すには少し力不足(-_-;) あと、ホワイトバランスがおかしくて少し色が変なのも気にしないでください。今アナライザ見てて気づいたけどこのヘビカメラUSB LowSpeedみたい…まぁ映るからええんやけど。ちなみに、音声と映像同時ライブストリーミングも大丈夫でしたが、部屋の中の音が丸聞こえになってしまうので映像のみですイヤぁ〜ん(^_^;)
でどこに問題が有ったかというと、おそらく次の2点。
- PPSとSPSを送るタイミング
- PTS自体
PPSとSPSを送るタイミング
H.264でエンコードした映像を送っているのですがその際にPPSとSPSを送らないといけません。元々は一番最初にだけ送っていたんだけどどうやらキーフレームの度にSPSとPPSを前置して送るほうがいいみたいです。こんなこと仕様にはどこにも書いてなかったと思うんだけどなぁ(゜レ゜)
ちなみに、PPSとSPSは次の2つのどちらかでMediaCodecのAVCエンコーダーから取得できます。
- MediaCodec#getOutputFormatで取得
- MediaCodec.BUFFER_FLAG_CODEC_CONFIGが付いてる時のoutputBufferから取得
1の方法では、MediaCodec#getOutputFormatで取得したMediaFormatからキー名がcsd-0となっているByteBufferを取得するとSPSが入っています。またキー名がcsd-1となっているByteBufferを取得するとPPSが入っています。
2の方法では、MediaCodec#dequeueOutputBufferを呼び出した時にMediaCodec.BufferInfoで受け取ったフラグにMediaCodec.BUFFER_FLAG_CODEC_CONFIGフラグが立っている時に取得できる出力バッファにSPSとPPSが一緒に入っています。AnnexBフォーマットだからね。
一方、音声をAACでエンコードして送る場合には、MediaCodecのAACエンコーダーからの出力データそのままではだめで、全てのフレームの先頭にATDSヘッダーを付けて送らないとだめでした。ATDSヘッダーはPPSやSPSと同じタイミングで音声用のMediaCodeエンコーダーから取得できるESDSを自前で解析してATDSヘッダーに組み立てなおさないとだめでした。
PTS自体
RTMPの仕様とかFLVの仕様を見る限りは、モノトニックでリニアなミリ秒単位の時刻であれば良くて、RTMPのストリーム中のチャンク間で同期がとれてさえいれば0ベースである必要も無いって書いてあるんだけど、どうやら0ベースで送ったほうが良いみたい。音声と映像を同時に送るときには両方のトラックで同期を取って古い方のデータから送る必要がありました。
あとバッドノウハウだけど、MediaCodecからエンコード終了した時にMediaCodec.BufferInfoで受け取ったpresentationTimeUsは時々値がフリップしちゃう時があるから調整しないとだめですからね。
アプリとしては長〜いUStreamの配信用URLを手入力しないといけないとか、カメラからの映像取得FPSを低くするとUStreamアプリで再生できなくなるとか、異常系の処理とかが不十分とかあるのでもう少しかかりそうだけど、近いうちに公開できるかも^^ UStreamのAPI叩いて配信情報取得したりってのは将来のお楽しみに置いておこう^^;
\(^o^)/\(^o^)/
2015/05/12追記:
どうも夕方ぐらいからはサーバーへのアップストリームは大丈夫でUSTREAMブロードキャスターの画面でプレビュー表示はできててもブラウザやアプリで再生しようとするとうまくいかないことが多いみたい(´・ω・`)朝の内は全然大丈夫みたいなのに。
やっぱり夕方になるとUSTREAM見る人が増えるからなのかなぁ? お金かけてまっとうに配信していると思わしき所は普通に見れるので…プログラム側で何かできることってあるんかな?
でもトマトって近くで見ると葉っぱも茎もトゲトゲしてんねんなぁ^^
2015/05/13追記:
native側のライブラリでエンディアンの扱いを一部修正し忘れてたのを見つけたので直してたりしたらUSTREAMの方は昨日よりもうまくいくようになったみたい。と言ってもまだ15時前やし、たまたまUSTREAMのサーバー側の状態が良いだけかもしれないからぬか喜び禁物だけど。
でも今度はLAN内にあるWowzaへライブストリーミングしたのが再生できんくなった↓ なっなにゆえにぃ〜(´・ω・`) VCSで巻き戻すとWowzaへライブストリーミングしたのが再生できるけどUSTREAMが不安定…果たして両立できるんやろか(-_-;)
2015/05/13もう一度追記:
Wowzaへライブストリーミングしたのが再生できんくなったのはエンディアン絡みだった。
RTMPの仕様書によると、数字は原則としてネットワークバイトオーダー(=ビッグエンディアン)となっております。ほとんどはその通りなのですが、2箇所だけ違うのですガ━━(;゚Д゚)━━ン!!
- Message Headerのmessage stream IDは24ビット(3バイト)整数でビッグエンディアン(仕様書5ページ)
これは普通やね。 - Message Formatのmessage stream IDは32ビット(4バイト)整数でリトルエンディアン(仕様書8ページ)。
なんでやねん。 - Chunk Message Header(Type 0)のmessage stream idは32ビット(4バイト)整数でリトルエンディアン(仕様書19ページ)。
なんでやねん。
何で同じ仕様書の中の同じ語句”message stream id”やのに3バイトやったり4バイトやったりネットワークバイトオーダー(ビッグエンディアン)やったりリトルエンディアンだったりが混在するねん(●`ε´●)
朝変更した時に全部ビッグエンディアンで書き込むようにしちゃったからおかしくなっちゃってた。Wowzaの方がUSTREAMのサーバー(FMSなんかな?)よりも仕様に忠実ってことやね。でもあえてそこをリトルエンディアンにする理由はこれっぽっちも思いつきません(●`ε´●)まぁでも今更仕様変えられへんわな。
スマホのUSTREAM公式アプリだと夕方から切断されやすくなったけどブラウザからなら無事再生出来ているからこれでUSTREAMもLAN内のWowzaもいけそう\(^o^)/
2015:05/17またまた追記:
CPUがx86の端末だとストリーミング出来ずにハングアップしてしまうのが修正できた\(^o^)/ByteBuffer#orderでネイティブオーダーを指定して無い箇所があったのとかエンディアンとか、x86端末だけMediaCodecのエンコード結果がちょっと違う形でBuyeBufferに収まってたりとか色々あいまってうまく動かんかった。でもリリースまでもう一息^^
でも6時間ぐらいストリーミングするとなぜか勝手に止まっちゃうんだよなぁ。誰だ止める奴は(●`ε´●)相変わらずトマトの葉っぱをライブストリーミング中(笑)
あっそうそう、こないだ書いたYケーブルとMeMoPad7(ME176C)でタブレットとカメラに同時給電しながら動かせるって話、Nexus7(2013)でも大丈夫だった。でもYケーブだけのおかげじゃなくて自分がちょっと特殊なつなぎ方しているからみたい。普通にYケーブル+カメラ+端末+普通のUSB電源を組み合わせるだけじゃだめだった(´・ω・`) まぁ今のつなぎ方をすれば少なくともMeMoPad7とNexus7(2013)はOKだからいいんだけどね。どっちもASUS製だからかな?
2015:05/18また…また追記:
だんだん日記見たくなってきた(笑)
6時間ぐらいで勝手に止まっちゃうのはネイティブ側のメモリがリークしてたからだった。と言うかガベージコレクタのないネイティブコードでよく6時間も持ってたなぁ^^ 直したら昨晩は14時間ぐらい、今日も朝3時前から12時間ぐらい平気だった。補助電源有りでもそれぐらいで端末の電池が切れちゃうってのがネックだなぁ(゜レ゜)特に夜はカメラのLEDライト分消費電力が増えるし(´・ω・`)
USB以外で十分給電出来る方法ないかなぁ?やっぱりQiかな?
でも楽天で「Qi」を検索したら「いなば 金のだし カップ まぐろ ささみ・かつお節入り 80g」とか出てくる(@@)キャットフードじゃん^^りんご乙女なんてのも♪美味しそうだけどそんなのいりませ〜ん^^/「冷やし中華はじめました」もいりませんキッパリ^^
ちなみに、「海石鍋用石」ってのが一番笑えるかも^^石ころ1kgで1313円なりぃ〜高っでも最初は5個で1313円かと思った(^_^;)だってぇ写真に石ころが5個映ってんだもん。しかし「変えるカエル店長」ってなんだ? ちなみに一番高いのは621,299,392円って…しかも送料別べっ別なのか?ちろん充電器じゃないよ(汗)
閑話休題
気を取り直して…でも出力2AのUSB電源使うと一晩かかってNexus7に満充電できる・・・これって効率悪すぎなくね?最大0.5A出力のUSB2.0に繋いででももっとましな事出来るぞ?うーんY字ケーブルにします^^