GStreamer 1.0 を PyGI で試してみた。
Seekbar は面倒くさいので付けていない、Play/Pause ボタンのみ。
動画ファイルをドラッグアンドドロップすれば再生できるサンプル。
#!/usr/bin/env python #-*- coding:utf-8 -*- import gi gi.require_version("Gtk", "3.0") gi.require_version("Gst", "1.0") """ GdkX11 @ get_xid() GstVideo @ xvimagesink """ from gi.repository import GObject, Gst, Gtk, Gdk, GdkX11, GstVideo class Player(Gtk.Window): """ Simple DnD Video Player """ def __init__(self): Gtk.Window.__init__(self) self.connect("delete-event", self.on_quit) # Status self.status = Gst.State.NULL # Video Area self.video_area = Gtk.DrawingArea() # Disable Double Buffered self.video_area.set_double_buffered(False) # Play/Pause Button self.button = Gtk.Button.new_with_label("Null") self.button.connect("clicked", self.on_button_clicked) # playbin self.player = Gst.ElementFactory.make("playbin", None) bus = self.player.get_bus() bus.add_signal_watch() bus.enable_sync_message_emission() bus.connect("message", self.on_message) bus.connect("sync-message::element", self.on_sync_message) # 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) # pack vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) vbox.pack_start(self.video_area, True, True, 0) vbox.pack_start(self.button, False, False, 0) self.add(vbox) self.resize(640, 360) self.show_all() def on_drag_data_received(self, widget, drag_context, x, y, data, info, time): uris = data.get_uris() self.player.set_state(Gst.State.NULL) self.player.props.uri = uris[0] self.player.set_state(Gst.State.PLAYING) def on_quit(self, widget, data=None): self.player.set_state(Gst.State.NULL) Gtk.main_quit() def on_sync_message(self, bus, message): if message.get_structure().get_name() == "prepare-window-handle": xid = self.video_area.props.window.get_xid() imagesink = message.src #imagesink.props.force_aspect_ratio = False imagesink.set_window_handle(xid) def on_message(self, bus, message): t = message.type if t == Gst.MessageType.EOS: self.player.set_state(Gst.State.NULL) self.status = Gst.State.NULL self.button.set_label("Null") elif t == Gst.MessageType.ERROR: self.messagebox(message.parse_error()) self.emit("delete-event", None) elif t == Gst.MessageType.STATE_CHANGED: status = message.parse_state_changed()[1] if status == Gst.State.PLAYING: if not self.status == Gst.State.PLAYING: self.status = Gst.State.PLAYING self.button.set_label("Pause") elif status == Gst.State.PAUSED: if not self.status == Gst.State.PAUSED: self.status = Gst.State.PAUSED self.button.set_label("Play") def on_button_clicked(self, widget, data=None): if not self.player.props.uri == "": if self.status == Gst.State.PLAYING: self.player.set_state(Gst.State.PAUSED) elif self.status == Gst.State.PAUSED: self.player.set_state(Gst.State.PLAYING) def messagebox(self, text): dlg = Gtk.MessageDialog( self, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, text) dlg.set_title("Error") r = dlg.run() dlg.destroy() return r if __name__ == "__main__": GObject.threads_init() Gst.init(None) Player() Gtk.main()
GdkX11 は xid を得るのに必要、GstVideo は DrawingArea に貼り付けるのに必要。
つまり音楽プレイヤーを作るなら別にインポートする必要は無い。
以前リンクしたところは GstPipeline に playbin をセットしていた。
けど普通に playbin 自体を GstPipeline として使えるということみたい。
expose_event が無くなったおかげか xid を得るのに一手間がいらなくなった。
アスペクト比を保持させない方法も PyGtk と同じだった。
STATE_CHANGED メッセージで再生中に Gst.State.PLAYING が延々流れてくるのだが…
PyGtk ではこんなだったかな、覚えていないや。
というか PyGtk と Gst 0.10 で作るのと全然変わっていなかったという。
GStreamer のバージョンが上がったメリットは今の私には解らない。
多分そのうち気がつくだろう、多分。
しかし fedora 18 で検索しても皆 GStreamer なんて一言も触れていない。
Nautilus でサムネイルできなくて皆阿鼻叫喚してるかと思ったけど実際の話メインで使っている人がほとんどいないってことなのね。
しかし今日だけで五回もフリーズした、早く安定しないかなぁ。