aboutsummaryrefslogtreecommitdiff
path: root/voctogui/lib/videodisplay.py
blob: 00648efe795f421857675639b4b2b2d2509dd6f5 (plain)
  1. import logging
  2. from gi.repository import Gst
  3. class VideoDisplay:
  4. """ Displays a Voctomix-Video-Stream into a GtkWidget """
  5. def __init__(self, drawing_area, port, play_audio=False, draw_callback=None, level_callback=None):
  6. self.log = logging.getLogger('VideoDisplay[%s]' % drawing_area.get_name())
  7. self.drawing_area = drawing_area
  8. self.draw_callback = draw_callback
  9. self.level_callback = level_callback
  10. # Setup Server-Connection, Demuxing and Decoding
  11. pipeline = """
  12. videotestsrc !
  13. timeoverlay !
  14. video/x-raw,width=1920,height=1080,framerate=25/1 !
  15. """.format(
  16. port=port
  17. )
  18. # If an overlay is required, add an cairooverlay-Element into the Video-Path
  19. if self.draw_callback:
  20. pipeline += """
  21. videoconvert !
  22. cairooverlay name=overlay !
  23. videoconvert !
  24. """
  25. # Video Display
  26. pipeline += """
  27. xvimagesink name=v
  28. """
  29. # If an Audio-Path is required, add an Audio-Path through a level-Element
  30. if self.level_callback or play_audio:
  31. pipeline += """
  32. audiotestsrc wave=blue-noise !
  33. audio/x-raw !
  34. level name=lvl interval=50000000 !
  35. """
  36. # If Playback is requested, push fo alsa
  37. if play_audio:
  38. pipeline += """
  39. alsasink
  40. """
  41. # Otherwise just trash the Audio
  42. else:
  43. pipeline += """
  44. fakesink
  45. """
  46. self.log.debug('Creating Display-Pipeline:\n%s', pipeline)
  47. self.pipeline = Gst.parse_launch(pipeline)
  48. self.drawing_area.realize()
  49. self.xid = self.drawing_area.get_property('window').get_xid()
  50. self.log.debug('Realized Drawing-Area with xid %u', self.xid)
  51. bus = self.pipeline.get_bus()
  52. bus.add_signal_watch()
  53. bus.enable_sync_message_emission()
  54. bus.connect('message::error', self.on_error)
  55. bus.connect("sync-message::element", self.on_syncmsg)
  56. if self.level_callback:
  57. bus.connect("message::element", self.on_level)
  58. if self.draw_callback:
  59. self.pipeline.get_by_name('overlay').connect('draw', self.on_draw)
  60. self.log.debug('Launching Display-Pipeline')
  61. self.pipeline.set_state(Gst.State.PLAYING)
  62. def on_syncmsg(self, bus, msg):
  63. if msg.get_structure().get_name() == "prepare-window-handle":
  64. self.log.info('Setting xvimagesink window-handle to %s', self.xid)
  65. msg.src.set_window_handle(self.xid)
  66. def on_error(self, bus, message):
  67. self.log.debug('Received Error-Signal on Display-Pipeline')
  68. (error, debug) = message.parse_error()
  69. self.log.debug('Error-Details: #%u: %s', error.code, debug)
  70. def on_level(self, bus, msg):
  71. if msg.src.name != 'lvl':
  72. return
  73. if msg.type != Gst.MessageType.ELEMENT:
  74. return
  75. peaks = msg.get_structure().get_value('peak')
  76. rms = msg.get_structure().get_value('rms')
  77. self.level_callback(peaks, rms)
  78. def on_draw(self, cairooverlay, cr, timestamp, duration):
  79. self.draw_callback(cr, timestamp, duration)