2
1
# -*- Mode: Python -*-
3
2
# vi:si:et:sw=4:sts=4:ts=4
6
# (c) 2005 Edward Hervey <edward at fluendo dot com>
5
# (c) 2005-2008 Edward Hervey <bilboed at bilboed dot com>
7
6
# Discovers multimedia information on files
9
8
# This library is free software; you can redistribute it and/or
10
9
# modify it under the terms of the GNU Lesser General Public
11
10
# License as published by the Free Software Foundation; either
12
11
# version 2.1 of the License, or (at your option) any later version.
14
13
# This library is distributed in the hope that it will be useful,
15
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
16
# Lesser General Public License for more details.
19
18
# You should have received a copy of the GNU Lesser General Public
20
19
# License along with this library; if not, write to the Free Software
21
20
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
81
def __init__(self, filename):
77
def __init__(self, filename, max_interleave=1.0, timeout=3000):
79
filename: str; absolute path of the file to be discovered.
80
max_interleave: int or float; the maximum frame interleave in seconds.
81
The value must be greater than the input file frame interleave
82
or the discoverer may not find out all input file's streams.
83
The default value is 1 second and you shouldn't have to change it,
84
changing it mean larger discovering time and bigger memory usage.
85
timeout: int; duration in ms for the discovery to complete.
82
87
gobject.GObject.__init__(self)
84
89
self.mimetype = None
107
112
self.finished = False
109
114
self._success = False
115
self._nomorepads = False
111
117
self._timeoutid = 0
118
self._timeout = timeout
119
self._max_interleave = max_interleave
113
121
if not os.path.isfile(filename):
122
self.debug("File '%s' does not exist, finished" % filename)
114
123
self.finished = True
117
126
# the initial elements of the pipeline
118
127
self.src = gst.element_factory_make("filesrc")
119
128
self.src.set_property("location", filename)
127
136
self.typefind.connect("have-type", self._have_type_cb)
128
137
self.dbin.connect("new-decoded-pad", self._new_decoded_pad_cb)
138
self.dbin.connect("no-more-pads", self._no_more_pads_cb)
129
139
self.dbin.connect("unknown-type", self._unknown_type_cb)
141
def _timed_out_or_eos(self):
142
if (not self.is_audio and not self.is_video) or \
143
(self.is_audio and not self.audiocaps) or \
144
(self.is_video and not self.videocaps):
145
self._finished(False)
131
149
def _finished(self, success=False):
132
150
self.debug("success:%d" % success)
133
151
self._success = success
144
162
self.set_state(gst.STATE_READY)
145
163
self.debug("about to emit signal")
146
164
self.emit('discovered', self._success)
149
166
def _bus_message_cb(self, bus, message):
150
167
if message.type == gst.MESSAGE_EOS:
168
self.debug("Got EOS")
169
self._timed_out_or_eos()
152
170
elif message.type == gst.MESSAGE_TAG:
153
171
for key in message.parse_tag().keys():
154
172
self.tags[key] = message.structure[key]
155
173
elif message.type == gst.MESSAGE_ERROR:
174
self.debug("Got error")
158
177
def discover(self):
167
186
self.bus.connect("message", self._bus_message_cb)
170
self._timeoutid = gobject.timeout_add(3000, self._finished)
189
self._timeoutid = gobject.timeout_add(self._timeout, self._timed_out_or_eos)
172
191
self.info("setting to PLAY")
173
192
if not self.set_state(gst.STATE_PLAYING):
223
242
for tag in self.tags.keys():
224
243
print "%20s :\t" % tag, self.tags[tag]
245
def _no_more_pads_cb(self, dbin):
246
self.info("no more pads")
247
self._nomorepads = True
226
249
def _unknown_type_cb(self, dbin, pad, caps):
227
250
self.debug("unknown type : %s" % caps.to_string())
228
251
# if we get an unknown type and we don't already have an
241
264
pad.info("no negotiated caps available")
243
pad.info("caps:%s" % caps.to_string)
266
pad.info("caps:%s" % caps.to_string())
244
267
# the caps are fixed
245
268
# We now get the total length of that stream
246
269
q = gst.query_new_duration(gst.FORMAT_TIME)
247
pad.info("sending position query")
270
pad.info("sending duration query")
248
271
if pad.get_peer().query(q):
249
272
format, length = q.parse_duration()
250
pad.info("got position query answer : %d:%d" % (length, format))
273
if format == gst.FORMAT_TIME:
274
pad.info("got duration (time) : %s" % (gst.TIME_ARGS(length),))
276
pad.info("got duration : %d [format:%d]" % (length, format))
253
gst.warning("position query didn't work")
279
gst.warning("duration query failed")
255
281
# We store the caps and length in the proper location
256
282
if "audio" in caps.to_string():
271
297
self.videowidth = caps[0]["width"]
272
298
self.videoheight = caps[0]["height"]
273
299
self.videorate = caps[0]["framerate"]
274
if (not self.is_audio) or self.audiocaps:
300
if self._nomorepads and ((not self.is_audio) or self.audiocaps):
275
301
self._finished(True)
277
303
def _new_decoded_pad_cb(self, dbin, pad, is_last):
286
312
self.warning("got a different caps.. %s" % caps.to_string())
288
314
if is_last and not self.is_video and not self.is_audio:
315
self.debug("is last, not video or audio")
289
316
self._finished(False)
291
318
# we connect a fakesink to the new pad...
292
319
pad.info("adding queue->fakesink")
293
fakesink = gst.element_factory_make("fakesink")
320
fakesink = gst.element_factory_make("fakesink", "fakesink%d-%s" %
321
(self.sinknumber, "audio" in caps.to_string() and "audio" or "video"))
294
323
queue = gst.element_factory_make("queue")
324
# we want the queue to buffer up to the specified amount of data
325
# before outputting. This enables us to cope with formats
326
# that don't create their source pads straight away,
327
# but instead wait for the first buffer of that stream.
328
# The specified time must be greater than the input file
329
# frame interleave for the discoverer to work properly.
330
queue.props.min_threshold_time = int(self._max_interleave * gst.SECOND)
331
queue.props.max_size_time = int(2 * self._max_interleave * gst.SECOND)
332
queue.props.max_size_bytes = 0
334
# If durations are bad on the buffers (common for video decoders), we'll
335
# never reach the min_threshold_time or max_size_time. So, set a
336
# max size in buffers, and if reached, disable the min_threshold_time.
337
# This ensures we don't fail to discover with various ffmpeg
338
# demuxers/decoders that provide bogus (or no) duration.
339
queue.props.max_size_buffers = int(100 * self._max_interleave)
340
def _disable_min_threshold_cb(queue):
341
queue.props.min_threshold_time = 0
342
queue.disconnect(signal_id)
343
signal_id = queue.connect('overrun', _disable_min_threshold_cb)
295
345
self.add(fakesink, queue)
296
346
queue.link(fakesink)
297
347
sinkpad = fakesink.get_pad("sink")