2023-08-12

image-converterで動画ファイルを開いたときに固まるのを避ける

先日の設定でEmacsから動画系のファイルも画像として扱えるようになったのですが、実際にimage-modeで開こうとすると膨大な時間がかかることが分かりました。

気が付いたきっかけは@yoyaさんのこのツイート。

実際にimage-modeでビデオファイルを表示させようとしたところ確かにEmacsが固まりました。巨大なビデオファイルの場合はそもそもEmacsがファイルを読み込む段階で止まっているようでしたが、小さめなビデオファイルの場合は裏でffmpegが何やらテンポラリディレクトリにmagick-で始まるファイルを生成していてそれにかなり時間がかかっているようでした。小さめなものであればそのうち終わります。

しかしimage-diredでサムネイルを生成する場合にはそれほど時間がかかりません。巨大なビデオファイルでも大丈夫です。基本的にdiredからビデオファイルを開くときは外部のプレイヤーを起動するようになっていて、あくまでサムネイルを生成するために動画系のファイルに対応しただけなので気が付きませんでした。image-modeで表示しようとするとダメでサムネイル生成は大丈夫。両者は何が違うのでしょうか。

実際に実行されるコマンドを元に調査したところ、入力ファイル名の後に [0] があるかどうかで変わることが分かりました。

magick convert video.mp4 jpg:image.jpg
magick convert video.mp4[0] jpg:image.jpg

おそらく入力を指定する段階で最初の1枚目だけと限定されているので問題を回避できるのでしょう。ImageMagickは沢山の形式に対応していますから、おそらく入力は形式毎にモジュール化されていて、入力モジュールには必要なフレームに関する情報が引き渡されず、かといって読み込みを必要になるまで遅延するような仕組みも無いため全て読み込むしかない、といったところではないでしょうか。

image-diredの方はこの問題に気が付いたのかちゃんと対策をしてくれていますが、image-converterの方は対策されていません。まぁ、動画なんて開くなよ、ということなのかもしれません。

とは言え、一応次のようなコードで無理矢理入力ファイルの末尾に [0] を付けるようにしたところ問題は解消しました。

;; image-converterがImageMagickで動画ファイルを変換するときに長時間
;; 固まるのを避ける。
;; 全フレーム読み込もうとしてしまうのだとか!
(defun my-image-converter--convert-magick (old-fun type source image-format)
  ;; ファイル名の後に[0]をつける。data形式の場合は未対応。
  (unless image-format
    (setq source (concat source "[0]")))
  (funcall old-fun type source image-format))

(advice-add 'image-converter--convert-magick :around
            'my-image-converter--convert-magick)