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
Related
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()
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()
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.uic import loadUiType
import youtube_dl
import pafy
import urllib.request
import urllib.parse
from urllib.parse import *
import win32clipboard
import sys
import os
import humanize
import subprocess
import time
import shutil
import re
from pySmartDL import SmartDL
from os.path import splitext, basename
from os import path
Close = False
ShutDown = False
Sleep = False
Restart = False
Paused = False
Stopped = False
Start = True
Resume = True
if getattr(sys, 'frozen', False):
# frozen
dir_ = os.path.dirname(sys.executable)
else:
# unfrozen
dir_ = os.path.dirname(os.path.realpath(__file__))
FORM_CLASS, _ = loadUiType(path.join(dir_, "main.ui"))
class MainApp(QMainWindow, FORM_CLASS):
def __init__(self, parent=None):
super(MainApp, self).__init__(parent)
QMainWindow.__init__(self)
self.setupUi(self)
self.lineEdit.installEventFilter(self)
self.lineEdit_3.installEventFilter(self)
self.lineEdit_6.installEventFilter(self)
self.Handle_Ui()
self.Handle_Buttons()
def closeEvent(self, evnt):
if self._want_to_close:
super(MainApp, self).closeEvent(evnt)
sys.exit()
def Handle_Ui(self):
#self.lineEdit.setFocus()
self.setFixedSize(861,441)
def Handle_Buttons(self):
self.pushButton_3.clicked.connect(self.open_file_loction)
self.pushButton_2.clicked.connect(self.Start)
self.pushButton_13.clicked.connect(self.Pause)
self.pushButton_14.clicked.connect(self.Stop)
self.pushButton.clicked.connect(self.Handle_Browse)
self.pushButton_4.clicked.connect(self.Download_youtube_video)
self.pushButton_10.clicked.connect(self.get_quality)
self.pushButton_5.clicked.connect(self.Browse2)
self.pushButton_6.clicked.connect(self.open_file_location2)
self.pushButton_11.clicked.connect(self.Search_Qualities)
self.pushButton_7.clicked.connect(self.Browse3)
self.pushButton_9.clicked.connect(self.download_playlist)
self.pushButton_8.clicked.connect(self.open_file_location3)
self.pushButton_12.clicked.connect(self.open_video)
self.comboBox_2.currentIndexChanged.connect(self.Action_Happened)
self.comboBox_3.currentIndexChanged.connect(self.Action_Happened)
self.comboBox_4.currentIndexChanged.connect(self.Action_Happened)
def Start(self):
global Start
global Stopped
global Paused
Start = True
Stopped = False
Paused = False
self.Download()
def Pause(self):
global Paused
global Start
global Resume
if self.pushButton_13.text()=="Pause Downloading":
Paused = True
Start = False
Stopped = False
Resume = False
self.pushButton_13.setText("Resume Downloading")
QApplication.processEvents()
elif self.pushButton_13.text()=="Resume Downloading":
Start = True
Paused = False
Resume = True
Stopped = False
self.pushButton_13.setText("Pause Downloading")
QApplication.processEvents()
def Stop(self):
global Stopped
global Start
Stopped = True
Start = False
Paused = False
self.Download()
def Download(self):
directory = os.path.expanduser("~") + "\AppData\Local\Temp\pySmartDL"
if not os.path.exists(directory):
os.makedirs(directory)
try:
global Paused
global Stopped
global Start
global XX
url = self.lineEdit.text()
save_location = self.lineEdit_2.text()
obj = SmartDL(url, progress_bar=False)
if Start == True:
try:
obj.start(blocking=False)
while True:
self.progressBar.setValue(obj.get_progress()*100)
self.label_8.setText("Downloaded: " + str(obj.get_dl_size(human=True)))
self.label_38.setText("Speed: " + str(obj.get_speed(human=True)))
self.label_39.setText("Remaining Time: " + str(obj.get_eta(human=True)))
time.sleep(0.2)
QApplication.processEvents()
if Paused == True:
obj.pause()
QApplication.processEvents()
if Resume == True:
obj.unpause()
QApplication.processEvents()
if obj.isFinished():
break
if Stopped == True:
obj.stop()
self.progressBar.setValue(0)
break
if obj.isSuccessful():
#os.rename(obj.get_dest(), save_location)
shutil.move(obj.get_dest(), save_location)
if Close == True:
QApplication.quit()
elif ShutDown == True:
os.system('shutdown -s')
elif Sleep == True:
os.system("rundll32.exe powrprof.dll,SetSuspendState 0,1,0")
elif Restart == True:
subprocess.call(["shutdown", "/r"])
if Stopped == False:
QMessageBox.information(self, "Download Completed", "Your Download is Completed")
except:
QMessageBox.warning(self, "Download Error", "Download Failed")
pass
except Exception as e:
pass
def main():
app = QApplication(sys.argv)
window = MainApp()
window.show()
app.exec_()
if __name__ == '__main__':
main()
I've been looking around for help on how to Apply Qthread on the above piece of code to update the progress Bar Dynamically with no "Not Responding problem"
I've read many topics and I could understand the main concept of Qthread but still can't get the idea on how to Apply it to my Code taking in consideration that download function is connected with a download button not running infinitely.
should I make a sub Qthread class or what can I do ?
If You Can help me with an example on how to use it with the above piece of code and I will Apply it on the remaining code of my Gui App..
Thanks in advance.
When implementing a QThread the task to be performed should be done in the run () method, if you want to update the GUI with data provided by the thread should not be done directly but through signals since the GUI should only be updated in the main thread called by this the GUI thread.
class DownloadThread(QThread):
dataChanged = pyqtSignal(int, str, str, str)
Started, Paused, Resume, Stopped = range(4)
downloadError = pyqtSignal()
downloadFinished = pyqtSignal()
def __init__(self, parent=None):
QThread.__init__(self, parent)
self.state = DownloadThread.Stopped
self.params = {"url": "", "save_location": ""}
def setParams(self, params):
self.params = params
def setState(self, state):
self.state = state
def run(self):
obj = SmartDL(self.params["url"], progress_bar=False)
try:
obj.start(blocking=False)
while True:
self.dataChanged.emit(obj.get_progress() * 100,
str(obj.get_dl_size(human=True)),
str(obj.get_speed(human=True)),
str(obj.get_eta(human=True)))
time.sleep(0.2)
if self.state == DownloadThread.Paused:
obj.pause()
if self.state == DownloadThread.Resume:
obj.unpause()
self.state = DownloadThread.Started
if obj.isFinished():
break
if self.state == DownloadThread.Stopped:
obj.stop()
self.progressBar.setValue(0)
break
if obj.isSuccessful():
# os.rename(obj.get_dest(), save_location)
shutil.move(obj.get_dest(), self.params["save_location"])
if self.state == DownloadThread.Started:
self.downloadFinished.emit()
except:
self.downloadError.emit()
You should avoid using global variables in addition that you can reduce several variables that are all updated at once by only one variable so I had to modify the GUI code.
class MainApp(QMainWindow, FORM_CLASS):
def __init__(self, parent=None):
# ...
self.Handle_Buttons()
self.download = DownloadThread(self)
self.download.dataChanged.connect(self.onDataChanged)
self.download.downloadError.connect(self.errorDownload)
self.download.downloadFinished.connect(self.successfulDownload)
def closeEvent(self, evnt):
# ...
def Handle_Ui(self):
# self.lineEdit.setFocus()
self.setFixedSize(861, 441)
def Handle_Buttons(self):
# ...
def onDataChanged(self, progress, downloaded, speed, remain):
self.progressBar.setValue(progress)
self.label_8.setText("Downloaded: " + downloaded)
self.label_38.setText("Speed: " + speed)
self.label_39.setText("Remaining Time: " + remain)
def Start(self):
directory = os.path.expanduser("~") + "\AppData\Local\Temp\pySmartDL"
if not os.path.exists(directory):
os.makedirs(directory)
params = {"url": self.lineEdit.text(),
"save_location": self.lineEdit_2.text()}
self.download.setParams(params)
self.download.setState(DownloadThread.Started)
self.download.start()
def Pause(self):
if self.pushButton_13.text() == "Pause Downloading":
self.download.setState(DownloadThread.Paused)
self.pushButton_13.setText("Resume Downloading")
elif self.pushButton_13.text() == "Resume Downloading":
self.download.setState(DownloadThread.Resume)
self.pushButton_13.setText("Pause Downloading")
def Stop(self):
self.download.setState(DownloadThread.Stopped)
self.progressBar.setValue(0)
def errorDownload(self):
QMessageBox.warning(self, "Download Error", "Download Failed")
def successfulDownload(self):
QMessageBox.information(self, "Download Completed", "Your Download is Completed")
I'm trying to create a rather unusual program that needs video to play smoothly from one clip to the next, without blinking. At this point, at the end of the stream, I change the path to the next clip and set it to playing again. This works well, except for a small blink in between, which is not optimal.
I'm figuring I can get rid of this by creating a transition between the video clips. But, as GStreamer tutorials for Python are lacking...how do I do this?
I'm using Python 2.7, PyGTK 2.24, and GStreamer.
Here is my current code:
import pygtk
pygtk.require('2.0')
import gtk, pango
import pygst
pygst.require('0.10')
import gst
import Trailcrest
import os, sys
class Video:
def __init__(self):
def on_message(bus, message):
if message.type == gst.MESSAGE_EOS:
# End of Stream
player.set_state(gst.STATE_NULL)
player.set_property("uri", "file://" + os.getcwd() + "/VID/BGA-AMB-HABT-001.ogv")
player.set_state(gst.STATE_PLAYING)
elif message.type == gst.MESSAGE_ERROR:
player.set_state(gst.STATE_NULL)
(err, debug) = message.parse_error()
print "Error: %s" % err, debug
def on_sync_message(bus, message):
if message.structure is None:
return False
if message.structure.get_name() == "prepare-xwindow-id":
gtk.gdk.threads_enter()
gtk.gdk.display_get_default().sync()
win_id = videowidget.window.xid
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
imagesink.set_xwindow_id(win_id)
gtk.gdk.threads_leave()
win = gtk.Window()
win.set_resizable(False)
win.set_has_frame(False)
win.set_position(gtk.WIN_POS_CENTER)
fixed = gtk.Fixed()
win.add(fixed)
fixed.show()
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size("IMG/IMG-AMB-HABT-001.png", 640, 480)
pixbuf = pixbuf.scale_simple(640, 480, gtk.gdk.INTERP_BILINEAR)
pixmap, mask = pixbuf.render_pixmap_and_mask()
img = gtk.Image()
img.set_from_pixmap(pixmap, mask)
fixed.put(img, 0, 0)
img.show()
videowidget = gtk.DrawingArea()
fixed.put(videowidget, 0, 0)
videowidget.set_size_request(640, 480)
videowidget.show()
# Setup GStreamer
player = gst.element_factory_make("playbin", "MultimediaPlayer")
bus = player.get_bus()
bus.add_signal_watch()
bus.enable_sync_message_emission()
#used to get messages that GStreamer emits
bus.connect("message", on_message)
#used for connecting video to your application
bus.connect("sync-message::element", on_sync_message)
player.set_property("uri", "file://" + os.getcwd() + "/VID/BGA-AMB-HABT-001.ogv")
player.set_state(gst.STATE_PLAYING)
win.show()
def main():
gtk.gdk.threads_init()
gtk.main()
return 0
if __name__ == "__main__":
Video()
main()
I'm working with PyQt and trying to get video from a webcam to play within a QT widget. I've found tutorials for C and Qt, and for python and gtk, but NOTHING for this combo of pyQt and gstreamer. Anybody get this working?
This plays the video fine, but in a separate window:
self.gcam = gst.parse_launch('v4l2src device=/dev/video0 ! autovideosink')
self.gcam.set_state(gst.STATE_PLAYING)
what I need is to get the overlay working so it's displayed within a widget on my GUI. Thanks, Gurus of the internet!
ok, so I've gotten a lot farther, but still in need of some help. I'm actually writing this for Maemo, but the following code works fine on my linux laptop:
class Vid:
def __init__(self, windowId):
self.player = gst.Pipeline("player")
self.source = gst.element_factory_make("v4l2src", "vsource")
self.sink = gst.element_factory_make("autovideosink", "outsink")
self.source.set_property("device", "/dev/video0")
self.scaler = gst.element_factory_make("videoscale", "vscale")
self.window_id = None
self.windowId = windowId
self.player.add(self.source, self.scaler, self.sink)
gst.element_link_many(self.source,self.scaler, self.sink)
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)
def on_message(self, bus, message):
t = message.type
if t == gst.MESSAGE_EOS:
self.player.set_state(gst.STATE_NULL)
elif t == gst.MESSAGE_ERROR:
err, debug = message.parse_error()
print "Error: %s" % err, debug
self.player.set_state(gst.STATE_NULL)
def on_sync_message(self, bus, message):
if message.structure is None:
return
message_name = message.structure.get_name()
if message_name == "prepare-xwindow-id":
win_id = self.windowId
assert win_id
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
imagesink.set_xwindow_id(win_id)
def startPrev(self):
self.player.set_state(gst.STATE_PLAYING)
print "should be playing"
vidStream = Vid(wId)
vidStream.startPrev()
where wId is the window id of the widget im trying to get to display the output in. When I run this on the N900, the screen goes black and blinks. Any ideas? I'm dying here!
EDIT: I've been asked to post the full code, and though I still need to clean it up a bit, here's the relevant part:
self.cameraWindow = QtGui.QWidget(self)
self.cameraWindow.setGeometry(QtCore.QRect(530, 20, 256, 192))
self.cameraWindow.setObjectName("cameraWindow")
self.cameraWindow.setAttribute(0, 1); # AA_ImmediateWidgetCreation == 0
self.cameraWindow.setAttribute(3, 1); # AA_NativeWindow == 3
global wId
wId = self.cameraWindow.winId()
self.camera = Vid(wId)
self.camera.startPrev()
class Vid:
def __init__(self, windowId):
self.player = gst.Pipeline("player")
self.source = gst.element_factory_make("v4l2src", "vsource")
self.sink = gst.element_factory_make("autovideosink", "outsink")
self.source.set_property("device", "/dev/video0")
#self.scaler = gst.element_factory_make("videoscale", "vscale")
self.fvidscale = gst.element_factory_make("videoscale", "fvidscale")
self.fvidscale_cap = gst.element_factory_make("capsfilter", "fvidscale_cap")
self.fvidscale_cap.set_property('caps', gst.caps_from_string('video/x-raw-yuv, width=256, height=192'))
self.window_id = None
self.windowId = windowId
print windowId
self.player.add(self.source, self.fvidscale, self.fvidscale_cap, self.sink)
gst.element_link_many(self.source,self.fvidscale, self.fvidscale_cap, self.sink)
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)
def on_message(self, bus, message):
t = message.type
if t == gst.MESSAGE_EOS:
self.player.set_state(gst.STATE_NULL)
elif t == gst.MESSAGE_ERROR:
err, debug = message.parse_error()
print "Error: %s" % err, debug
self.player.set_state(gst.STATE_NULL)
def on_sync_message(self, bus, message):
if message.structure is None:
return
message_name = message.structure.get_name()
if message_name == "prepare-xwindow-id":
win_id = self.windowId
assert win_id
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
imagesink.set_xwindow_id(win_id)
def startPrev(self):
self.player.set_state(gst.STATE_PLAYING)
def pausePrev(self):
self.player.set_state(gst.STATE_NULL)
This is piecing together a few bits, and I can't test it right now, but maybe it will be helpful to someone. Good luck!
If you're happening to use PySide instead of PyQt on a platform other than Linux, winId() returns a PyCObject which can't be used directly with native functions or other modules. In my case this came in handy when using GStreamer (pygst) with PySide on Microsoft Windows:
from ctypes import pythonapi, c_void_p, py_object
...
if message_name == 'prepare-xwindow-id':
# convert winId from PyCObject to void pointer
pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
hWnd = pythonapi.PyCObject_AsVoidPtr(self.videoWidget.winId())
# set window handle to video sink
self.videoSink.set_xwindow_id(hWnd)
Got it! It appears I needed to force the resolution of the pipeline to match the resolution of the widget where I was pumping the video to:
self.fvidscale_cap = gst.element_factory_make("capsfilter", "fvidscale_cap")
self.fvidscale_cap.set_property('caps', gst.caps_from_string('video/x-raw-yuv, width=256, height=192'))
Then just add those to the pipeline like the other elements, and it works great. Man, it seems so easy looking at it now, but when I was pounding my head against the wall for a few days it wasn't so obvious...
Ptterb can you post your full code please?
I copied your code.
Added fvidscale_cap to pipeline, with:
self.player.add(self.source, self.scaler, self.fvidscale_cap, self.sink)
gst.element_link_many(self.source,self.scaler, self.fvidscale_cap, self.sink)
From the main program I create a new QWidget, and pass its winId() to Vid constructor.
The widget start loading, but crashes.
The output says:
should be playing
Segmentation fault
The pasted code is not showing gobject loading, which cannot be dismissed.
It took me a good while to figure out what was missing. Thanks Jun for having
a working audio example.
import gobject, pygst
pygst.require('0.10')
import gst
from PyQt4.QtGui import QMainWindow, QWidget, QApplication
import sys
class Video(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
container = QWidget()
self.setCentralWidget(container)
self.windowId = container.winId()
self.setGeometry(300,300,640,480)
self.show()
def setUpGst(self):
self.player = gst.Pipeline("player")
source = gst.element_factory_make("v4l2src", "vsource")
sink = gst.element_factory_make("xvimagesink", "sink")
fvidscale_cap = gst.element_factory_make("capsfilter", "fvidscale_cap")
fvidscale = gst.element_factory_make("videoscale", "fvidscale")
caps = gst.caps_from_string('video/x-raw-yuv')
fvidscale_cap.set_property('caps', caps)
source.set_property("device", "/dev/video0")
self.player.add(source, fvidscale, fvidscale_cap, sink)
gst.element_link_many(source,fvidscale, fvidscale_cap, sink)
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)
def on_message(self, bus, message):
t = message.type
if t == gst.MESSAGE_EOS:
self.player.set_state(gst.STATE_NULL)
print "end of message"
elif t == gst.MESSAGE_ERROR:
err, debug = message.parse_error()
print "Error: %s" % err, debug
self.player.set_state(gst.STATE_NULL)
def on_sync_message(self, bus, message):
if message.structure is None:
return
message_name = message.structure.get_name()
if message_name == "prepare-xwindow-id":
win_id = self.windowId
assert win_id
imagesink = message.src
imagesink.set_xwindow_id(win_id)
def startPrev(self):
self.player.set_state(gst.STATE_PLAYING)
print "should be playing"
if __name__ == "__main__":
gobject.threads_init()
app = QApplication(sys.argv)
video = Video()
video.setUpGst()
video.startPrev()
sys.exit(app.exec_())