ClojureとGStreamerで動画再生


はこべにっき#さんの記事を参考に Clojure バージョンを書いてみました。leiningen で作ったプロジェクトの lib ディレクトリに gstreamer と jna の jar を放り込むだけで動作しました。OS は Ubuntu9.10 です。

ミニマムコード

(ns sample_gst.core
  (:import [org.gstreamer Gst]
           [org.gstreamer.elements PlayBin]
           [org.gstreamer.swing VideoComponent]))

(defn -main [& args]
  (Gst/init)
  (let [video-component (VideoComponent.)
        play-bin (doto (PlayBin. "sample")
                   (.setInputFile (java.io.File. (first args)))
                   (.setVideoSink (.getElement video-component)))
        frame (doto (javax.swing.JFrame. "Clojure と GStreamer で動画再生")
                (.setSize 400 300)
                (.add video-component))]
    (.setVisible frame true)
    (.play play-bin)))

slime repl にロードして、

user> (in-ns 'sample_gst.core)
#<Namespace sample_gst.core>
sample_gst.core> (-main "動画ファイル名")

とすると、起動したJFrameの中で動画再生がはじまります。手元にあった mp4 ファイルと flv ファイルで動作することを確認しました。swf はダメでした。
たったこれだけのコードで動画再生アプリが作れるとは感動モノです。これまで触ってきた動画プログラミング環境の中でも一番簡単なんじゃないかなあ。Frameサイズを変更するとアスペクト比を保ったまま動画サイズも変更されます。

ちゃんと停止させる

上のミニマムコードでは、再生中にFrameを閉じても音楽が止まらず最後まで流れてしまいました。次のようにすればFrameと一緒に音楽再生もとまります。

(ns sample_gst.core
  (:import [org.gstreamer Gst]
           [org.gstreamer.elements PlayBin]
           [org.gstreamer.swing VideoComponent]))

(defn -main [& args]
  (Gst/init)
  (let [video-component (VideoComponent.)
        play-bin (doto (PlayBin. "sample")
                   (.setInputFile (java.io.File. (first args)))
                   (.setVideoSink (.getElement video-component)))
        frame (doto (javax.swing.JFrame. "Clojure と GStreamer で動画再生")
                (.setSize 400 300)
                (.add video-component))]
    (.addWindowListener frame
                        (proxy [java.awt.event.WindowAdapter][]
                          (windowClosing [e]
                                         (.stop play-bin))))
    (.setVisible frame true)
    (.play play-bin)))

操作性・拡張性に期待

再生が簡単なだけでなく、データを管理するPlayBin、ビューを司るVideoComponentと責務が割り振られていて色々いじる上でも分かり易そうです。VideoComponent は swing の Componentなので、swing の知識だけでも色々操作できるんじゃないでしょうかね。たとえば AWTUtilities/setWindowOpacity を一行追加するだけで動画を半透明にできました。

動画は最前面で再生しています。背後の文字やミクが透けて見えてます。

追記

VideoPlayer や MediaPlayer というオブジェクトを使うとパイプラインデータ(Bin)を意識せずに動画プレーヤーを操作する感覚でプログラミングができるようです。
MediaPlayer/addMediaListener で MediaListener を登録すると、再生終了時にアクションを起こすといった制御も可能になります。