#!/usr/bin/env python import sys import traceback from math import pi import pygtk pygtk.require ("2.0") import gobject gobject.threads_init() import pygst pygst.require('0.10') import gst import cairo WIDTH, HEIGHT = 640, 480 FRAMES = 300 FRAMERATE = 15 class PyGstBufferDraw(gst.Element): _sinkpadtemplate = gst.PadTemplate ("sink", gst.PAD_SINK, gst.PAD_ALWAYS, gst.caps_from_string ("video/x-raw-rgb,bpp=32,depth=32,blue_mask=-16777216,green_mask=16711680, red_mask=65280, alpha_mask=255,width=[ 1, 2147483647 ],height=[ 1, 2147483647 ],framerate=[ 0/1, 2147483647/1 ]")) _srcpadtemplate = gst.PadTemplate ("src", gst.PAD_SRC, gst.PAD_ALWAYS, gst.caps_from_string ("video/x-raw-rgb,bpp=32,depth=32,blue_mask=-16777216,green_mask=16711680, red_mask=65280, alpha_mask=255,width=[ 1, 2147483647 ],height=[ 1, 2147483647 ],framerate=[ 0/1, 2147483647/1 ]")) def __init__(self): gst.Element.__init__(self) self.sinkpad = gst.Pad(self._sinkpadtemplate, "sink") self.sinkpad.set_chain_function(self.chainfunc) self.sinkpad.set_event_function(self.eventfunc) self.sinkpad.set_getcaps_function(gst.Pad.proxy_getcaps) self.sinkpad.set_setcaps_function(gst.Pad.proxy_setcaps) self.add_pad (self.sinkpad) self.srcpad = gst.Pad(self._srcpadtemplate, "src") self.srcpad.set_event_function(self.srceventfunc) self.srcpad.set_query_function(self.srcqueryfunc) self.srcpad.set_getcaps_function(gst.Pad.proxy_getcaps) self.srcpad.set_setcaps_function(gst.Pad.proxy_setcaps) self.add_pad (self.srcpad) def chainfunc(self, pad, buffer): try: outbuf = buffer.copy_on_write () self.draw_on (outbuf) return self.srcpad.push (outbuf) except: return GST_FLOW_ERROR def eventfunc(self, pad, event): return self.srcpad.push_event (event) def srcqueryfunc (self, pad, query): return self.sinkpad.query (query) def srceventfunc (self, pad, event): return self.sinkpad.push_event (event) def draw_on (self, buf): try: caps = buf.get_caps() width = caps[0]['width'] height = caps[0]['height'] framerate = caps[0]['framerate'] surface = cairo.ImageSurface.create_for_data (buf, cairo.FORMAT_ARGB32, width, height, 4 * width) ctx = cairo.Context(surface) except: print "Failed to create cairo surface for buffer" traceback.print_exc() return try: center_x = width/4 center_y = 3*height/4 # draw a circle radius = float (min (width, height)) * 0.25 ctx.set_source_rgba (0.0, 0.0, 0.0, 0.9) ctx.move_to (center_x, center_y) ctx.arc (center_x, center_y, radius, 0, 2.0*pi) ctx.close_path() ctx.fill() ctx.set_source_rgba (1.0, 1.0, 1.0, 1.0) ctx.set_font_size(0.3 * radius) txt = "Hello World" extents = ctx.text_extents (txt) ctx.move_to(center_x - extents[2]/2, center_y + extents[3]/2) ctx.text_path(txt) ctx.fill() except: print "Failed cairo render" traceback.print_exc() gobject.type_register(PyGstBufferDraw) pipe = gst.Pipeline() vt = gst.element_factory_make ("videotestsrc") cf = gst.element_factory_make ("capsfilter") c1 = PyGstBufferDraw() color = gst.element_factory_make ("ffmpegcolorspace") scale = gst.element_factory_make ("videoscale") q1 = gst.element_factory_make ("queue") sink = gst.element_factory_make ("autovideosink") caps = gst.caps_from_string ("video/x-raw-rgb,width=%d,height=%d,framerate=%d/1" % (WIDTH, HEIGHT, FRAMERATE)) cf.set_property ("caps", caps) vt.set_property ("num-buffers", FRAMES) pipe.add (vt, cf, c1, q1, color, scale, sink) gst.element_link_many (vt, cf, c1, q1, color, scale, sink) def on_eos (bus, msg): mainloop.quit() bus = pipe.get_bus() bus.add_signal_watch() bus.connect('message::eos', on_eos) pipe.set_state (gst.STATE_PLAYING) mainloop = gobject.MainLoop() try: mainloop.run() except: pass pipe.set_state (gst.STATE_NULL) pipe.get_state (gst.CLOCK_TIME_NONE)