Package flumotion :: Package component :: Package consumers :: Package hlsstreamer :: Module hlssink
[hide private]

Source Code for Module flumotion.component.consumers.hlsstreamer.hlssink

  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 gst 
 19  import gobject 
 20   
 21   
 22  # IMPORTANT NOTE 
 23  # This module defines a pyhon implementation of the gstreamer hlssink element, 
 24  # which was not yet upstream the day it was released. It will also be used in 
 25  # cases where this element is missing too. 
 26   
 27   
28 -class Fragment(gobject.GObject):
29 ''' 30 I am a Python implementation of the GstFragment 31 ''' 32 index = 0 33 name = 'fragment' 34 duration = 0 35 buf = None 36 37 __gproperties__ = { 38 'buffer': (gobject.TYPE_PYOBJECT, 39 'Buffer', 'GstBuffer with the data of the fragment', 40 gobject.PARAM_READABLE), 41 'index': (gobject.TYPE_UINT, 'Index', 'Index of the fragment', 42 0, gobject.G_MAXUINT, 0, gobject.PARAM_READABLE), 43 'name': (gobject.TYPE_STRING, 'Name', 'Name of the fragment', 44 'fragment', gobject.PARAM_READABLE), 45 'duration': (gobject.TYPE_UINT64, 'duration', 46 'Duration of the fragment in ns', 47 0, gst.CLOCK_TIME_NONE, 0, gobject.PARAM_READABLE)} 48
49 - def __init__(self, index, buf):
50 gobject.GObject.__init__(self) 51 self.index = index 52 self.name = "fragment-%s" % index 53 self.duration = buf.duration 54 self.buf = buf
55
56 - def do_get_property(self, prop):
57 if prop.name == "name": 58 return self.name 59 if prop.name == "index": 60 return self.index 61 if prop.name == "duration": 62 return self.duration 63 if prop.name == "buffer": 64 return self.buf 65 else: 66 raise AttributeError('unknown property %s' % property.name)
67 68
69 -class HLSSink(gst.Element):
70 ''' 71 I am a python implementation the gstreamer hlssink element. 72 ''' 73 74 __gstdetails__ = ('HLSSink', 'Sink', 75 'Sink for HTTP Live Streaming', 76 'Flumotion Dev Team') 77 78 __gsignals__ = {"new-fragment": (gobject.SIGNAL_RUN_LAST, 79 gobject.TYPE_NONE, []), 80 "eos": (gobject.SIGNAL_RUN_LAST, 81 gobject.TYPE_NONE, []), 82 "pull-fragment": (gobject.SIGNAL_RUN_LAST | 83 gobject.SIGNAL_ACTION, 84 gobject.TYPE_OBJECT, [])} 85 86 __gproperties__ = { 87 'fragment': (gobject.TYPE_OBJECT, 88 'fragment', 'last gstfragment', 89 gobject.PARAM_READABLE), 90 'sync': (gobject.TYPE_BOOLEAN, 91 'sync', 'sync', False, 92 gobject.PARAM_WRITABLE), 93 'playlist-max-window': (gobject.TYPE_INT, 94 'playlist max window', 'playlist max window', 95 0, gobject.G_MAXINT, 0, gobject.PARAM_WRITABLE), 96 'write-to-disk': (gobject.TYPE_BOOLEAN, 97 'Write to disk', 'Write to disk', False, 98 gobject.PARAM_WRITABLE)} 99 100 _sinkpadtemplate = gst.PadTemplate("sink", 101 gst.PAD_SINK, 102 gst.PAD_ALWAYS, 103 gst.caps_from_string("video/mpegts; " 104 "video/webm")) 105
106 - def __init__(self):
107 gst.Element.__init__(self) 108 109 self._reset_fragment() 110 self._last_fragment = None 111 self._last_event_ts = gst.CLOCK_TIME_NONE 112 113 self.sinkpad = gst.Pad(self._sinkpadtemplate, "sink") 114 self.sinkpad.set_chain_function(self.chainfunc) 115 self.sinkpad.set_event_function(self.eventfunc) 116 self.add_pad(self.sinkpad)
117
118 - def chainfunc(self, pad, buf):
119 if buf.flag_is_set(gst.BUFFER_FLAG_IN_CAPS): 120 self._in_caps = True 121 return gst.FLOW_OK 122 123 self._fragment.append(buf) 124 return gst.FLOW_OK
125
126 - def eventfunc(self, pad, event):
127 s = event.get_structure() 128 if event.type != gst.EVENT_CUSTOM_DOWNSTREAM or \ 129 s.get_name() != 'GstForceKeyUnit': 130 return True 131 132 # Ignore the first GstForceKeyUnit event 133 if len(self._fragment) == 0: 134 return True 135 136 self._finish_fragment(s['timestamp'], s['count']) 137 return True
138
139 - def do_get_property(self, prop):
140 if prop.name == "fragment": 141 return self._last_fragment
142
143 - def do_set_property(self, prop, value):
144 # Properties ignored, only added to replicate the ones 145 # of the original sink 146 pass
147
148 - def _reset_fragment(self, last_event_ts = gst.CLOCK_TIME_NONE):
149 self._fragment = [] 150 self._in_caps = False 151 self._last_event_ts = last_event_ts
152
153 - def _finish_fragment(self, timestamp, index):
154 # Write streamheaders at the beginning of each fragment 155 s = self.sinkpad.get_negotiated_caps()[0] 156 frag = [] 157 if s.has_field('streamheader'): 158 frag = list(s['streamheader']) 159 frag.extend(self._fragment) 160 161 # Check for discontinuities 162 if self._last_event_ts == gst.CLOCK_TIME_NONE or\ 163 timestamp <= self._last_event_ts: 164 self._reset_fragment(timestamp) 165 self._last_fragment = None 166 return 167 168 # Create the GstBuffer 169 data = ''.join([b.data for b in frag]) 170 buf = gst.Buffer(data) 171 buf.timestamp = self._last_event_ts 172 buf.duration = timestamp - buf.timestamp 173 if self._in_caps: 174 buf.flag_set(gst.BUFFER_FLAG_IN_CAPS) 175 176 # Create the GstFragment and emit the new-fragment signal 177 self._last_fragment = Fragment(index, buf) 178 self.emit('new-fragment') 179 self._reset_fragment(timestamp)
180 181
182 -def register():
183 gobject.type_register(HLSSink) 184 gst.element_register(HLSSink, 'hlssink', gst.RANK_MARGINAL)
185