I have Tkinter application with some gstreamer pipelines to display different
streams and I'd like to detect when one of the pipelines loses connection. I tried with bus messages but it seems to me that it doesn't post the message at all. I created a widget to manage the gstreamer logic and the code for the widget is the following. from tkinter.ttk import Widget import gi # Needed for set_window_handle(): gi.require_version('GstVideo', '1.0') gi.require_version('Gst', '1.0') from gi.repository import Gst, GstVideo class GstWidget(Widget): def __init__(self, gst_launch_string, x, y, width, height, master=None, **kw): super(GstWidget, self).__init__(master, 'frame', **kw) self.place(x=x, y=y, width=width, height=height) self.frame_id = self.winfo_id() self.player = Gst.parse_launch(gst_launch_string) self.player.set_state(Gst.State.PLAYING) self.bus = self.player.get_bus() self.bus.add_signal_watch() self.bus.connect('message::error', self.on_error) self.bus.connect('message::state-changed', self.on_status_changed) self.bus.connect('message::eos', self.on_eos) self.bus.connect('message::info', self.on_info) self.bus.enable_sync_message_emission() self.bus.connect('sync-message::element', self.set_frame_handle) def on_status_changed(self, bus, message): print('status_changed message -> {}'.format(message)) def on_eos(self, bus, message): print('eos message -> {}'.format(message)) def on_info(self, bus, message): print('info message -> {}'.format(message)) def on_error(self, bus, message): print('error message -> {}'.format(message.parse_error())) def play(self): print('Current state of my pipeline is {}'.format(self.player.current_state)) print('setting pipeline state to playing') self.player.set_state(Gst.State.PLAYING) def close(self): self.player.set_state(Gst.State.NULL) def is_playing(self): print('\t\t{}'.format(self.player.current_state)) return self.player.current_state is not Gst.State.PLAYING def set_frame_handle(self, bus, message): if message.get_structure().get_name() == 'prepare-window-handle': frame = message.src frame.set_property('force-aspect-ratio', True) frame.set_window_handle(self.frame_id) Can anyone point to me where I'm wrong? I've put breakpoints to all events and also it's not printing anything from the events that I'd like to watch. And also can you point me if there's any way to retry to connect the pipeline on a lost connection? -- Sent from: http://gstreamer-devel.966125.n4.nabble.com/ _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
About not receiving messages: You are not showing how you instantiate GstWidget and getting everything up and running. So from your code (as share), you are missing a main loop. You are also missing some important initialization steps.
Le Mardi 19 septembre 2017 15h00, WisdomPill <[hidden email]> a écrit : I have Tkinter application with some gstreamer pipelines to display different streams and I'd like to detect when one of the pipelines loses connection. I tried with bus messages but it seems to me that it doesn't post the message at all. I created a widget to manage the gstreamer logic and the code for the widget is the following. from tkinter.ttk import Widget import gi # Needed for set_window_handle(): gi.require_version('GstVideo', '1.0') gi.require_version('Gst', '1.0') from gi.repository import Gst, GstVideo class GstWidget(Widget): def __init__(self, gst_launch_string, x, y, width, height, master=None, **kw): super(GstWidget, self).__init__(master, 'frame', **kw) self.place(x=x, y=y, width=width, height=height) self.frame_id = self.winfo_id() self.player = Gst.parse_launch(gst_launch_string) self.player.set_state(Gst.State.PLAYING) self.bus = self.player.get_bus() self.bus.add_signal_watch() self.bus.connect('message::error', self.on_error) self.bus.connect('message::state-changed', self.on_status_changed) self.bus.connect('message::eos', self.on_eos) self.bus.connect('message::info', self.on_info) self.bus.enable_sync_message_emission() self.bus.connect('sync-message::element', self.set_frame_handle) def on_status_changed(self, bus, message): print('status_changed message -> {}'.format(message)) def on_eos(self, bus, message): print('eos message -> {}'.format(message)) def on_info(self, bus, message): print('info message -> {}'.format(message)) def on_error(self, bus, message): print('error message -> {}'.format(message.parse_error())) def play(self): print('Current state of my pipeline is {}'.format(self.player.current_state)) print('setting pipeline state to playing') self.player.set_state(Gst.State.PLAYING) def close(self): self.player.set_state(Gst.State.NULL) def is_playing(self): print('\t\t{}'.format(self.player.current_state)) return self.player.current_state is not Gst.State.PLAYING def set_frame_handle(self, bus, message): if message.get_structure().get_name() == 'prepare-window-handle': frame = message.src frame.set_property('force-aspect-ratio', True) frame.set_window_handle(self.frame_id) Can anyone point to me where I'm wrong? I've put breakpoints to all events and also it's not printing anything from the events that I'd like to watch. And also can you point me if there's any way to retry to connect the pipeline on a lost connection? -- Sent from: http://gstreamer-devel.966125.n4.nabble.com/ _______________________________________________ gstreamer-devel mailing list _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
I do have those two lines but in a class that inherits from Tkinter window...
The code is the following import json from configparser import ConfigParser from threading import Timer from time import time, sleep from tkinter import Tk import gi from lib.descriptors import ConfigurationDescriptor, StreamDescriptor from lib.widgets import SensorStreamWidget gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject class VisualizerApp(Tk): def __init__(self): super(VisualizerApp, self).__init__() self.config(cursor='none', background='black') self.attributes("-fullscreen", True) # Update the app to apply the geometry self.update() self.config_filename = 'conf/config.ini' self.conf = self.init_configuration() self.streams = list() self.calculate_streams_rectangles() Gst.init(None) GObject.threads_init() self.streaming_widgets = self.init_streaming_widgets() def init_configuration(self): conf = self.parse_configuration() row_height = int(conf['grid']['row_height']) streams_filename = conf['grid']['streams_filename'] streams_json = json.load(open(streams_filename)) d = { 'row_height': row_height, 'streams': streams_json['streams'] } return ConfigurationDescriptor(d) def calculate_streams_rectangles(self): x = 0 y = 0 for stream_dict in self.conf.streams: initial_resolution = stream_dict['resolution'] initial_width = int(initial_resolution['width']) initial_height = int(initial_resolution['height']) final_height = self.conf.row_height final_width = initial_width * self.conf.row_height / initial_height if x + final_width >= self.winfo_width(): x = 0 y += self.conf.row_height d = { 'x': x, 'y': y, 'width': final_width, 'height': final_height } stream_dict.update(d) # TODO remove this is only for debug purposes print(json.dumps(d, indent=4)) self.streams.append(StreamDescriptor(stream_dict)) x += final_width def parse_configuration(self): conf = ConfigParser() conf.read(self.config_filename) return conf def init_streaming_widgets(self): streaming_widgets = list() for stream in self.streams: streaming_widget = SensorStreamWidget(stream, self) streaming_widgets.append(streaming_widget) return streaming_widgets then I have a widgets.py file with the following from tkinter.ttk import Widget import gi # Needed for set_window_handle(): gi.require_version('GstVideo', '1.0') gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject, GstVideo class GstWidget(Widget): def __init__(self, gst_launch_string, x, y, width, height, master=None, **kw): super(GstWidget, self).__init__(master, 'frame', **kw) self.place(x=x, y=y, width=width, height=height) self.frame_id = self.winfo_id() self.player = Gst.parse_launch(gst_launch_string) self.player.set_state(Gst.State.PLAYING) self.bus = self.player.get_bus() self.bus.add_signal_watch() self.bus.connect('message::error', self.on_error) self.bus.connect('message::state-changed', self.on_status_changed) self.bus.connect('message::eos', self.on_eos) self.bus.connect('message::info', self.on_info) self.bus.enable_sync_message_emission() self.bus.connect('sync-message::element', self.set_frame_handle) def on_status_changed(self, bus, message): print('status_changed message -> {}'.format(message)) def on_eos(self, bus, message): print('eos message -> {}'.format(message)) def on_info(self, bus, message): print('info message -> {}'.format(message)) def on_error(self, bus, message): print('error message -> {}'.format(message.parse_error())) def play(self): print('Current state of my pipeline is {}'.format(self.player.current_state)) print('setting pipeline state to playing') self.player.set_state(Gst.State.PLAYING) def close(self): self.player.set_state(Gst.State.NULL) def is_playing(self): print('\t\t{}'.format(self.player.current_state)) return self.player.current_state is not Gst.State.PLAYING def set_frame_handle(self, bus, message): if message.get_structure().get_name() == 'prepare-window-handle': frame = message.src frame.set_property('force-aspect-ratio', True) frame.set_window_handle(self.frame_id) class SensorStreamWidget(GstWidget): def __init__(self, stream, master=None, **kw): gstreamer_launch_string = 'tcpclientsrc host={} port={} ! gdpdepay ! ' \ 'rtph264depay ! avdec_h264 ! videoconvert ! ' \ 'autovideosink sync=false'.format(stream.host, stream.port) x = stream.x y = stream.y width = stream.width height = stream.height self.stream_descriptor = stream super(SensorStreamWidget, self).__init__(gstreamer_launch_string, x, y, width, height, master, **kw) then I start my app from a file called main.py from lib.app import VisualizerApp if __name__ == '__main__': window = VisualizerApp() window.mainloop() I tried moving the two lines to the init method of the GstWidget but without success. -- Sent from: http://gstreamer-devel.966125.n4.nabble.com/ _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
I call the GObject and Gst init() methods in main. Something else I noticed is that you put your pipeline in PLAYING state before conencting. Not sure it explains your problem but you might miss some messages. Do you receive the sync-message:element ? Le Mercredi 20 septembre 2017 16h11, WisdomPill <[hidden email]> a écrit : I do have those two lines but in a class that inherits from Tkinter window... The code is the following import json from configparser import ConfigParser from threading import Timer from time import time, sleep from tkinter import Tk import gi from lib.descriptors import ConfigurationDescriptor, StreamDescriptor from lib.widgets import SensorStreamWidget gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject class VisualizerApp(Tk): def __init__(self): super(VisualizerApp, self).__init__() self.config(cursor='none', background='black') self.attributes("-fullscreen", True) # Update the app to apply the geometry self.update() self.config_filename = 'conf/config.ini' self.conf = self.init_configuration() self.streams = list() self.calculate_streams_rectangles() Gst.init(None) GObject.threads_init() self.streaming_widgets = self.init_streaming_widgets() def init_configuration(self): conf = self.parse_configuration() row_height = int(conf['grid']['row_height']) streams_filename = conf['grid']['streams_filename'] streams_json = json.load(open(streams_filename)) d = { 'row_height': row_height, 'streams': streams_json['streams'] } return ConfigurationDescriptor(d) def calculate_streams_rectangles(self): x = 0 y = 0 for stream_dict in self.conf.streams: initial_resolution = stream_dict['resolution'] initial_width = int(initial_resolution['width']) initial_height = int(initial_resolution['height']) final_height = self.conf.row_height final_width = initial_width * self.conf.row_height / initial_height if x + final_width >= self.winfo_width(): x = 0 y += self.conf.row_height d = { 'x': x, 'y': y, 'width': final_width, 'height': final_height } stream_dict.update(d) # TODO remove this is only for debug purposes print(json.dumps(d, indent=4)) self.streams.append(StreamDescriptor(stream_dict)) x += final_width def parse_configuration(self): conf = ConfigParser() conf.read(self.config_filename) return conf def init_streaming_widgets(self): streaming_widgets = list() for stream in self.streams: streaming_widget = SensorStreamWidget(stream, self) streaming_widgets.append(streaming_widget) return streaming_widgets then I have a widgets.py file with the following from tkinter.ttk import Widget import gi # Needed for set_window_handle(): gi.require_version('GstVideo', '1.0') gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject, GstVideo class GstWidget(Widget): def __init__(self, gst_launch_string, x, y, width, height, master=None, **kw): super(GstWidget, self).__init__(master, 'frame', **kw) self.place(x=x, y=y, width=width, height=height) self.frame_id = self.winfo_id() self.player = Gst.parse_launch(gst_launch_string) self.player.set_state(Gst.State.PLAYING) self.bus = self.player.get_bus() self.bus.add_signal_watch() self.bus.connect('message::error', self.on_error) self.bus.connect('message::state-changed', self.on_status_changed) self.bus.connect('message::eos', self.on_eos) self.bus.connect('message::info', self.on_info) self.bus.enable_sync_message_emission() self.bus.connect('sync-message::element', self.set_frame_handle) def on_status_changed(self, bus, message): print('status_changed message -> {}'.format(message)) def on_eos(self, bus, message): print('eos message -> {}'.format(message)) def on_info(self, bus, message): print('info message -> {}'.format(message)) def on_error(self, bus, message): print('error message -> {}'.format(message.parse_error())) def play(self): print('Current state of my pipeline is {}'.format(self.player.current_state)) print('setting pipeline state to playing') self.player.set_state(Gst.State.PLAYING) def close(self): self.player.set_state(Gst.State.NULL) def is_playing(self): print('\t\t{}'.format(self.player.current_state)) return self.player.current_state is not Gst.State.PLAYING def set_frame_handle(self, bus, message): if message.get_structure().get_name() == 'prepare-window-handle': frame = message.src frame.set_property('force-aspect-ratio', True) frame.set_window_handle(self.frame_id) class SensorStreamWidget(GstWidget): def __init__(self, stream, master=None, **kw): gstreamer_launch_string = 'tcpclientsrc host={} port={} ! gdpdepay ! ' \ 'rtph264depay ! avdec_h264 ! videoconvert ! ' \ 'autovideosink sync=false'.format(stream.host, stream.port) x = stream.x y = stream.y width = stream.width height = stream.height self.stream_descriptor = stream super(SensorStreamWidget, self).__init__(gstreamer_launch_string, x, y, width, height, master, **kw) then I start my app from a file called main.py from lib.app import VisualizerApp if __name__ == '__main__': window = VisualizerApp() window.mainloop() I tried moving the two lines to the init method of the GstWidget but without success. -- Sent from: http://gstreamer-devel.966125.n4.nabble.com/ _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
I finally figured it out. The "problem" was with the tkinter mainloop. Since
GStreamer depends heavily on Glib and tkinter doesn't use the glib mainloop I had to create one like suggested by @jldupont at tkinter integration with glib mainloop -- Sent from: http://gstreamer-devel.966125.n4.nabble.com/ _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Free forum by Nabble | Edit this page |