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