tee src pad buffers

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

tee src pad buffers

Ron McOuat
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
Reply | Threaded
Open this post in threaded view
|

Re: tee src pad buffers

Tim-Philipp Müller-2
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
Reply | Threaded
Open this post in threaded view
|

Re: tee src pad buffers

Josep Torra
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
Reply | Threaded
Open this post in threaded view
|

Re: tee src pad buffers

Ron McOuat
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
Reply | Threaded
Open this post in threaded view
|

Re: tee src pad buffers

Ron McOuat
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