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 でサムネイルできなくて皆阿鼻叫喚してるかと思ったけど実際の話メインで使っている人がほとんどいないってことなのね。
しかし今日だけで五回もフリーズした、早く安定しないかなぁ。