Write and Run

it's a simple way, but the only way.

WASIを叩くWASMを手書きしてLucetでHello, world!する

WASI がなんだとか WASM がなんだとかは詳しく説明しません。各位やって。

まず Lucet を入れる。

github.com

はい

Hello, world! するには fd_write があればよさそう。

wasmtime/WASI-api.md at master · CraneStation/wasmtime · GitHub

引数はだいたい見りゃわかる。が、__wasi_ciovec_t っつーのが引っかかる。

とはいえこれも見りゃわかる。

wasmtime/WASI-api.md at master · CraneStation/wasmtime · GitHub

バッファへのポインタとバッファの長さを持ってる構造体。

で、fd_write にはそいつのポインタを渡してやればいいということがわかる。

というところまでわかったら WAT を書く。S 式。

(module
  (import "wasi_unstable" "fd_write" (func $__wasi_fd_write (param i32 i32 i32 i32) (result i32)))
  (func $_start
    i32.const 1
    i32.const 16
    i32.const 13
    i32.const 24
    call $__wasi_fd_write
    drop)
  (memory 1)
  (data (i32.const 0) "Hello, world!\00\00\00\00\00\00\00\0d\00\00\00")
  (export "_start" (func $_start)))

import ってやつでリンクをやってて、data でメモリの初期値を埋めてる。export はエントリポイントの公開。

で、data に埋まってる初期値が大切で、ここに

"Hello, world!"(13bytes) + padding[0x00 0x00 0x00](3bytes) + buf address[0x00 0x00 0x00 0x00] (4bytes = i32) + buf length[0x0d 0x00 0x00 0x00](4bytes = i32)

が埋まっている。

buf address と buf length ってのが __wasi_ciovec_t の中身。

ので、スタックに

1  ;; stdout の fd
16 ;; buf address へのアドレス
13 ;; "Hello, world!" のバイト数。buf length とは別にこれも必要らしい
24 ;; `nwritten` へのアドレスっぽい。戻り値はスタックに返ってくるんじゃねーのかよ(スタックにも返ってくるんだよな)

というかんじで積んでやって、call $__wasi_fd_write してやる。

最後、スタックに nwritten と思しき値が残ってしまうのでそいつを drop で消し飛ばせば完了。

hello.wat みたいな名前で保存してやって、以下のように実行できる。

lucetc-wasi -o hello.so hello.wat
lucet-wasi hello.so

楽しいね

デカいテレビとXbox One Xを買ってランボルギーニを乗り回す

f:id:koba789:20181216034813j:image

はい

 

サイバーマンデーにそそのかされてデカいテレビを買いました。

2018年も暮れなので、4K HDR な OLED です。ナウい

サイズは65インチ。デカい。

なお部屋は8畳1K。狭い。

 

で、テレビだけ買っても 4K HDR コンテンツを吐ける箱がなけりゃ意味なかろうということで、Xbox One X という箱を買いました。

Forza Motorsport 7 と Forza Horizon 4 というブーブーゲームが付いてるモデル。

 

私が暮らしている恵比寿(正確には違うが)という街は大変イカれた場所で、昼飯を食いに外に出るだけでランボルギーニを眺められるようなシティなのですが、デカいテレビと箱があるとなんと外に出ずとも部屋でランボルギーニを運転できます。

はえらい。

 

冒頭の画像はランボルギーニラカンで崖から飛び降りる瞬間を写したもの。

ゲームの世界では一軒家並みの値段の車で紐なしバンジーしても無料。

はえらい。

 

私は人間を歩かせたり武器を構えて何かを射るようなゲームが苦手なのですが、Forza は人間を歩かせたり武器を構えて何かを射たりということがないので助かっています。

 

ちなみに据え置きのゲーム機を手に入れるのはこれがやっと2台目で、ちなみに1台目は2ヶ月前に中古で買った Wii です。

携帯ゲーム機はというと DSi をバイト先の忘年会のビンゴ大会で当てたのが最後。

ゲーム機ってゲームできてすごいですね。

 

現実世界に置いてあるテレビの方は、現在こたつの上に曖昧に乗せてあるだけという状態で邪魔だしデカいしデカいし邪魔なので、いろいろして壁掛けにする算段です。

これもいい感じにシュッとしたら記事にしたい。

 

なお、テレビの登場によって今まで使っていたプロジェクターは失職となりました。

WXGA のくせに今までよく頑張ったと思います。解像度はともかくとしてランプがクソ明るかったのはよかった。

 

最後は崖からゴロゴロと転がってボコボコになり、リアスポイラーがバイバイしてしまった WRX STI で締めようと思います。

f:id:koba789:20181216040808j:image

ちなみに耳も取れてる👂

OBS Studioで使えるHDMIキャプチャを5000円で手に入れる

ヤァヤァ、KOBA789 であるぞ。

今回はおもしろハードウェア活用術のご紹介です。

安い HDMI キャプチャデバイスが欲しい

欲しい。欲しいじゃないですか。

ゲームにしろカメラの映像にしろ、なんらかの映像をオンラインで生配信したいと思ったとき、真っ先に必要になる機材が HDMI キャプチャデバイスです。
日常的にパソコンやってると USB Audio IF とか、ウェブカムとか、そういうのは案外持ってるもんですが、HDMI キャプチャは持ってないがち。

しかし HDMI キャプチャデバイスというのはあまり一般的なデバイスではないので案外高い。
いくら安くても1万は切れないことが多くて、まぁ2〜3万は覚悟が必要になるわけです。

映像ソースが1本しかないのであれば、まぁ買い切りだし1個くらい買ってもいいか、となるもんですが、これが2本、3本となると話は別です。
ちょっときつい。
ロスレスなんて言わないから、なんなら60fpsも諦めるから、安いやつが欲しい、そういうケースはあります。

たとえば勉強会の配信とか。
スライドなんて数十秒に1回しか切り替わらんし、演台の人間もほとんど動かないので60fpsは要らない。
大したディティールも要らんのでキャプチャデバイスロスレスだろうとロッシーだろうと、配信を見てる人にはほとんど差がわからない。

あと、登壇者のマシンとカメラが離れてるとか、そういうこともあって映像を数十メールくらい伝送する必要があったりします。
20m の HDMI のケーブルとか結構いいお値段するし、太くて取り回しはだるいし、かといって安いケーブルだと信号がロスってちゃんと伝送できないこともあります。

こういう願いを全部叶えてくれる、ナイスなデバイスないかな〜〜と思ってたら、あったんです。

LKV373

自称「120m HDMI extender over CAT5/5e/6」
自称というか、ちゃんと HDMI 延長器として銘を受けて生まれてきたデバイスです。本来は送信側と受信側をペアにして使います。

ただこのデバイス、over CAT5/5/6 とか言いながら、実は LAN ケーブルに律儀に IP を流しています。
中に流れているパケットの正体は細切れになった JPEG の断片を含む独自プロトコルUDP のパケットなので、受信側を外して代わりに一般的な NIC を搭載したコンピュータを繋ぐと映像を容易に受信することができます。
nJPEG に圧縮されているので原理的にはロッシーですが、言うほど劣化は目立たなくて、許せるレベル。

当然 CAT5 とかのいわゆるふつーの LAN ケーブルを使えるわけので、数十メール伝送するくらい楽勝ですし、ケーブルも安いしどこでも買える。

詳しいことはこの記事に書いてあるので、興味のある人はぜひ。

Reverse engineering Lenkeng HDMI over IP extender | danman's blog

一般的な NIC で容易に受信可能とはいえ、中身は独自のプロトコルなので、既存のソフトウェアにそのまま食わせることはできません。
生配信用のデファクトスタンダードである OBS Studio なんかに食わせられると最高なんですが、もうひと手間必要です。

OBS Studio 用のプラグインを書く

OBS Studio にはプラグイン機構があり、仕様に沿った動的リンクライブラリを用意してやると機能を拡張することができます。
拡張できる機能にもエンコーダとか映像入力とか、いくらか種類があります。

今回は映像を入力したいので、Source という機能を持つプラグインを実装しました。

実装の方法は至って簡単で、 libobs/obs-module.h というヘッダファイルのインターフェースに従って必要な関数を実装、export するだけです。
だいたいのことはこのページを読めばわかります。

Plugins — OBS Studio 20.1.0 documentation

普通なら実装言語は当然C言語ですが、2018年も末になって新規でC言語を書きたくなかったので、Rust で書くことにしました。

Rust は C++ などと同様、C言語の呼び出し規約と互換性のある動的リンクライブラリを生成することができるので、better C として使うことができます。

まずは libobs とリンクする必要があるため、Rust のビルドシステムである cargo に、libobs のビルドシステムを組み込んでやる必要があります。
libobs はビルドシステムとして cmake を利用しているのですが、cmake という crate を使うとシュッと連携させることができます。ほんと便利。
さらに、バインディングは頑張って手で書かなくても bindgen という crate を使うことでヘッダファイルから自動生成できます。マジで優秀。
というわけで、だいたい全部自動で準備が整います。

動画の JPEG フレームをデコードするため、同様の方法で、libjpeg-turbo もリンクしてやります。
Pure Rust な実装の JPEG デコーダもあるのですが、インターフェースの兼ね合いなどもあって断念しました。
libjpeg-turbo は SIMD 命令などを活用することで JPEG の高速な圧縮と伸張ができるライブラリです。
このライブラリを選んだ一番の理由は、出力形式として libobs と互換性のある BGRX フォーマットが使えたことです。
ピクセルエンディアンJPEG デコーダと libobs でズレていると、毎フレームごとにフォーマットを揃える必要があり、実行速度上のペナルティが大きくなります。
動画のフレームのデコードは速度が命なので、これはとても大切でした。

で、できあがったものがこちらです。

github.com

今は macOS でしかビルドを確認していませんが、ちょっと編集すれば Linux でもビルドできるんではないかと思っています。

使い方

  1. ビルドできたライブラリを、OBS Studio のプラグインディレクトリに入れる
  2. PC に NIC を刺す
  3. NIC の IP アドレスを 192.168.168.0/24 のうちの任意に設定
  4. OBS を起動
  5. 入力ソースとして "LENKENG" を追加
  6. Interface Address に3で設定した IP アドレスを設定
  7. たぶんこの時点では動かないので OBS を再起動
  8. 動く

7 でちゃんと動かないのは、俺が実装をサボったからです。 誰か source_info.update をちゃんと実装して Pull Request を投げてください。

おわり

2018年に個人でウェブサービスを開発するときの気持ち

  • (ウェブ系の)最近の技術のトレンドは組織のスケールにフォーカスしている気がする
  • 企業などのデカい開発組織で開発をするための技術(ツールや方法論)が充実してきた
  • 従来は企業での開発もあまり規模が大きくなかったので、個人での開発と同じような技術を利用していた気がする
  • 今では企業と個人では開発の規模に大きな隔たりがある気がする(昔も当然あったが、それはどんどん拡大している)
  • 規模が違うと適切な方法論やツールも違う
  • たとえばマイクロサービス化
  • 個人の規模でやっても不幸になりがち
  • サービスを分割したからといって自分以外のだれかがパラレルで開発をやってくれるわけではない
  • 運用・管理コストが自分に跳ね返ってくるだけ
  • シングルスレッド CPU でたくさんスレッド走らせたときの不毛さに近い
  • コンテナ技術とかもそう
  • デカい組織での便利な使い方と、個人での便利な使い方は違う
  • うっかり個人で企業の真似すると不幸
  • いずれにせよ便利な技術だけど、適切な使い方は違う
  • kubernetes とかもむずかしい
  • そもそも運用だるいがち
  • 組織だと運用コストよりスケーラビリティのメリットのほうが大きいかもしれない
  • 個人だとだいたい運用コストのほうがでかい(運用してるけどやはりつらい。家に帰った後の時間で面倒見られる規模じゃないと思う)
  • でも kubernetes 前提の便利ツールとかはたくさんある
  • 便利ツール使いたい
  • 個人開発でもコミュニティの恩恵を受けたい
  • でも無理
  • 以上、お気持ち