現代のWebで、今もっとも「古典的な」技術、HTTP Clock 。
HTTP Clockを支える技術 ACT.1 、HTTP Clockを支える技術 ACT.2 、では、主に「HTMLをストリーミングする」ことで、時計を描画する方法を記述してきました。
どれも「HTMLが」ストリーミングされ、「じわじわと」描画されることに依存しています。
我々にとって、HTMLをストリーミングすることで時計が作れることは、もはや当たり前であり、面白くありません。
更には、ACT.2 の <select>
を使ったバージョンでは、Safariで表示出来ない問題を発生させてしまいました。
今回は、HTMLストリーミングを使わない方法を考えてみましょう。
HTTP Clockの使える他の手段 ¶
さて、他に「面白い」手段はないでしょうか…。
ブラウザに対して、ストリーミングする方法……。
WebSocketとか…? ¶
WebSocket は…HTTPとは言い難いですね。
同様の理由で、WebTransport 、WebRTC も没です。
HTTP Clockではなくなってしまいます…。
Server-Sent Events も… JavaScriptに依存するため没ですね…。
動画ストリーミング形式は… ¶
MPEG-DASH や HTTP Live Streaming なども考えられますが、JavaScript無し文脈では、ブラウザの互換性問題が発生するでしょう…。
画像形式は……? ¶
Motion JPEG (RFC2435 )…!!!!
と思いましたが、これによってストリーミングできても特に面白くないですね。実際、多くの監視カメラ製品などが、Motion JPEGでストリーミングしてきますしね。
毎フレームJPEG圧縮しなければなりませんし、サーバー負荷も気になります…。
H.264 などは、もはや論外ですね…。
全クライアントに画面全体を書き換える差分を送る設計であるHTTP Clockでは、フレーム間差分を活かしたコーデックが効果を発揮しづらくなってしまいます。
あ!!! アニメーションGIF (GIF89a + Graphics Control Extension)…!!!!
アニメーションGIF ¶
皆さん知ってる、いわゆるGIFアニメですね!
注釈1: 正確には NetScape Navigator が GIF89a に Graphics Control Extension を付加したものですが、その正確な成り立ちについては本稿では触れません。
注釈2: GIF (LZW) は特許問題をかつて (~2004年まで) 孕んでいましたが、私が2才の頃の話なので、知ったことではありません。
注釈3: なぜその背景を知っているかについては、私は個人的に幼少期に画像エディタDibas32 1.04 (1997/05/31)を愛用しており、GIF を特許問題によりサポートしていなかった為です。
ストリーミングできるんですか? ¶
はい!HTMLと違って、受信しながら表示できることが期待できるのです!
GIFはふるーーい規格です。時は1987年。人類が未だ「アナログモデム」による「パソコン通信」をしていた時代。「常時接続」の「ブロードバンドインターネット」が普及する前から存在した訳です。
当時の遅い通信路では、画像のダウンロードに何秒もかかり、表示されるまでが長いと、イライラする訳です。
そのため、受信しながら「じわじわと」表示する機能があるのです。特に、インターレース GIF は「じわじわと」表示しないと、意味を成しませんからね。
ここまで読んでいただいた皆さんなら、時刻のストリーミングにも使えそうだと思ったはずです…!
注釈1: 「常時接続」とは、現代のインターネットでは当たり前ですが、当時は通信路が「電話」に依存しており、必要なときにのみ接続する形だったのです。
注釈2: 「ブロードバンドインターネット」とは、電話線に依らない、ADSLや光通信など、比較的高速なインターネット接続のことを指します。
注釈3: 光回線以前、コンピューターの通信は「電話線」に依存していました。現代でも電話線を用いたダイヤルアップ接続を体験したい方は、グレーの公衆電話に対応機器を持ち込むのが簡単です。グレーの公衆電話も既に絶滅危惧種なので、滑り込むなら今がチャンスです。
注釈4: 「パソコン通信」とは「TCP/IP」に依らない 1:1 のコンピューター同士の直接の通信を指します。かつて、「IPアドレス」なんてものは無くても「電話番号」で通信できたのです。
アニメーションGIFってどういう構造? ¶
おおよそ、以下のような構造をしています。
[GIFヘッダー]
`- ファイルヘッダー
[Graphics Control Extension]
`- 画像拡張情報 (次フレームまでの遅延時間など)
[Image]
`- 画像ヘッダー + 画像
[Graphics Control Extension (N枚目)]
[Image (N枚目)]
[Trailer]
GIFヘッダー部に解像度など、大凡の形式が記述されます。
その後、フレーム情報が続くわけです。
特に、Graphic Control Extension部が重要で、次のフレームまでの遅延時間を記述することでフレームレートを決定しています。
また、幸いなことに、全体のフレーム数上限もGIF形式上存在しないみたいです。
これなら際限なく、時刻をストリーミングできそうです!とってもうれしい!
参考文献:
- GIF: Summary from the Encyclopedia of Graphics File Formats
- とほほのGIFフォーマット入門 - とほほのWWW入門
- GIF画像ファイル フォーマット - 略して仮。
- Cover Sheet for the GIF89a Specification
結局毎フレームエンコードしなきゃじゃない? ¶
実際のところ、これを作るまで私もそう思っていました。
驚くべきことに、アニメーションGIFは、高度なレイヤー構造を持っていたのです…!
そう、先程のフレームは全てレイヤーとして扱われていたのです…!
GIFのレイヤー構造? ¶
レイヤー機能つき画像編集ソフトウェアを思い浮かべてみてください。
キャンバスとレイヤーがありますね?それです。
GIFヘッダーがキャンバスに、フレームがレイヤーに相当するわけです。
フレームは、レイヤーと同様、サイズと位置、それぞれを持っています。
GIFのレイヤー構造はなんのために? ¶
例えば、キャラクターが瞬きするアニメーションを考えてみましょう。
まず、1フレーム目にキャラクターが目を開いた画像を置いて…。 2フレーム目には、キャラクターが目を閉じた画像を置いて…。
でも良いのですが、これでは容量が大きくなってしまいます。
そこで2フレーム目には「閉じた目だけ」を置き、1フレーム目に重ね合わせることで、アニメーションを作れるのです!
便利ですねー!
レイヤー構造のHTTP Clockへの応用 ¶
HTTP Clockの用途を思い出すと、単色塗りつぶしの背景画像と、数字と記号の各桁の画像と、を重ねるだけで良いということになりますね。 (SVG Editionに近いです。)
つまり、それらを起動時に圧縮し、必要になったときにレイヤー位置情報付きで送信すればよいのです。
これなら配送時に圧縮処理は必要はありません!
GIFヘッダー部を送信
黒塗りレイヤーを表示遅延ほぼゼロで送信
1900-01-01
09:00:00 を表示遅延ほぼゼロでそれぞれ送信
#### 1秒サボタージュ ####
黒塗りレイヤーを表示遅延ほぼゼロで送信
1900-01-01
09:00:01 を表示遅延ほぼゼロでそれぞれ送信
#### 1秒サボタージュ ####
...
の繰り返しで行けそうです…!
それが作れるGIFエンコーダーあるの? ¶
ない!(私調べ。)
ので作り、mygif と言うモジュールに切り出しました。(述べ450行くらいです。)
自分が使うExtensionのみをサポートしています。
実装は binrw
と bitfield_struct
によって作られています。
(とても黒魔術的にバイナリを扱えるクレートなので、オススメです!)
HTTP Clock - Banner ¶
というわけ (様々な罠にハマった苦労略) で、バナーが出来たわけです!
やったー!
現代GIFレンダラーの思わぬ罠たち ¶
なんかもう処理系依存すぎて何も面白くないので詳細は解説しません…。
私は、原因がわかるまで何度かふて寝しました。
気になったらHTTP Clock内にある mygif を元にGIFを作ってみるなり、GIFエンコーダー自作するなりして試してみてください…!
- Pixel Aspect Ratioは ffplay や VLC 以外まともに描画されない。
- LZW の Minimum Code Size (1 ~ 8 bit) は 8 bit でなければ正しく描画しないクライアントがいる
- 画像の色深度 (1 ~ 8 bit) が、8 bitでなければ正しく描画しないクライアントがいる
- フレームの遅延時間 (センチ秒単位) が 0cs, 1cs だと正常に扱われず、10csと扱われる。 (2csは期待通りに動く。)
HTTP Clockのバナー描画が違う!? ¶
Chromium系 と Firefox系, Safari系 とで描画結果が異なります!
気になる方はぜひ両方のブラウザを入れて、挙動を観察してみてください!
(仕様書を読む限りではChromium系の描画が正しそうな気がしています。)
次回? ¶
やる気が出たときにでも HTTP Clockとその周辺ソフトウェアとの互換性の話を書くかも知れません。
お楽しみに…?