I'm trying to use GStreamer to loop MPEG-4 files smoothly. I want to play the video and audio if there is any and loop the playback. My app uses GTK for UI.
Right now I have three problems:
The video playback is choppy/jerky on the Raspberry Pi 4, I'm running it on. By choppy/jerky, I mean that every ~1-2 seconds, playback freezes for some fraction of a second. When playing the same video in the VLC app, it is smooth.
Audio is not played. Again, when played in VLC, the audio is there as expected. It was my understanding that playbin elements automatically play both audio and video.
When the end of the video is reached, the last frame is frozen for 1-2 seconds before the video starts playing from the first frame again.
I currently have the following code.
video_player.py:
#!/usr/bin/python3
import os
import gi
gi.require_version("Gst", "1.0")
gi.require_version("Gtk", "3.0")
gi.require_version("GstVideo", "1.0")
from gi.repository import Gst, Gtk, GstVideo
class VideoPlayer(Gtk.DrawingArea):
def __init__(self, video_uri: str, loop: bool):
super().__init__()
self.__loop = loop
self.__video_uri = "file:///" + os.path.abspath(video_uri)
self.__xid = None
Gst.init(None)
self.connect("realize", self.__on_realize)
self.set_size_request(1920, 1080) # Hardcoded for this example
self.__playbin = Gst.ElementFactory.make("playbin", "player")
self.__bus = self.__playbin.get_bus()
self.__bus.add_signal_watch()
self.__bus.connect("message::eos", self.__on_video_end)
self.__bus.enable_sync_message_emission()
self.__bus.connect("sync-message::element", self.__on_sync_message)
self.__playbin.set_property("uri", self.__video_uri)
def __on_realize(self, widget: Gtk.Window, data=None) -> None:
window = widget.get_window()
self.__xid = window.get_xid()
def __on_sync_message(self, bus: Gst.Bus, message: Gst.Message) -> None:
if message.get_structure().get_name() == "prepare-window-handle":
image_sink = message.src
image_sink.set_property("force-aspect-ratio", True)
image_sink.set_window_handle(self.__xid)
def __on_video_end(self, bus: Gst.Bus, message: Gst.Message) -> None:
if self.__loop:
self.__playbin.set_state(Gst.State.NULL)
self.__playbin.set_state(Gst.State.PLAYING)
def play(self) -> None:
if self.__playbin.get_state(0).state != Gst.State.PLAYING:
self.__playbin.set_state(Gst.State.PLAYING)
main.py:
#!/usr/bin/python3
from video_player import VideoPlayer
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
window = Gtk.Window()
video_player = VideoPlayer("test_video.mp4", loop=True)
window.add(video_player)
window.fullscreen()
window.show_all()
video_player.play()
Gtk.main()
This answer provides an example that uses VLC; This was accepted by the author of the question (see comments) - GStreamer on Raspberry Pi 4 and other similar SOCs is often times laggy and a soft solution, without starting to modify the Gstreamer library, is probably not going to help the OP.
Please notice that the code has been inspired by https://www.codementor.io/#princerapa/python-media-player-vlc-gtk-favehuy2b but has been modified to accommodate for your needs.
The required change to make the video loop, which is not provided in the aforementioned link is passing the argument '--input-repeat=-1' to the vlcinstance.
Install dependencies (this assumes you already have gtk installed)
pip install python-vlc
Your code:
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
gi.require_version('GdkX11', '3.0')
from gi.repository import GdkX11
import vlc
MRL = "" # File to play
WIDTH = 300
HEIGHT = 300
class ApplicationWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Python-Vlc Media Player")
self.player_paused=False
self.is_player_active = False
self.connect("destroy",Gtk.main_quit)
def show(self):
self.show_all()
def setup_objects_and_events(self):
self.playback_button = Gtk.Button()
self.stop_button = Gtk.Button()
self.play_image = Gtk.Image.new_from_icon_name(
"gtk-media-play",
Gtk.IconSize.MENU
)
self.pause_image = Gtk.Image.new_from_icon_name(
"gtk-media-pause",
Gtk.IconSize.MENU
)
self.stop_image = Gtk.Image.new_from_icon_name(
"gtk-media-stop",
Gtk.IconSize.MENU
)
self.playback_button.set_image(self.play_image)
self.stop_button.set_image(self.stop_image)
self.playback_button.connect("clicked", self.toggle_player_playback)
self.stop_button.connect("clicked", self.stop_player)
self.draw_area = Gtk.DrawingArea()
self.draw_area.set_size_request(WIDTH,HEIGHT)
self.draw_area.connect("realize",self._realized)
self.hbox = Gtk.Box(spacing=6)
self.hbox.pack_start(self.playback_button, True, True, 0)
self.hbox.pack_start(self.stop_button, True, True, 0)
self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.add(self.vbox)
self.vbox.pack_start(self.draw_area, True, True, 0)
self.vbox.pack_start(self.hbox, False, False, 0)
def stop_player(self, widget, data=None):
self.player.stop()
self.is_player_active = False
self.playback_button.set_image(self.play_image)
def toggle_player_playback(self, widget, data=None):
"""
Handler for Player's Playback Button (Play/Pause).
"""
if self.is_player_active == False and self.player_paused == False:
self.player.play()
self.playback_button.set_image(self.pause_image)
self.is_player_active = True
elif self.is_player_active == True and self.player_paused == True:
self.player.play()
self.playback_button.set_image(self.pause_image)
self.player_paused = False
elif self.is_player_active == True and self.player_paused == False:
self.player.pause()
self.playback_button.set_image(self.play_image)
self.player_paused = True
else:
pass
def _realized(self, widget, data=None):
self.vlcInstance = vlc.Instance("--no-xlib", "--input-repeat=-1")
self.player = self.vlcInstance.media_player_new()
win_id = widget.get_window().get_xid()
self.player.set_xwindow(win_id)
self.player.set_mrl(MRL)
self.player.play()
self.playback_button.set_image(self.pause_image)
self.is_player_active = True
if __name__ == '__main__':
if not sys.argv[1:]:
print("Exiting \nMust provide the MRL.")
sys.exit(1)
if len(sys.argv[1:]) == 1:
MRL = sys.argv[1]
window = ApplicationWindow()
window.setup_objects_and_events()
window.show()
Gtk.main()
window.player.stop()
window.vlcInstance.release()
Related
I've battled with the following for a couple of days, and distilled a very compact version of the problem which still shows the issue. The following program shows a basic window, and first opens a FileChooserDialog.
Here's the version which fails - it does not show the Cancel and Accept buttons in the dialog:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib, Gtk
class Script():
def __init__(self, parent, width = 800):
self.parent = parent
def script_file_dialog(self):
fc = Gtk.FileChooserDialog(
parent = self.parent,
title = "title",
action = Gtk.FileChooserAction.OPEN,
do_overwrite_confirmation = True)
fc.add_buttons = ("Cancel", Gtk.ResponseType.CANCEL,
"Open", Gtk.ResponseType.ACCEPT)
return fc
class MainWindow(Gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.connect("destroy", lambda x: Gtk.main_quit())
self.set_default_size(1000, 580)
self.script = Script(self)
fc = self.script.script_file_dialog()
if fc.run() == 1:
print("one")
fc.destroy()
self.show_all()
def on_test_clicked(self, btn):
#~ self.script.on_open_script(btn)
self.script = Script(self)
fc = self.script.script_file_dialog()
if fc.run() == 1:
print("one")
fc.destroy()
def run(self):
Gtk.main()
def main(args):
mainwdw = MainWindow()
mainwdw.run()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
And the following, almost identical version does work as intended.
Note the only difference is when instancing the FileChooserDialog,
the buttons are passed as keyword parameters. This is deprecated, and
produces a warning.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib, Gtk
class Script():
def __init__(self, parent, width = 800):
self.parent = parent
def script_file_dialog(self):
fc = Gtk.FileChooserDialog(
parent = self.parent,
title = "title",
action = Gtk.FileChooserAction.OPEN,
do_overwrite_confirmation = True,
buttons = ("Cancel", Gtk.ResponseType.CANCEL,
"Open", Gtk.ResponseType.ACCEPT))
return fc
class MainWindow(Gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.connect("destroy", lambda x: Gtk.main_quit())
self.set_default_size(1000, 580)
self.script = Script(self)
fc = self.script.script_file_dialog()
if fc.run() == 1:
print("one")
fc.destroy()
self.show_all()
def on_test_clicked(self, btn):
#~ self.script.on_open_script(btn)
self.script = Script(self)
fc = self.script.script_file_dialog()
if fc.run() == 1:
print("one")
fc.destroy()
def run(self):
Gtk.main()
def main(args):
mainwdw = MainWindow()
mainwdw.run()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
I tried delaying the showing of the dialog by triggering it by a button
after the main dialog was shown. What's more, I've used the first pattern
in other programs, and it's working there.
It's probably the stay-at-home rules which are slowly getting me crazy...
Anyone sees the problem?
The first version has a typo:
fc.add_buttons = ("Cancel", Gtk.ResponseType.CANCEL,
"Open", Gtk.ResponseType.ACCEPT)
should be:
fc.add_buttons("Cancel", Gtk.ResponseType.CANCEL,
"Open", Gtk.ResponseType.ACCEPT)
So, I'm using GTK+/VLC to create a window with a video playback area and a "next" button.
It starts by playing the first video file and clicking next button will skip to the next media file, playing it. Everything working great so far.
My problem is, if I wait for MediaPlayerEndReached to be fired, button_Next() is executed but the video does not change.
Am I missing anything?
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
gi.require_version('GdkX11', '3.0')
from gi.repository import GdkX11
import vlc
import time
from os import listdir
from os.path import join
startingPath = './files/'
# ----------------------------------
class MediaWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Media Player")
self.set_decorated(False) # removes titlebar
self.move(300,150)
self.connect("destroy", Gtk.main_quit)
self.currFldrIdx = 0
self.currFileIdx = 0
self.Fldrs = []
for fldrs in sorted(listdir(startingPath)):
self.Fldrs.append(join(startingPath,fldrs))
print self.Fldrs
self.num_Fldrs = len(self.Fldrs)
# vlc
self.vlcInstance = vlc.Instance('--no-xlib')
self.vlcPlayer = self.vlcInstance.media_player_new()
def setup_objects_and_events(self):
self.pause_nextImg = Gtk.Image.new_from_icon_name(
"gtk-media-forward",
Gtk.IconSize.MENU
)
# Buttons
self.button_Next = Gtk.Button()
self.button_Next.set_image(self.pause_nextImg)
self.button_Next.connect("clicked", self.on_button_NextImg)
# Area
self.draw_area = Gtk.DrawingArea()
self.draw_area.set_size_request(800,480)
self.draw_area.connect("realize",self._realized)
# Grid ------------------------------------
self.hbox1 = Gtk.Box()
self.hbox1.pack_start(self.draw_area, True, True, 0)
self.hbox2 = Gtk.Box()
self.hbox2.pack_start(self.button_Next, True, True, 0)
self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.add(self.vbox)
self.vbox.pack_start(self.hbox1, True, True, 0)
self.vbox.pack_start(self.hbox2, False, True, 0)
def on_button_NextImg(self, widget):
print 'next!'
num_FldrFiles = len(listdir(self.Fldrs[self.currFldrIdx]))
self.currFileIdx = self.currFileIdx+1 if self.currFileIdx+1<num_FldrFiles else 0
fileToShow = join(self.Fldrs[self.currFldrIdx], sorted(listdir(self.Fldrs[self.currFldrIdx]))[self.currFileIdx])
print 'now showing' + fileToShow
self.vlcPlayer.set_xwindow(self.win_id)
self.vlcPlayer.set_mrl(fileToShow)
self.vlcPlayer.play()
def _realized(self, widget, data=None):
fileToShow = join(self.Fldrs[self.currFldrIdx], sorted(listdir(self.Fldrs[self.currFldrIdx]))[self.currFileIdx])
self.win_id = widget.get_window().get_xid()
self.vlcPlayer.set_xwindow(self.win_id)
self.vlcPlayer.set_mrl(fileToShow)
self.events = self.vlcPlayer.event_manager()
self.events.event_attach(vlc.EventType.MediaPlayerEndReached, self.EventManager)
self.vlcPlayer.play()
def EventManager(self, event):
if event.type == vlc.EventType.MediaPlayerEndReached:
print "Event reports - finished, playing next"
self.button_Next.clicked()
# ----------------------------------
if __name__ == '__main__':
# Create
win = MediaWindow()
# Setup
win.setup_objects_and_events()
win.show_all()
Gtk.main()
Your problem is described here:
the libvlc API is not reentrant within its callbacks https://forum.videolan.org/viewtopic.php?f=32&t=80305
and here: https://forum.videolan.org/viewtopic.php?t=82502
You should typically have a mainloop in your application (gobject.mainloop(), or Qt mainloop), so you should instead register a method to restart the player from there
This is bit mucked about with for the file names but your code now registers the GObject.idle_add() function that is required.
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
gi.require_version('GdkX11', '3.0')
from gi.repository import GdkX11
import vlc
import time
from os import listdir
from os.path import join
startingPath = './files/'
# ----------------------------------
class MediaWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Media Player")
self.autoPlay = 0
self.set_decorated(False) # removes titlebar
self.move(300,150)
self.connect("destroy", Gtk.main_quit)
self.currFldrIdx = 0
self.currFileIdx = 0
self.Fldrs = ['/home/public/2005.mp3','/home/public/happy.mp3','/home/public/vp.mp3']
#for fldrs in sorted(listdir(startingPath)):
# self.Fldrs.append(join(startingPath,fldrs))
self.num_Fldrs = len(self.Fldrs) - 1
# vlc
self.vlcInstance = vlc.Instance('--no-xlib')
self.vlcPlayer = self.vlcInstance.media_player_new()
def setup_objects_and_events(self):
self.pause_nextImg = Gtk.Image.new_from_icon_name(
"gtk-media-forward",
Gtk.IconSize.MENU
)
# Buttons
self.button_Next = Gtk.Button()
self.button_Next.set_image(self.pause_nextImg)
self.button_Next.connect("clicked", self.on_button_NextImg)
# Area
self.draw_area = Gtk.DrawingArea()
self.draw_area.set_size_request(800,480)
self.draw_area.connect("realize",self._realized)
# Grid ------------------------------------
self.hbox1 = Gtk.Box()
self.hbox1.pack_start(self.draw_area, True, True, 0)
self.hbox2 = Gtk.Box()
self.hbox2.pack_start(self.button_Next, True, True, 0)
self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.add(self.vbox)
self.vbox.pack_start(self.hbox1, True, True, 0)
self.vbox.pack_start(self.hbox2, False, True, 0)
def on_button_NextImg(self, widget=None):
self.currFileIdx += 1
if self.currFileIdx > self.num_Fldrs:
self.currFileIdx = 0
fileToShow = self.Fldrs[self.currFileIdx]
media = self.vlcInstance.media_new_path(fileToShow)
self.vlcPlayer.set_media(media)
if self.vlcPlayer.play() == -1:
print ("error playing",fileToShow)
else:
print("now playing",fileToShow)
def _realized(self, widget, data=None):
fileToShow = self.Fldrs[self.currFldrIdx]
self.win_id = widget.get_window().get_xid()
self.vlcPlayer.set_xwindow(self.win_id)
self.vlcPlayer.set_mrl(fileToShow)
self.events = self.vlcPlayer.event_manager()
self.events.event_attach(vlc.EventType.MediaPlayerEndReached, self.EventManager)
self.vlcPlayer.play()
def EventManager(self, event):
if event.type == vlc.EventType.MediaPlayerEndReached:
GObject.idle_add(self.on_button_NextImg)
# ----------------------------------
if __name__ == '__main__':
# Create
win = MediaWindow()
# Setup
win.setup_objects_and_events()
win.show_all()
Gtk.main()
So I have the following code (python 2.7) that checks for a combination of keypresses and shows/hides a gtk window with a few gtk entry boxes. The show/hide works until the window locks up and stops responding, and the inner part of the window turns black. I have to kill the process and start it up again once that window turns black. I've tried all different combinations of show_all() and returning True after hiding the window to no avail. I'm not sure what I'm doing wrong here.
In the end I'd like to be able to press this key combination and show/hide this window without the contents going away.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
import pyxhook
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Configurator")
self.box = Gtk.Box(spacing=6)
self.add(self.box)
self.ipEntry = Gtk.Entry()
self.ipEntry.set_text("IP Address")
self.maskEntry = Gtk.Entry()
self.maskEntry.set_text("NetMask")
self.gatewayEntry = Gtk.Entry()
self.gatewayEntry.set_text("gatewayEntry")
self.button1 = Gtk.Button(label="Save")
self.button1.connect("clicked", self.on_button1_clicked)
self.box.pack_start(self.ipEntry, True, True, 0)
self.box.pack_start(self.maskEntry, True, True, 0)
self.box.pack_start(self.gatewayEntry, True, True, 0)
self.box.pack_start(self.button1, True, True, 0)
#catch window destroy event and stop it from happening
self.connect('delete-event', self.on_destroy)
def on_button1_clicked(self, widget):
print("Hello")
def on_destroy(self, widget=None, *data):
print("tried to destroy")
self.hide()
return True
#list of ascii keypresses to test if a certain combination of keys is pressed
keypresses = []
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
win.set_keep_above(True)
def OnKeyboardEvent(event):
#ascii 227 is l_control, ascii 225 is l_shift, ascii 120 is x
#bring the following external variables into the scope of this function
global keypresses
global win
#check if gtk window is hidden or visible
isVisible = win.get_property("visible")
#store our keypress if it is worthy of being stored (we started with a control character)
if event.Ascii == 227 or ( len(keypresses) >= 1 and keypresses[0] == 227 ):
print("here" + str(len(keypresses)))
keypresses.append(event.Ascii)
#check if we have three items in keypresses to compare, then see if it's the right combination
if len(keypresses) == 3 and keypresses[0] == 227 and keypresses[1] == 225 and keypresses[2] == 120:
#show/hide our window
if isVisible:
win.hide()
del keypresses[:]
keypresses = []
else:
win.show_all()
#clear out our list to compare again
del keypresses[:]
keypresses = []
elif len(keypresses) >= 3:
del keypresses[:]
keypresses = []
#create instance of hook manager
HookManager = pyxhook.HookManager()
#define our callback to fire when a key is pressed
HookManager.KeyDown = OnKeyboardEvent
#hook the keyboard
HookManager.HookKeyboard()
#start our listener
HookManager.start()
Gtk.main()
#close the hook listener when gtk main loop exits
HookManager.cancel()
Here is a small hack that tests the window show/hide when pressing F5. When you press it a second window will show or hide and i've tested for sometime without problems. Maybe it's the HookManager that somehow is messing with the Gtk/Glib mainloop. Nonetheless my method only works if there is a window to grab the key presses, so you will need, indeed, some form of grabbing key presses if your goal is to have no GUI:
#!/usr/bin/python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
#import pyxhook
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Configurator")
self.box = Gtk.Box(spacing=6)
self.add(self.box)
self.ipEntry = Gtk.Entry()
self.ipEntry.set_text("IP Address")
self.maskEntry = Gtk.Entry()
self.maskEntry.set_text("NetMask")
self.gatewayEntry = Gtk.Entry()
self.gatewayEntry.set_text("gatewayEntry")
self.button1 = Gtk.Button(label="Save")
self.button1.connect("clicked", self.on_button1_clicked)
self.box.pack_start(self.ipEntry, True, True, 0)
self.box.pack_start(self.maskEntry, True, True, 0)
self.box.pack_start(self.gatewayEntry, True, True, 0)
self.box.pack_start(self.button1, True, True, 0)
#catch window destroy event and stop it from happening
self.connect('delete-event', self.on_destroy)
self.connect('key-press-event', self.on_keypress)
def on_keypress(self, widget, event):
global w
if event.keyval == Gdk.KEY_F5:
isVisible = w.get_property("visible")
if (isVisible):
w.hide()
else:
w.show()
print("Keypress")
def on_button1_clicked(self, widget):
print("Hello")
def on_destroy(self, widget=None, *data):
print("tried to destroy")
self.hide()
return False
w = MyWindow()
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
win.set_keep_above(True)
Gtk.main()
I have looked at this tutorial,http://lzone.de/media+player+with+gstreamer+and+pygi, on how to stream audio from the web using Gtk3 and Gstreamer. I have working code minus the ability for actual music to be played. I need help, I'm new to making apps, but I think the issues stems from self.player.set_property('uri', self.uri) not doing its magic to fetch the music from the url self.uri = 'http://mp3channels.webradio.antenne.de/chillout'
Here is my source:
import sys, os, pygtk
import gi
gi.require_version('Gst', '1.0')
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gtk
from gi.repository import Gst
GObject.threads_init()
Gst.init(None)
class PlaybackInterface():
def __init__(self):
self.playing = False
# A free example sound track
self.uri = 'http://mp3channels.webradio.antenne.de/chillout'
# GTK window and widgets
self.window = Gtk.Window()
self.window.set_size_request(300,50)
vbox = Gtk.Box(Gtk.Orientation.HORIZONTAL, 0)
vbox.set_margin_top(3)
vbox.set_margin_bottom(3)
self.window.add(vbox)
self.playButtonImage = Gtk.Image()
self.playButtonImage.set_from_stock("gtk-media-play", Gtk.IconSize.BUTTON)
self.playButton = Gtk.Button.new()
self.playButton.add(self.playButtonImage)
self.playButton.connect("clicked", self.playToggled)
Gtk.Box.pack_start(vbox, self.playButton, False, False, 0)
self.slider = Gtk.HScale()
self.slider.set_margin_left(6)
self.slider.set_margin_right(6)
self.slider.set_draw_value(False)
self.slider.set_range(0, 100)
self.slider.set_increments(1, 10)
Gtk.Box.pack_start(vbox, self.slider, True, True, 0)
self.label = Gtk.Label(label='0:00')
self.label.set_margin_left(6)
self.label.set_margin_right(6)
Gtk.Box.pack_start(vbox, self.label, False, False, 0)
self.window.show_all()
# GStreamer Setup
self.player = Gst.ElementFactory.make('playbin', None)
self.player.set_property('uri', self.uri)
# Set properties
# bus = self.player.get_bus()
# bus.connect("message", self.on_message)
# self.player.connect("about-to-finish", self.on_finished)
def on_message(self, bus, message):
t = message.type
if t == Gst.Message.EOS:
self.player.set_state(Gst.State.NULL)
self.playing = False
elif t == Gst.Message.ERROR:
self.player.set_state(Gst.State.NULL)
err, debug = message.parse_error()
print "Error: %s" % err, debug
self.playing = False
self.updateButtons()
def on_finished(self, player):
self.playing = False
self.slider.set_value(0)
self.label.set_text("0:00")
self.updateButtons()
def play(self):
self.player.set_state(Gst.State.PLAYING)
GObject.timeout_add(1000, self.updateSlider)
def stop(self):
self.player.set_state(Gst.State.NULL)
def playToggled(self, w):
self.slider.set_value(0)
self.label.set_text("0:00")
if(self.playing == False):
self.play()
else:
self.stop()
self.playing=not(self.playing)
self.updateButtons()
def updateSlider(self):
if(self.playing == False):
return False # cancel timeout
try:
if self.IS_GST010:
nanosecs = self.player.query_position(Gst.Format.TIME)[2]
duration_nanosecs = self.player.query_duration(Gst.Format.TIME)[2]
else:
nanosecs = self.player.query_position(Gst.Format.TIME)[1]
duration_nanosecs = self.player.query_duration(Gst.Format.TIME)[1]
# block seek handler so we don't seek when we set_value()
# self.slider.handler_block_by_func(self.on_slider_change)
duration = float(duration_nanosecs) / Gst.SECOND
position = float(nanosecs) / Gst.SECOND
self.slider.set_range(0, duration)
self.slider.set_value(position)
self.label.set_text ("%d" % (position / 60) + ":%02d" % (position % 60))
except Exception as e:
# pipeline must not be ready and does not know position
print e
pass
return True
def updateButtons(self):
if(self.playing == False):
self.playButtonImage.set_from_stock("gtk-media-play", Gtk.IconSize.BUTTON)
else:
self.playButtonImage.set_from_stock("gtk-media-stop", Gtk.IconSize.BUTTON)
player = PlaybackInterface()
Gtk.main()
Gstreamer has a lot of dependencies. Peep the link https://raw.githubusercontent.com/Psychtoolbox-3/Psychtoolbox-3/beta/Psychtoolbox/PsychDocumentation/GStreamer.m. I uploaded working code on my Github account (At least on my machine) that will play and stop an audio stream from an http source. https://github.com/jchiefelk/musicplayer
I made this Python script:
from gi.repository import Gtk, Gdk, GdkX11, Wnck
from subprocess import PIPE, Popen
class WindowError(Exception):
pass
def undecorate(aWindow):
gdkdis = GdkX11.X11Display.get_default()
gdkwin = GdkX11.X11Window.foreign_new_for_display(gdkdis, aWindow.get_xid())
gdkwin.set_decorations(Gdk.WMDecoration.BORDER)
def dropdown(aTitle):
Gtk.main_iteration()
screen = Wnck.Screen.get_default()
screen.force_update()
for window in screen.get_windows():
if window.get_name() == aTitle:
timestamp = Gtk.get_current_event_time()
undecorate(window)
window.set_skip_pager(True)
window.set_skip_tasklist(True)
window.stick()
window.pin()
window.maximize_horizontally()
window.set_geometry(Wnck.WindowGravity.STATIC,
Wnck.WindowMoveResizeMask.Y,
0, 0, -1, -1)
window.activate(timestamp)
window.unminimize(timestamp)
break
else:
raise WindowError('Window with title "{}" not found'.format(aTitle))
def getActive():
Gtk.main_iteration()
screen = Wnck.Screen.get_default()
screen.force_update()
return screen.get_active_window()
def main():
active = getActive()
if active.get_name() == 'Dropdown Terminal':
if active.is_minimized():
dropdown('Dropdown Terminal')
else:
active.minimize()
return
else:
try:
dropdown('Dropdown Terminal')
except WindowError:
Popen(['roxterm', '--profile=Dropdown'], stdout=PIPE, stderr=PIPE)
dropdown('Dropdown Terminal')
if __name__ == "__main__":
main()
What it does is it makes roxterm act like Guake. The only problem I have with it is when I Popen a new roxterm instance and move the window to (0,0) right after, the final y-position of the window is a few visible pixels down. I used the set_geometry function in the wnck library to do this. Any ideas on how to fix it? Thanks.
Oops, forgot to mention that I solved this issue. I changed some stuff in the code, but I think using GdkWindow to reposition instead of Wnck fixed the positioning problem. This version keeps the dropdown terminal open until the hotkey is pressed again. BTW, I mapped the hotkey to this script by adding a custom hotkey in Gnome's keyboard preferences.
from gi.repository import Gtk, Gdk, GdkX11, Wnck
from subprocess import PIPE, Popen
class WindowError(Exception):
pass
def getScreen():
Gtk.main_iteration()
screen = Wnck.Screen.get_default()
screen.force_update()
return screen
def getGDKWindow(aWindow):
gdkdisplay = GdkX11.X11Display.get_default()
gdkwindow = GdkX11.X11Window.foreign_new_for_display(gdkdisplay, aWindow.get_xid())
return gdkwindow
def getWindow(aTitle):
screen = getScreen()
active = screen.get_active_window()
if active.get_name() == aTitle:
return active
for window in screen.get_windows():
if window.get_name() == aTitle:
return window
return None
def adjust(aWindow):
gdkwindow = getGDKWindow(aWindow)
gdkwindow.set_decorations(Gdk.WMDecoration.BORDER)
gdkwindow.move(0,0)
aWindow.set_skip_pager(True)
aWindow.set_skip_tasklist(True)
aWindow.maximize_horizontally()
aWindow.stick()
aWindow.make_above()
def onWindowOpen(aScreen, aWindow, aData):
if aWindow.get_name() == aData:
adjust(aWindow)
Gtk.main_quit()
def main():
timestamp = Gtk.get_current_event_time()
window = getWindow('Dropdown Terminal')
if window:
if window.is_minimized():
window.activate(timestamp)
window.unminimize(timestamp)
else:
window.minimize()
else:
Popen(['roxterm', '--separate', '--profile=Dropdown', '--directory=.'])
getScreen().connect('window-opened', onWindowOpen, 'Dropdown Terminal')
Gtk.main()
if __name__ == "__main__":
main()