[gst-devel] Seek works strangely with filesink

David Banks amoebae at gmail.com
Wed Sep 17 22:20:26 CEST 2008


Hi, I'm just getting started with GStreamer.  I want to write a program to load
an Ogg file, play it, and seek to a random point within the file every two
seconds.  In addition, I want to be able to save the output of the program to a
file.

I initially wrote the program using the pipeline:

filesrc | oggdemux | vorbisdec | audioconvert | autoaudiosink

Basically according to the example given in the application development manual.
I added the function 'cb_timeout0' to detect the length and do the seek.  That
version worked perfectly and produced exactly what I expected.

I then tried to make it write its output to a file.  I initially tried to simply
replace 'autoaudiosink' with 'filesink', but couldn't figure out the format of
the raw samples in the output file.  Since I wanted WAV output anyway, I tried
using wavenc.  After a little trial and error, I found the pipeline below:

filesrc | oggdemux | vorbisdec | audioconvert | wavenc | filesink

I converted it to the program below.  This program displays an odd behaviour,
however.  Its output is always the size of the fully decoded Ogg file, no matter
where you interrupt it.  That is, even if you run it for only a few seconds
(when it .  In addition, the seeks in the output are erratic.  For
example, if you run the program for three minutes, the output file might contain
only three or four seeks.  They seem to occur at random points in the output.

Why is the filesink output so different from the autoaudiosink output?  Is it
possible the seeks are happening in the *output* rather than the input file?  I
tried replacing the first parameter to gst_element_seek() with a pointer to the
demuxer rather than the entire pipeline, but still the same behaviour.

// gcc -o demo -Wall -g $(pkg-config --libs --cflags $(libs)) demo.c

#include <stdio.h>

#include <gst/gst.h>
#include <glib.h>

static gboolean cb_bus(GstBus *bus, GstMessage *msg, gpointer data);
static void cb_pad_added(GstElement *element, GstPad *pad, gpointer data);
gboolean cb_timeout0(gpointer data);

gint32 pos = 0;

int main(int argc, char **argv) {
    GMainLoop *loop;
    GstElement *pipeline, *source, *demuxer, *decoder, *conv1, *conv2, *sink;
    GstBus *bus;

    gst_init(&argc, &argv);
    loop = g_main_loop_new(NULL, FALSE);

    if (argc != 2) {
        g_printerr("Usage: %s <ogg vorbis filename>\n", argv[0]);
        return 1;
    }

    pipeline = gst_pipeline_new("audio-player");
    source = gst_element_factory_make("filesrc", "file-source");
    demuxer = gst_element_factory_make("oggdemux", "ogg-demuxer");
    decoder = gst_element_factory_make("vorbisdec", "vorbis-decoder");
    conv1    = gst_element_factory_make("audioconvert", NULL);
    conv2    = gst_element_factory_make("wavenc", NULL);
    sink    = gst_element_factory_make("filesink", "audio-output");

    if (!pipeline || !source || !demuxer || !decoder || !conv1 ||
!conv2 || !sink) {
        g_printerr("pipeline failed to create properly, exiting\n");
        return 1;
    }

    g_object_set(G_OBJECT(source), "location", argv[1], NULL);
    g_object_set(G_OBJECT(sink), "location", "/home/amoe/foo.wav", NULL);

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

    gst_bin_add_many(
        GST_BIN(pipeline),
        source, demuxer, decoder, conv1, conv2, sink, NULL
    );

    gst_element_link(source, demuxer);
    gst_element_link_many(decoder, conv1, conv2, sink, NULL);


    g_signal_connect(
        demuxer, "pad-added", G_CALLBACK(cb_pad_added), decoder
    );

    g_print("Now playing: %s\n", argv[1]);
    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    // seek
    g_timeout_add(2 * 1000, cb_timeout0, pipeline);

    g_print("running...\n");
    g_main_loop_run(loop);

    g_print("returned, stopping playback\n");
    gst_element_set_state(pipeline, GST_STATE_NULL);

    g_print("deleting pipeline\n");
    gst_object_unref(GST_OBJECT(pipeline));

    return 0;
}

gboolean cb_timeout0(gpointer data) {
    GstElement *pipeline = (GstElement *) data;
    GstFormat fmt = GST_FORMAT_TIME;
    gboolean test;
    gint64 len;
    guint64 len_seconds;

    test = gst_element_seek(
        pipeline,
        1.0,
        GST_FORMAT_TIME,
        GST_SEEK_FLAG_FLUSH,
        GST_SEEK_TYPE_SET,
        pos * GST_SECOND,
        GST_SEEK_TYPE_NONE,
        -1
        );
    printf("seek: %d\n", test);

    test = gst_element_query_duration(
        pipeline, &fmt, &len
    );

    len_seconds = len / GST_SECOND;
    printf("total time: %lld (%llds)\n", len, len_seconds);
    pos = g_random_int_range(0, len_seconds);
    printf("random: %d\n", pos);

    puts("timeout called");

    return TRUE;
}

static gboolean cb_bus(GstBus *bus, GstMessage *msg, gpointer data) {

    return TRUE;
}

static void cb_pad_added(GstElement *element, GstPad *pad, gpointer data) {

    GstPad *sinkpad;
    GstElement *decoder = (GstElement *) data;

    puts("pad added callback");
    g_print("dynamic pad created, linking demuxer/decoder\n");

    sinkpad = gst_element_get_static_pad(decoder, "sink");
    gst_pad_link(pad, sinkpad);

    gst_object_unref(sinkpad);

}

Thanks,
-- 
David Banks <amoebae at gmail.com>




More information about the gstreamer-devel mailing list