mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
examples/remuxer.py: Another code dump. I know it breaks the freeze but it's just a wee example :)
Original commit message from CVS: 2006-04-19 Andy Wingo <wingo@pobox.com> * examples/remuxer.py: Another code dump. I know it breaks the freeze but it's just a wee example :)
This commit is contained in:
parent
6a46407057
commit
4a4637e756
2 changed files with 124 additions and 14 deletions
|
@ -1,3 +1,8 @@
|
|||
2006-04-19 Andy Wingo <wingo@pobox.com>
|
||||
|
||||
* examples/remuxer.py: Another code dump. I know it breaks the
|
||||
freeze but it's just a wee example :)
|
||||
|
||||
2006-04-10 Edward Hervey <edward@fluendo.com>
|
||||
|
||||
* gst/gsttaglist.override: (tag_foreach_func_list):
|
||||
|
|
|
@ -8,6 +8,7 @@ pygtk.require('2.0')
|
|||
import sys
|
||||
|
||||
import gobject
|
||||
gobject.threads_init()
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
|
@ -289,6 +290,7 @@ class RemuxProgressDialog(ProgressDialog):
|
|||
self.set_completed(False)
|
||||
|
||||
def update_position(self, pos):
|
||||
print pos
|
||||
pos = min(max(pos, self.start), self.stop)
|
||||
remaining = self.stop - pos
|
||||
minutes = remaining // (gst.SECOND * 60)
|
||||
|
@ -300,21 +302,56 @@ class RemuxProgressDialog(ProgressDialog):
|
|||
self.set_response_sensitive(CANCELLED, not completed)
|
||||
self.set_response_sensitive(SUCCESS, completed)
|
||||
|
||||
def set_connection_blocked_async_marshalled(pads, proc, *args, **kwargs):
|
||||
def clear_list(l):
|
||||
while l:
|
||||
l.pop()
|
||||
|
||||
to_block = list(pads)
|
||||
to_relink = [(x, x.get_peer()) for x in pads]
|
||||
|
||||
def on_pad_blocked_sync(pad, is_blocked):
|
||||
if pad not in to_block:
|
||||
# can happen after the seek and before unblocking -- racy,
|
||||
# but no prob, bob.
|
||||
return
|
||||
to_block.remove(pad)
|
||||
if not to_block:
|
||||
# marshal to main thread
|
||||
gobject.idle_add(on_pads_blocked)
|
||||
|
||||
def on_pads_blocked():
|
||||
for src, sink in to_relink:
|
||||
src.link(sink)
|
||||
proc(*args, **kwargs)
|
||||
for src, sink in to_relink:
|
||||
src.set_blocked_async(False, lambda *x: None)
|
||||
clear_list(to_relink)
|
||||
|
||||
for src, sink in to_relink:
|
||||
src.unlink(sink)
|
||||
src.set_blocked_async(True, on_pad_blocked_sync)
|
||||
|
||||
class Remuxer(gst.Pipeline):
|
||||
|
||||
__gsignals__ = {'done': (gobject.SIGNAL_RUN_LAST, None, (int,))}
|
||||
|
||||
def __init__(self, fromuri, touri, start, stop):
|
||||
# HACK: should do Pipeline.__init__, but that doesn't do what we
|
||||
# want; there's a bug open aboooot that
|
||||
self.__gobject_init__()
|
||||
|
||||
assert start >= 0
|
||||
assert stop > start
|
||||
|
||||
self.src = gst.element_make_from_uri(gst.URI_SRC, fromuri)
|
||||
self.remuxbin = RemuxBin()
|
||||
self.remuxbin = RemuxBin(start, stop)
|
||||
self.sink = gst.element_make_from_uri(gst.URI_SINK, touri)
|
||||
self.resolution = UNKNOWN
|
||||
|
||||
if gobject.signal_lookup('allow-overwrite', self.sink.__class__):
|
||||
self.sink.connect('allow-overwrite', self._allow_overwrite)
|
||||
|
||||
self.add(self.src, self.remuxbin, self.sink)
|
||||
|
||||
self.src.link(self.remuxbin)
|
||||
|
@ -326,11 +363,56 @@ class Remuxer(gst.Pipeline):
|
|||
self.start_time = start
|
||||
self.stop_time = stop
|
||||
|
||||
self._query_id = -1
|
||||
|
||||
def _allow_overwrite(self, sink, uri):
|
||||
name = self.sink.get_uri()
|
||||
name = (gst.uri_has_protocol(name, 'file')
|
||||
and gst.uri_get_location(name)
|
||||
or name)
|
||||
m = gtk.MessageDialog(self.window,
|
||||
gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
gtk.MESSAGE_QUESTION,
|
||||
gtk.BUTTONS_NONE,
|
||||
("The file %s already exists. Would you "
|
||||
"like to replace it?") % name)
|
||||
b = gtk.Button(stock=gtk.STOCK_CANCEL)
|
||||
b.show()
|
||||
m.add_action_widget(b, CANCELLED)
|
||||
b = gtk.Button('Replace')
|
||||
b.show()
|
||||
m.add_action_widget(b, SUCCESS)
|
||||
txt = ('If you replace an existing file, its contents will be '
|
||||
'overwritten.')
|
||||
m.format_secondary_text(txt)
|
||||
resp = m.run()
|
||||
m.destroy()
|
||||
return resp == SUCCESS
|
||||
|
||||
def _start_queries(self):
|
||||
def do_query():
|
||||
try:
|
||||
# HACK: self.remuxbin.query() should do the same
|
||||
# (requires implementing a vmethod, dunno how to do that
|
||||
# although i think it's possible)
|
||||
# HACK: why does self.query_position(..) not give useful
|
||||
# answers?
|
||||
pad = self.remuxbin.get_pad('src')
|
||||
pos, duration = pad.query_position(gst.FORMAT_TIME)
|
||||
if pos != gst.CLOCK_TIME_NONE:
|
||||
self.pdialog.update_position(pos)
|
||||
except gst.QueryError:
|
||||
print 'query failed'
|
||||
pass
|
||||
return True
|
||||
if self._query_id == -1:
|
||||
self._query_id = gobject.timeout_add(100, # 10 Hz
|
||||
do_query)
|
||||
|
||||
def _stop_queries(self):
|
||||
pass
|
||||
if self._query_id != -1:
|
||||
gobject.source_remove(self._query_id)
|
||||
self._query_id = -1
|
||||
|
||||
def _bus_watch(self, bus, message):
|
||||
if message.type == gst.MESSAGE_ERROR:
|
||||
|
@ -341,15 +423,17 @@ class Remuxer(gst.Pipeline):
|
|||
gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_CLOSE,
|
||||
"Error processing file")
|
||||
txt = 'There was an error processing your file: %r' % message
|
||||
gerror, debug = message.parse_error()
|
||||
txt = ('There was an error processing your file: %s\n\n'
|
||||
'Debug information:\n%s' % (gerror, debug))
|
||||
m.format_secondary_text(txt)
|
||||
m.run()
|
||||
m.destroy()
|
||||
self.response(FAILURE)
|
||||
elif message.type == gst.MESSAGE_WARNING:
|
||||
print 'warning', message
|
||||
elif message.type == gst.MESSAGE_EOS:
|
||||
print 'eos, woot'
|
||||
elif message.type == gst.MESSAGE_SEGMENT_DONE:
|
||||
print 'eos, woot', message.src
|
||||
self.pdialog.set_task('Finished')
|
||||
self.pdialog.update_position(self.stop_time)
|
||||
self._stop_queries()
|
||||
|
@ -372,6 +456,7 @@ class Remuxer(gst.Pipeline):
|
|||
self.set_state(gst.STATE_NULL)
|
||||
self.pdialog.destroy()
|
||||
self.pdialog = None
|
||||
self.window.set_sensitive(True)
|
||||
self.emit('done', response)
|
||||
|
||||
def start(self, main_window):
|
||||
|
@ -386,20 +471,22 @@ class Remuxer(gst.Pipeline):
|
|||
self.stop_time)
|
||||
self.pdialog.show()
|
||||
self.pdialog.connect('response', lambda w, r: self.response(r))
|
||||
|
||||
self.set_state(gst.STATE_PAUSED)
|
||||
|
||||
def run(self, main_window):
|
||||
self.start(None)
|
||||
self.start(main_window)
|
||||
loop = gobject.MainLoop()
|
||||
self.connect('done', lambda *x: gobject.idle_add(loop.quit))
|
||||
loop.run()
|
||||
return self.resolution
|
||||
|
||||
class RemuxBin(gst.Bin):
|
||||
def __init__(self):
|
||||
def __init__(self, start_time, stop_time):
|
||||
self.__gobject_init__()
|
||||
|
||||
self.parsers = self._find_parsers()
|
||||
self.parsefactories = self._find_parsers()
|
||||
self.parsers = []
|
||||
|
||||
self.demux = gst.element_factory_make('oggdemux')
|
||||
self.mux = gst.element_factory_make('oggmux')
|
||||
|
@ -412,6 +499,9 @@ class RemuxBin(gst.Bin):
|
|||
self.demux.connect('pad-added', self._new_demuxed_pad)
|
||||
self.demux.connect('no-more-pads', self._no_more_pads)
|
||||
|
||||
self.start_time = start_time
|
||||
self.stop_time = stop_time
|
||||
|
||||
def _find_parsers(self):
|
||||
registry = gst.registry_get_default()
|
||||
ret = {}
|
||||
|
@ -427,19 +517,32 @@ class RemuxBin(gst.Bin):
|
|||
def _new_demuxed_pad(self, element, pad):
|
||||
format = pad.get_caps()[0].get_name()
|
||||
|
||||
if format not in self.parsers:
|
||||
if format not in self.parsefactories:
|
||||
self.async_error("Unsupported media type: %s", format)
|
||||
return
|
||||
|
||||
parser = gst.element_factory_make(self.parsers[format])
|
||||
queue = gst.element_factory_make('queue', 'queue_' + format)
|
||||
parser = gst.element_factory_make(self.parsefactories[format])
|
||||
self.add(queue)
|
||||
self.add(parser)
|
||||
queue.set_state(gst.STATE_PAUSED)
|
||||
parser.set_state(gst.STATE_PAUSED)
|
||||
pad.link(parser.get_compatible_pad(pad))
|
||||
pad.link(queue.get_compatible_pad(pad))
|
||||
queue.link(parser)
|
||||
parser.link(self.mux)
|
||||
self.parsers.append(parser)
|
||||
|
||||
def _do_segment_seek(self):
|
||||
flags = gst.SEEK_FLAG_SEGMENT | gst.SEEK_FLAG_FLUSH
|
||||
# HACK: self.seek should work, should try that at some point
|
||||
return self.demux.seek(1.0, gst.FORMAT_TIME, flags,
|
||||
gst.SEEK_TYPE_SET, self.start_time,
|
||||
gst.SEEK_TYPE_SET, self.stop_time)
|
||||
|
||||
def _no_more_pads(self, element):
|
||||
# this is when we should commit to paused or something
|
||||
pass
|
||||
pads = [x.get_pad('src') for x in self.parsers]
|
||||
set_connection_blocked_async_marshalled(pads,
|
||||
self._do_segment_seek)
|
||||
|
||||
|
||||
class PlayerWindow(gtk.Window):
|
||||
|
@ -547,6 +650,8 @@ class PlayerWindow(gtk.Window):
|
|||
button.connect('clicked', lambda *x: self.do_remux())
|
||||
|
||||
def do_remux(self):
|
||||
if self.player.is_playing():
|
||||
self.play_toggled()
|
||||
in_uri = self.player.get_location()
|
||||
out_uri = in_uri[:-4] + '-remuxed.ogg'
|
||||
r = Remuxer(in_uri, out_uri,
|
||||
|
|
Loading…
Reference in a new issue