Python get bus message reconnection

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Python get bus message reconnection

WisdomPill
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
Reply | Threaded
Open this post in threaded view
|

Re: Python get bus message reconnection

filnet
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.
gobject.threads_init()
Gst.init(None)

Googling "gstreamer python tkinter" brings loads of examples with the missing parts.


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?



--
_______________________________________________
gstreamer-devel mailing list



_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Python get bus message reconnection

WisdomPill
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
Reply | Threaded
Open this post in threaded view
|

Re: Python get bus message reconnection

filnet
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
Reply | Threaded
Open this post in threaded view
|

Re: Python get bus message reconnection

WisdomPill
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