the mystery of video thumbs

ここのところ Xubuntu の tumblerd がよく落ちる。tumlberd というのはファイルシステムを監視して新しく作られたファイルに対して必要ならサムネイルを生成するデーモンなのだが、これが微妙に不安定で、実際ググってもよく落ちるだの、CPUが100%で張り付くだのという記事ばかりが引っかかる。

よく落ちるのは XFCE 付属のファイルマネージャである thunar も同じで、特に以前 CIFS をマウントしてたときなんかは1日1回固まっていた。なんでそれぞれそんなに出来が悪いのかはよく分からない。サムネイルの場合は対象が外からやってくる得体の知れないデータ列であるので、まあやむを得ないのかなと思わなくもないが。

さて tumblerd が落ちまくる中で気づいたのだが、ファイルマネージャ中の動画のファイルにサムネイルが生成されなくなっているのである。ここで、tumblerd はサムネイル生成を司っているわけだが、実際に生成を行うわけではない。どの mime タイプに対して何をどうするかは /usr/share/thumbnailers/ 以下に(正確には、$XDG_DATA_DIRS のどこかに)収められている ini ファイル的なものに定義されている。そこに記述されたコマンドラインが実際にサムネイルを生成する。なぜそれらを呼び出すだけの元請けである tumblerd が落ちまくるのかはよく分からない。

が、そこを見ても動画のサムネイラーは特に定義されていないのであった。なるほどそれなら生成されないのは当然だ。解決…してない。今まで動画のサムネイルを誰が生成してたんだ? よく分からない。

動画のサムネイルを生成するパッケージというのは ffmpegthumbnailer というものがあるのだが、今のところそれは入っていない。よく分からない。ffmpeg のパッケージ内の何かが上手いこと働いてたのか?

何も分からぬ。何も思い出せぬ。このままでは人間どもを根絶やしにするしかない。

nijiura shift has started! #4

あぷとあぷ小がリニューアルされて塩辛瓶の仕様に近くなったのでそれに合わせて微調整。塩辛瓶のアップローダというのは拙作の Stannum Uploader なのだが、ソースのタイムスタンプを見ると2010年1月18日だそうだ。ほぼ10年前だ。

それまでの塩辛瓶は Sn Uploader をそのまま使ってたんだと思うが、何か忘れたがこれじゃちょっと物足りないねという話になって、その時にドバっと書いて塩辛瓶に独占的に贈呈したのだ。

そういうわけで開発の経緯をもうほとんど覚えていない。久しぶりにざっとソースを眺めてみたけど、もう本当に清々しいほどぜんぜん中身も覚えてない。だめだこりゃ。

nijiura shift has started! #3

スレッドの自動追尾機能を実装した。これは本来の想定ではバックグラウンド側の処理であり、ページを閉じても勝手に追尾したりフロントエンド側では追尾中のスレッドの一覧を操作できたりするといいなあなど思っていたのだが。

まあ、なんというか…大変ですしね。やろうとすると例えばサービスワーカーも動かさないといけないとかなかなか壮大な話になってしまい、つまるところめんどくさいので…そういうわけでフロントエンド側で完結する機能となった。

さて要するに自動リロード機能なのであるが、難しいのはリロード間隔をどう算出するか? という点である。これは直近のレス n を取り出し、次のレスがつくまでの時間を出し、その中央値を取ることにした。その値に、何レスつくまで待つかの値をかけて最終的な待機時間になる。

とこのように内部的にはそこそこ複雑なパラメータが動いているが、要するに勢いのあるスレッドは頻繁に、そうではないスレッドはのんびり更新するようになっている。追尾をオンにすると画像の通り緑色のバーがにゅっと伸びて、縮んでいく。幅が0になって消えたらリロードが行われる。

使ってみると、例えば実況なんかでもいちいちリロードする必要がないので便利といえば便利だが、むしろ適当なスレを開いてる状態で眠さで死にそうな時に布団に入り、覚醒後にスレの行方を確認できるのがよいかもしれない。

その他、全く関係ないが、サイズが大きすぎる画像を添付した際に自動的に jpeg の再圧縮をしていた処理を多段階にした。つまりクオリティ 90% から始まって、2MB に収まるまでだんだんクオリティを下げつつトライするようにした。

その他もろもろ更新。

nijiura shift has started! #2

赤福プラスがふたば内の画像掲示板にオートリンクを施す際、塩辛瓶(という外部アップローダ)とふたば内の他の板の画像に関してはサムネイルを表示するようにしているが、例外的にふたば内のアップローダであるあぷとあぷ小だけはその対象外になっていた。なぜならそれらのアップローダはサムネイルを生成していないからである。

これが気になっていたので、あぷ/あぷ小用のサムネイルサービスを作った。

まずあぷは https://dec.2chan.net/up/src/f99999.??? という感じにファイルが置かれる。あぷ小は https://dec.2chan.net/up2/src/fu99999.??? という感じ。数字部分の桁数は決まってない。拡張子はだいたいにおいて mime タイプにふさわしいものが付けられるが、mht や webp など一部 xxx になってしまって何のファイルか判別しにくいものもある。この意図は不明。

ということを踏まえて、jpg/gif/png のファイルに関して、https://appsweets.net/thumbnail/up/f99999s.png といった感じでここにアクセスすると最大 250×250 に収まるサムネイルが png で返ってくる。つまり元のアップローダの up/up2 と、ファイル名のベース部分を取り出して繋ぎ、それに s.png を付ければいい。

存在しないファイルに対して、あるいはその他のエラーに対してはでっかいばってんマークの画像を http ステータス 200 で返すようになっている。このとき、X-Error-Reason ヘッダにちょっとだけエラーの内容が含まれる。

また、referer ヘッダが存在し、それがふたばのドメインである必要がある。referer が送出されていない、あるいはふたばのドメインでない場合もばってんエラーになる。

ついでにそれぞれのアップローダのインデックスを開いた際にサムネイルを付加するようにした。

nijiura shift has started!

何やら今ふたばではレイアウトを変更しているらしい。では今週末はそれに合わせて虹裏シフトに入ることにしよう。虹裏シフトとは赤福プラスのソースをつらつら眺めたりぼんやりいもげを見ることである。

そんなこんなでいくつかバグを潰した。

動画を添付ファイルとして選択した場合、サムネイルが出なくなっていたのを修正した。従来は取得した動画に対応する video 要素をそのまま canvas#drawImage に与えれば最初のフレームを描画してくれたのだが、そうではなくなったようなので、手動で play() して最初の timeupdate イベントが発生する時点まで待つようにした。

レイアウトの変更に伴って、カタログの表示方法がかなり変更されている。なんと script 要素の中にカタログデータが json で記述されて、ブラウザ側で html に組み立て直すようになっている。へー。それはそれでよいのだが、時々この json が奇妙なことがある。具体的には「表」とか「能」とかの後ろに「\」が入っていることがあるのだ。はいもうお分かりですね。これはとてもプロダクトレベルに達してないな、などと思ってたらカタログだけ従来の形式に戻ったので、管理人さんも認識しているようだ。たぶん。

OSのファイルマネージャからファイルをドロップしようとしてドロップせず、単にブラウザ上をポインタが通過した際にドロップインジケータが出っぱなしになることがあるのを修正した。

添付ファイルを含んだレスの幅が妙になるのを一応修正した。もともとのふたばの画像掲示板では、画像レス中の画像は float:left されていたのでそれを踏襲するわけだが(ちなみに現在のふたばではもう float は使っていない)、これはレスのブロックの幅がその内容にフィットするというデザインと非常に相性が悪い。float 要素を含んだブロック要素の幅がどう自動決定されるかは仕様が規定されているのだが、ざっくり言うとまず float 要素を含まずにレンダリングした際の幅が候補のひとつになり:

それが採られると、こんな感じにみにくいものになる:

本来は、こうなってほしい:

これを CSS だけで解決する方法は思いつかなかった。仕方がないのでページロード後に javascript でごにょごにょするようにした。敗北感を覚える。

thumbnails every 5 seconds

とある動画があったとして、例えば5秒毎にその再生位置の画像を生成したい。

$ ffmpeg -i 01.mp4 -vf fps=12/60 "%03d.jpg"

ffmpeg でこんなふうにすると良いらしい。秒数の指定が逆数になるのが何とも言えない。ところでファイル名は上記のような連番よりも、分-秒.jpg という形のほうがありがたいのだが。どうすれば良いのだろうか。

ググってみると、-strftime 1 というスイッチを付加するとそんな感じのプレースホルダが有効になるのだそうだ。なるほど。きっと基準時間はその時々の再生位置なのだろう素敵だ。

とか思いつつ試してみたところ、基準時間は普通に現在時刻だった。いや、そうじゃないだろ! いや、そうじゃないだろ! 保存時のタイムスタンプが欲しい時に使うためのものなのかな。

これをどうすれば良いのかは調べてもよく分からなかったので、とりあえず連番で出力するようにし、適当なスクリプトでそれをリネームするようにした。

memento of what you did

矩形云々をやると言いつつ、今度は undo/redo 周りに手を付けるライブ感覚。

レイヤーが3枚固定だった頃は、undo の仕組みはかなりシンプルで、リニアなリストに各レイヤー(を png でエンコードした data URL)を保持していた。それを undo マネージャが適宜使用するという memento パターンである。

さてレイヤーの枚数が自由になったので、リストの要素としてレイヤーそのものを直接持つのは容量的に良くなくなった。

そこで、undo リストとレイヤーのデータは管理を別にし、特に後者は版数と参照カウンタを伴ったクラスタとして保持するようにした。そのため undo リスト側では対応する版のレイヤーに対するポインタのみを保持することになる。

ところでひとつ気になるのは、前述の通りレイヤーをエンコードして保持している。これは容量削減のためなのだがエンコードに時間がかかるようだとよくない。ペンでクロスハッチを描く場合なんかは高速かつ大量に undo 情報の追加が行われる。ここで追加がもたつくのは避けたい。

なのでエンコードではなくcanvas要素そのものを保持することも考えられる。実はそのほうが undo 時に非同期的にデコードする処理を挟まなくていい分楽ではある。あるいはハイブリッドに、とりあえずクラスタ内のレイヤーはcanvasで持っといて、利用されないままある程度の時間が経過したら自動的にエンコードするとかにすればいいのかな。それがいいかもしれない。

* * *

data URL ではなく toBlob() で非同期的に blob に変換するようにした。これに伴い undo 情報の追加は数ミリ秒のオーダーになった。これならいいかな。

merge #2

統合と結合の違いについて考えてみる。

前の記事の通り、結合という訳はおかしいのであるが、では統合はどうかと言うとこちらは別に合ってるわけでも合ってないわけでもないどうでもいい感じ。重要なのは、結合と統合は実際に動作が異なるということだ。

それには、まず背景レイヤーと通常のレイヤーの違いを認識しておく必要がある。桃では、背景レイヤーは

  • 常にレイヤーの最奥にある
  • 削除できない
  • 移動できない
  • 不透明度が1ではないピクセルを置けない(これは変えるかもしれない)
  • そのサイズがキャンバス自体のサイズを表している

という扱いになっている。逆に通常レイヤーはサイズと位置が自由で、特に位置とは背景レイヤーに対する相対位置を意味している。

それを踏まえて、まず統合とは全てのレイヤーを背景レイヤー上に合成することだ。この際、各通常レイヤーの、キャンバスサイズからはみ出した部分はすべて切り落とされる。一方で結合は通常レイヤーの大きさと位置が保持される。

ところでPhotoshopやgimpの場合、可視レイヤーの結合が背景レイヤーも含める仕様になっているのだがこれはいいのだろうか。つまり背景レイヤーを含めて全てのレイヤーが可視である状態だと、可視レイヤーの結合と画像の統合に基本的に違いがないのである。

これはちょっと気になったので、桃における可視レイヤーの結合は背景を除外するようにした。

merge

と言いつつ矩形選択よりも先にレイヤーの結合・統合を片付けたい。

この結合・統合というのは、Photoshop 日本語版の用語なのだが、まずこれがおかしい。訳がおかしい。

英語版における “Merge Down” が「レイヤーを結合」、”Merge Visible” が「可視レイヤーを結合」と訳されている。つまり、Merge → 結合ということなのだが。結合という熟語は文字通り複数の何かが結びつきあうことそのものを意味していて、そしてそれ以上の含みはない。結合されるもの同士がどうなるのか、元のままなのか、とか、一度結合したものは元に戻れるのか、という副次的な意味はない。

しかしレイヤーのMergeというのは、それを実行した結果、複数のレイヤーがひとつになって、しかもそれは可逆ではない…というのが最も重要な点だ。味噌とマヨネーズを混ぜ合わせたら、Undo という時間操作魔法以外にもうそれを分離することはできないのと同じだ。こういった視点は、上記の通り、結合という熟語があまり関心を払っていない部分である。すなわち Merge を結合と訳すことにおける決定的なズレがここにある。それでもなお結合という言葉を使うなら、「レイヤーを結合(してひとつにする)」のようにしなければならず、そして括弧内がこのメニュー項目の最も重要なポイントなのだが、あろうことか最も重要な箇所が省略されている。

一方で、結合という言葉を捨てるとすると、例えば融合とか、溶融とか、一体化とか合体とかそんな感じのほうが合っている。いや最も merge の意味を正しく表しているのは実は「まぜまぜ」だ。語感も merge と似ている。「下のレイヤーとまぜまぜ」。

などとつらつらかんがえた結果、結局「結合」のままで行くことにした。

tweak layers #8

レイヤーパレットを作ったことでヘッダからレイヤー関連を一旦削除したが、キャンバス上部にも最低限のレイヤー操作インターフェースがあったほうがいいかなということで追加しなおした。

レイヤーパレット上のサムネイルは、レイヤー全体を対象とするのではなく、透明色を除いた実際の内容部分を対象とするようにした。

次は範囲選択時の演算を作る。