1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import gst
20 import gobject
21 import time
22
23
25 '''
26 I mux the metadata with title changes into audio stream.
27 '''
28
29 _DEFAULT_FRAMESIZE = 256
30 _DEFAULT_NUMFRAMES = 16
31 _MAX_INT = int(1 << 31 - 1)
32
33
34 __gproperties__ = {
35 'frame-size': (int,
36 'size of the frame in bytes',
37 'The size in bytes of the frame',
38 1, _MAX_INT, _DEFAULT_FRAMESIZE,
39 gobject.PARAM_READWRITE),
40 'num-frames': (int,
41 'number of frames per data block',
42 'The number of frames per data block',
43 1, _MAX_INT, _DEFAULT_NUMFRAMES,
44 gobject.PARAM_READWRITE),
45 'icy-metaint': (int,
46 'number of bytes per data block',
47 'The length of data block',
48 1, _MAX_INT, _DEFAULT_FRAMESIZE * _DEFAULT_NUMFRAMES,
49 gobject.PARAM_READABLE),
50 'iradio-title': (str,
51 'title of currently playing song',
52 'Title of currently playing song',
53 None, gobject.PARAM_READABLE),
54 'iradio-timestamp': (int,
55 'last title timestamp',
56 'Epoch time of last title change',
57 -_MAX_INT, _MAX_INT, -1, gobject.PARAM_READABLE)}
58
59 __gsignals__ = {"broadcast-title": (gobject.SIGNAL_RUN_LAST,\
60 gobject.TYPE_NONE, [])}
61
62 __gstdetails__ = ('IcyMux', 'Codec/Muxer',
63 'Icy format muxer',
64 'Flumotion Dev Team')
65
66 _sinkpadtemplate = gst.PadTemplate("sink",
67 gst.PAD_SINK,
68 gst.PAD_ALWAYS,
69 gst.caps_from_string("audio/mpeg;application/ogg"))
70
71 _srcpadtemplate = gst.PadTemplate("src",
72 gst.PAD_SRC,
73 gst.PAD_ALWAYS,
74 gst.caps_from_string("application/x-icy, " +\
75 "metadata-interval= (int)[0, MAX]"))
76
95
97 self.adapter = gst.Adapter()
98 self._frameCount = 0
99 self._shouldOutputMetadata = False
100 self._lastTitle = None
101 self._lastTitleTimestamp = -1
102
104 self.debug("Will broadcast title.")
105 self._shouldOutputMetadata = True
106
108 self.debug("Received event %r" % event)
109 if event.type == gst.EVENT_TAG:
110 struc = event.get_structure()
111 if 'title' in struc.keys():
112 self._lastTitle = struc['title']
113 self._lastTitleTimestamp = int(time.time())
114 self.debug("Stored title: %r on timestamp %r" %\
115 (self._lastTitle, self._lastTitleTimestamp))
116 self._shouldOutputMetadata = True
117 return True
118
122
124 if property.name == "frame-size":
125 return self._frameSize
126 elif property.name == "num-frames":
127 return self._numFrames
128 elif property.name == "icy-metaint":
129 return self._icyMetaint
130 elif property.name == "iradio-title":
131 return self._lastTitle
132 elif property.name == 'iradio-timestamp':
133 return self._lastTitleTimestamp
134 else:
135 raise AttributeError('unknown property %s' % property.name)
136
138 if property.name == "frame-size":
139 self.debug("Setting frame-size to %s" % value)
140 self._frameSize = int(value)
141 self._recountMetaint()
142 elif property.name == "num-frames":
143 self.debug("Setting num-frames to %s" % value)
144 self._numFrames = int(value)
145 self._recountMetaint()
146 elif property.name == "icy-metaint":
147 raise AttributeError("readonly property %s" % property.name)
148 else:
149 raise AttributeError('unknown property %s' % property.name)
150
152 if transition == gst.STATE_CHANGE_PAUSED_TO_READY:
153 self._reset()
154 return gst.Element.do_change_state(self, transition)
155
157 self.adapter.push(buffer)
158 while self.adapter.available() >= self._frameSize:
159 frame = self.adapter.take_buffer(self._frameSize)
160 self._setCapsAndFlags(frame)
161 if self._frameCount == 0:
162
163 frame.flag_unset(gst.BUFFER_FLAG_DELTA_UNIT)
164 self.log('marked as keyframe')
165
166 self.srcpad.push(frame)
167 self.log('Pushed frame of size %d' % frame.size)
168 self._frameCount += 1
169
170 if self._frameCount == self._numFrames:
171 self.outputMetadata()
172 self._frameCount = 0
173 return gst.FLOW_OK
174
182
188
190 buf.set_caps(gst.caps_from_string("application/x-icy, " +\
191 "metadata-interval=%d" % self._icyMetaint))
192 buf.flag_set(gst.BUFFER_FLAG_DELTA_UNIT)
193
194
195 gst.element_register(IcyMux, "icymux")
196
197
211