python: Add a Gst.init_python function to be called from plugins
[platform/upstream/gstreamer.git] / subprojects / gst-python / examples / plugins / python / mixer.py
1 '''
2 Simple mixer element, accepts 320 x 240 RGBA at 30 fps
3 on any number of sinkpads.
4
5 Requires PIL (Python Imaging Library)
6
7 Example pipeline:
8
9 gst-launch-1.0 py_videomixer name=mixer ! videoconvert ! autovideosink \
10         videotestsrc ! mixer. \
11         videotestsrc pattern=ball ! mixer. \
12         videotestsrc pattern=snow ! mixer.
13 '''
14
15 import gi
16
17 gi.require_version('Gst', '1.0')
18 gi.require_version('GstBase', '1.0')
19 gi.require_version('GObject', '2.0')
20
21 from gi.repository import Gst, GObject, GstBase
22
23 Gst.init_python()
24
25 try:
26     from PIL import Image
27 except ImportError:
28     Gst.error('py_videomixer requires PIL')
29     raise
30
31 # Completely fixed input / output
32 ICAPS = Gst.Caps(Gst.Structure('video/x-raw',
33                                format='RGBA',
34                                width=320,
35                                height=240,
36                                framerate=Gst.Fraction(30, 1)))
37
38 OCAPS = Gst.Caps(Gst.Structure('video/x-raw',
39                                format='RGBA',
40                                width=320,
41                                height=240,
42                                framerate=Gst.Fraction(30, 1)))
43
44 class BlendData:
45     def __init__(self, outimg):
46         self.outimg = outimg
47         self.pts = 0
48         self.eos = True
49
50 class Videomixer(GstBase.Aggregator):
51     __gstmetadata__ = ('Videomixer','Video/Mixer', \
52                       'Python video mixer', 'Mathieu Duponchelle')
53
54     __gsttemplates__ = (
55             Gst.PadTemplate.new_with_gtype("sink_%u",
56                                 Gst.PadDirection.SINK,
57                                 Gst.PadPresence.REQUEST,
58                                 ICAPS,
59                                 GstBase.AggregatorPad.__gtype__),
60             Gst.PadTemplate.new_with_gtype("src",
61                                 Gst.PadDirection.SRC,
62                                 Gst.PadPresence.ALWAYS,
63                                 OCAPS,
64                                 GstBase.AggregatorPad.__gtype__)
65     )
66
67     def mix_buffers(self, agg, pad, bdata):
68         buf = pad.pop_buffer()
69         _, info = buf.map(Gst.MapFlags.READ)
70
71         img = Image.frombuffer('RGBA', (320, 240), info.data, "raw", 'RGBA', 0, 1)
72
73         bdata.outimg = Image.blend(bdata.outimg, img, alpha=0.5)
74         bdata.pts = buf.pts
75
76         buf.unmap(info)
77
78         bdata.eos = False
79
80         return True
81
82     def do_aggregate(self, timeout):
83         outimg = Image.new('RGBA', (320, 240), 0x00000000)
84
85         bdata = BlendData(outimg)
86
87         self.foreach_sink_pad(self.mix_buffers, bdata)
88
89         data = bdata.outimg.tobytes()
90
91         outbuf = Gst.Buffer.new_allocate(None, len(data), None)
92         outbuf.fill(0, data)
93         outbuf.pts = bdata.pts
94         self.finish_buffer (outbuf)
95
96         # We are EOS when no pad was ready to be aggregated,
97         # this would obviously not work for live
98         if bdata.eos:
99             return Gst.FlowReturn.EOS
100
101         return Gst.FlowReturn.OK
102
103 GObject.type_register(Videomixer)
104 __gstelementfactory__ = ("py_videomixer", Gst.Rank.NONE, Videomixer)