2 Simple mixer element, accepts 320 x 240 RGBA at 30 fps
3 on any number of sinkpads.
5 Requires PIL (Python Imaging Library)
9 gst-launch-1.0 py_videomixer name=mixer ! videoconvert ! autovideosink \
10 videotestsrc ! mixer. \
11 videotestsrc pattern=ball ! mixer. \
12 videotestsrc pattern=snow ! mixer.
17 gi.require_version('Gst', '1.0')
18 gi.require_version('GstBase', '1.0')
19 gi.require_version('GObject', '2.0')
21 from gi.repository import Gst, GObject, GstBase
28 Gst.error('py_videomixer requires PIL')
31 # Completely fixed input / output
32 ICAPS = Gst.Caps(Gst.Structure('video/x-raw',
36 framerate=Gst.Fraction(30, 1)))
38 OCAPS = Gst.Caps(Gst.Structure('video/x-raw',
42 framerate=Gst.Fraction(30, 1)))
45 def __init__(self, outimg):
50 class Videomixer(GstBase.Aggregator):
51 __gstmetadata__ = ('Videomixer','Video/Mixer', \
52 'Python video mixer', 'Mathieu Duponchelle')
55 Gst.PadTemplate.new_with_gtype("sink_%u",
56 Gst.PadDirection.SINK,
57 Gst.PadPresence.REQUEST,
59 GstBase.AggregatorPad.__gtype__),
60 Gst.PadTemplate.new_with_gtype("src",
62 Gst.PadPresence.ALWAYS,
64 GstBase.AggregatorPad.__gtype__)
67 def mix_buffers(self, agg, pad, bdata):
68 buf = pad.pop_buffer()
69 _, info = buf.map(Gst.MapFlags.READ)
71 img = Image.frombuffer('RGBA', (320, 240), info.data, "raw", 'RGBA', 0, 1)
73 bdata.outimg = Image.blend(bdata.outimg, img, alpha=0.5)
82 def do_aggregate(self, timeout):
83 outimg = Image.new('RGBA', (320, 240), 0x00000000)
85 bdata = BlendData(outimg)
87 self.foreach_sink_pad(self.mix_buffers, bdata)
89 data = bdata.outimg.tobytes()
91 outbuf = Gst.Buffer.new_allocate(None, len(data), None)
93 outbuf.pts = bdata.pts
94 self.finish_buffer (outbuf)
96 # We are EOS when no pad was ready to be aggregated,
97 # this would obviously not work for live
99 return Gst.FlowReturn.EOS
101 return Gst.FlowReturn.OK
103 GObject.type_register(Videomixer)
104 __gstelementfactory__ = ("py_videomixer", Gst.Rank.NONE, Videomixer)