gstreamer/docs/manual/advanced-position.xml
Ronald S. Bultje 2abdd0bfda docs/manual/: Update (until threads/scheduling) Application Development Manual; remove GstThread, add GstBus, add sim...
Original commit message from CVS:
* docs/manual/advanced-clocks.xml:
* docs/manual/advanced-interfaces.xml:
* docs/manual/advanced-metadata.xml:
* docs/manual/advanced-position.xml:
* docs/manual/advanced-schedulers.xml:
* docs/manual/advanced-threads.xml:
* docs/manual/appendix-porting.xml:
* docs/manual/basics-bins.xml:
* docs/manual/basics-bus.xml:
* docs/manual/basics-elements.xml:
* docs/manual/basics-helloworld.xml:
* docs/manual/basics-pads.xml:
* docs/manual/highlevel-components.xml:
* docs/manual/manual.xml:
* docs/manual/thread.fig:
Update (until threads/scheduling) Application Development Manual;
remove GstThread, add GstBus, add simple porting checklist, add
documentation for tag writing, clocks, make all examples until this
part compile and run.
* examples/manual/Makefile.am:
Update from changes to Application Development Manual; add bus
example, remove thread example.
2005-06-29 09:25:51 +00:00

184 lines
6.2 KiB
XML

<chapter id="chapter-queryevents">
<title>Position tracking and seeking</title>
<para>
So far, we've looked at how to create a pipeline to do media processing
and how to make it run. Most application developers will be interested
in providing feedback to the user on media progress. Media players, for
example, will want to show a slider showing the progress in the song,
and usually also a label indicating stream length. Transcoding
applications will want to show a progress bar on how much percent of
the task is done. &GStreamer; has built-in support for doing all this
using a concept known as <emphasis>querying</emphasis>. Since seeking
is very similar, it will be discussed here as well. Seeking is done
using the concept of <emphasis>events</emphasis>.
</para>
<sect1 id="section-querying">
<title>Querying: getting the position or length of a stream</title>
<para>
Querying is defined as requesting a specific stream-property related
to progress tracking. This includes getting the length of a stream (if
available) or getting the current position. Those stream properties
can be retrieved in various formats such as time, audio samples, video
frames or bytes. The function most commonly used for this is
<function>gst_element_query ()</function>, although some convenience
wrappers are provided as well (such as
<function>gst_element_query_position ()</function>). You can generally
query the pipeline directly, it'll figure out the internal details
for you, like which element to query.
</para>
<para>
Internally, queries will be sent to the sinks, and
<quote>dispatched</quote> backwards until one element can handle it;
that result will be sent back to the function caller. Usually, that
is the demuxer, although with live sources (from a webcam), it is the
source itself.
</para>
<programlisting><!-- example-begin query.c a -->
#include &lt;gst/gst.h&gt;
<!-- example-end query.c a -->
<!-- example-begin query.c b --><!--
static gboolean
my_bus_callback (GstBus *bus,
GstMessage *message,
gpointer data)
{
GMainLoop *loop = data;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR: {
GError *err;
gchar *debug;
gst_message_parse_error (message, &amp;err, &amp;debug);
g_print ("Error: %s\n", err-&gt;message);
g_error_free (err);
g_free (debug);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_EOS:
/* end-of-stream */
g_main_loop_quit (loop);
break;
default:
break;
}
/* remove from queue */
return TRUE;
}
--><!-- example-end query.c b -->
<!-- example-begin query.c c -->
static gboolean
cb_print_position (GstElement *pipeline)
{
GstFormat fmt = GST_FORMAT_TIME;
gint64 pos, len;
if (gst_element_query_position (pipeline, &amp;fmt, &amp;pos, &amp;len)) {
g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
GST_TIME_ARGS (pos), GST_TIME_ARGS (len));
}
/* call me again */
return TRUE;
}
gint
main (gint argc,
gchar *argv[])
{
GstElement *pipeline;
<!-- example-end query.c c -->
[..]<!-- example-begin query.c d --><!--
GMainLoop *loop;
gchar *l;
/* init */
gst_init (&amp;argc, &amp;argv);
/* args */
if (argc != 2) {
g_print ("Usage: %s &lt;filename&gt;\n", argv[0]);
return -1;
}
/* build pipeline, the easy way */
l = g_strdup_printf ("filesrc location=\"%s\" ! oggdemux ! vorbisdec ! "
"audioconvert ! audioscale ! alsasink",
argv[1]);
pipeline = gst_parse_launch (l, NULL);
g_free (l);
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
my_bus_callback, NULL);
/* play */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
loop = g_main_loop_new (NULL, FALSE);
--><!-- example-end query.c d -->
<!-- example-begin query.c e -->
/* run pipeline */
g_timeout_add (200, (GSourceFunc) cb_print_position, pipeline);
g_main_loop_run (loop);
<!-- example-end query.c e -->
[..]<!-- example-begin query.c f --><!--
/* clean up */
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
return 0;
--><!-- example-end query.c f -->
<!-- example-begin query.c g -->
}
<!-- example-end query.c g --></programlisting>
</sect1>
<sect1 id="section-eventsseek">
<title>Events: seeking (and more)</title>
<para>
Events work in a very similar way as queries. Dispatching, for
example, works exactly the same for events (and also has the same
limitations), and they can similarly be sent to the toplevel pipeline
and it will figure out everything for you. Although there are more
ways in which applications and elements can interact using events,
we will only focus on seeking here. This is done using the seek-event.
A seek-event contains a seeking offset, a seek method (which indicates
relative to what the offset was given), a seek format (which is the
unit of the offset, e.g. time, audio samples, video frames or bytes)
and optionally a set of seeking-related flags (e.g. whether internal
buffers should be flushed). The behaviour of a seek is also wrapped
in the function <function>gst_element_seek ()</function>.
</para>
<programlisting>
static void
seek_to_time (GstElement *pipeline,
gint64 time_nanoseconds)
{
gst_element_seek (pipeline,
GST_SEEK_METHOD_SET | GST_FORMAT_TIME |
GST_SEEK_FLAG_FLUSH, time_nanoseconds);
}
</programlisting>
<para>
It is possible to do multiple seeks in short time-intervals, such as
a direct response to slider movement. After a seek, internally, the
pipeline will be paused (if it was playing), the position will be
re-set internally, the demuxers and decoders will decode from the new
position onwards and this will continue until all sinks have data
again. If it was playing originally, it will be set to playing again,
too. Since the new position is immediately available in a video output,
you will see the new frame, even if your pipeline is not in the playing
state.
</para>
</sect1>
</chapter>