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