|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import time
import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Gst", "1.0")
from gi.repository import Gst, Gtk, GLib
class GenericException(Exception):
pass
class Handler:
def on_window_destroy(self, *args):
Gtk.main_quit()
def on_playpause_togglebutton_toggled(self, widget):
if app.playpause_button.get_active():
img = Gtk.Image.new_from_icon_name(Gtk.STOCK_MEDIA_PLAY,
Gtk.IconSize.BUTTON)
widget.set_property("image", img)
app.pause()
else:
img = Gtk.Image.new_from_icon_name(Gtk.STOCK_MEDIA_PAUSE,
Gtk.IconSize.BUTTON)
widget.set_property("image", img)
app.play()
def on_forward_clicked(self, widget):
app.skip_time()
def on_backward_clicked(self, widget):
app.skip_time(-1)
def on_progress_value_changed(self, widget):
app.on_slider_seek
def on_vbutton_clicked(self, widget):
app.clear_playbin()
app.setup_player("mediaplayer.avi")
if app.playpause_button.get_active() is True:
app.playpause_button.set_active(False)
else:
app.play()
def on_ibutton_clicked(self, widget):
app.clear_playbin()
app.setup_player("mediaplayer.jpg")
app.pause()
class GstPlayer:
def __init__(self):
# init GStreamer
Gst.init(None)
# setting up builder
builder = Gtk.Builder()
builder.add_from_file("23_gtksink_player.glade")
builder.connect_signals(Handler())
#self.movie_window = builder.get_object("play_here")
self.playpause_button = builder.get_object("playpause_togglebutton")
self.slider = builder.get_object("progress")
self.slider_handler_id = self.slider.connect("value-changed", self.on_slider_seek)
# setting up videoplayer
self.player = Gst.ElementFactory.make("playbin", "player")
self.sink = Gst.ElementFactory.make("gtksink")
# setting up media widget
video_widget = self.sink.get_property("widget")
builder.get_object("video_box").add(video_widget)
window = builder.get_object("window")
window.show_all()
def setup_player(self, f):
# file to play must be transmitted as uri
uri = "file://" + os.path.abspath(f)
self.player.set_property("uri", uri)
self.player.set_property("video-sink", self.sink)
def play(self):
self.is_playing = True
self.player.set_state(Gst.State.PLAYING)
# starting up a timer to check on the current playback value
GLib.timeout_add(1000, self.update_slider)
def pause(self):
self.is_playing = False
self.player.set_state(Gst.State.PAUSED)
def current_position(self):
status,position = self.player.query_position(Gst.Format.TIME)
return position
def skip_time(self, direction=1):
# skip 20 seconds on forward/backward button
app.player.seek_simple(Gst.Format.TIME,
Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
self.current_position() + float(20) * Gst.SECOND * direction,
)
def update_slider(self):
if not self.is_playing:
return False # cancel timeout
else:
success, self.duration = self.player.query_duration(Gst.Format.TIME)
# adjust duration and position relative to absolute scale of 100
self.mult = 100 / (self.duration / Gst.SECOND)
if not success:
raise GenericException("Couldn't fetch duration")
# fetching the position, in nanosecs
success, position = self.player.query_position(Gst.Format.TIME)
if not success:
raise GenericException("Couldn't fetch current position to update slider")
# block seek handler so we don't seek when we set_value()
self.slider.handler_block(self.slider_handler_id)
self.slider.set_value(float(position) / Gst.SECOND * self.mult)
self.slider.handler_unblock(self.slider_handler_id)
return True # continue calling every x milliseconds
def on_slider_seek(self, widget):
seek_time = app.slider.get_value()
self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, seek_time * Gst.SECOND / self.mult)
def clear_playbin(self):
try:
self.player.set_state(Gst.State.NULL)
except:
pass
def main(self):
Gtk.main()
app = GstPlayer()
app.main()
|