Seek failing on paused pipeline

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

Seek failing on paused pipeline

David Banks-3
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  <[hidden email]>

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Seek failing on paused pipeline

Arnout Vandecappelle
 Hoi David,

 Not that I know much about seeking, but since nobody else is replying, I
will :-)

 There is no need to use a bus watch in order to wait for the state to change
to paused.  Instead, you can simply do the following from main():

    gst_element_set_state(pipeline, GST_STATE_PAUSED);
    gst_element_get_state(pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);

 The gst_element_get_state is required because setting the state to PAUSED
happens asynchronously.

 The reason that you get 'stream is now ready' several times is that you get a
bus message for the state change of each individual element; it's only the
last one (that of the pipeline) that is actually OK.  In fact, trying to seek
on the pipeline which is not yet completely prerolled (i.e. state is not yet
PAUSED) causes the pipeline to remain in an erroneous state...

 When you set the state to PLAYING, the playing thread will run concurrently
with your main thread.  Therefore, some output will already be generated in
the file before you start seeking.  By delaying the PLAYING until after
you've done the seek, you avoid this problem.

 Does this clarify things?
 Regards,
 Arnout

On Thursday 09 October 2008 17:36:28 David Banks wrote:

> 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

--
Arnout Vandecappelle                               arnout at mind be
Senior Embedded Software Architect                 +32-16-286540
Essensium/Mind                                     http://www.mind.be
G.Geenslaan 9, 3001 Leuven, Belgium                BE 872 984 063 RPR Leuven
LinkedIn profile: http://www.linkedin.com/in/arnoutvandecappelle
GPG fingerprint:  D206 D44B 5155 DF98 550D  3F2A 2213 88AA A1C7 C933

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gstreamer-devel