{"id":1734,"date":"2013-07-30T23:01:53","date_gmt":"2013-07-31T02:01:53","guid":{"rendered":"http:\/\/tangopardo.com.ar\/2cf7\/?p=1734"},"modified":"2014-12-04T08:49:17","modified_gmt":"2014-12-04T11:49:17","slug":"using-the-gstreamer-controller-subsystem-from-python","status":"publish","type":"post","link":"https:\/\/tangopardo.com.ar\/2cf7\/2013\/07\/30\/using-the-gstreamer-controller-subsystem-from-python","title":{"rendered":"Using the Gstreamer Controller subsystem from Python."},"content":{"rendered":"<p>This is more or less a direct translation of the examples found at gstreamer\/tests\/examples\/controller\/*.c to their equivalents using the gi bindings for Gstreamer under Python. The documentation can be found <a title=\"Gstreamer docs for the controller subsystem\" href=\"http:\/\/cgit.freedesktop.org\/gstreamer\/gstreamer\/tree\/docs\/design\/part-controller.txt\">here<\/a>. Reading the source also helps a lot.<\/p>\n<p>The basic premise is that you can attach a controller to almost any property of an object, set an interpolation function and give it pairs of (time, value) so they are smoothly changed. I&#8217;m using a pad as a target instead of an element just because it fits my immediate needs but it really can be any Element.<\/p>\n<p>First you need to import Gstreamer and initialize it:<br \/>\n<code><br \/>\n#!\/usr\/bin\/python<br \/>\nimport gi<br \/>\nimport sys<br \/>\nfrom gi.repository import GObject<br \/>\ngi.require_version('Gst', '1.0')<br \/>\nfrom gi.repository import Gst<br \/>\nfrom gi.repository import GstController<br \/>\nfrom gi.repository import Gtk<br \/>\nfrom gi.repository import GLib<\/p>\n<p>GObject.threads_init()<br \/>\nGst.init(sys.argv)<\/p>\n<p><\/code><\/p>\n<p>Then create your elements. This is by no means the best way but lets me cut a bit on all the boilerplate.<\/p>\n<p><code><br \/>\np = Gst.parse_launch (\"\"\"videomixer name=mix ! videoconvert ! xvimagesink<br \/>\nvideotestsrc pattern=\"snow\" ! videoconvert ! mix.sink_0<br \/>\nvideotestsrc ! videoconvert ! mix.sink_1<br \/>\n\"\"\")<\/p>\n<p>m = p.get_by_name (\"mix\")<br \/>\ns0 = [pad for pad in m.pads if pad.name == 'sink_0'][0]<br \/>\ns0.set_property (\"xpos\", 100)<br \/>\n<\/code><\/p>\n<p>Here I created two test sources, one with bars and another with static that also has an horizontal offset. If we were to start the pipeline right now ( p.set_state (Gst.State.PLAYING) ) we would see something like this:<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/tangopardo.com.ar\/2cf7\/wp-content\/uploads\/2013\/07\/captura_testinterpolation.png\"><img loading=\"lazy\" decoding=\"async\" width=\"422\" height=\"269\" data-attachment-id=\"1736\" data-permalink=\"https:\/\/tangopardo.com.ar\/2cf7\/2013\/07\/30\/using-the-gstreamer-controller-subsystem-from-python\/captura_testinterpolation\" data-orig-file=\"https:\/\/tangopardo.com.ar\/2cf7\/wp-content\/uploads\/2013\/07\/captura_testinterpolation.png\" data-orig-size=\"422,269\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"captura_testinterpolation\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/tangopardo.com.ar\/2cf7\/wp-content\/uploads\/2013\/07\/captura_testinterpolation-300x191.png\" data-large-file=\"https:\/\/tangopardo.com.ar\/2cf7\/wp-content\/uploads\/2013\/07\/captura_testinterpolation.png\" class=\"aligncenter  wp-image-1736\" alt=\"captura_testinterpolation\" src=\"http:\/\/tangopardo.com.ar\/2cf7\/wp-content\/uploads\/2013\/07\/captura_testinterpolation.png\" srcset=\"https:\/\/tangopardo.com.ar\/2cf7\/wp-content\/uploads\/2013\/07\/captura_testinterpolation.png 422w, https:\/\/tangopardo.com.ar\/2cf7\/wp-content\/uploads\/2013\/07\/captura_testinterpolation-300x191.png 300w\" sizes=\"auto, (max-width: 422px) 100vw, 422px\" \/><\/a><\/p>\n<p>So far it works. Now I&#8217;d like to animate the alpha property of s0 (the sink pads of a videomixer have interesting properties like alpha, zorder, xpos and ypos). First we create a control source and set the interpolation mode:<\/p>\n<p><code>cs = GstController.InterpolationControlSource()<br \/>\ncs.set_property('mode', GstController.InterpolationMode.LINEAR)<\/code><\/p>\n<p>Then we create a control binding for the property we want to animate and add it to our element:<\/p>\n<p><code>cb = GstController.DirectControlBinding.new(s0, 'alpha', cs)<br \/>\ns0.add_control_binding(cb)<\/code><\/p>\n<p>It is worth noting that the same control source can be used with more than one control binding.<\/p>\n<p>Now we just need to add a couple of points and play:<\/p>\n<p><code>cs.set(0*Gst.SECOND, 1)<br \/>\ncs.set(4*Gst.SECOND, 0.5)<br \/>\np.set_state (Gst.State.PLAYING)<\/code><\/p>\n<p>If you are not running this from the interpreter remember to add GObject.MainLoop().run() , otherwise the script will end instead of keep playing. Here I&#8217;ve used absolute times, to animate in the middle of a playing state you need to get the current time and set the points accordingly, something like this will do most of the cases:<\/p>\n<p><code><br \/>\nstart = p.get_clock().get_time() # XXX: you better check for errors<br \/>\nend = start + endtime*Gst.SECOND<br \/>\n<\/code><\/p>\n<h4>Avoiding too much bookkeeping<\/h4>\n<p>You can get the controller and control source of an element with:<br \/>\n<code><br \/>\ncontrol_binding = element.get_control_binding('property')<br \/>\nif control_binding:<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;control_source = control_binding.get_property('control_source')<br \/>\n<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is more or less a direct translation of the examples found at gstreamer\/tests\/examples\/controller\/*.c to their equivalents using the gi bindings for Gstreamer under Python. The documentation can be found here. Reading the source also helps a lot. The basic premise is that you can attach a controller to almost any property of an object, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[51,13,24,4,22],"tags":[52,64],"class_list":["post-1734","post","type-post","status-publish","format-standard","hentry","category-opcode","category-electronica","category-hacks","category-python","category-software-libre","tag-gstreamer","tag-python"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pmnbC-rY","_links":{"self":[{"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/posts\/1734","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/comments?post=1734"}],"version-history":[{"count":10,"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/posts\/1734\/revisions"}],"predecessor-version":[{"id":1745,"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/posts\/1734\/revisions\/1745"}],"wp:attachment":[{"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/media?parent=1734"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/categories?post=1734"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tangopardo.com.ar\/2cf7\/wp-json\/wp\/v2\/tags?post=1734"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}