@numa08 猫耳帽子の女の子

明日目が覚めたら俺達の業界が夢のような世界になっているとイイナ。

jcom から手紙が来ていた話

f:id:numanuma08:20180924100630j:plain

先月末、jcomからお知らせという件名で手紙が届いていた。

jcom から来た手紙を Google DriveOCR 機能で読み取った結果を修正したものが以下。

J:COM NET サービスご利用に関するお願い 平素はJ:COM NET サービスをご利用いただき誠にありがとうございます。 このたび J:COM NET サービスのご利用方法に関してお願いがございまして、ご連絡いたしました。突然のご案内になり申し訳ございません。 お客さまのご紹約されている回線から、9月26日 と 9月27日 の2日間にわたり、大量のデータ送信(※) 確認されました。この状況が続きますと、インターネット回線の通信品質に影響が出る恐れがございますの で、ご利用状況の見直しをお願い申し上げます。 また、データバックアップの為に他社クラウドサービスをご利用の場合は、一度に大量のデータ送信を行わ ず、日にちを分散してデータ送信いただけますようお願いいたします。 引き続き、データが一定水準を超える場合は、改めて書面にて実施期間をお知らせした上で、通信速度 の制限が発生しますので、やめて下さいますようお願い申し上げます。 ご不明点がございましたら、お手数ではございますが、弊社カスタマーセンターまでご連絡くださいますよ うお願いいたします。 今後も弊社サービスをご愛顧賜りますよう、重ねてお願い申し上げます。 ※大量データ送信とは、お客さまのパソコンなどからインターネット網に送信される1日あたり 30GB(ギガ バイト)以上の上り(アップロード)データ通信と定義しています。これは一般的なご利用の約 30MB と比較 して、およそ1000 倍に該当します。 30GB 以上のデータ量の目安では、DVD に格納されるデータ量(1枚約 4.7GB)の約7枚以上、もしくは CD (1 枚約 700MW), 44枚以上、またはデンタルカメラ写真(1枚約 6MB)の約 5120 枚以上に相当します。

初動

ちょうどこの手紙が届いたタイミングで俺は東京へ出張に行っていた。そのため、初動として動いてくれたのは奥さんの方で、 jcom への問い合わせを行っていてくれた。具体的な問い合わせのログが残っていたわけではないのだが、訪ねたことは

  • データの送信が行われていた詳細な時間帯
  • 送信されていたデータのプロトコルなど、詳細な情報

の2点。しかし、電話の担当者曰く手紙に描かれていること以上のことはわからないとして、情報が得られなかった。

対応、原因解明

自分がこのことを知ったのは、東京への出張から返ってきた9/29の夜。疲れ果てて返ってきたところに、奥さんに言われたので、まあ明日(日曜日)に考えてみるかーと思って、一応PCの電源だけを落として寝た。さて、翌朝の日曜日、いったい何が発生したのかを考えてみた。

大量のデータを送信するようなプロセスを起動した記憶は無いことを考えるとウィルスの可能性もあるなー、面倒くさいなーと思ってPCの前に座った瞬間、ちょうど1週間前に北海道へ行った際に Sony のアクションカメラで撮影したデータを Google Drive でバックアプをしたことを思い出した。4k 動画で全部で2時間くらい。これだわ・・・。

対策

対策といった対策を特に取っていない。jcom の手紙には

また、データバックアップの為に他社クラウドサービスをご利用の場合は、一度に大量のデータ送信を行わ ず、日にちを分散してデータ送信いただけますようお願いいたします。

とあったので、日をまたいでのバックアップをすることが適切なんだろうな。ただ、4k 動画で撮影した動画と言えどほとんどが車載動画で、全部を見返すことはあんまり無さそうということを考えると、今後はバックアップを行うファイルを選ぶのが良さそう。

そんなことを考えた9月末でした。

#ドラえもん展 強烈な精神的汚染による自分自身都の対話。あるいは、なぜドラえもんがそこにいないのか。

f:id:numanuma08:20180918010846j:plain

作品鑑賞とはすなわち自分との対話の一環である。その作品を通して自分がどう感じたのかを自分自身に問いかけることで、自分自身の心や頭が何を考え何を感じ、そしてそれらはどういう傾向があるのかを考察する。作品は絵画や彫刻、映像だけであるとは限らない。食べ物や飲み物を対象にするときもあれば、車などの乗り物であったり他愛のない食器やそのあたりの草であったりもする。

いずれにせよ人々はそこにリソースを割かないことが往々にしてある。自分との対話とは即ち、記憶の掘り起こしであり自分を形作ってきた物の再認識であり、それらは全てが心地よいものではない。そもそも、この活動は非常に疲れる。だから、美術館に行っても気になるものや話題のものだけを鑑賞したら、それ以外についてはあんまり時間をかけない。

もしも、すべての作品が自分の興味を引くものだけで構成された展示会があったらどうなるのか。脳をフル活用して疲れ果てた人はどうなるのか。その先は何のか。

それは、自分と自分以外の境界線の喪失である。自分がどこまで自分なのかどこからが他人なのか、他の鑑賞中の客なのか、それとも作者なのか。その境が曖昧になってくる。高熱を出して朦朧とする意識の中で立っているときのような、自分が見ている景色は誰かが見ている景色のような。強力な精神汚染。

ドラえもん展はそんな展示会だった。

物心ついた頃からドラえもんというコンテンツに強く惹かれてしまうようになった自分にとって、ドラえもんのみで構成された展示会は夢のような場所であると同時に、精神的疲労を強く覚える場所だった。

一つ一つの作品に強い思い入れを抱き、作者の思いを想像し、それを通して自分の内面を見つめ直す。その一つ一つのプロセスが少しづつ心を蝕む。

流し見をすればいいのではないだろうか? いや、それはできない。なぜならドラえもんだから。

しかし、何となく展示の企画者の意図も感じた。村上隆氏の大型作品「あんなこといいなできたらいいな」に始まりシンヤマザキ氏の「(Pink) Dust In The Wind ~すべては(ピンクの)もやの中に」で終わる作品配置は深く見れば見るほど、破壊され蝕まれる精神状態を表すように見えてならない。

ドラえもん展のテーマはそもそも「あなたにとってのドラえもん」だった。つまり、画家や彫刻家、クリエイターがあるいは子供のときに、あるいは大人になってから見つめ直したドラえもんを自分の形で表現したものだ。この世のすべての作品は受け取り手にとって十人十色、100人いれば101通りの受け取り方があり得る。「あなたにとっての」とは各クリエイターの心の中にあるドラえもんを、言ってみれば各クリエイターの心の中を覗き見する行為に他ならない。

私は人の心を理解することはできないと思う。したがって、人の心の中を覗き見することは自分にとっての「理解の及ばない」エリアを見ることに他ならない。自分の理解ができないものを見ることは即ち自分の精神的限界点を超えてしまうことなのだ。

ドラえもん展にはそれだけのパワーが有った。

気鋭の若手現代アーティスト達によるドラえもん展の展示は、見ているものに対する精神的汚染に他ならない。しかし、自分の心が乱される中で自分という個を保つために自分との対話が生まれる。

自分にとってのドラえもんは何だろうか・・・。それを問いかける機会ともなった。

私にとってのドラえもん

それは、SFとの出会い。

それは、漫画との出会い。

それは、アニメとの出会い。

それは、藤子・F・不二雄との出会い。

大人になってしまった今では、少年時代との出会い。

ドラえもんと言えば思い出すのは、初めて大学の単位を落としたときのこと。一年生の線形代数学の授業だった。

自分にとって「単位を落とす」とか「留年をする」はフィクションの中のことだった。

キテレツ大百科の勉三さんみたいな、あるいは「アパートの木」の五郎さんのような、どこか昭和の薫りの漂う漫画の中の出来事だと思っていた。

それが現実になったとき、大きなショックを受けた。自分の中の価値観が壊れてしまうような衝撃。自分が自分を保つため、選んだのは「ドラえもん」だった。

てんとう虫コミックス第6巻の「さようならドラえもん」。あるいは大長編ドラえもんの「のび太の宇宙開拓史」。そして、テント虫コミックス第35巻「ドラえもんに休日を」。

自分の中の「泣ける」ドラえもんの話。

これを「泣く」ことこそが、自分自身だと思っていた。落第が決定したときにこれらの作品を読んだ。でも、泣けなかった・・・。

泣くことができなかったショック。自分が自分でなくなるかのようなショックに涙を流した。

なぜここにドラえもんが居ないのか。

いくつかある最終回を除けばドラえもんが居なくなった瞬間は漫画の中では描かれない。大学生になったのび太がタイムマシンを利用していたシーンもあれば、大人になったのび太ドラえもんとの再会を懐かしむシーンも有る(45年後・・・

ドラえもんは最も近くて最も遠い存在だったのかもしれない。近くにいるけれど見つけられない。灯台下暗し。「心をゆらして」探せば見つかるのかもしれない。

今では、そんなこともあったと思える。

結局、自分を立ち直らせたのはしばらくしてから発売された劇場版ドラえもんのDVD BOX だったり、藤子・F・不二雄大全集だった。

自分が自分であること、それはドラえもんを読んで「すこし」笑っていたり「すこし」泣いていたりすること。

そんな、在りし日の思い出を揺り起こすことだった。

ドラえもん展を見に行ってほぼ1年。今では、全国を巡回している。大阪に来る日もあるだろう。

1年前とはもしかしたら「すこし」違う、でもやっぱり一緒な自分を見つめ直すこの展覧会をまた見に行こうと思う。

そのアプリ、本当に MVI が必要?

久々に技術っぽいポエムを。

Qiita で Android の MVI アーキテクチャについての記事を書いている。

qiita.com

思ったよりも大作になってきて、ちょっとどこから編集を追記すれば良いのかなという気持ちになっていたりするのだけれど、ぼちぼち作っていきたい(また書籍化したい・・・?)。

さて、 この Qiita の記事を書くきっかけはあるプロジェクトの中で MVI アーキテクチャを採用しませんか?ということになったため。練習レベルで MVI アーキテクチャiOS の Reactor Kit を使ったコードを書いたことはあるけれど、ちゃんとプロダクトで使ったこともないし、人に説明ができる感じでもないなという状態だったため、今一度自分のスキルセットを確認しようと思い筆を執った次第。

で、コードを書いていて思ったのだけれど全部が全部 MVI っぽい感じのコードにはならない。まあ、そんなのは当たり前で、アーキテクチャを決める会なんかのときにも「いやあ、全部が全部 MVI っぽい書き方にすると大変っすよー」みたいなことは言うのだけれど、具体的に「全部が全部」じゃない部分ってどれよ?ってのを今ならある程度言語化できそうなので、忘備録的な意味合いでちょっとまとめておく。

プロジェクトが終わった時に考え方が変わっているかどうかが見もの。ちゃんとプロジェクトが終わりますようにという思いも込めて 🙏

静的な View

そもそも MVI を導入する目的は「複雑になった画面の状態を抽象化し、コードで表現できるようにしてデバッグやテストをしやすくする」ことだと思う。その目的にそぐわないのが「静的な View」だ。一般的なアプリだと

  • ヘルプ、使い方画面
  • WebView だけの画面

とか。「WebViewだって、View の中身のページが変わるじゃん!」みたいな考えもできるけれど、中身のコンテンツ自体は WebView が状態を管理してくれることが多いのでそっちに任せておくのが良さそう。静的な View しか存在しない画面は MVI っぽく作る必要がないし、動的に変化をする画面でも 静的な部分については State で管理をする必要はない。

画面遷移

画面遷移も Fragment なり Activity なりを管理してくれるのは os なので、アプリの方では気にしない。ボタンを押したりしたら普通に startActivity や add/replaseFragment で画面を開けばいい。個人的には Espresso でテストがしやすいので EventBus 的に Fragment → Activity で通信を行う仕組みを作っていると、EventBus をモック化することで Fragment の UI テストがしやすくなるので好み。ただしこれは MVI とは関係がない。

Runtime Permission

これもなー、画面遷移に近いのかなーって思っている。ボタンを押して現在位置を取得する、みたいな実装の場合

  1. ボタンを押す
  2. リスナーで Runtime Permission のチェック
  3. Permission の状態に応じて ViewModel に対して Intent を飛ばす

のように、View 側で Permission の管理をしちゃうのが良さそう。Runtime Permission 関連の API が Context に依存していてさらに画面上にダイアログなんかも出ちゃうので、このダイアログを State で管理をするとかやりたくないよね?って感じ。

ダイアログ、 Toast、 SnackBar

これに関してはまだよくわからない。 State に isShowDialog: Bool なフラグをもたせておいて、 True なら表示をすればいいのだけれど、じゃあいつ False になるんだろうか?Toast や SnackBar も同じ。これらの View が「閉じた」というイベントをトリガーにしてフラグを倒すのかな。SnackBar は簡単にできそうだけれどダイアログと Toast は大変そう。 Droidkaigi でも Toast に関しては「表示してからn秒後にフラグを倒す Intent を発行する」とか言ってて、やべえなって思った。ダイアログに関してはダイアログが閉じられるケースを全部網羅するの?まじで?って気持ちもある。

画面遷移に近いようなきもするけれど、こういう UI を出したいタイミングって非同期処理なりビジネスロジックの終了をトリガーに行うことが多いイメージ。なので「ボタンを押したらすぐ表示」というわけにはいかないよね。

大変そう。頑張ってフラグで管理をするのかな。

俺にとってのみれぃ、つまりプリパラそしてでじこちゃんときどきハートキャッチプリキュア

みれぃは自分自身だった。

アニメ「プリパラ」を始めて見たのが確か2018年の5月くらい。 Netflix で配信が配信されていて、目が止まったのが最初。

序盤のらぁらのがんばりに涙を流しながら見ていたけど、あるとき俺が見ていたアイドルはラァラではなかったことに気がついた。

みれぃだ。

日常生活では生徒会長や風紀委員として、そしてプリパラでは語尾が「ぷり」のポップなアイドルとして、彼女は自分を表現していた。彼女は全部を計算して、計算どおりに練習をして頂点を目指そうとする彼女の姿は天才ではない自分と重なっていた。

第2シーズンに入ってプリパラがセレパラになってしまった世界。彼女は努力をしてトップを目指そうとしていた。しかし、しかしだ。彼女の努力は天才たちによって打ち砕かれてしまう。そふぃのライブを見て勝利をすることに諦めてしまう。さらに彼女に追い打ちをかけたのが、紫京院への対決の宣言。自分の行動に対して過剰に責任をおってしまう。

自分の責任で、あるいはそう思い込んだときにどん底に落ちるこれほど苦しいことはない。それが、俺にはわかる。

自分は、電気通信大学という名前となんとなくソフトウェアや情報工学が好きだったので大学を選んだ。この場所なら自分が最高に輝くことができる、最高に才能を発揮することができる。そう信じて大学に進んだ。

でも、現実は違った。大学1年生のときに線形代数学の単位を落としてしまったときに最初の涙を流した。そのあと、3年生のときに実験の単位が足りなくて4年生に進学できなかった。その理由は簡単で、3年生の実験の授業が理解できなかったから。根拠のない自信で自分はソフトウェアやプログラミングに強いと思っていた。でも、現実は違ったんだ。学問の奥は深くて難しくて自分には理解ができなかった。

それが辛かった。自分にはできると思っていた自信が破壊されてしまった。

みれぃもそうなんだ。成績が優秀でしっかりとした性格。自分の中で全部を解決できる。そして、何より自分はプリパラが大好き、自分の中で満足のできる努力をしてきた。それが彼女の根拠だった。それが紫京院を前に、そふぃを前に打ち砕かれて涙を流す。

完全に俺とかぶっていた。根拠として信じていたものが打ち砕かれたとき人はだめになってしまう。彼女もそうだった。俺が大学3年生のときも、実験の内容が理解できなくて引きこもり状態になってしまった。あの時の俺とみれぃが完全に被ってしまう。そして、その理由が自分自信にあることが嫌だった。だから動けなくなってしまった。動きたくなってしまった。暗い部屋でゲームをするだけの存在になってしまった。

そんな彼女をライブのステージに戻したのはがぁるるだった。がぁるるのライブはたとえ途中でこけても続けた。人の誰よりも努力を続けて立ち上がったがぁるるのライブはみれぃの涙になった。それは自分の経験にもある。同期の人達に厳しいことを言われたり、教授に頭を下げてレポートを遅れて提出したり。その中で人に頼ることを覚えたり。みれぃもそうなんだよな。自分ひとりで立ち続けていたから人に頼ったり、だれかの力で立っていることに気がつけなかった。シーズン1の最初の方ではらぁらに対してきつい言葉を言ってしまうことがよくあった。でも、それは自分が自分ひとりの力である程度のところまでこれてしまったと勘違いをしていたから。

「自分がこれくらいできるのだから、お前もこれくらいできるだろう」と思ってしまう衝動は自分にも経験がある。彼女もそうなんだ。だから「自分がこれくらいできた」という自信が破壊されたときに立ち上がれなくなってしまう。

そんな彼女が再度立ち上がったのが地下パラだった。地下パラでの成功体験の積み重ねが彼女の力になっていった。俺もそうだ。C言語ポインターとかの概念がわからなくて詰んでいたときに、Androidが登場した。Androidのアプリを開発するためにjavaを覚えて、参照渡しの概念がわったとき、かつてのC言語のレポートくらいなら書けるようになっていた。必要なのは成功体験でもあった。

でも、それだけじゃない。彼女をステージに立たせたのは彼女とそして彼女を支えるそらみスマイルやドレッシングパフェやだった。彼女のソロライブ、そしてエアリーチェンジを実現した曲「ぷりっとぱ〜ふぇくと」はそらみスマイルの「トライアングル・スター」のアレンジ。彼女を立たせていたのは、そらみスマイルだったんだ。


プリパラ 84話 『 ぷりっとぱ~ふぇくと 』 みれぃ

「むいてもむいても」と一皮むける彼女。「唇をキスの形スタンバイ」と彼女が計算の末に作り出した最高の言葉「ぷり」。みれぃは自分の力と仲間の力で最高潮に達した。

少しずつの成功体験、仲間の協力、それが彼女の力になった、自分の力になった。

彼女はすべてを受けいれて次のステージへ進んだ。彼女はチェンジをしたんだ。

チェンジ、そう、ハートキャッチプリキュアのテーマだ。

ミラージュプリキュアの試練の中でブロッサムはチェンジする前の自分を受け入れる。かつての嫌いな自分も自分自信だったことを受け入れる。今の俺ならそれができる。ステージに再度立ったみれぃもそれができる。完璧じゃない自分を受け入れて今の自分を見つめてより高みを目指すことができる。

みれぃを応援したのがそらみスマイルやドレッシングパフェだったように、俺を応援してくれたのが id:henteko07 だったり @sseze だったり id:ytRino だったりする。Android道という勉強会をやっていたときに助けられた。

そして、無条件に応援をしてくれたのがでじこちゃんだった。健気に頑張る彼女を見て自分もそうしようと思うことができた。でじこちゃんのおかげであのときがあったし、今がある。

numa08.hateblo.jp

今なら最高に可愛いのはでじこちゃんだって迷いなく言える。でも、過去の自分を投影してそして過去の自分を受け入れられる存在としてみれぃも好きだって言える。俺の中のみれぃはそんな存在なんだ。

Elastic Leadership を読んだ

エラスティックリーダーシップ ―自己組織化チームの育て方

エラスティックリーダーシップ ―自己組織化チームの育て方

2018年の Droidkaigi の中でこの本が紹介されていたので、会社の経費でポチってもらった。回し読みをしてようやく順番が回ってきた。

numa08.hateblo.jp

感想

チームが今ある状態を「サバイバルフェーズ」「学習フェーズ」「自己組織化フェーズ」に分割し、リーダーはチームを自己組織化フェーズへと導くことが仕事であるとしているのが著者の主張だと感じた。これに関して自分はたしかにそのとおりだと感じた。思えば、自分は小さな組織でリーダー的なポジションになることが多かった。例えば高校の部活動、例えば大学のサークル、例えばバイトetc...

どんなチームであっても思うのは、メンバーに勝手にやってほしいと思うことだった。今にして思えば、それは自己組織化フェーズへと進化したチームのことだったのだろう。そしてこれは、大体のリーダーが考えていることだと思う。よく言う「経営者的思考を身に着けてください」と経営者が言うアレだと思う。

チームのメンバーはチームリーダーが自己組織化されたチームを目指していても、メンバー自体はそこまでの給料をもらっていない事を考えるとモチベーションは普通の状態では持ち合わせない。チームリーダーの仕事で難しい部分は、自己組織化されたチームの状態がどういうもので、なぜそれを目指すのかをチームメンバーで共有するところかもしれないと感じた。

自分たちのチームはどんなチームだろうか

この本を読んで、自分たちのチームがどんなチームなのかを振り返ってみたいと思う。実は、今のチーム(コベリン)は会社全体をチームとして見たときにまだサバイバルフェーズのままなのかなと感じている。と言うのも、案件に関するノウハウの共有もできていない部分も多く(バス因子)、スケジュールがカツカツと言うわけではないが、組織で体系的に学習ができているわけでもない。

例えば、デザインであれば今のところ社長がほぼ1人でこなしている。これはバス因子だろう。こういったノウハウやスキルを他のメンバーがみんな学習し始めることで初めて学習フェーズへの移行ができていると言えるのではないだろうか。バス因子のリストアップをするだけでも良いかもしれない。学習フェーズでは生産性が落ちるだろうが、それは仕方のないことなんだろう。

小手先のタスクリストという意味であれば、あとはコミットメント言語をしっかりと使っていくことだろうか。本を読んで感心したのは「バグを明日までに取り除きます」という発言は、約束できる言葉では無いと批判していたこと。ソフトウェアのエンジニアならだいたい今日考えられると思うけれど、バグは大体の場合自分が思っているよりも広範囲に影響を与える物だったり、修正自体は簡単だけれど調査がめちゃくちゃ大変なものが多い。つまり、こう言った場合に利用するコミットメント言語は「少なくとも、1日に5時間はバグの調査を行います。そのために、他のタスクを止められるように調整します」と言うことだ。確かに、そのとおりだなと思った。リーダーがサポートする部分は、コミットメント言語を得ること、そしてそれを実現するためにサポートすることなのだろう。

こうやってこの本を読んで自分のチームを見直すと色々と不十分な部分が目立つ。もちろん、ある側面ではできている部分もあるだろうが、ある側面ではできていない部分もあるのだろう。学習フェーズとサバイバルフェーズの中間くらいにはいるかもしれないが、自己組織化フェーズには至っていないと言ったところだろうか。

DJI Tello のビデオストリーム iOS でデコードする

できあがったものがこちら

github.com

4月の終わりにDJIから発売されたトイドローン、Tello。発売と同時に購入したけど、前評判通りに高い安定性を発揮してくる上、風がなければ屋外でも遊べるので、今までとは違うアングルからの写真撮影が楽しめて面白い。

そんな Tello は今のところスマホWifiで接続をして操作することしかできない。この値段帯のトイドローンならだいたいプロポが付いて来るんだけど、そういうのを削って本体のコストにしたってことなのかな?

あと、一応UDPで通信をするAPIもあるのだけれど、純正アプリと同じことはできない。純正アプリではカメラの画像をリアルタイムにプレビューできるし、前後左右上下の操作以外にもフリップや360度回転、手のひら着地なんかのコマンドを実行できる。一方で公開されているAPIは前後左右上下の操作を行うことしかできない。

そういった部分に不満を覚えつつ、夜な夜なパケットキャプチャしたデータを眺めていたら、すでに同じようなことをしていた人が海外にはいたらしい。go言語で書かれたiot用ライブラリのgobotにtelloの隠しインターフェースが追加されて公開されていた。

Hello, Tello - Hacking Drones With Go

日本版が出る前に公開されたエントリーなので、最初にこのブログをみつければパケットを開くこともなかっただろうな。

このエントリーのサンプルコードを実行するだけで、 mplayer を利用して動画のプレビューをPCから行うことができる。さらに、動画の仕様に関しては次のように書かれていた。

The streaming video is also sent to the ground station on a different UDP port. Unfortunately the Tello does not just use one of the existing standards for streaming video such as RTSP. Instead, the raw video packets are sent via UDP and need to be reassembled and decoded before they can be viewed.

Since the size of a single video frame is larger than the size of a single UDP packet, the Tello breaks apart each frame, and sends the packets with header of 2 bytes to indicate how they need to be reassembled.

Position Usage 0 Sequence number 1 Sub-sequence number 2-n Video data The video data itself is just H264 encoded YUV420p. Using this information, it is possible to decode the video using standard tools such as ffmpeg, once you remove the header bytes.

H264でエンコードされたYUV420pのピクセルデータだけど、いわゆる動画配信用のプロトコルには則っていなくて、生のバイナリをUDPで送っているので適当にデコードする必要があるよ!!って感じ。

H264でエンコードされた動画だったら、ffmpeg + lib264 とかでデコードできそうだなと思ったので、iOS 上でやってみることにした。

コード解説

ffmpeg や libx264 のビルドはすでにビルド用のスクリプトを作ってくれた人がいたので、それを利用した。

github.com

github.com

実際に動画のフレームをデコードする実装の抜粋が以下。

gistb93addb5b78d3a6417df2e7d77412655

コードの全体はこちら

Turkey/ImageDecoder.mm at 430f060486b902ee0f9178b4dc20bdc7de2242e8 · numa08/Turkey · GitHub

ffmpeg にバイナリを与える

利用しているのは ffmpeg , libx264 、そしてさっきの gobot を iOS 用にラップしたライブラリ。gobot は tello が送ってくる動画のバイナリをコールバックで渡してくるので、バイナリを処理する必要がある。アプリ側はバイナリを得ることはできるのだけれど、どうやらffmpegのインターフェースを利用する場合、直接バイナリを渡すには AVIOContext インスタンスを作って、コールバックを利用してバイナリを返す必要があるのだけれど、ちょっと考えることが多くて面倒くさい。

そこで、 NSPipe というAPIを利用することにした。

NSPipe - Foundation | Apple Developer Documentation

Linuxpipe(8)をラップしたAPIで、 pipe の作成、そして書き込みと読み込み用の file descriptor を作ってくれる。また、linux は pipe を作ると pipe:<file descriptor> というファイル名でアクセスをすることができるようになる(これの仕様ってどこに書かれてるんだ?)。この仕組みを利用することにした。

init[NSPipe pipe] を使って NSPipeインスタンスを生成する。 Tello と通信を行い動画のバイナリを取得する onNewFrame: では [self.fifoPipe.fileHandleForWriting writeData:packet]; を行うことで動画のフレームを書き込んでいる。 ffmpeg を利用する captureInFFMpeg では

int fileDescriptor = self.fifoPipe.fileHandleForReading.fileDescriptor;
const char* file = [NSString stringWithFormat:@"pipe:%d", fileDescriptor].UTF8String;
// 中略
ret = avformat_open_input(&format_context, file, input_format, &format_dictionary);

として pipe:<file descriptor> というパスのファイルをパラメータにして ffmpeg に与えている。こうすることでファイルの入力なら簡単にできる ffmpeg にファイルに見せかけたバイナリを渡す仕組みを実現することができた。

正しいバイナリを作る

Tello から取得したバイナリを ffmpeg に与えることができたのであとは ffmpegAPIを使ってデコーダーを実装していく。これはそんなに面白くないので割愛。

しかし、実は Tello から送られてくるバイナリは厳密には動画の生のバイナリではない。実は1つのフレームのバイナリを8個の送信に分割して送ってくる。今回、アプリを作り始めるまで知らなかったのだけれど udp は送信容量に上限がある。

UDPパケットサイズと転送レートの関係:プログラマー社長のブログ:オルタナティブ・ブログ

Ethernetフレームは最大サイズが1518バイトですので、そこから、Ethernetヘッダ(14バイト)とFCS(4バイト)を除いた、1500バイトが送出できる最大サイズになります。IPv4UDPを送出するには、IPv4ヘッダ(20バイト以上)とUDPヘッダ(8バイト)を除き、1472バイト以下がデータサイズになります。

今まで心を無にしてHTTPを触ってきたので、こんな仕様があることを知らなかった。動画のバイナリは 1472 バイトを余裕で超えるので、分割されるというわけ。どうやら8個のパケットに分割されているようなので、8という数字を決め打ちにしてしまって実装を進めることにした。

動画のフレームを受け取るonNewFrame: で、8個分の NSDayaNSArray を作り、マージして書き込みを行う。

[self.packetArray addObject:frame];
if (self.packetArray.count == 8) {
  NSMutableData *packet = [NSMutableData data];
  for (NSData *d in self.packetArray) {
    [packet appendData:d];
  }
[self.fifoPipe.fileHandleForWriting writeData:packet];
self.packetArray = [NSMutableArray array];
}

先頭に正しい動画のフレームを挿入する

ここまで実装をしてどうにか iPhone の画面上に Tello の動画をプレビューすることができた。

そのしばらく後

コードを全く変えていないのに h264 がデコードに失敗するようになった。なんで??なんで??

どうやら、先頭のフレームに含まれているヘッダー情報を正しく読み込むことができなくて失敗しているように思えたので、じゃあ正しい情報を与えてやればいけるのでは・・・?と思い実装。

PCで取得をした Tello の動画のフレームの先頭をプロジェクトに加えて、Telloが動画フレームを返すより前に ffmpeg に渡してやることにした。コードではopenのあたり。

// 正しいフレーム情報をもった動画ファイルを読み込んで、
// avformat_find_stream_info を成功させる
dispatch_async(writeFifoQueue, ^{
        NSString *p = [[NSBundle mainBundle] pathForResource:@"movie" ofType:@"mov"];
        FILE *i_file = fopen(p.UTF8String, "r");
        if (i_file == NULL) {
            NSLog(@"failed fopen");
            return;
        }
        int buffer_size = 10 * 1024;
        char buff[buffer_size];
        size_t size;
        while (true) {
            size = fread(buff, buffer_size, 1, i_file);
            if (size == 0) {
                break;
            }
            write(self.fifoPipe.fileHandleForWriting.fileDescriptor, buff, buffer_size);
        }
});

ちょっとパワーの有る方法だったけどこれで確実に成功するようになった。めでたい!!ちゃんとgcdを利用していたので、変なブロック処理やwaitを挟む必要が無いのも偉い。

感想

iOSシステムコールって読んで良いんだ・・・?

最近、LinuxシステムコールAPIに関する本を読んで勉強し直したところだったのでちゃんと役立てられて嬉しい。

numa08.hateblo.jp

C言語最高!!これで行きていける!!!みたいなことを考えることもなく、それでもswiftとかkotlinとかレイヤーの高いところで生きていきたいのだけれど、とは言え触ることができるっていうのは良いことだと思う。

あと、go言語で書かれたライブラリを利用できたのも良かった。個人的にgo言語は好きな言語で、CLIのツールを作ってgithubのスターを稼いだこともあったけど、しばらくご無沙汰だったため、久しぶりに利用できたことが素直に嬉しい。はじめ、gobotのtello関連のモジュールだけをswiftに移植しようかと考えていたけど、流石に面倒だったのでやめた。gomobile を利用することでiOSAndroid向けのアプリやライブラリをビルドすることができることは知っていたけど試したことはなかったので、良い挑戦だった。と言っても、gobotが依存しているライブラリも少ないためか、特に何もしなくてもそのまま素直にビルドをすることができた。時代はgo言語って感じ。

今後

この手順で最終的に UIImage インスタンスを取得することができたので、例えば Vision framework なんかを利用して自動操縦の自撮りドローンなんかを実装できそうだなーって考えている。

ふつうのLinuxプログラミング 第2版 を読んだ

今年の頭からLinuxAPIシステムコール、libcなんかについてちゃんと勉強をしようという気持ちになったので、それ関連の本を読んでた。

numa08.hateblo.jp

前回読んだ「[試して理解] Linuxのしくみ」という本も良い本で、LinuxというOSがどういう仕組で動いているのかという触りを理解するためにかなり役立った。そこから一歩踏み込んで、ちゃんとLinuxシステムコールやlibcのAPIを使えるようになりたいと思ったので、次の本を読んだ。

実は、第1版が家にあったんだけど(たぶん、奥さんが買った)、利用しているOSにFedora Coreとあったので、内容が古いなと感じたため第2版を購入した。久しぶりにこういう本を読みながら写経をしていたのだけど、やっぱり紙の本が良いなと思ってしまった。

初めてやってみるのにはちょうどいい構成の本だった

あんまりLinuxの基本的な仕組みについては詳しくない自分でも読み進めることができる内容だった。本の構成としてはシステムコールAPIの解説の後に headcat と言ったコマンドを模したプログラムを作る例題がある。そのあとで、少しレベルの上がった練習問題が掲載されている。練習問題の解答はサポートサイトにある。

練習問題の内容は本の内容から見るとちょっと難しいので、自分の理解度に応じて挑戦をしてみるのが良いと思った。実際、自分もちょっと後回しにして本を読むことを優先していった。ただ、最初の方で man コマンドの利用方法や読み方の解説があるので自分で関連するAPIを調べながら進めることができた。

練習問題の内容は多少レベルが高いかもしれないけれど、例題や解説の書き方は非常に親切で分かりやすかった。manページは情報が全て書かれているけど、その分、文章が分かりにくくかったりするので、本の内容を読んでからmanを見ると「あ〜なるほど〜」ってなる。

章の構成はストリームやファイルシステム、シグナルの取扱を一通り学んだあとで最終的にネットワークプログラミングへと進んでいく。ネットワークプログラミングと言っても、TCPのソケット通信を行うくらいでページとしては少ない。そして、最後に総仕上げのおさらいとして、HTTPサーバーの構築を行う。この組み合わせが面白かった。

HTTPサーバーは、ファイルシステム上のファイルの読み込みに加えて、シグナルの取扱やマルチプロセス、ソケット通信を行う必要があることから本の内容のおさらいとしてはぴったりの内容だと感じた。

また、この本を読む前に[試して理解]Linuxのしくみを読んでおくと、登場するAPIシステムコールが何を行っているものなのかという事前知識を持って挑むことができるので、ちょうど良かった。

[試して理解]Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識

[試して理解]Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識

この本を読んだあと

「詳解Unixプログラミング」のような分厚い本に手を出しても良いかもしれないと考えている。その一方で、ここまでで蓄えた知識を使って、なんかのアプリケーションを作ってもいいなーっとも思っている。戯れに、二酸化炭素濃度センサーを購入してみた。

ja.aliexpress.com

せっかく raspberry pi もあるので、 Linux の仕組みの上でこういったセンサー類を利用しやすくする何かを作っても良いかもしれない。