How to ensure restructuring of pipeline at a particular keyframe/ buffer?

Peter Rennert p.rennert at cs.ucl.ac.uk
Tue Dec 4 10:03:01 PST 2012


Heya,

What I want to do is the following. At a certain time or external event 
I want to disconnect a "recording bin" of a pipeline and replace it with 
a spare "recording bin" of the same kind.

stage A:             .----------------------------------------.
src --> queue_0 --> queue --> h264parse --> mp4mux --> filesink
		     '------------- recording bin 1 ----------'

stage B:               .----------------------------------------.
src --> queue_0 -/-   queue --> h264parse --> mp4mux --> filesink
		       '------------- recording bin 1 ----------'

stage C:             .----------------------------------------.
src --> queue_0 --> queue --> h264parse --> mp4mux --> filesink
		     '------------- recording bin 2 ----------'


That works so far, no complains.

Moreover, I want to do an additional step. I want to manipulate the very 
first buffer that is send to "recording bin 2" in stage C. 
Unfortunately, as I do it now, the second buffer processed by "recording 
bin2" is manipulated. That is the only part that does not work and that 
this question is about.

I invoke stage B with:

GstPad* pad = gst_element_get_pad(this->queue_0, "src");

this->handler_id = gst_pad_add_buffer_probe (pad, GCallback(checkForKeyframes), this);

in checkForKeyFrames(), so stage B, I check for the next key frame, 
manipulate the buffer and invoke the swapping of my recording bins:

int UVCH264Cam::checkForKeyframes(GstPad *pad, GstBuffer *buffer, gpointer user_data){
     UVCH264Cam* cam = (UVCH264Cam*) user_data;

     if(!GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {

         // keyframe

         gst_pad_remove_data_probe(pad, cam->handler_id);

         if(cam->inSwapingBuffers){
             /* copy meta data into new key frame */
             QByteArray camHeader = QByteArray::fromHex("0000000167640028ac7680780227e5c0512000000300200000079c080002dc6c000b71b7bdf03c2211a80000000168ee38b0000000016588");            GstBuffer* newBuffer = gst_buffer_try_new_and_alloc(camHeader.size());
             memcpy(GST_BUFFER_DATA(newBuffer), camHeader.data_ptr(), camHeader.size());
             buffer = gst_buffer_merge(newBuffer, buffer);
             gst_buffer_unref(newBuffer);

             /* block pad and swap recording bins */
             gst_pad_set_blocked_async(gst_element_get_pad(cam->queue_0) , "src"), true, swapBins, cam);
         }
     }
     return GST_PAD_PROBE_PASS;
}

If I now probe the h264parse sink of "recording bin 2", I see that the 
second arriving buffer got manipulated, not the first. That is very 
strange for me. I considered delays, because of the asynchronous 
blocking. But now it seems the swapping is happening too fast, because 
that makes me think that the buffer probe at queue_0 gets invoked after 
the previous buffer left, but before that buffer arrives at "recording 
bin 1". So I swap the pipeline while the buffer flows from queue_0 to 
the "recording bin 1" and it arrives at "recording bin 2", or during the 
swapping process the dataflow is interrupted and continued at "recording 
bin 2". The latter would most probably cause some error in gstreamer, so 
I am not seriously thinking about that.

What do i do wrong here? How can I make sure that in stage C my pipeline 
only processes data that comes after (including) the keyframe I detected 
at the source of queue_0 -- the keyframe that invoked actually stage B 
and therefore should be the first processed in stage C? One thing that I 
need to avoid is to set the src which is a camera source to anything 
else than GST_STATE_PLAYING. My code works so far, if I am not 
considering the problem described here. The file destination is changed, 
the muxers continue to work properly, I get no complains by gstreamer.

I am out of ideas here. I would be very grateful for any help.

Thanks


More information about the gstreamer-devel mailing list