[gst-devel] Seek failing on paused pipeline

David Banks amoebae at gmail.com
Thu Oct 9 17:36:28 CEST 2008


Dear gst-devel,

Further to my question a while back, I have now progressed to my next task.
This time I'm trying to capture a section from a stream to a file, using
gst_element_seek().  My program is included below.

As you can see, I watch for state changes on the bus.  When the pipeline goes to
PAUSED state, I perform the seek.  To quote the manual for
gst_element_seek_simple: 'In a completely prerolled PAUSED or PLAYING pipeline,
seeking is always guaranteed to return TRUE on a seekable media type.'  Since I
seek while the pipeline is paused, I expect the program below to give the
output:

stream is now ready
seek result: 1

And 'output.wav' should contain the 10 second period from 10 to 20 seconds of
'/home/amoe/test.ogg'.  In reality, I get this output:

stream is now ready
seek result: 0
stream is now ready
seek result: 0
stream is now ready
seek result: 0
stream is now ready
seek result: 0
stream is now ready
seek result: 0
stream is now ready
seek result: 1

And 'output.wav' contains the entire decoding of 'test.ogg'.

The really strange thing is that sometimes it will give the 10-second output I
expect, maybe once in every 100 runs?  The console output will always be the
same, though.

I really don't know what's going on here.  As far as I can see, I'm not missing
any events, and the seek should be executed before the pipeline goes to PLAYING
state, so my first thought (that the whole file is getting decoded to
'output.wav' before the seek has a chance to be executed) should not be
possible.

Any ideas?

Thanks,
David

#include <stdio.h>
#include <stdbool.h>

#include <gst/gst.h>

GstElement *pipeline, *audio;
gboolean seek_succeeded = FALSE;

static void cb_new_decoded_pad(
    GstElement *decodebin, GstPad *pad, gboolean last, gpointer data
);
static gboolean cb_bus_watch(GstBus *bus, GstMessage *message, gpointer data);
void handle_state_change();

int main(int argc, char **argv) {
    GMainLoop *loop;
    GstElement *src, *dec, *conv1, *conv2, *sink;
    GstPad *audiopad;
    GstBus *bus;

    gst_init(&argc, &argv);

    loop = g_main_loop_new(NULL, FALSE);

    pipeline = gst_pipeline_new("pipeline");
    audio    = gst_bin_new("audiobin");

    src = gst_element_factory_make("filesrc", "source");
    dec = gst_element_factory_make("decodebin", "decoder");
    conv1 = gst_element_factory_make("audioconvert", "aconv");
    conv2 = gst_element_factory_make("wavenc", "wconv");
    sink = gst_element_factory_make("filesink", "sink");

    g_object_set(G_OBJECT(src), "location", "/home/amoe/test.ogg", NULL);
    g_object_set(G_OBJECT(sink), "location", "output.wav", NULL);

    gst_bin_add_many(GST_BIN(pipeline), src, dec, NULL);
    gst_element_link(src, dec);

    gst_bin_add_many(GST_BIN(audio), conv1, conv2, sink, NULL);
    gst_element_link(conv1, conv2);
    gst_element_link(conv2, sink);

    // Do some voodoo
    audiopad = gst_element_get_static_pad(conv1, "sink");
    gst_element_add_pad(audio, gst_ghost_pad_new("sink", audiopad));
    gst_object_unref(audiopad);

    gst_bin_add(GST_BIN(pipeline), audio);

    // Connect signals & buses
    g_signal_connect(
        dec, "new-decoded-pad", G_CALLBACK(cb_new_decoded_pad), NULL
    );

    bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
    gst_bus_add_watch(bus, cb_bus_watch, loop);
    gst_object_unref(bus);

    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    g_main_loop_run(loop);

    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(GST_OBJECT(pipeline));

    return 0;
}

static void cb_new_decoded_pad(
    GstElement *decodebin, GstPad *pad, gboolean last, gpointer data
) {
    GstPad *audiopad;

    audiopad = gst_element_get_static_pad(audio, "sink");
    gst_pad_link(pad, audiopad);
}

static gboolean cb_bus_watch(GstBus *bus, GstMessage *message, gpointer data) {
    GMainLoop *loop = data;

    switch (GST_MESSAGE_TYPE(message)) {
    case GST_MESSAGE_EOS:
        g_main_loop_quit(loop);
        break;
    case GST_MESSAGE_STATE_CHANGED:
        handle_state_change(message);
        break;
    default:
        break;
    }

    return TRUE;
}

void handle_state_change(GstMessage *msg) {
    GstState previous;
    GstState current;
    GstState pending;
    gboolean ret;

    gst_message_parse_state_changed(msg, &previous, &current, &pending);

    if (current == GST_STATE_PAUSED && !seek_succeeded) {
        printf("stream is now ready\n");

        // Not working.  NB, the use of GST_SEEK_FLAG_FLUSH changes the stream
        // to one that never gets EOS?  Why?
        ret = gst_element_seek(
            pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE,
            GST_SEEK_TYPE_SET, 10 * GST_SECOND,
            GST_SEEK_TYPE_SET, 20 * GST_SECOND
        );

        printf("seek result: %d\n", ret);
        seek_succeeded = ret;
    }
}


-- 
David Banks  <amoebae at gmail.com>




More information about the gstreamer-devel mailing list