docs: manual: fix formatting
[platform/upstream/gstreamer.git] / docs / manual / advanced-position.xml
1 <chapter id="chapter-queryevents">
2   <title>Position tracking and seeking</title>
3
4   <para>
5     So far, we've looked at how to create a pipeline to do media processing
6     and how to make it run. Most application developers will be interested
7     in providing feedback to the user on media progress. Media players, for
8     example, will want to show a slider showing the progress in the song,
9     and usually also a label indicating stream length. Transcoding
10     applications will want to show a progress bar on how much percent of
11     the task is done. &GStreamer; has built-in support for doing all this
12     using a concept known as <emphasis>querying</emphasis>. Since seeking
13     is very similar, it will be discussed here as well. Seeking is done
14     using the concept of <emphasis>events</emphasis>.
15   </para>
16
17   <sect1 id="section-querying">
18     <title>Querying: getting the position or length of a stream</title>
19
20     <para>
21       Querying is defined as requesting a specific stream property related
22       to progress tracking. This includes getting the length of a stream (if
23       available) or getting the current position. Those stream properties
24       can be retrieved in various formats such as time, audio samples, video
25       frames or bytes. The function most commonly used for this is
26       <function>gst_element_query ()</function>, although some convenience
27       wrappers are provided as well (such as
28       <function>gst_element_query_position ()</function> and
29       <function>gst_element_query_duration ()</function>). You can generally
30       query the pipeline directly, and it'll figure out the internal details
31       for you, like which element to query.
32     </para>
33
34     <para>
35       Internally, queries will be sent to the sinks, and
36       <quote>dispatched</quote> backwards until one element can handle it;
37       that result will be sent back to the function caller. Usually, that
38       is the demuxer, although with live sources (from a webcam), it is the
39       source itself.
40     </para>
41
42     <programlisting>
43 <!-- example-begin query.c a -->
44 #include &lt;gst/gst.h&gt;
45 <!-- example-end query.c a -->
46 <!-- example-begin query.c b --><!--
47 static void
48 my_bus_message_cb (GstBus     *bus,
49                    GstMessage *message,
50                    gpointer    data)
51 {
52   GMainLoop *loop = (GMainLoop *) data;
53
54   switch (GST_MESSAGE_TYPE (message)) {
55     case GST_MESSAGE_ERROR: {
56       GError *err;
57       gchar *debug;
58
59       gst_message_parse_error (message, &amp;err, &amp;debug);
60       g_print ("Error: %s\n", err-&gt;message);
61       g_error_free (err);
62       g_free (debug);
63
64       g_main_loop_quit (loop);
65       break;
66     }
67     case GST_MESSAGE_EOS:
68       /* end-of-stream */
69       g_main_loop_quit (loop);
70       break;
71     default:
72       break;
73   }
74 }
75 -->
76 <!-- example-end query.c b -->
77 <!-- example-begin query.c c -->
78 static gboolean
79 cb_print_position (GstElement *pipeline)
80 {
81   gint64 pos, len;
82
83   if (gst_element_query_position (pipeline, GST_FORMAT_TIME, &amp;pos)
84     &amp;&amp; gst_element_query_duration (pipeline, GST_FORMAT_TIME, &amp;len)) {
85     g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
86              GST_TIME_ARGS (pos), GST_TIME_ARGS (len));
87   }
88
89   /* call me again */
90   return TRUE;
91 }
92
93 gint
94 main (gint   argc,
95       gchar *argv[])
96 {
97   GstElement *pipeline;
98 <!-- example-end query.c c -->
99 [..]<!-- example-begin query.c d --><!--
100   GstStateChangeReturn ret;
101   GMainLoop *loop;
102   GError *err = NULL;
103   GstBus *bus;
104   gchar *l;
105
106   /* init */
107   gst_init (&amp;argc, &amp;argv);
108
109   /* args */
110   if (argc != 2) {
111     g_print ("Usage: %s &lt;filename&gt;\n", argv[0]);
112     return -1;
113   }
114
115   loop = g_main_loop_new (NULL, FALSE);
116
117   /* build pipeline, the easy way */
118   l = g_strdup_printf ("filesrc location=\"%s\" ! oggdemux ! vorbisdec ! "
119                        "audioconvert ! audioresample ! alsasink",
120                        argv[1]);
121   pipeline = gst_parse_launch (l, &amp;err);
122   if (pipeline == NULL || err != NULL) {
123     g_printerr ("Cannot build pipeline: %s\n", err->message);
124     g_error_free (err);
125     g_free (l);
126     if (pipeline)
127       gst_object_unref (pipeline);
128     return -1;
129   }
130   g_free (l);
131
132   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
133   gst_bus_add_signal_watch (bus);
134   g_signal_connect (bus, "message", G_CALLBACK (my_bus_message_cb), loop);
135   gst_object_unref (bus);
136
137   /* play */
138   ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
139   if (ret == GST_STATE_CHANGE_FAILURE)
140     g_error ("Failed to set pipeline to PLAYING.\n");
141 --><!-- example-end query.c d -->
142 <!-- example-begin query.c e -->
143   /* run pipeline */
144   g_timeout_add (200, (GSourceFunc) cb_print_position, pipeline);
145   g_main_loop_run (loop);
146 <!-- example-end query.c e -->
147 [..]<!-- example-begin query.c f --><!--
148   /* clean up */
149   gst_element_set_state (pipeline, GST_STATE_NULL);
150   gst_object_unref (GST_OBJECT (pipeline));
151
152   return 0;
153 --><!-- example-end query.c f -->
154 <!-- example-begin query.c g -->
155 }
156     <!-- example-end query.c g --></programlisting>
157   </sect1>
158
159   <sect1 id="section-eventsseek">
160     <title>Events: seeking (and more)</title>
161
162     <para>
163       Events work in a very similar way as queries. Dispatching, for
164       example, works exactly the same for events (and also has the same
165       limitations), and they can similarly be sent to the toplevel pipeline
166       and it will figure out everything for you. Although there are more
167       ways in which applications and elements can interact using events,
168       we will only focus on seeking here. This is done using the seek-event.
169       A seek-event contains a playback rate, a seek offset format (which is
170       the unit of the offsets to follow, e.g. time, audio samples, video
171       frames or bytes), optionally a set of seeking-related flags (e.g.
172       whether internal buffers should be flushed), a seek method (which
173       indicates relative to what the offset was given), and seek offsets.
174       The first offset (cur) is the new position to seek to, while
175       the second offset (stop) is optional and specifies a position where
176       streaming is supposed to stop. Usually it is fine to just specify
177       GST_SEEK_TYPE_NONE and -1 as end_method and end offset. The behaviour
178       of a seek is also wrapped in the <function>gst_element_seek ()</function>.
179     </para>
180
181     <programlisting>
182 static void
183 seek_to_time (GstElement *pipeline,
184               gint64      time_nanoseconds)
185 {
186   if (!gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
187                          GST_SEEK_TYPE_SET, time_nanoseconds,
188                          GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
189     g_print ("Seek failed!\n");
190   }
191 }
192     </programlisting>
193     <para>
194       Seeks with the GST_SEEK_FLAG_FLUSH should be done when the pipeline is
195       in PAUSED or PLAYING state. The pipeline will automatically go to preroll
196       state until the new data after the seek will cause the pipeline to preroll
197       again. After the pipeline is prerolled, it will go back to the state
198       (PAUSED or PLAYING) it was in when the seek was executed. You can wait
199       (blocking) for the seek to complete with
200       <function>gst_element_get_state()</function> or by waiting for the
201       ASYNC_DONE message to appear on the bus.
202     </para>
203
204     <para>
205       Seeks without the GST_SEEK_FLAG_FLUSH should only be done when the
206       pipeline is in the PLAYING state. Executing a non-flushing seek in the
207       PAUSED state might deadlock because the pipeline streaming threads might
208       be blocked in the sinks.
209     </para>
210
211     <para>
212       It is important to realise that seeks will not happen instantly in the
213       sense that they are finished when the function
214       <function>gst_element_seek ()</function> returns. Depending on the
215       specific elements involved, the actual seeking might be done later in
216       another thread (the streaming thread), and it might take a short time
217       until buffers from the new seek position will reach downstream elements
218       such as sinks (if the seek was non-flushing then it might take a bit
219       longer).
220     </para>
221
222     <para>
223       It is possible to do multiple seeks in short time-intervals, such as
224       a direct response to slider movement. After a seek, internally, the
225       pipeline will be paused (if it was playing), the position will be
226       re-set internally, the demuxers and decoders will decode from the new
227       position onwards and this will continue until all sinks have data
228       again. If it was playing originally, it will be set to playing again,
229       too. Since the new position is immediately available in a video output,
230       you will see the new frame, even if your pipeline is not in the playing
231       state.
232     </para>
233   </sect1>
234 </chapter>
235