aboutsummaryrefslogtreecommitdiff
path: root/voctocore/lib/streamblanker.py
blob: b3f460c421953d8be59f2157294efa857578113c (plain)
  1. import logging
  2. from gi.repository import Gst
  3. from enum import Enum
  4. from lib.config import Config
  5. class StreamBlanker(object):
  6. log = logging.getLogger('StreamBlanker')
  7. def __init__(self):
  8. self.acaps = Config.get('mix', 'audiocaps')
  9. self.vcaps = Config.get('mix', 'videocaps')
  10. self.names = Config.getlist('stream-blanker', 'sources')
  11. self.log.info('Configuring StreamBlanker video %u Sources', len(self.names))
  12. pipeline = """
  13. compositor name=vmix !
  14. {vcaps} !
  15. intervideosink channel=video_streamblanker_out
  16. audiomixer name=amix !
  17. {acaps} !
  18. interaudiosink channel=audio_streamblanker_out
  19. intervideosrc channel=video_mix_streamblanker !
  20. {vcaps} !
  21. vmix.
  22. interaudiosrc channel=audio_mix_streamblanker !
  23. {acaps} !
  24. amix.
  25. interaudiosrc channel=audio_streamblanker !
  26. {acaps} !
  27. amix.
  28. """.format(
  29. acaps=self.acaps,
  30. vcaps=self.vcaps
  31. )
  32. for name in self.names:
  33. pipeline += """
  34. intervideosrc channel=video_{name}_streamblanker !
  35. {vcaps} !
  36. vmix.
  37. """.format(
  38. name=name,
  39. vcaps=self.vcaps
  40. )
  41. self.log.debug('Creating Mixing-Pipeline:\n%s', pipeline)
  42. self.mixingPipeline = Gst.parse_launch(pipeline)
  43. self.log.debug('Binding Error & End-of-Stream-Signal on Mixing-Pipeline')
  44. self.mixingPipeline.bus.add_signal_watch()
  45. self.mixingPipeline.bus.connect("message::eos", self.on_eos)
  46. self.mixingPipeline.bus.connect("message::error", self.on_error)
  47. self.log.debug('Initializing Mixer-State')
  48. self.blankSource = None
  49. self.applyMixerState()
  50. self.log.debug('Launching Mixing-Pipeline')
  51. self.mixingPipeline.set_state(Gst.State.PLAYING)
  52. def on_eos(self, bus, message):
  53. self.log.debug('Received End-of-Stream-Signal on Mixing-Pipeline')
  54. def on_error(self, bus, message):
  55. self.log.debug('Received Error-Signal on Mixing-Pipeline')
  56. (error, debug) = message.parse_error()
  57. self.log.debug('Error-Details: #%u: %s', error.code, debug)
  58. def applyMixerState(self):
  59. self.applyMixerStateAudio()
  60. self.applyMixerStateVideo()
  61. def applyMixerStateAudio(self):
  62. mixpad = self.mixingPipeline.get_by_name('amix').get_static_pad('sink_0')
  63. blankpad = self.mixingPipeline.get_by_name('amix').get_static_pad('sink_1')
  64. mixpad.set_property('volume', int(self.blankSource is None))
  65. blankpad.set_property('volume', int(self.blankSource is not None))
  66. def applyMixerStateVideo(self):
  67. mixpad = self.mixingPipeline.get_by_name('vmix').get_static_pad('sink_0')
  68. mixpad.set_property('alpha', int(self.blankSource is None))
  69. for idx, name in enumerate(self.names):
  70. blankpad = self.mixingPipeline.get_by_name('vmix').get_static_pad('sink_%u' % (idx+1))
  71. blankpad.set_property('alpha', int(self.blankSource == idx))
  72. def setBlankSource(self, source):
  73. self.blankSource = source
  74. self.applyMixerState()