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 ("iterate"). Most application developers will be |
---|
7 | interested in providing feedback to the user on media progress. Media |
---|
8 | players, for example, will want to show a slider showing the progress in |
---|
9 | the song, and usually also a label indicating stream length. Transcoding |
---|
10 | applications will want to show a progress bar on how much % of the task |
---|
11 | is done. &GStreamer; has built-in support for doing all this using a |
---|
12 | concept known as <emphasis>querying</emphasis>. Since seeking is very |
---|
13 | similar, it will be discussed here as well. Seeking is done using the |
---|
14 | 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 functions used are <function>gst_element_query |
---|
26 | ()</function> and <function>gst_pad_query ()</function>. |
---|
27 | </para> |
---|
28 | |
---|
29 | <para> |
---|
30 | Obviously, using either of the above-mentioned functions requires the |
---|
31 | application to know <emphasis>which</emphasis> element or pad to run |
---|
32 | the query on. This is tricky, but there are some good sides to the |
---|
33 | story. The good thing is that elements (or, rather, pads - since |
---|
34 | <function>gst_element_query ()</function> internally calls |
---|
35 | <function>gst_pad_query ()</function>) forward (<quote>dispatch</quote>) |
---|
36 | events and queries to peer pads (or elements) if they don't handle it |
---|
37 | themselves. The bad side is that some elements (or pads) will handle |
---|
38 | events, but not the specific formats that you want, and therefore it |
---|
39 | still won't work. |
---|
40 | </para> |
---|
41 | |
---|
42 | <para> |
---|
43 | Most queries will, fortunately, work fine. Queries are always |
---|
44 | dispatched backwards. This means, effectively, that it's easiest to |
---|
45 | run the query on your video or audio output element, and it will take |
---|
46 | care of dispatching the query to the element that knows the answer |
---|
47 | (such as the current position or the media length; usually the demuxer |
---|
48 | or decoder). |
---|
49 | </para> |
---|
50 | |
---|
51 | <programlisting><!-- example-begin query.c a --> |
---|
52 | #include <gst/gst.h> |
---|
53 | |
---|
54 | gint |
---|
55 | main (gint argc, |
---|
56 | gchar *argv[]) |
---|
57 | { |
---|
58 | GstElement *sink, *pipeline; |
---|
59 | <!-- example-end query.c a --> |
---|
60 | [..]<!-- example-begin query.c b --><!-- |
---|
61 | gchar *l; |
---|
62 | |
---|
63 | /* init */ |
---|
64 | gst_init (&argc, &argv); |
---|
65 | |
---|
66 | /* args */ |
---|
67 | if (argc != 2) { |
---|
68 | g_print ("Usage: %s <filename>\n", argv[0]); |
---|
69 | return -1; |
---|
70 | } |
---|
71 | |
---|
72 | /* build pipeline, the easy way */ |
---|
73 | l = g_strdup_printf ("filesrc location=\"%s\" ! oggdemux ! vorbisdec ! " |
---|
74 | "audioconvert ! audioscale ! alsasink name=a", |
---|
75 | argv[1]); |
---|
76 | pipeline = gst_parse_launch (l, NULL); |
---|
77 | sink = gst_bin_get_by_name (GST_BIN (pipeline), "a"); |
---|
78 | g_free (l); |
---|
79 | |
---|
80 | /* play */ |
---|
81 | gst_element_set_state (pipeline, GST_STATE_PLAYING); |
---|
82 | --><!-- example-end query.c b --> |
---|
83 | <!-- example-begin query.c c --> |
---|
84 | /* run pipeline */ |
---|
85 | do { |
---|
86 | gint64 len, pos; |
---|
87 | GstFormat fmt = GST_FORMAT_TIME; |
---|
88 | |
---|
89 | if (gst_element_query (sink, GST_QUERY_POSITION, &fmt, &pos) && |
---|
90 | gst_element_query (sink, GST_QUERY_TOTAL, &fmt, &len)) { |
---|
91 | g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r", |
---|
92 | GST_TIME_ARGS (pos), GST_TIME_ARGS (len)); |
---|
93 | } |
---|
94 | } while (gst_bin_iterate (GST_BIN (pipeline))); |
---|
95 | <!-- example-end query.c c --> |
---|
96 | [..]<!-- example-begin query.c d --><!-- |
---|
97 | /* clean up */ |
---|
98 | gst_element_set_state (pipeline, GST_STATE_NULL); |
---|
99 | gst_object_unref (GST_OBJECT (pipeline)); |
---|
100 | |
---|
101 | return 0; |
---|
102 | --><!-- example-end query.c d --> |
---|
103 | <!-- example-begin query.c e --> |
---|
104 | } |
---|
105 | <!-- example-end query.c e --></programlisting> |
---|
106 | <para> |
---|
107 | If you are having problems with the dispatching behaviour, your best |
---|
108 | bet is to manually decide which element to start running the query on. |
---|
109 | You can get a list of supported formats and query-types with |
---|
110 | <function>gst_element_get_query_types ()</function> and |
---|
111 | <function>gst_element_get_formats ()</function>. |
---|
112 | </para> |
---|
113 | </sect1> |
---|
114 | |
---|
115 | <sect1 id="section-eventsseek"> |
---|
116 | <title>Events: seeking (and more)</title> |
---|
117 | |
---|
118 | <para> |
---|
119 | Events work in a very similar way as queries. Dispatching, for |
---|
120 | example, works exactly the same for events (and also has the same |
---|
121 | limitations). Although there are more ways in which applications |
---|
122 | and elements can interact using events, we will only focus on seeking |
---|
123 | here. This is done using the seek-event. A seek-event contains a |
---|
124 | seeking offset, a seek method (which indicates relative to what the |
---|
125 | offset was given), a seek format (which is the unit of the offset, |
---|
126 | e.g. time, audio samples, video frames or bytes) and optionally a |
---|
127 | set of seeking-related flags (e.g. whether internal buffers should be |
---|
128 | flushed). The behaviour of a seek is also wrapped in the function |
---|
129 | <function>gst_element_seek ()</function>. |
---|
130 | </para> |
---|
131 | |
---|
132 | <programlisting> |
---|
133 | static void |
---|
134 | seek_to_time (GstElement *audiosink, |
---|
135 | gint64 time_nanonseconds) |
---|
136 | { |
---|
137 | gst_element_seek (audiosink, |
---|
138 | GST_SEEK_METHOD_SET | GST_FORMAT_TIME | |
---|
139 | GST_SEEK_FLAG_FLUSH, time_nanoseconds); |
---|
140 | } |
---|
141 | </programlisting> |
---|
142 | </sect1> |
---|
143 | </chapter> |
---|
144 | |
---|