Python with GTK+ 3 Gst

そろそろ Y901x の GTK+ 3 化の準備。
gi.repository に Gst があるからコチラを使えばいいのかな。

GStreamer Application Development Manual (0.10.35.1)

0.10 だから別に変わっていないんだが PyGtk と同じには書けないし。
前回 Drag & Drop をやったので DnD されたファイルを再生できるのみを。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
import gi
try:
    gi.require_version("Gtk", "3.0")
except:
    print "This Program is GTK+ 3.0 or later."
    sys.exit()

from gi.repository import Gst, Gtk, Gio, Gdk

class Win(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        # DnD
        dnd_list = Gtk.TargetEntry.new("text/uri-list", 0, 0)
        self.drag_dest_set(
                Gtk.DestDefaults.MOTION |
                Gtk.DestDefaults.HIGHLIGHT |
                Gtk.DestDefaults.DROP,
                [dnd_list],
                Gdk.DragAction.MOVE )
        self.drag_dest_add_uri_targets()
        self.connect("drag-data-received", self.on_drag_data_received)
        # Gst
        Gst.init(sys.argv)
        self.player = Gst.ElementFactory.make("playbin2", "player")
        # self
        self.set_title("movie player")
        self.show_all()

    def on_drag_data_received(self, widget, drag_context, x, y, data, info, time):
        uris = data.get_uris()
        self.player.set_property("uri", uris[0])
        self.player.set_state(Gst.State.PLAYING)

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(
                self,
                application_id="apps.test.gst",
                flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.connect("activate", self.on_activate)
        
    def on_activate(self, application, user_data=None):
        Gdk.threads_init()
        w = Win()
        w.set_application(self)

if __name__ == "__main__":
    app = App()
    app.run(sys.argv)

これで動画なら別ウインドウが出て再生できるだけのアプリ完成。
ほとんど変わっていなかった、けどやはり Gst.init() で初期化が必要になる。
PyGtk が親切すぎただけなんですけど。

しかし肝心なシグナルのハンドラで困った。

Bus

bus.add_watch なんてアトリビュートは無いんだが…
しかたがないから一番下の書き方をしてもエラーだし…

#bus.connect("message::state-changed", self.gst_on_message) # Error
bus.connect("message", self.gst_on_message)

#####

def gst_on_message(self, bus, message):
    print message # all messages are None

以前の手段では全部 None になってしまう…

python – GStreamer bus sends None message – Stack Overflow

わーい、同じことで詰まっている人を見つけた。
ってどうすりゃいいんだ…
ヤケクソだ、PyGI じゃない以前の gst を使ってやる。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
import gi
try:
    gi.require_version("Gtk", "3.0")
except:
    print "This Program is GTK+ 3.0 or later."
    sys.exit()

from gi.repository import Gtk, Gio, Gdk
import gst

class Win(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        # DnD
        dnd_list = Gtk.TargetEntry.new("text/uri-list", 0, 0)
        self.drag_dest_set(
                Gtk.DestDefaults.MOTION |
                Gtk.DestDefaults.HIGHLIGHT |
                Gtk.DestDefaults.DROP,
                [dnd_list],
                Gdk.DragAction.MOVE )
        self.drag_dest_add_uri_targets()
        self.connect("drag-data-received", self.on_drag_data_received)
        # old Gst
        self.player = gst.element_factory_make("playbin2", "player")
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.enable_sync_message_emission()
        bus.connect("message", self.gst_on_message)
        # self
        self.set_title("movie player")
        self.show_all()

    def on_drag_data_received(self, widget, drag_context, x, y, data, info, time):
        uris = data.get_uris()
        self.player.set_property("uri", uris[0])
        self.player.set_state(gst.STATE_PLAYING)

    def gst_on_message(self, bus, message, user_data=None):
        print message # OK

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(
                self,
                application_id="apps.test.gst",
                flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.connect("activate", self.on_activate)
        
    def on_activate(self, application, user_data=None):
        Gdk.threads_init()
        w = Win()
        w.set_application(self)

if __name__ == "__main__":
    app = App()
    app.run(sys.argv)

よし、コレなら問題ない。
しかしこの GStreamer バインディングを今後も残してくれるのだろうか?
やはり PyGI を使ったほうがいいよな…
もう少し勉強します。