~ubuntu-branches/ubuntu/precise/gst0.10-python/precise

« back to all changes in this revision

Viewing changes to gst/extend/discoverer.py

Tags: upstream-0.10.8
Import upstream version 0.10.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
70
70
    otherstreams = []
71
71
 
72
72
    finished = False
 
73
    sinknumber = 0
73
74
    tags = {}
74
75
 
75
76
 
76
 
    def __init__(self, filename):
 
77
    def __init__(self, filename, max_interleave=1.0):
 
78
        """
 
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
        """
77
86
        gobject.GObject.__init__(self)
78
87
 
79
88
        self.mimetype = None
102
111
        self.finished = False
103
112
        self.tags = {}
104
113
        self._success = False
 
114
        self._nomorepads = False
105
115
 
106
116
        self._timeoutid = 0
 
117
        self._max_interleave = max_interleave
107
118
 
108
119
        if not os.path.isfile(filename):
109
120
            self.debug("File '%s' does not exist, finished" % filename)
122
133
        # callbacks
123
134
        self.typefind.connect("have-type", self._have_type_cb)
124
135
        self.dbin.connect("new-decoded-pad", self._new_decoded_pad_cb)
 
136
        self.dbin.connect("no-more-pads", self._no_more_pads_cb)
125
137
        self.dbin.connect("unknown-type", self._unknown_type_cb)
126
138
 
 
139
    def _timed_out_or_eos(self):
 
140
        if (not self.is_audio and not self.is_video) or \
 
141
                (self.is_audio and not self.audiocaps) or \
 
142
                (self.is_video and not self.videocaps):
 
143
            self._finished(False)
 
144
        else:
 
145
            self._finished(True)
 
146
 
127
147
    def _finished(self, success=False):
128
148
        self.debug("success:%d" % success)
129
149
        self._success = success
140
160
        self.set_state(gst.STATE_READY)
141
161
        self.debug("about to emit signal")
142
162
        self.emit('discovered', self._success)
143
 
        
144
163
 
145
164
    def _bus_message_cb(self, bus, message):
146
165
        if message.type == gst.MESSAGE_EOS:
147
 
            self._finished()
 
166
            self.debug("Got EOS")
 
167
            self._timed_out_or_eos()
148
168
        elif message.type == gst.MESSAGE_TAG:
149
169
            for key in message.parse_tag().keys():
150
170
                self.tags[key] = message.structure[key]
151
171
        elif message.type == gst.MESSAGE_ERROR:
 
172
            self.debug("Got error")
152
173
            self._finished()
153
174
 
154
175
    def discover(self):
163
184
        self.bus.connect("message", self._bus_message_cb)
164
185
 
165
186
        # 3s timeout
166
 
        self._timeoutid = gobject.timeout_add(3000, self._finished)
 
187
        self._timeoutid = gobject.timeout_add(3000, self._timed_out_or_eos)
167
188
        
168
189
        self.info("setting to PLAY")
169
190
        if not self.set_state(gst.STATE_PLAYING):
219
240
            for tag in self.tags.keys():
220
241
                print "%20s :\t" % tag, self.tags[tag]
221
242
 
 
243
    def _no_more_pads_cb(self, dbin):
 
244
        self.info("no more pads")
 
245
        self._nomorepads = True
 
246
 
222
247
    def _unknown_type_cb(self, dbin, pad, caps):
223
248
        self.debug("unknown type : %s" % caps.to_string())
224
249
        # if we get an unknown type and we don't already have an
236
261
        if not caps:
237
262
            pad.info("no negotiated caps available")
238
263
            return
239
 
        pad.info("caps:%s" % caps.to_string)
 
264
        pad.info("caps:%s" % caps.to_string())
240
265
        # the caps are fixed
241
266
        # We now get the total length of that stream
242
267
        q = gst.query_new_duration(gst.FORMAT_TIME)
259
284
                self.audiofloat = True
260
285
            else:
261
286
                self.audiodepth = caps[0]["depth"]
262
 
            if (not self.is_video) or self.videocaps:
 
287
            if self._nomorepads and ((not self.is_video) or self.videocaps):
263
288
                self._finished(True)
264
289
        elif "video" in caps.to_string():
265
290
            self.videocaps = caps
267
292
            self.videowidth = caps[0]["width"]
268
293
            self.videoheight = caps[0]["height"]
269
294
            self.videorate = caps[0]["framerate"]
270
 
            if (not self.is_audio) or self.audiocaps:
 
295
            if self._nomorepads and ((not self.is_audio) or self.audiocaps):
271
296
                self._finished(True)
272
297
 
273
298
    def _new_decoded_pad_cb(self, dbin, pad, is_last):
282
307
            self.warning("got a different caps.. %s" % caps.to_string())
283
308
            return
284
309
        if is_last and not self.is_video and not self.is_audio:
 
310
            self.debug("is last, not video or audio")
285
311
            self._finished(False)
286
312
            return
287
313
        # we connect a fakesink to the new pad...
288
314
        pad.info("adding queue->fakesink")
289
 
        fakesink = gst.element_factory_make("fakesink")
 
315
        fakesink = gst.element_factory_make("fakesink", "fakesink%d-%s" % 
 
316
            (self.sinknumber, "audio" in caps.to_string() and "audio" or "video"))
 
317
        self.sinknumber += 1
290
318
        queue = gst.element_factory_make("queue")
291
 
        # we want the queue to buffer up to 2 seconds of data before outputting
292
 
        # This enables us to cope with formats that don't create their source
293
 
        # pads straight away, but instead wait for the first buffer of that
294
 
        # stream.
295
 
        queue.props.min_threshold_time = 1 * gst.SECOND
296
 
        queue.props.max_size_time = 2 * gst.SECOND
 
319
        # we want the queue to buffer up to the specified amount of data 
 
320
        # before outputting. This enables us to cope with formats 
 
321
        # that don't create their source pads straight away, 
 
322
        # but instead wait for the first buffer of that stream.
 
323
        # The specified time must be greater than the input file
 
324
        # frame interleave for the discoverer to work properly.
 
325
        queue.props.min_threshold_time = int(self._max_interleave * gst.SECOND)
 
326
        queue.props.max_size_time = int(2 * self._max_interleave * gst.SECOND)
297
327
        queue.props.max_size_bytes = 0
298
328
 
299
329
        # If durations are bad on the buffers (common for video decoders), we'll
300
 
        # never reach the min_threshold_time or max_size_time. So, set a large 
 
330
        # never reach the min_threshold_time or max_size_time. So, set a
301
331
        # max size in buffers, and if reached, disable the min_threshold_time.
302
332
        # This ensures we don't fail to discover with various ffmpeg 
303
333
        # demuxers/decoders that provide bogus (or no) duration.
304
 
        queue.props.max_size_buffers = 100
 
334
        queue.props.max_size_buffers = int(100 * self._max_interleave)
305
335
        def _disable_min_threshold_cb(queue):
306
336
            queue.props.min_threshold_time = 0
307
337
            queue.disconnect(signal_id)