Package flumotion :: Package component :: Package converters :: Package overlay :: Module overlay
[hide private]

Source Code for Module flumotion.component.converters.overlay.overlay

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008,2009 Fluendo, S.L. 
  6  # Copyright (C) 2010,2011 Flumotion Services, S.A. 
  7  # All rights reserved. 
  8  # 
  9  # This file may be distributed and/or modified under the terms of 
 10  # the GNU Lesser General Public License version 2.1 as published by 
 11  # the Free Software Foundation. 
 12  # This file is distributed without any warranty; without even the implied 
 13  # warranty of merchantability or fitness for a particular purpose. 
 14  # See "LICENSE.LGPL" in the source distribution for more information. 
 15  # 
 16  # Headers in this file shall remain intact. 
 17   
 18  import gobject 
 19  import gst 
 20   
 21  from flumotion.common import messages, gstreamer 
 22  from flumotion.common.i18n import N_, gettexter 
 23  from flumotion.component import feedcomponent 
 24  from flumotion.component.converters.overlay import genimg 
 25   
 26  __version__ = "$Rev$" 
 27  T_ = gettexter() 
 28   
 29  # FIXME: This class only needed for gst-plugins-base < 0.10.22 
 30  # Remove when we do not need compatibility with < 0.10.22 
 31   
 32   
33 -class OverlayImageSource(gst.BaseSrc):
34 __gstdetails__ = ('FluOverlaySrc', 'Source', 35 'Overlay Image source for flumotion', 'Zaheer Merali') 36 __gsttemplates__ = ( 37 gst.PadTemplate("src", 38 gst.PAD_SRC, 39 gst.PAD_ALWAYS, 40 gst.caps_new_any())) 41 imgBuf = "" 42 capsStr = "" 43 duration = 1.0/25 44
45 - def __init__(self):
46 gst.BaseSrc.__init__(self) 47 self.set_format(gst.FORMAT_TIME)
48
49 - def do_create(self, offset, length):
50 self.debug("Pushing buffer") 51 gstBuf = gst.Buffer(self.imgBuf) 52 padcaps = gst.caps_from_string(self.capsStr) 53 gstBuf.set_caps(padcaps) 54 gstBuf.timestamp = 0 55 gstBuf.duration = self.duration * gst.SECOND 56 return gst.FLOW_OK, gstBuf
57 58
59 -class Overlay(feedcomponent.ParseLaunchComponent):
60 checkTimestamp = True 61 checkOffset = True 62 _filename = None 63 CAPS_TEMPLATE = "video/x-raw-rgb,bpp=32,depth=32,width=%d,height=%d," \ 64 "red_mask=-16777216,green_mask=16711680,blue_mask=65280," \ 65 "alpha_mask=255,endianness=4321,framerate=0/1" 66
67 - def get_pipeline_string(self, properties):
68 pipeline = ('@eater:default@ ! ffmpegcolorspace !' 69 'video/x-raw-yuv,format=(fourcc)AYUV ! videomixer name=mix !' 70 '@feeder:default@') 71 return pipeline
72
73 - def _set_source_image(self, width, height):
74 imgBuf, imagesOverflowed, textOverflowed = \ 75 genimg.generateOverlay( 76 text=self.text, 77 font=self.font, 78 showFlumotion=self.showFlumotion, 79 showCC=self.showCC, 80 showXiph=self.showXiph, 81 width=width, height=height) 82 83 if textOverflowed: 84 m = messages.Warning( 85 T_(N_("Overlayed text '%s' too wide for the video image."), 86 self.text), mid="text-too-wide") 87 self.addMessage(m) 88 89 if imagesOverflowed: 90 m = messages.Warning( 91 T_(N_("Overlayed logotypes too wide for the video image.")), 92 mid="image-too-wide") 93 self.addMessage(m) 94 95 if self.source.get_factory().get_name() == 'appsrc': 96 self.imgBuf = imgBuf 97 else: 98 self.source.imgBuf = imgBuf
99
100 - def _set_source_caps(self, width, height):
101 self.capsStr = self.CAPS_TEMPLATE % (width, height) 102 if self.source.get_factory().get_name() == 'appsrc': 103 self.source.set_property('caps', gst.Caps(self.capsStr)) 104 else: 105 self.source.capsStr = self.capsStr
106
107 - def _set_source_framerate(self, framerate):
108 self.duration = float(framerate.denom) / framerate.num 109 if self.source.get_factory().get_name() != 'appsrc': 110 self.source.duration = duration
111
112 - def _notify_caps_cb(self, pad, param):
113 caps = pad.get_negotiated_caps() 114 if caps is None: 115 return 116 struct = pad.get_negotiated_caps().get_structure(0) 117 height = struct['height'] 118 width = struct['width'] 119 framerate = struct['framerate'] 120 121 self._set_source_image(width, height) 122 self._set_source_caps(width, height) 123 self._set_source_framerate(framerate) 124 125 if not self.sourceBin.get_pad("src").is_linked(): 126 self.sourceBin.link_filtered(self.videomixer, 127 gst.Caps("video/x-raw-yuv, format=(fourcc)AYUV")) 128 self.sourceBin.set_locked_state(False) 129 self.sourceBin.set_state(gst.STATE_PLAYING)
130
131 - def _add_source_bin(self, pipeline):
132 if gstreamer.element_factory_exists("appsrc") and \ 133 gstreamer.get_plugin_version("app") >= (0, 10, 22, 0): 134 self.source = gst.element_factory_make('appsrc', 'source') 135 self.source.set_property('do-timestamp', True) 136 self.source.connect('need-data', self.push_buffer) 137 else: 138 #FIXME: fluoverlaysrc only needed on gst-plugins-base < 0.10.22 139 gobject.type_register(OverlayImageSource) 140 gst.element_register(OverlayImageSource, "fluoverlaysrc", 141 gst.RANK_MARGINAL) 142 self.source = gst.element_factory_make('fluoverlaysrc', 'source') 143 # create the source bin 144 self.sourceBin = gst.Bin() 145 # create the alphacolor element 146 alphacolor = gst.element_factory_make('alphacolor') 147 # add the elements to the source bin and link them 148 self.sourceBin.add_many(self.source, alphacolor) 149 self.source.link(alphacolor) 150 pipeline.add(self.sourceBin) 151 # create the source ghost pad 152 self.sourceBin.add_pad(gst.GhostPad('src', alphacolor.get_pad('src'))) 153 # set the locked state and wait until we get the first caps change 154 # and we know the widht and height of the input stream 155 self.sourceBin.set_locked_state(True)
156
157 - def configure_pipeline(self, pipeline, properties):
158 p = properties 159 self.fixRenamedProperties(p, [ 160 ('show_text', 'show-text'), 161 ('fluendo_logo', 'fluendo-logo'), 162 ('cc_logo', 'cc-logo'), 163 ('xiph_logo', 'xiph-logo')]) 164 165 if p.get('width', None) is not None: 166 self.warnDeprecatedProperties(['width']) 167 if p.get('height', None) is not None: 168 self.warnDeprecatedProperties(['height']) 169 170 self.font=p.get('font', None) 171 self.showFlumotion=p.get('fluendo-logo', False) 172 self.showCC=p.get('cc-logo', False) 173 self.showXiph=p.get('xiph-logo', False) 174 if p.get('show-text', False): 175 self.text = p.get('text', 'set the "text" property') 176 else: 177 self.text = None 178 179 vmixerVersion = gstreamer.get_plugin_version('videomixer') 180 if vmixerVersion == (0, 10, 7, 0): 181 m = messages.Warning( 182 T_(N_("The 'videomixer' GStreamer element has a bug in this " 183 "version (0.10.7). You may see many errors in the debug " 184 "output, but it should work correctly anyway.")), 185 mid="videomixer-bug") 186 self.addMessage(m) 187 188 self.videomixer = pipeline.get_by_name("mix") 189 # add a callback for caps change to configure the image source 190 # properly using the caps of the input stream 191 self.videomixer.get_pad('sink_0').connect('notify::caps', 192 self._notify_caps_cb) 193 # the source is added to the pipeline, but it's not linked yet, and 194 # remains with a locked state until we have enough info about the 195 # input stream 196 self._add_source_bin(pipeline)
197
198 - def push_buffer(self, source, arg0):
199 """ 200 Pushes buffer to appsrc in GStreamer 201 202 @param source: the appsrc element to push to 203 @type source: GstElement 204 """ 205 self.log("Pushing buffer") 206 gstBuf = gst.Buffer(self.imgBuf) 207 padcaps = gst.caps_from_string(self.capsStr) 208 gstBuf.set_caps(padcaps) 209 gstBuf.duration = int(self.duration * gst.SECOND) 210 source.emit('push-buffer', gstBuf)
211