[pitivi] elements: Use audio-clipping probe before adder.
- From: Edward Hervey <edwardrv src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [pitivi] elements: Use audio-clipping probe before adder.
- Date: Fri, 31 Jul 2009 11:10:51 +0000 (UTC)
commit 6141eb25aeb56b270b1b53ff454390b08fb474ec
Author: Edward Hervey <bilboed bilboed com>
Date: Thu Jul 30 19:30:17 2009 +0200
elements: Use audio-clipping probe before adder.
This ensures that we're not sending too much data to adder which would
result in weird 'clipping' sound.
THIS IS A HACK ! It should be fixed in adder (see #590265)
pitivi/elements/Makefile.am | 1 +
pitivi/elements/audioclipper.py | 169 +++++++++++++++++++++++++++++++++++++++
pitivi/elements/mixer.py | 8 ++-
3 files changed, 176 insertions(+), 2 deletions(-)
---
diff --git a/pitivi/elements/Makefile.am b/pitivi/elements/Makefile.am
index 516c4d3..5976dc4 100644
--- a/pitivi/elements/Makefile.am
+++ b/pitivi/elements/Makefile.am
@@ -3,6 +3,7 @@ elementsdir = $(libdir)/pitivi/python/pitivi/elements
elements_PYTHON = \
__init__.py \
arraysink.py \
+ audioclipper.py \
imagefreeze.py \
mixer.py \
singledecodebin.py \
diff --git a/pitivi/elements/audioclipper.py b/pitivi/elements/audioclipper.py
new file mode 100644
index 0000000..db8a637
--- /dev/null
+++ b/pitivi/elements/audioclipper.py
@@ -0,0 +1,169 @@
+# PiTiVi , Non-linear video editor
+#
+# pitivi/elements/audioclipper.py
+#
+# Copyright (c) 2009, Edward Hervey <bilboed bilboed com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+"""
+Audio clipping element
+"""
+
+import gobject
+import gst
+import gst.interfaces
+import gst.audio
+from pitivi.utils import data_probe
+
+class AudioClipper(gst.Element):
+
+ __gstdetails__ = (
+ "Audio clipper",
+ "Generic/Audio",
+ "Clip audio buffers according to segments",
+ "Edward Hervey <bilboed bilboed com>"
+ )
+
+ _srctemplate = gst.PadTemplate("src", gst.PAD_SRC, gst.PAD_ALWAYS,
+ gst.Caps("audio/x-raw-int;audio/x-raw-float"))
+ _sinktemplate = gst.PadTemplate("sink", gst.PAD_SINK, gst.PAD_ALWAYS,
+ gst.Caps("audio/x-raw-int;audio/x-raw-float"))
+
+ __gsttemplates__ = (_srctemplate, _sinktemplate)
+
+ def __init__(self):
+ gst.Element.__init__(self)
+ # add the source/sink pads
+ self.srcpad = gst.Pad(self._srctemplate)
+ self.sinkpad = gst.Pad(self._sinktemplate)
+ self.sinkpad.set_chain_function(self._chain)
+ self.sinkpad.set_event_function(self._sinkevent)
+ self.sinkpad.set_setcaps_function(self._setcaps)
+ self.add_pad(self.sinkpad)
+ self.add_pad(self.srcpad)
+ self.segment = gst.Segment()
+ self.segment.init(gst.FORMAT_UNDEFINED)
+
+ def _setcaps(self, sinkpad, caps):
+ self.debug("caps %s" % caps.to_string())
+ res = self.srcpad.get_peer().set_caps(caps)
+ self.debug("res %r" % res)
+ if res is True:
+ self.rate = caps[0]["rate"]
+ self.bps = (caps[0]["width"] / 8) * caps[0]["channels"]
+ self.bitrate = self.rate * self.bps
+ self.debug("rate:%d, bps:%d" % (self.rate, self.bps))
+ return res
+
+ def _sinkevent(self, pad, event):
+ self.debug("event:%r" % event)
+ if event.type == gst.EVENT_NEWSEGMENT:
+ self.debug("%r" % list(event.parse_new_segment()))
+ self.segment.set_newsegment(*event.parse_new_segment())
+ elif event.type == gst.EVENT_FLUSH_STOP:
+ self.segment.init(gst.FORMAT_UNDEFINED)
+ return self.srcpad.push_event(event)
+
+ def _chain(self, pad, inbuf):
+ pad.debug("inbuf %r %s %s" % (inbuf, gst.TIME_ARGS(inbuf.timestamp),
+ gst.TIME_ARGS(inbuf.duration)))
+ start = inbuf.timestamp
+ if inbuf.duration == gst.CLOCK_TIME_NONE:
+ stop = inbuf.timestamp + (inbuf.size * gst.SECOND) / self.bitrate
+ else:
+ stop = inbuf.timestamp + inbuf.duration
+ clip, nstart, nstop = self.segment.clip(gst.FORMAT_TIME, start, stop)
+ self.debug("clip:%r, nstart:%s, nstop:%s" % (clip, gst.TIME_ARGS(nstart),
+ gst.TIME_ARGS(nstop)))
+ if clip is True:
+ if nstart != start and nstop != stop:
+ self.debug("clipping")
+ nduration = nstop - nstart
+ # clip the buffer
+ offset = (nstart - start) * self.bitrate
+ # size
+ nsize = nduration * self.bitrate
+ b2 = inbuf.create_sub(offset, nsize)
+ b2.timestamp = nstart
+ b2.duration = nstop - nstart
+ self.debug("buffer clipped")
+ return self.srcpad.push(b2)
+ self.debug("buffer untouched, just pushing forward")
+ return self.srcpad.push(inbuf)
+ self.debug("buffer dropped")
+ return gst.FLOW_OK
+
+gobject.type_register(AudioClipper)
+gst.element_register(AudioClipper, 'audio-clipper')
+
+class ClipperProbe(object):
+
+ def __init__(self, pad):
+ self._pad = pad
+ self._pad.add_buffer_probe(self._bufferprobe)
+ self._pad.add_event_probe(self._eventprobe)
+ self.segment = gst.Segment()
+ self.segment.init(gst.FORMAT_UNDEFINED)
+ self._pad.connect("notify::caps", self._capsChangedCb)
+
+ def _capsChangedCb(self, pad, unk):
+ c = pad.get_negotiated_caps()
+ if c is None:
+ return
+ pad.debug("caps:%s" % c.to_string())
+ if c.is_fixed():
+ self.rate = c[0]["rate"]
+ self.bps = (c[0]["width"] / 8) * c[0]["channels"]
+ self.bitrate = self.rate * self.bps
+ pad.debug("rate:%d, bps:%d" % (self.rate, self.bps))
+
+ def _eventprobe(self, pad, event):
+ pad.debug("event %r" % event)
+ if event.type == gst.EVENT_NEWSEGMENT:
+ pad.debug("%r" % list(event.parse_new_segment()))
+ self.segment.set_newsegment(*event.parse_new_segment())
+ elif event.type == gst.EVENT_FLUSH_STOP:
+ self.segment.init(gst.FORMAT_UNDEFINED)
+ return True
+
+ def _bufferprobe(self, pad, inbuf):
+ start = inbuf.timestamp
+ if inbuf.duration == gst.CLOCK_TIME_NONE:
+ stop = inbuf.timestamp + (inbuf.size * gst.SECOND) / self.bitrate
+ else:
+ stop = inbuf.timestamp + inbuf.duration
+ pad.debug("inbuf %s %s" % (gst.TIME_ARGS(start),
+ gst.TIME_ARGS(stop)))
+ clip, nstart, nstop = self.segment.clip(gst.FORMAT_TIME, start, stop)
+ pad.debug("clip:%r, nstart:%s, nstop:%s" % (clip, gst.TIME_ARGS(nstart),
+ gst.TIME_ARGS(nstop)))
+ if clip is True:
+ if nstart != start or nstop != stop:
+ pad.debug("clipping")
+ nduration = nstop - nstart
+ # clip the buffer
+ offset = (nstart - start) * self.bitrate
+ # size
+ nsize = nduration * self.bitrate
+ pad.debug("changing data")
+ #inbuf.data = inbuf.data[offset:offset+nsize]
+ #inbuf = inbuf.create_sub(offset, nsize)
+ inbuf.timestamp = nstart
+ inbuf.duration = nstop - nstart
+ pad.debug("buffer clipped")
+ return False
+ return clip
diff --git a/pitivi/elements/mixer.py b/pitivi/elements/mixer.py
index 78080b6..c8908a3 100644
--- a/pitivi/elements/mixer.py
+++ b/pitivi/elements/mixer.py
@@ -26,6 +26,8 @@ Audio and Video mixers
import gobject
import gst
+from pitivi.elements.audioclipper import ClipperProbe
+
class SmartAdderBin(gst.Bin):
__gstdetails__ = (
@@ -73,10 +75,12 @@ class SmartAdderBin(gst.Bin):
adderpad = self.adder.get_request_pad("sink%d")
aresample.get_pad("src").link(adderpad)
+ clipper = ClipperProbe(aresample.get_pad("src"))
+
pad = gst.GhostPad(name, aconv.get_pad("sink"))
pad.set_active(True)
self.add_pad(pad)
- self.inputs[name] = (pad, aconv, aresample, adderpad)
+ self.inputs[name] = (pad, aconv, aresample, clipper, adderpad)
self.pad_count += 1
return pad
@@ -84,7 +88,7 @@ class SmartAdderBin(gst.Bin):
self.debug("pad:%r" % pad)
name = pad.get_name()
if name in self.inputs.keys():
- sinkpad, aconv, aresample, adderpad = self.inputs.pop(name)
+ sinkpad, aconv, aresample, clipper, adderpad = self.inputs.pop(name)
# we deactivate this pad to make sure that if ever the streaming
# thread was doing something downstream (like getting caps) it will
# return with GST_FLOW_WRONG_STATE and not GST_FLOW_NOT_LINKED (which is
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]