summaryrefslogtreecommitdiff
path: root/voctocore/experiments/failovertest2.py
blob: 919b9465f9303d55a477be43c281a0ed1705457c (plain)
  1. #!/usr/bin/python3
  2. from os import path
  3. import gi
  4. gi.require_version('Gst', '1.0')
  5. from gi.repository import GObject, Gst
  6. GObject.threads_init()
  7. Gst.init(None)
  8. class FramegrabberSource(Gst.Bin):
  9. def __init__(self, uri):
  10. super().__init__()
  11. # Create elements
  12. self.http = Gst.ElementFactory.make('souphttpsrc', None)
  13. self.demux = Gst.ElementFactory.make('multipartdemux', None)
  14. self.parse = Gst.ElementFactory.make('jpegparse', None)
  15. self.dec = Gst.ElementFactory.make('jpegdec', None)
  16. # Add elements to Bin
  17. self.add(self.http)
  18. self.add(self.parse)
  19. self.add(self.demux)
  20. self.add(self.dec)
  21. # Set properties
  22. self.http.set_property('location', uri)
  23. self.http.set_property('timeout', 5)
  24. #self.http.set_property('is-live', True)
  25. #self.http.set_property('do-timestamp', True)
  26. # Connect signal handlers
  27. self.demux.connect('pad-added', self.on_demux_pad_added)
  28. # Link elements
  29. self.http.link(self.demux)
  30. # dynamic linked # self.demux.link(self.parse)
  31. self.parse.link(self.dec)
  32. # Add Ghost Pads
  33. self.add_pad(
  34. Gst.GhostPad.new('src', self.dec.get_static_pad('src'))
  35. )
  36. def on_demux_pad_added(self, element, pad):
  37. string = pad.query_caps(None).to_string()
  38. print('on_demux_pad_added():', string)
  39. if string.startswith('image/jpeg'):
  40. pad.link(self.parse.get_static_pad('sink'))
  41. class FailoverFilter(Gst.Bin):
  42. def __init__(self):
  43. super().__init__()
  44. self.queue = Gst.ElementFactory.make('queue', None)
  45. self.failsrc = Gst.ElementFactory.make('videotestsrc', None)
  46. self.capsfilter = Gst.ElementFactory.make('capsfilter', None)
  47. self.switch = Gst.ElementFactory.make('input-selector', "sw")
  48. # Add elements to Bin
  49. self.add(self.queue)
  50. self.add(self.failsrc)
  51. self.add(self.capsfilter)
  52. self.add(self.switch)
  53. # Request Pads
  54. self.goodpad = self.switch.get_request_pad('sink_%u')
  55. self.failpad = self.switch.get_request_pad('sink_%u')
  56. # Set properties
  57. self.switch.set_property('active-pad', self.goodpad)
  58. self.capsfilter.set_property('caps', Gst.Caps.from_string('video/x-raw,format=I420,width=640,height=480'))
  59. # Connect signal handlers
  60. self.queue.connect('underrun', self.on_queue)
  61. self.queue.connect('running', self.on_queue)
  62. # Link elements
  63. self.queue.get_static_pad('src').link(self.goodpad)
  64. self.failsrc.link(self.capsfilter)
  65. self.capsfilter.get_static_pad('src').link(self.failpad)
  66. # Add Ghost Pads
  67. self.add_pad(
  68. Gst.GhostPad.new('sink', self.queue.get_static_pad('sink'))
  69. )
  70. self.add_pad(
  71. Gst.GhostPad.new('src', self.switch.get_static_pad('src'))
  72. )
  73. def on_queue(self, queue):
  74. level = queue.get_property('current-level-buffers')
  75. print('on_queue()', level)
  76. switch = queue.get_parent().get_by_name("sw")
  77. switch.set_property('active-pad', switch.get_static_pad('sink_1' if level == 0 else 'sink_0'))
  78. class VideomixerWithDisplay(Gst.Bin):
  79. def __init__(self):
  80. super().__init__()
  81. # Create elements
  82. self.secondsrc = Gst.ElementFactory.make('videotestsrc', None)
  83. self.mixer = Gst.ElementFactory.make('videomixer', None)
  84. self.q1 = Gst.ElementFactory.make('queue', None)
  85. self.q2 = Gst.ElementFactory.make('queue', None)
  86. self.display = Gst.ElementFactory.make('ximagesink', None)
  87. # Add elements to Bin
  88. self.add(self.secondsrc)
  89. self.add(self.mixer)
  90. self.add(self.display)
  91. self.add(self.q1)
  92. self.add(self.q2)
  93. # Set properties
  94. self.secondsrc.set_property('pattern', 'ball')
  95. # Request Pads
  96. self.firstpad = self.mixer.get_request_pad('sink_%u')
  97. self.secondpad = self.mixer.get_request_pad('sink_%u')
  98. # Set pad-properties
  99. self.secondpad.set_property('alpha', 0.7)
  100. self.secondpad.set_property('xpos', 50)
  101. self.secondpad.set_property('ypos', 50)
  102. # Link elements
  103. self.q1.get_static_pad('src').link(self.firstpad)
  104. self.q2.get_static_pad('src').link(self.secondpad)
  105. self.secondsrc.link(self.q2)
  106. self.mixer.link(self.display)
  107. # Add Ghost Pads
  108. self.add_pad(
  109. Gst.GhostPad.new('sink', self.q1.get_static_pad('sink'))
  110. )
  111. class Example:
  112. def __init__(self):
  113. self.mainloop = GObject.MainLoop()
  114. self.pipeline = Gst.Pipeline()
  115. self.bus = self.pipeline.get_bus()
  116. self.bus.add_signal_watch()
  117. self.bus.connect('message::eos', self.on_eos)
  118. self.bus.connect('message::error', self.on_error)
  119. # Create elements
  120. self.grabbersrc = FramegrabberSource(
  121. uri='http://beachcam.kdhnc.com/mjpg/video.mjpg?camera=1')
  122. self.failover = FailoverFilter()
  123. self.mixdisplay = VideomixerWithDisplay()
  124. # Add elements to pipeline
  125. self.pipeline.add(self.grabbersrc)
  126. self.pipeline.add(self.failover)
  127. self.pipeline.add(self.mixdisplay)
  128. self.grabbersrc.link(self.failover)
  129. self.failover.link(self.mixdisplay)
  130. def run(self):
  131. self.pipeline.set_state(Gst.State.PLAYING)
  132. self.mainloop.run()
  133. def kill(self):
  134. self.pipeline.set_state(Gst.State.NULL)
  135. self.mainloop.quit()
  136. def on_eos(self, bus, msg):
  137. print('on_eos()')
  138. #self.kill()
  139. def on_error(self, bus, msg):
  140. print('on_error():', msg.parse_error())
  141. #self.kill()
  142. example = Example()
  143. example.run()