I am using the tee element to replicate a stream. In seems the buffer
passed in from gst_tee_chain() to gst_tee_handle_buffer() and then gst_tee_do_push() has an extra ref placed on it as it is pushed out each src pad. From this I presume tee replicates references and not actual contents. I see a function gst_tee_buffer_alloc() and if the alloc fails gst_tee_find_buffer_alloc() but do not see where they are called. My issue is using a live source, downstream from the tee I offset time stamps using a buffer probe handler for when recording is turned on or off in one of the branches. The time offset changes bleed into the other tee branches because of what I think is buffer reference copying instead of content copying. Since most users would not want to do this I don't feel it is appropriate to treat his as a defect. I probably missed something, still learning this great library. Could I please get confirmation of my understanding of tee pad buffers? Where is gst_tee_buffer_alloc used? As an alternate I could feed the front end into a multifdsink and then pull the data out for the different purposes by connecting to that element using a UNIX socket. I would prefer to not do this for efficiency reasons but the system use is minimal for moving data around so maybe not a good reason to avoid this approach. Thanks Ron McOuat ------------------------------------------------------------------------------ Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise -Strategies to boost innovation and cut costs with open source participation -Receive a $600 discount off the registration fee with the source code: SFAD http://p.sf.net/sfu/XcvMzF8H _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/gstreamer-devel |
On Fri, 2009-02-27 at 10:26 -0800, Ron McOuat wrote:
Hi, > [tee element internals] From this I presume tee replicates references > and not actual contents. Correct. > My issue is using a live source, downstream from the tee I offset time > stamps using a buffer probe handler for when recording is turned on or > off in one of the branches. The time offset changes bleed into the other > tee branches because of what I think is buffer reference copying instead > of content copying. Correct. You aren't really allowed to do this in a buffer probe callback. What you want to do before changing the offset is gst_buffer_make_writable(), which will copy the buffer *structure* and metadata if needed (but not the content) so you can change it. However, you can't use that in a pad probe callback, since you can't return the new buffer pointer. You should/need to write an element to do this. > As an alternate I could feed the front end into a multifdsink and then > pull the data out for the different purposes by connecting to that > element using a UNIX socket. I would prefer to not do this for > efficiency reasons but the system use is minimal for moving data around > so maybe not a good reason to avoid this approach. The latest gst-plugins-base release contains the appsink element, which is a much easier and much more efficient way to get data out of a pipeline if you have to. Cheers -Tim ------------------------------------------------------------------------------ Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise -Strategies to boost innovation and cut costs with open source participation -Receive a $600 discount off the registration fee with the source code: SFAD http://p.sf.net/sfu/XcvMzF8H _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/gstreamer-devel |
In reply to this post by Ron McOuat
Hi Ron,
If the timestamps on the other branches are not really important you can also send a newsegment to the tee element to notify it on all branches. This is what I did in the small experimental project attached to this mail. It's not completely working, there's some strange issue with the theora encoder when I try to generate keyframes at each 10 frames/1 second of recording. Could someone give me some help in fix the issues? It could be added to gst-python set of examples if you believe that it's interesting. Thanks in advance. Josep Ron McOuat wrote: > I am using the tee element to replicate a stream. In seems the buffer > passed in from gst_tee_chain() to gst_tee_handle_buffer() and then > gst_tee_do_push() has an extra ref placed on it as it is pushed out each > src pad. From this I presume tee replicates references and not actual > contents. I see a function gst_tee_buffer_alloc() and if the alloc fails > gst_tee_find_buffer_alloc() but do not see where they are called. > > My issue is using a live source, downstream from the tee I offset time > stamps using a buffer probe handler for when recording is turned on or > off in one of the branches. The time offset changes bleed into the other > tee branches because of what I think is buffer reference copying instead > of content copying. Since most users would not want to do this I don't > feel it is appropriate to treat his as a defect. > > I probably missed something, still learning this great library. Could I > please get confirmation of my understanding of tee pad buffers? Where is > gst_tee_buffer_alloc used? > > As an alternate I could feed the front end into a multifdsink and then > pull the data out for the different purposes by connecting to that > element using a UNIX socket. I would prefer to not do this for > efficiency reasons but the system use is minimal for moving data around > so maybe not a good reason to avoid this approach. > > Thanks > > Ron McOuat > > ------------------------------------------------------------------------------ > Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA > -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise > -Strategies to boost innovation and cut costs with open source participation > -Receive a $600 discount off the registration fee with the source code: SFAD > http://p.sf.net/sfu/XcvMzF8H > _______________________________________________ > gstreamer-devel mailing list > [hidden email] > https://lists.sourceforge.net/lists/listinfo/gstreamer-devel #!/usr/bin/env python # -*- Mode: Python -*- # vi:si:et:sw=4:sts=4:ts=4 # record.py # (c) 2009 Josep Torra <n770galaxy at gmail dot com> # Record from v4l2src and alsasrc. # An small project to learn how to use gst-python and dynamicly change # a pipleline in the fly. # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library 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 # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. import pygtk pygtk.require('2.0') import sys import gobject gobject.threads_init() import pygst pygst.require('0.10') import gst import gst.interfaces import gtk class SnapshotElement(gst.Element): _srcpadtemplate = \ gst.PadTemplate("src", gst.PAD_SRC, gst.PAD_ALWAYS, gst.caps_new_any()) _sinkpadtemplate = \ gst.PadTemplate("sink", gst.PAD_SINK, gst.PAD_ALWAYS, gst.caps_new_any()) __gstdetails__ = ('SnapshotElement','Element', \ 'Snapshot Element', 'Person') def __init__(self): gst.Element.__init__(self) gst.debug("Snapshot Init") self.sinkpad = gst.Pad(self._sinkpadtemplate, "sink") self.add_pad(self.sinkpad) self.srcpad = gst.Pad(self._srcpadtemplate, "src") self.add_pad(self.srcpad) self.sinkpad.set_chain_function(self.chainfunc) gst.debug('added pads and chain functions') self.doSnapshot = False def chainfunc(self, pad, buffer): # only one buffer is pushed downstream if self.doSnapshot: gst.debug("Take snapshot") self.doSnapshot = False # send the buffer ret = self.srcpad.push(buffer) if ret != gst.FLOW_OK: return ret # send EOS self.srcpad.push_event(gst.event_new_eos()) # otherwise the buffers are dropped return gst.FLOW_OK def do_snapshot(self): self.doSnapshot = True class PhotoBin(gst.Bin): def __init__(self, location): gst.Bin.__init__(self, "PhotoBin") # Create elements self.snapshot = SnapshotElement() # gst.element_factory_make("snapshot", "snap") colorspace = gst.element_factory_make("ffmpegcolorspace", "cs") penc = gst.element_factory_make("jpegenc", "penc") self.psink = gst.element_factory_make("filesink", "psink") # Set properties self.set_location(location) self.psink.set_property('async', False) # Add elements to bin self.add(self.snapshot, colorspace, penc, self.psink) # Link the elements gst.element_link_many(self.snapshot, colorspace, penc, self.psink) self.sinkpad = gst.GhostPad("sink", self.snapshot.get_static_pad("sink")) self.add_pad(self.sinkpad) # Take filesink bus self.binbus = self.psink.get_bus() # Create a new bus and replace the filesink one in order to intercept # the EOS message in filesink bus = gst.Bus() self.psink.set_bus(bus) bus.add_signal_watch() bus.connect('message', self.on_message) def set_location(self, location): self.psink.set_property('location', location) gst.debug("set location %s on photobin" % location) def get_sinkpad(self): return self.sinkpad def on_message(self, bus, message): t = message.type if t == gst.MESSAGE_EOS: #self.binbus.post(message) self.binbus.post(gst.message_new_element(self, gst.Structure("snapshot-complete"))) gst.debug("post snapshot-complete") else: self.binbus.post(message) def do_snapshot(self): self.snapshot.do_snapshot() class AudioEncBin(gst.Bin): def __init__(self, samplerate): gst.Bin.__init__(self, "AudioEncBin") gst.debug("AudioEncBin init") self.configure(15 * gst.SECOND) # Create elements asrc = gst.element_factory_make("alsasrc", "asrc") q1 = gst.element_factory_make("queue", "aequeue1") acapsfilt = gst.Caps("audio/x-raw-int, rate=(int) %s" % samplerate) audioconvert = gst.element_factory_make("audioconvert", "ac") q2 = gst.element_factory_make("queue", "aequeue2") aenc = gst.element_factory_make("vorbisenc", "aenc") q3 = gst.element_factory_make("queue", "aequeue3") # Add elements to bin self.add(asrc, q1, audioconvert, q2, aenc, q3) # Link the elements q1.link(audioconvert, acapsfilt) gst.element_link_many(audioconvert, q2, aenc, q3) asrc.link(q1) # Create the pads self.srcpad = gst.GhostPad("src", q3.get_static_pad("src")) self.add_pad(self.srcpad) # Add a buffer probe to do retimestamping pad = q1.get_static_pad("sink") pad.add_buffer_probe(self.buffer_probe) def get_srcpad(self): return self.srcpad def configure(self, duration): self.adjust_ts = True self.eos = False self.duration = duration def buffer_probe(self, pad, buffer): gst.log ("audio buffer in with ts %d" % (buffer.timestamp)) if self.adjust_ts: self.adjust_ts = False self.delta_ts = buffer.timestamp newseg = gst.event_new_new_segment(False, 1, gst.FORMAT_TIME, 0, -1, 0) pad.send_event(newseg) gst.debug("send newsegment on audio branch") buffer.flag_set(gst.BUFFER_FLAG_DISCONT) buffer.timestamp = buffer.timestamp - self.delta_ts if buffer.timestamp > self.duration: if not self.eos: eos_event = gst.event_new_eos() pad.send_event(eos_event) self.eos = True gst.debug("send eos on audio branch") gst.log("drop audio buffer") return False gst.log ("audio buffer out with ts %d" % (buffer.timestamp)) return True class VideoEncBin(gst.Bin): def __init__(self): gst.Bin.__init__(self, "VideoEncBin") gst.debug("VideoEncBin init") # Create elements queue1 = gst.element_factory_make("queue", "vequeue1") videorate = gst.element_factory_make("videorate", "vr") videoscale = gst.element_factory_make("videoscale", "vs") colorconv = gst.element_factory_make("ffmpegcolorspace", "vcc") vcapsfilt = gst.Caps("video/x-raw-yuv, width=(int)160, height=(int)120, framerate=(fraction)10/1") venc = gst.element_factory_make("theoraenc", "venc") venc.set_property('keyframe-auto', False) venc.set_property('keyframe-freq', 20) venc.set_property('keyframe-force', 20) venc.set_property('keyframe-mindistance', 3) queue2 = gst.element_factory_make("queue", "vequeue2") # Add elements to bin self.add (queue1, videorate, videoscale, colorconv, venc, queue2) # Link the elements colorconv.link (venc, vcapsfilt) gst.element_link_many(queue1, videorate, videoscale, colorconv) venc.link (queue2) # Create the pads self.sinkpad = gst.GhostPad("sink", queue1.get_static_pad("sink")) self.srcpad = gst.GhostPad("src", queue2.get_static_pad("src")) self.add_pad(self.sinkpad) self.add_pad(self.srcpad) def get_sinkpad(self): return self.sinkpad def get_srcpad(self): return self.srcpad class MuxerBin(gst.Bin): def __init__(self, location): gst.Bin.__init__(self, "MuxerBin") gst.debug("MuxerBin init") # Create elements self.muxer = gst.element_factory_make("oggmux", "muxer") self.msink = gst.element_factory_make("filesink", "msink") self.set_location(location) self.msink.set_property('async', False) # Add elements to bin self.add (self.muxer, self.msink) # Link the elements gst.element_link_many(self.muxer, self.msink) self.gasinkpad = None self.gvsinkpad = None # Take filesink bus self.binbus = self.msink.get_bus() # Create a new bus and replace the filesink one in order to intercept # the EOS message in filesink bus = gst.Bus() self.msink.set_bus(bus) bus.add_signal_watch() bus.connect('message', self.on_message) def on_message(self, bus, message): t = message.type if t == gst.MESSAGE_EOS: #self.binbus.post(message) self.binbus.post(gst.message_new_element(self, gst.Structure("clip-complete"))) gst.debug("Post clip-complete") else: self.binbus.post(message) def set_location(self, location): self.msink.set_property('location', location) gst.debug("set location %s on muxerbin" % location) def audio_pad(self): if self.gasinkpad == None: self.asink = self.muxer.get_request_pad("sink_%d") self.gasinkpad = gst.GhostPad("asink", self.asink) self.add_pad(self.gasinkpad) gst.debug("created audio pad in muxer") return self.gasinkpad def remove_audio_pad(self): gst.debug("remove audio pad") if self.gasinkpad != None: self.remove_pad(self.gasinkpad) self.muxer.release_request_pad(self.asink) self.asink = None self.gasinkpad = None def video_pad(self): if self.gvsinkpad == None: self.vsink = self.muxer.get_request_pad("sink_%d") self.gvsinkpad = gst.GhostPad("vsink", self.vsink) self.add_pad(self.gvsinkpad) gst.debug("created video pad in muxer") return self.gvsinkpad def remove_video_pad(self): gst.debug("remove video pad") if self.gvsinkpad != None: self.remove_pad(self.gvsinkpad) self.muxer.release_request_pad(self.vsink) self.vsink = None self.gvsinkpad = None class LiveBin(gst.Bin): def __init__(self, videowidget): gst.Bin.__init__(self, "LiveBin") gst.debug("LiveBin init") self.configure(15 * gst.SECOND, False) self.adjust_ts = False self.delta_ts = 0 # Create elements vsrc = gst.element_factory_make("v4l2src", "vsrc") q1 = gst.element_factory_make("queue", "vq1") self.vtee = gst.element_factory_make("tee", "vtee") q2 = gst.element_factory_make("queue", "vq2") # set queue leaky, we don't want to block video encoder feed, but # prefer drop some buffers in xvimagesink instead. q2.set_property('leaky', 2) vsink = gst.element_factory_make("xvimagesink", "vsink") # Add elements to bin self.add (vsrc, q1, self.vtee, q2, vsink) # Link the elements gst.element_link_many(vsrc, q1, self.vtee, q2, vsink) # Create the pads self.psrcpad = gst.GhostPad("psrc", self.vtee.get_request_pad("src%d")) self.add_pad(self.psrcpad) vpad = self.vtee.get_request_pad("src%d") self.vsrcpad = gst.GhostPad("vsrc", vpad) self.add_pad(self.vsrcpad) self.videowidget = videowidget # Add a buffer probe to do retimestamping self.vsrcpad.add_buffer_probe(self.buffer_probe) def on_sync_message(self, bus, message): if message.structure is None: return if message.structure.get_name() == 'prepare-xwindow-id': # Sync with the X server before giving the X-id to the sink gtk.gdk.display_get_default().sync() self.videowidget.set_sink(message.src) message.src.set_property('force-aspect-ratio', True) def get_psrcpad(self): return self.psrcpad def get_vsrcpad(self): return self.vsrcpad def configure(self, duration, recording): self.adjust_ts = True self.eos = False self.duration = duration self.recording = recording def buffer_probe(self, pad, buffer): gst.log ("video buffer in with ts %d" % (buffer.timestamp)) if self.adjust_ts: self.adjust_ts = False self.delta_ts = buffer.timestamp spad = self.vtee.get_static_pad("sink") newseg = gst.event_new_new_segment(False, 1, gst.FORMAT_TIME, 0, -1, 0) spad.send_event(newseg) buffer.flag_set(gst.BUFFER_FLAG_DISCONT) gst.debug("send newsegment on video branch") buffer.timestamp = buffer.timestamp - self.delta_ts gst.log ("video buffer out with ts %d" % (buffer.timestamp)) if self.recording and buffer.timestamp > self.duration: if not self.eos: eos_event = gst.event_new_eos() pad.push_event(eos_event) self.eos = True gst.debug("send eos on video branch") gst.log("drop video buffer") return False return True class VideoWidget(gtk.DrawingArea): def __init__(self): gtk.DrawingArea.__init__(self) self.imagesink = None self.unset_flags(gtk.DOUBLE_BUFFERED) def do_expose_event(self, event): if self.imagesink: self.imagesink.expose() return False else: return True def set_sink(self, sink): assert self.window.xid self.imagesink = sink self.imagesink.set_xwindow_id(self.window.xid) class RecordPipeline(gst.Pipeline): def __init__(self, videowidget): gst.Pipeline.__init__(self) gst.debug("RecordPipeline init") self.audioclip = False self.videoclip = False self.livebin = LiveBin(videowidget) self.photobin = PhotoBin("test.jpg") self.videoencbin = VideoEncBin() self.audioenc8kbin = AudioEncBin("8000") self.audioenc16kbin = AudioEncBin("16000") self.muxerbin = MuxerBin("test.ogg") bus = self.get_bus() bus.enable_sync_message_emission() bus.add_signal_watch() bus.connect('sync-message::element', self.livebin.on_sync_message) bus.connect('message', self.on_message) self.add(self.livebin) def on_message(self, bus, message): t = message.type if t == gst.MESSAGE_ERROR: err, debug = message.parse_error() print "Error: %s" % err, debug elif t == gst.MESSAGE_EOS: print "EOS" elif t == gst.MESSAGE_ELEMENT: if message.structure.has_name("snapshot-complete"): print "Snapshot completed" self.remove_photobin() if message.structure.has_name("clip-complete"): print "Clip recorded" if self.audioclip: self.audioclip = False self.close_audioclip() if self.videoclip: self.videoclip = False self.close_videoclip() def do_photo(self): gst.debug("do_photo") sinkpad = self.photobin.get_sinkpad() srcpad = self.livebin.get_psrcpad() if srcpad.set_blocked(True): self.add(self.photobin) self.photobin.sync_state_with_parent() srcpad.link(sinkpad) self.photobin.do_snapshot() srcpad.set_blocked(False) def remove_photobin(self): gst.debug("remove_photobin") sinkpad = self.photobin.get_sinkpad() srcpad = self.livebin.get_psrcpad() if srcpad.set_blocked(True): srcpad.unlink(sinkpad) self.remove(self.photobin) self.photobin.set_state(gst.STATE_NULL) srcpad.set_blocked(False) def do_photo_and_audioclip(self): gst.debug("do_photo_and_audioclip") self.audioclip = True gst.debug("get pads") sinkpad = self.muxerbin.audio_pad() srcpad = self.audioenc16kbin.get_srcpad() self.do_photo() gst.debug("try to add some elements") self.add(self.audioenc16kbin) self.add(self.muxerbin) gst.debug("sync state in the added elements") self.muxerbin.sync_state_with_parent() self.audioenc16kbin.sync_state_with_parent() gst.debug("link pads") srcpad.link(sinkpad) gst.debug("ask for a timestamp readjustment") self.audioenc16kbin.configure(15 * gst.SECOND) def close_audioclip(self): gst.debug("close_audioclip") self.audioenc16kbin.set_state(gst.STATE_NULL) self.muxerbin.set_state(gst.STATE_NULL) self.remove(self.audioenc16kbin) self.remove(self.muxerbin) self.muxerbin.remove_audio_pad() def do_photo_and_videoclip(self): gst.debug("do_photo_and_videoclip") self.videoclip = True gst.debug("get pads") asinkpad = self.muxerbin.audio_pad() asrcpad = self.audioenc8kbin.get_srcpad() vsinkpad = self.muxerbin.video_pad() vsrcpad = self.livebin.get_vsrcpad() vesinkpad = self.videoencbin.get_sinkpad() vesrcpad = self.videoencbin.get_srcpad() self.do_photo() gst.debug("try to add some elements") self.add(self.audioenc8kbin) self.add(self.videoencbin) self.add(self.muxerbin) gst.debug("sync state in the added elements") self.muxerbin.sync_state_with_parent() self.videoencbin.sync_state_with_parent() self.audioenc8kbin.sync_state_with_parent() gst.debug("link pads") asrcpad.link(asinkpad) vsrcpad.link(vesinkpad) vesrcpad.link(vsinkpad) gst.debug("ask for a timestamp readjustment") self.audioenc8kbin.configure(15 * gst.SECOND) self.livebin.configure(15 * gst.SECOND, True) def close_videoclip(self): gst.debug("close_videoclip") asinkpad = self.muxerbin.audio_pad() asrcpad = self.audioenc8kbin.get_srcpad() vsinkpad = self.muxerbin.video_pad() vsrcpad = self.livebin.get_vsrcpad() vesinkpad = self.videoencbin.get_sinkpad() vesrcpad = self.videoencbin.get_srcpad() asrcpad.unlink(asinkpad) vsrcpad.unlink(vesinkpad) vesrcpad.unlink(vsinkpad) self.remove(self.audioenc8kbin) self.remove(self.videoencbin) self.remove(self.muxerbin) self.audioenc8kbin.set_state(gst.STATE_NULL) self.videoencbin.set_state(gst.STATE_NULL) self.muxerbin.set_state(gst.STATE_NULL) self.muxerbin.remove_audio_pad() self.muxerbin.remove_video_pad() self.livebin.configure(15 * gst.SECOND, False) class RecordWindow(gtk.Window): def __init__(self): gtk.Window.__init__(self) self.set_default_size(640, 480) self.create_ui() self.pipeline = RecordPipeline(self.videowidget) self.pipeline.set_state(gst.STATE_PLAYING) def on_delete_event(): self.pipeline.set_state(gst.STATE_NULL) gtk.main_quit() self.connect('delete-event', lambda *x: on_delete_event()) def create_ui(self): vbox = gtk.VBox() self.add(vbox) self.videowidget = VideoWidget() vbox.pack_start(self.videowidget) hbox = gtk.HBox() vbox.pack_start(hbox, fill=False, expand=False) button1 = gtk.Button() button1.set_property('can-default', True) button1.set_focus_on_click(False) button1.set_label("Take a photo") button1.show() hbox.pack_start(button1, False) button1.set_property('has-default', True) button1.connect('clicked', lambda *args: self.do_photo()) button2 = gtk.Button() button2.set_property('can-default', True) button2.set_focus_on_click(False) button2.set_label("Take a photo and record an audio clip") button2.show() hbox.pack_start(button2, False) button2.set_property('has-default', True) button2.connect('clicked', lambda *args: self.do_photo_and_audioclip()) button3 = gtk.Button() button3.set_property('can-default', True) button3.set_focus_on_click(False) button3.set_label("Take a photo and record a video clip") button3.show() hbox.pack_start(button3, False) button3.set_property('has-default', True) button3.connect('clicked', lambda *args: self.do_photo_and_videoclip()) def do_photo(self): self.pipeline.do_photo() def do_photo_and_audioclip(self): self.pipeline.do_photo_and_audioclip() def do_photo_and_videoclip(self): self.pipeline.do_photo_and_videoclip() def main(args): # Need to register our derived widget types for implicit event # handlers to get called. gobject.type_register(SnapshotElement) gobject.type_register(RecordWindow) gobject.type_register(VideoWidget) w = RecordWindow() w.show_all() gtk.main() if __name__ == '__main__': sys.exit(main(sys.argv)) ------------------------------------------------------------------------------ Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise -Strategies to boost innovation and cut costs with open source participation -Receive a $600 discount off the registration fee with the source code: SFAD http://p.sf.net/sfu/XcvMzF8H _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/gstreamer-devel |
Hi Josep,
As Tim-Philipp Muller commented in the same thread it isn't really valid to poke new times into the buffer without calling gst_buffer_make_writable but even if you do make this call the new buffer can't be returned on a buffer probe. In my case I do care about the timestamps changing in the other branches of the tee. It appears in record.py you are changing buffer timestamps in both the video and audio branch (lines 184 and 380) as well as sending the new segment message. At least in your case the adjusting is occurring in the audio and video portions of the map which are independent until you get to the muxer. With what I was doing I had two branches after a tee doing the timestamp adjusting and destructively interfering with each other with some bizarre results. I will try your example at some point tomorrow and see if I can spot anything. Ron Josep Torra wrote: > Hi Ron, > > If the timestamps on the other branches are not really important you > can also send a newsegment to the tee element to notify it on all > branches. > > This is what I did in the small experimental project attached to this > mail. > > It's not completely working, there's some strange issue with the > theora encoder when I try to generate keyframes at each 10 frames/1 > second of recording. > > Could someone give me some help in fix the issues? > > It could be added to gst-python set of examples if you believe that > it's interesting. > > Thanks in advance. > > Josep > > Ron McOuat wrote: >> I am using the tee element to replicate a stream. In seems the buffer >> passed in from gst_tee_chain() to gst_tee_handle_buffer() and then >> gst_tee_do_push() has an extra ref placed on it as it is pushed out >> each src pad. From this I presume tee replicates references and not >> actual contents. I see a function gst_tee_buffer_alloc() and if the >> alloc fails gst_tee_find_buffer_alloc() but do not see where they are >> called. >> >> My issue is using a live source, downstream from the tee I offset >> time stamps using a buffer probe handler for when recording is turned >> on or off in one of the branches. The time offset changes bleed into >> the other tee branches because of what I think is buffer reference >> copying instead of content copying. Since most users would not want >> to do this I don't feel it is appropriate to treat his as a defect. >> >> I probably missed something, still learning this great library. Could >> I please get confirmation of my understanding of tee pad buffers? >> Where is gst_tee_buffer_alloc used? >> >> As an alternate I could feed the front end into a multifdsink and >> then pull the data out for the different purposes by connecting to >> that element using a UNIX socket. I would prefer to not do this for >> efficiency reasons but the system use is minimal for moving data >> around so maybe not a good reason to avoid this approach. >> >> Thanks >> >> Ron McOuat >> >> ------------------------------------------------------------------------------ >> >> Open Source Business Conference (OSBC), March 24-25, 2009, San >> Francisco, CA >> -OSBC tackles the biggest issue in open source: Open Sourcing the >> Enterprise >> -Strategies to boost innovation and cut costs with open source >> participation >> -Receive a $600 discount off the registration fee with the source >> code: SFAD >> http://p.sf.net/sfu/XcvMzF8H >> _______________________________________________ >> gstreamer-devel mailing list >> [hidden email] >> https://lists.sourceforge.net/lists/listinfo/gstreamer-devel > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------------ > Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA > -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise > -Strategies to boost innovation and cut costs with open source participation > -Receive a $600 discount off the registration fee with the source code: SFAD > http://p.sf.net/sfu/XcvMzF8H > ------------------------------------------------------------------------ > > _______________________________________________ > gstreamer-devel mailing list > [hidden email] > https://lists.sourceforge.net/lists/listinfo/gstreamer-devel ------------------------------------------------------------------------------ Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise -Strategies to boost innovation and cut costs with open source participation -Receive a $600 discount off the registration fee with the source code: SFAD http://p.sf.net/sfu/XcvMzF8H _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/gstreamer-devel |
In reply to this post by Tim-Philipp Müller-2
Thanks Tim for your kind advice. This clarifies the way forward for me.
I also found the resettime element by Arnout Vandecappelle which I believe does what I need. Tim-Philipp Müller wrote: > On Fri, 2009-02-27 at 10:26 -0800, Ron McOuat wrote: > > Hi, > > >> [tee element internals] From this I presume tee replicates references >> and not actual contents. >> > > Correct. > > >> My issue is using a live source, downstream from the tee I offset time >> stamps using a buffer probe handler for when recording is turned on or >> off in one of the branches. The time offset changes bleed into the other >> tee branches because of what I think is buffer reference copying instead >> of content copying. >> > > Correct. You aren't really allowed to do this in a buffer probe > callback. What you want to do before changing the offset is > gst_buffer_make_writable(), which will copy the buffer *structure* and > metadata if needed (but not the content) so you can change it. However, > you can't use that in a pad probe callback, since you can't return the > new buffer pointer. > > You should/need to write an element to do this. > > > >> As an alternate I could feed the front end into a multifdsink and then >> pull the data out for the different purposes by connecting to that >> element using a UNIX socket. I would prefer to not do this for >> efficiency reasons but the system use is minimal for moving data around >> so maybe not a good reason to avoid this approach. >> > > The latest gst-plugins-base release contains the appsink element, which > is a much easier and much more efficient way to get data out of a > pipeline if you have to. > > Cheers > -Tim > > > > ------------------------------------------------------------------------------ > Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA > -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise > -Strategies to boost innovation and cut costs with open source participation > -Receive a $600 discount off the registration fee with the source code: SFAD > http://p.sf.net/sfu/XcvMzF8H > _______________________________________________ > gstreamer-devel mailing list > [hidden email] > https://lists.sourceforge.net/lists/listinfo/gstreamer-devel > > ------------------------------------------------------------------------------ Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA -OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise -Strategies to boost innovation and cut costs with open source participation -Receive a $600 discount off the registration fee with the source code: SFAD http://p.sf.net/sfu/XcvMzF8H _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/gstreamer-devel |
Free forum by Nabble | Edit this page |