Implement our own theme, yay!
[platform/upstream/gstreamer.git] / manual-queryevents.md
1 ---
2 title: Position tracking and seeking
3 ...
4
5 # Position tracking and seeking
6
7 So far, we've looked at how to create a pipeline to do media processing
8 and how to make it run. Most application developers will be interested
9 in providing feedback to the user on media progress. Media players, for
10 example, will want to show a slider showing the progress in the song,
11 and usually also a label indicating stream length. Transcoding
12 applications will want to show a progress bar on how much percent of the
13 task is done. GStreamer has built-in support for doing all this using a
14 concept known as *querying*. Since seeking is very similar, it will be
15 discussed here as well. Seeking is done using the concept of *events*.
16
17 ## Querying: getting the position or length of a stream
18
19 Querying is defined as requesting a specific stream property related to
20 progress tracking. This includes getting the length of a stream (if
21 available) or getting the current position. Those stream properties can
22 be retrieved in various formats such as time, audio samples, video
23 frames or bytes. The function most commonly used for this is
24 `gst_element_query ()`, although some convenience wrappers are provided
25 as well (such as `gst_element_query_position ()` and
26 `gst_element_query_duration ()`). You can generally query the pipeline
27 directly, and it'll figure out the internal details for you, like which
28 element to query.
29
30 Internally, queries will be sent to the sinks, and “dispatched”
31 backwards until one element can handle it; that result will be sent back
32 to the function caller. Usually, that is the demuxer, although with live
33 sources (from a webcam), it is the source itself.
34
35 ``` c
36
37 #include <gst/gst.h>
38
39
40
41
42 static gboolean
43 cb_print_position (GstElement *pipeline)
44 {
45   gint64 pos, len;
46
47   if (gst_element_query_position (pipeline, GST_FORMAT_TIME, &pos)
48     && gst_element_query_duration (pipeline, GST_FORMAT_TIME, &len)) {
49     g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
50          GST_TIME_ARGS (pos), GST_TIME_ARGS (len));
51   }
52
53   /* call me again */
54   return TRUE;
55 }
56
57 gint
58 main (gint   argc,
59       gchar *argv[])
60 {
61   GstElement *pipeline;
62
63 [..]
64
65   /* run pipeline */
66   g_timeout_add (200, (GSourceFunc) cb_print_position, pipeline);
67   g_main_loop_run (loop);
68
69 [..]
70
71 }
72     
73 ```
74
75 ## Events: seeking (and more)
76
77 Events work in a very similar way as queries. Dispatching, for example,
78 works exactly the same for events (and also has the same limitations),
79 and they can similarly be sent to the toplevel pipeline and it will
80 figure out everything for you. Although there are more ways in which
81 applications and elements can interact using events, we will only focus
82 on seeking here. This is done using the seek-event. A seek-event
83 contains a playback rate, a seek offset format (which is the unit of the
84 offsets to follow, e.g. time, audio samples, video frames or bytes),
85 optionally a set of seeking-related flags (e.g. whether internal buffers
86 should be flushed), a seek method (which indicates relative to what the
87 offset was given), and seek offsets. The first offset (cur) is the new
88 position to seek to, while the second offset (stop) is optional and
89 specifies a position where streaming is supposed to stop. Usually it is
90 fine to just specify GST\_SEEK\_TYPE\_NONE and -1 as end\_method and end
91 offset. The behaviour of a seek is also wrapped in the `gst_element_seek
92 ()`.
93
94 ``` c
95 static void
96 seek_to_time (GstElement *pipeline,
97           gint64      time_nanoseconds)
98 {
99   if (!gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
100                          GST_SEEK_TYPE_SET, time_nanoseconds,
101                          GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
102     g_print ("Seek failed!\n");
103   }
104 }
105     
106 ```
107
108 Seeks with the GST\_SEEK\_FLAG\_FLUSH should be done when the pipeline
109 is in PAUSED or PLAYING state. The pipeline will automatically go to
110 preroll state until the new data after the seek will cause the pipeline
111 to preroll again. After the pipeline is prerolled, it will go back to
112 the state (PAUSED or PLAYING) it was in when the seek was executed. You
113 can wait (blocking) for the seek to complete with
114 `gst_element_get_state()` or by waiting for the ASYNC\_DONE message to
115 appear on the bus.
116
117 Seeks without the GST\_SEEK\_FLAG\_FLUSH should only be done when the
118 pipeline is in the PLAYING state. Executing a non-flushing seek in the
119 PAUSED state might deadlock because the pipeline streaming threads might
120 be blocked in the sinks.
121
122 It is important to realise that seeks will not happen instantly in the
123 sense that they are finished when the function `gst_element_seek ()`
124 returns. Depending on the specific elements involved, the actual seeking
125 might be done later in another thread (the streaming thread), and it
126 might take a short time until buffers from the new seek position will
127 reach downstream elements such as sinks (if the seek was non-flushing
128 then it might take a bit longer).
129
130 It is possible to do multiple seeks in short time-intervals, such as a
131 direct response to slider movement. After a seek, internally, the
132 pipeline will be paused (if it was playing), the position will be re-set
133 internally, the demuxers and decoders will decode from the new position
134 onwards and this will continue until all sinks have data again. If it
135 was playing originally, it will be set to playing again, too. Since the
136 new position is immediately available in a video output, you will see
137 the new frame, even if your pipeline is not in the playing state.
138