1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import gst
19 import urlparse
20
21 from twisted.internet import reactor
22
23 from flumotion.common import gstreamer
24 from flumotion.common.i18n import gettexter
25 from flumotion.component.base import http
26 from flumotion.component.component import moods
27 from flumotion.component.common.streamer.fragmentedstreamer import\
28 FragmentedStreamer, Stats
29 from flumotion.component.consumers.hlsstreamer.resources import \
30 HTTPLiveStreamingResource
31 from flumotion.component.consumers.hlsstreamer.hlsring import HLSRing
32 from flumotion.component.consumers.hlsstreamer import hlssink
33
34 __all__ = ['HLSStreamer']
35 __version__ = ""
36 T_ = gettexter()
37
38
39 SUPPORTED_FORMATS = {"video/mpegts": ("video/mpegts", "video/mpegts", "ts"),
40 "video/webm": ("video/webm", "video/webm", "webm")}
41
42
44 DEFAULT_SESSION_TIMEOUT = 30
45 DEFAULT_FRAGMENT_PREFIX = 'fragment'
46 DEFAULT_MAIN_PLAYLIST = 'main.m3u8'
47 DEFAULT_STREAM_PLAYLIST = 'stream.m3u8'
48 DEFAULT_STREAM_BITRATE = 300000
49 DEFAULT_KEYFRAMES_PER_SEGMENT = 10
50
51 logCategory = 'hls-streamer'
52
53 _mime_type = None
54 _content_type = None
55 _stream_setup = False
56
58 self.debug("HTTP live streamer initialising")
59 self.hlsring = None
60
63
65 return self._content_type
66
73
78
81
113
115 """Stops serving fragments, resets the playlist and starts
116 waiting for new segments to become happy again
117 """
118 self.info("Soft restart, resetting playlist and waiting to fill "
119 "the initial fragments window")
120 self._ready = False
121 self._fragmentsCount = 0
122 self._last_index = 0
123 self.hlsring.reset()
124
132
136
140
142
143 if not self._stream_setup:
144 sink = self.get_element("sink")
145 pad = sink.get_pad("sink")
146 caps = pad.get_negotiated_caps()
147 name = caps.get_structure(0).get_name()
148 self._setup_stream_type(name)
149
150 self._fragmentsCount = self._fragmentsCount + 1
151
152
153 if self._fragmentsCount == self._minWindow:
154 self.info("%d fragments received. Changing mood to 'happy'",
155 self._fragmentsCount)
156 self.setMood(moods.happy)
157 self._ready = True
158
159 b = fragment.get_property('buffer')
160 index = fragment.get_property('index')
161 duration = fragment.get_property('duration')
162
163 if index < self._last_index:
164 self.warning("Found a discontinuity last index is %s but current "
165 "one is %s", self._last_index, index)
166 self.soft_restart()
167
168 fragName = self.hlsring.addFragment(b.data, index,
169 round(duration / float(gst.SECOND)))
170 self.info('Added fragment "%s", index=%s, duration=%s',
171 fragName, index, gst.TIME_ARGS(duration))
172
173
174
176 self.log("hlsink created a new fragment")
177 try:
178 fragment = hlssink.get_property('fragment')
179 except:
180 fragment = hlssink.emit('pull-fragment')
181 reactor.callFromThread(self._process_fragment, fragment)
182
183
184