aboutsummaryrefslogtreecommitdiff
path: root/voctocore/experiments/shmsrc.py
blob: 742767b2c8eb898d6ab72d69fef9d8520cebd5c6 (plain)
  1. #!/usr/bin/python3
  2. import time
  3. from gi.repository import GLib, Gst
  4. class ShmSrc(Gst.Bin):
  5. last_buffer_arrived = 0
  6. is_in_failstate = True
  7. def __init__(self, socket, caps):
  8. super().__init__()
  9. # Create elements
  10. self.shmsrc = Gst.ElementFactory.make('shmsrc', None)
  11. self.identity1 = Gst.ElementFactory.make('identity', None)
  12. self.identity2 = Gst.ElementFactory.make('identity', None)
  13. self.switch = Gst.ElementFactory.make('input-selector', None)
  14. self.failsrc = Gst.ElementFactory.make('videotestsrc', None)
  15. # Add elements to Bin
  16. self.add(self.shmsrc)
  17. self.add(self.identity1)
  18. self.add(self.identity2)
  19. self.add(self.switch)
  20. self.add(self.failsrc)
  21. # Get Switcher-Pads
  22. self.goodpad = self.switch.get_request_pad('sink_%u')
  23. self.failpad = self.switch.get_request_pad('sink_%u')
  24. # Set properties
  25. self.shmsrc.set_property('socket-path', socket)
  26. self.shmsrc.set_property('is-live', True)
  27. self.shmsrc.set_property('do-timestamp', True)
  28. #self.identity1.set_property('sync', True)
  29. self.identity2.set_property('sync', True)
  30. self.switch.set_property('active-pad', self.failpad)
  31. self.failsrc.set_property('pattern', 'snow')
  32. # Link elements
  33. self.shmsrc.link_filtered(self.identity1, caps)
  34. self.identity1.get_static_pad('src').link(self.goodpad)
  35. self.failsrc.link_filtered(self.identity2, caps)
  36. self.identity2.get_static_pad('src').link(self.failpad)
  37. # Install pad probes
  38. self.shmsrc.get_static_pad('src').add_probe(Gst.PadProbeType.BLOCK | Gst.PadProbeType.EVENT_DOWNSTREAM, self.event_probe, None)
  39. self.shmsrc.get_static_pad('src').add_probe(Gst.PadProbeType.BLOCK | Gst.PadProbeType.BUFFER, self.data_probe, None)
  40. # Install Watchdog
  41. GLib.timeout_add(500, self.watchdog)
  42. # Add Ghost Pads
  43. self.add_pad(
  44. Gst.GhostPad.new('sink', self.switch.get_static_pad('src'))
  45. )
  46. def do_handle_message(self, msg):
  47. if msg.type == Gst.MessageType.ERROR:
  48. print("do_handle_message(): dropping error")
  49. return
  50. print("do_handle_message()", msg.src, msg.type)
  51. Gst.Bin.do_handle_message(self, msg)
  52. def event_probe(self, pad, info, ud):
  53. e = info.get_event()
  54. if e.type == Gst.EventType.EOS:
  55. self.switch_to_failstate()
  56. return Gst.PadProbeReturn.DROP
  57. return Gst.PadProbeReturn.PASS
  58. def data_probe(self, pad, info, ud):
  59. self.last_buffer_arrived = time.time()
  60. self.switch_to_goodstate()
  61. return Gst.PadProbeReturn.PASS
  62. def watchdog(self):
  63. if self.last_buffer_arrived + 0.1 < time.time():
  64. print("watchdog()::timeout")
  65. self.switch_to_failstate()
  66. if self.last_buffer_arrived + 3 < time.time() and round(time.time() % 3) == 0:
  67. print("watchdog()::restart")
  68. self.restart()
  69. return True
  70. def restart(self):
  71. self.shmsrc.set_state(Gst.State.NULL)
  72. # this somehow solves parts of the multi-output-timestamping-issue
  73. # starting the 2nd src n seconds after the program started freezes it for n seconds
  74. self.shmsrc.set_start_time(0)
  75. self.shmsrc.set_base_time(self.get_parent().get_base_time())
  76. self.shmsrc.set_state(Gst.State.PLAYING)
  77. def switch_to_goodstate(self):
  78. if not self.is_in_failstate:
  79. return
  80. print("switch_to_goodstate()")
  81. self.is_in_failstate = False
  82. self.switch.set_property('active-pad', self.goodpad)
  83. def switch_to_failstate(self):
  84. if self.is_in_failstate:
  85. return
  86. print("switch_to_failstate()")
  87. self.is_in_failstate = True
  88. self.switch.set_property('active-pad', self.failpad)