d8f38e8f896df881e6490c5a1ed6fc7213caceb0
[platform/upstream/gstreamer.git] / gst / gstevent.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wim.taymans@chello.be>
4  *
5  * gstevent.c: GstEvent subsystem
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /**
24  * SECTION:gstevent
25  * @short_description: Structure describing events that are passed up and down
26  *                     a pipeline
27  * @see_also: #GstPad, #GstElement
28  *
29  * The event classes are used to construct and query events.
30  *
31  * Events are usually created with gst_event_new_*() which takes the extra
32  * event parameters as arguments.
33  * Events can be parsed with their respective gst_event_parse_*() functions.
34  * The event should be unreffed with gst_event_unref().
35  *
36  * Events are passed between elements in parallel to the data stream. Some events
37  * are serialized with buffers, others are not. Some events only travel downstream,
38  * others only upstream. Some events can travel both upstream and downstream. 
39  * 
40  * The events are used to signal special conditions in the datastream such as EOS
41  * or the start of a new segment. Events are also used to flush the pipeline of
42  * any pending data.
43  *
44  * Most of the event API is used inside plugins. The application usually only 
45  * constructs and uses the seek event API when it wants to perform a seek in the
46  * pipeline. 
47
48  * gst_event_new_seek() is usually used to create a seek event and it takes
49  * the needed parameters for a seek event.
50  * <example>
51  * <title>performing a seek on a pipeline</title>
52  *   <programlisting>
53  *   GstEvent *event;
54  *   gboolean result;
55  *   ...
56  *   // construct a seek event to play the media from second 2 to 5, flush
57  *   // the pipeline to decrease latency.
58  *   event = gst_event_new_seek (1.0, 
59  *      GST_FORMAT_TIME, 
60  *      GST_SEEK_FLAG_FLUSH,
61  *      GST_SEEK_TYPE_SET, 2 * GST_SECOND,
62  *      GST_SEEK_TYPE_SET, 5 * GST_SECOND);
63  *   ...
64  *   result = gst_element_send_event (pipeline, event);
65  *   if (!result)
66  *     g_warning ("seek failed");
67  *   ...
68  *   </programlisting>
69  * </example>
70  */
71 #include <string.h>             /* memcpy */
72
73 #include "gst_private.h"
74
75 #include "gstinfo.h"
76 #include "gstevent.h"
77 #include "gstenumtypes.h"
78 #include "gstutils.h"
79
80 static void gst_event_init (GTypeInstance * instance, gpointer g_class);
81 static void gst_event_class_init (gpointer g_class, gpointer class_data);
82 static void gst_event_finalize (GstEvent * event);
83 static GstEvent *_gst_event_copy (GstEvent * event);
84
85 void
86 _gst_event_initialize (void)
87 {
88   gst_event_get_type ();
89 }
90
91 typedef struct
92 {
93   gint type;
94   gchar *name;
95   GQuark quark;
96 } GstEventQuarks;
97
98 static GstEventQuarks event_quarks[] = {
99   {GST_EVENT_UNKNOWN, "unknown", 0},
100   {GST_EVENT_FLUSH_START, "flush-start", 0},
101   {GST_EVENT_FLUSH_STOP, "flush-stop", 0},
102   {GST_EVENT_EOS, "eos", 0},
103   {GST_EVENT_NEWSEGMENT, "newsegment", 0},
104   {GST_EVENT_TAG, "tag", 0},
105   {GST_EVENT_BUFFERSIZE, "buffersize", 0},
106   {GST_EVENT_QOS, "qos", 0},
107   {GST_EVENT_SEEK, "seek", 0},
108   {GST_EVENT_NAVIGATION, "navigation", 0},
109   {GST_EVENT_CUSTOM_UPSTREAM, "custom-upstream", 0},
110   {GST_EVENT_CUSTOM_DOWNSTREAM, "custom-downstream", 0},
111   {GST_EVENT_CUSTOM_DOWNSTREAM_OOB, "custom-downstream-oob", 0},
112   {GST_EVENT_CUSTOM_BOTH, "custom-both", 0},
113   {GST_EVENT_CUSTOM_BOTH_OOB, "custom-both-oob", 0},
114
115   {0, NULL, 0}
116 };
117
118 /**
119  * gst_event_type_get_name:
120  * @type: the event type
121  *
122  * Get a printable name for the given event type. Do not modify or free.
123  *
124  * Returns: a reference to the static name of the event.
125  */
126 const gchar *
127 gst_event_type_get_name (GstEventType type)
128 {
129   gint i;
130
131   for (i = 0; event_quarks[i].name; i++) {
132     if (type == event_quarks[i].type)
133       return event_quarks[i].name;
134   }
135   return "unknown";
136 }
137
138 /**
139  * gst_event_type_to_quark:
140  * @type: the event type
141  *
142  * Get the unique quark for the given event type.
143  *
144  * Returns: the quark associated with the event type
145  */
146 GQuark
147 gst_event_type_to_quark (GstEventType type)
148 {
149   gint i;
150
151   for (i = 0; event_quarks[i].name; i++) {
152     if (type == event_quarks[i].type)
153       return event_quarks[i].quark;
154   }
155   return 0;
156 }
157
158 /**
159  * gst_event_type_get_flags:
160  * @type: a #GstEventType
161  *
162  * Gets the #GstEventTypeFlags associated with @type.
163  *
164  * Returns: a #GstEventTypeFlags.
165  */
166 GstEventTypeFlags
167 gst_event_type_get_flags (GstEventType type)
168 {
169   GstEventTypeFlags ret;
170
171   ret = type & ((1 << GST_EVENT_TYPE_SHIFT) - 1);
172
173   return ret;
174 }
175
176 GType
177 gst_event_get_type (void)
178 {
179   static GType _gst_event_type;
180   int i;
181
182   if (G_UNLIKELY (_gst_event_type == 0)) {
183     static const GTypeInfo event_info = {
184       sizeof (GstEventClass),
185       NULL,
186       NULL,
187       gst_event_class_init,
188       NULL,
189       NULL,
190       sizeof (GstEvent),
191       0,
192       gst_event_init,
193       NULL
194     };
195
196     _gst_event_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
197         "GstEvent", &event_info, 0);
198
199     for (i = 0; event_quarks[i].name; i++) {
200       event_quarks[i].quark = g_quark_from_static_string (event_quarks[i].name);
201     }
202   }
203
204   return _gst_event_type;
205 }
206
207 static void
208 gst_event_class_init (gpointer g_class, gpointer class_data)
209 {
210   GstEventClass *event_class = GST_EVENT_CLASS (g_class);
211
212   event_class->mini_object_class.copy =
213       (GstMiniObjectCopyFunction) _gst_event_copy;
214   event_class->mini_object_class.finalize =
215       (GstMiniObjectFinalizeFunction) gst_event_finalize;
216 }
217
218 static void
219 gst_event_init (GTypeInstance * instance, gpointer g_class)
220 {
221   GstEvent *event;
222
223   event = GST_EVENT (instance);
224
225   GST_EVENT_TIMESTAMP (event) = GST_CLOCK_TIME_NONE;
226 }
227
228 static void
229 gst_event_finalize (GstEvent * event)
230 {
231   g_return_if_fail (event != NULL);
232   g_return_if_fail (GST_IS_EVENT (event));
233
234   GST_CAT_LOG (GST_CAT_EVENT, "freeing event %p type %s", event,
235       gst_event_type_get_name (GST_EVENT_TYPE (event)));
236
237   if (GST_EVENT_SRC (event)) {
238     gst_object_unref (GST_EVENT_SRC (event));
239     GST_EVENT_SRC (event) = NULL;
240   }
241   if (event->structure) {
242     gst_structure_set_parent_refcount (event->structure, NULL);
243     gst_structure_free (event->structure);
244   }
245 }
246
247 static GstEvent *
248 _gst_event_copy (GstEvent * event)
249 {
250   GstEvent *copy;
251
252   copy = (GstEvent *) gst_mini_object_new (GST_TYPE_EVENT);
253
254   GST_EVENT_TYPE (copy) = GST_EVENT_TYPE (event);
255   GST_EVENT_TIMESTAMP (copy) = GST_EVENT_TIMESTAMP (event);
256
257   if (GST_EVENT_SRC (event)) {
258     GST_EVENT_SRC (copy) = gst_object_ref (GST_EVENT_SRC (event));
259   }
260   if (event->structure) {
261     copy->structure = gst_structure_copy (event->structure);
262     gst_structure_set_parent_refcount (copy->structure,
263         &event->mini_object.refcount);
264   }
265   return copy;
266 }
267
268 static GstEvent *
269 gst_event_new (GstEventType type)
270 {
271   GstEvent *event;
272
273   event = (GstEvent *) gst_mini_object_new (GST_TYPE_EVENT);
274
275   GST_CAT_DEBUG (GST_CAT_EVENT, "creating new event %p %s", event,
276       gst_event_type_get_name (type));
277
278   event->type = type;
279   event->src = NULL;
280   event->structure = NULL;
281
282   return event;
283 }
284
285 /**
286  * gst_event_new_custom:
287  * @type: The type of the new event
288  * @structure: The structure for the event. The event will take ownership of
289  * the structure.
290  *
291  * Create a new custom-typed event. This can be used for anything not
292  * handled by other event-specific functions to pass an event to another
293  * element.
294  *
295  * Make sure to allocate an event type with the #GST_EVENT_MAKE_TYPE macro,
296  * assigning a free number and filling in the correct direction and
297  * serialization flags.
298  *
299  * New custom events can also be created by subclassing the event type if
300  * needed.
301  *
302  * Returns: The new custom event.
303  */
304 GstEvent *
305 gst_event_new_custom (GstEventType type, GstStructure * structure)
306 {
307   GstEvent *event;
308
309   event = gst_event_new (type);
310   if (structure) {
311     gst_structure_set_parent_refcount (structure, &event->mini_object.refcount);
312     event->structure = structure;
313   }
314   return event;
315 }
316
317 /**
318  * gst_event_get_structure:
319  * @event: The #GstEvent.
320  *
321  * Access the structure of the event.
322  *
323  * Returns: The structure of the event. The structure is still
324  * owned by the event, which means that you should not free it and
325  * that the pointer becomes invalid when you free the event.
326  *
327  * MT safe.
328  */
329 const GstStructure *
330 gst_event_get_structure (GstEvent * event)
331 {
332   g_return_val_if_fail (GST_IS_EVENT (event), NULL);
333
334   return event->structure;
335 }
336
337 /**
338  * gst_event_new_flush_start:
339  *
340  * Allocate a new flush start event. The flush start event can be send
341  * upstream and downstream and travels out-of-bounds with the dataflow.
342  * It marks pads as being in a WRONG_STATE to process more data.
343  *
344  * Elements unlock and blocking functions and exit their streaming functions
345  * as fast as possible.
346  *
347  * This event is typically generated after a seek to minimize the latency
348  * after the seek.
349  *
350  * Returns: A new flush start event.
351  */
352 GstEvent *
353 gst_event_new_flush_start (void)
354 {
355   return gst_event_new (GST_EVENT_FLUSH_START);
356 }
357
358 /**
359  * gst_event_new_flush_stop:
360  *
361  * Allocate a new flush stop event. The flush start event can be send
362  * upstream and downstream and travels out-of-bounds with the dataflow.
363  * It is typically send after sending a FLUSH_START event to make the
364  * pads accept data again.
365  *
366  * Elements can process this event synchronized with the dataflow since
367  * the preceeding FLUSH_START event stopped the dataflow.
368  *
369  * This event is typically generated to complete a seek and to resume
370  * dataflow.
371  *
372  * Returns: A new flush stop event.
373  */
374 GstEvent *
375 gst_event_new_flush_stop (void)
376 {
377   return gst_event_new (GST_EVENT_FLUSH_STOP);
378 }
379
380 /**
381  * gst_event_new_eos:
382  *
383  * Create a new EOS event. The eos event can only travel downstream
384  * synchronized with the buffer flow. Elements that receive the EOS
385  * event on a pad can return UNEXPECTED as a GstFlowReturn when data
386  * after the EOS event arrives.
387  *
388  * The EOS event will travel up to the sink elements in the pipeline
389  * which will then post the GST_MESSAGE_EOS on the bus.
390  *
391  * When all sinks have posted an EOS message, the EOS message is
392  * forwarded to the application.
393  *
394  * Returns: The new EOS event.
395  */
396 GstEvent *
397 gst_event_new_eos (void)
398 {
399   return gst_event_new (GST_EVENT_EOS);
400 }
401
402 /**
403  * gst_event_new_new_segment:
404  * @update: is this segment an update to a previous one
405  * @rate: a new rate for playback
406  * @format: The format of the segment values
407  * @start_value: the start value of the segment
408  * @stop_value: the stop value of the segment
409  * @stream_time: stream time for buffer timestamps.
410  *
411  * Allocate a new newsegment event with the given format/values tripplets.
412  *
413  * The newsegment event marks the range of buffers to be processed. All
414  * data not within the segment range is not to be processed. This can be
415  * used intelligently by plugins to use more efficient methods of skipping
416  * unneeded packets.
417  *
418  * The stream time of the segment is used to convert the buffer timestamps
419  * into the stream time again, this is usually done in sinks to report the 
420  * current stream_time. @stream_time cannot be -1.
421  *
422  * The @start_value cannot be -1, the @stop_value can be -1. If there
423  * is a valid @stop_value given, it must be greater or equal than @start_value.
424  *
425  * After a newsegment event, the buffer stream time is calculated with:
426  *
427  *   stream_time + (TIMESTAMP(buf) - start_value) * ABS (rate)
428  *
429  * Returns: A new newsegment event.
430  */
431 GstEvent *
432 gst_event_new_new_segment (gboolean update, gdouble rate, GstFormat format,
433     gint64 start_value, gint64 stop_value, gint64 stream_time)
434 {
435   g_return_val_if_fail (rate != 0.0, NULL);
436
437   if (format == GST_FORMAT_TIME) {
438     GST_CAT_INFO (GST_CAT_EVENT,
439         "creating newsegment update %d, rate %lf, format GST_FORMAT_TIME, "
440         "start %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT
441         ", stream_time %" GST_TIME_FORMAT,
442         update, rate, GST_TIME_ARGS (start_value),
443         GST_TIME_ARGS (stop_value), GST_TIME_ARGS (stream_time));
444   } else {
445     GST_CAT_INFO (GST_CAT_EVENT,
446         "creating newsegment update %d, rate %lf, format %d, "
447         "start %lld, stop %lld, stream_time %lld",
448         update, rate, format, start_value, stop_value, stream_time);
449   }
450   if (stream_time == -1)
451     g_return_val_if_fail (stream_time != -1, NULL);
452
453   if (start_value == -1)
454     g_return_val_if_fail (start_value != -1, NULL);
455
456   if (stop_value != -1)
457     g_return_val_if_fail (start_value <= stop_value, NULL);
458
459   return gst_event_new_custom (GST_EVENT_NEWSEGMENT,
460       gst_structure_new ("GstEventNewsegment",
461           "update", G_TYPE_BOOLEAN, update,
462           "rate", G_TYPE_DOUBLE, rate,
463           "format", GST_TYPE_FORMAT, format,
464           "start_val", G_TYPE_INT64, start_value,
465           "stop_val", G_TYPE_INT64, stop_value,
466           "stream_time", G_TYPE_INT64, stream_time, NULL));
467 }
468
469 /**
470  * gst_event_parse_new_segment:
471  * @event: The event to query
472  * @update: A pointer to the update flag of the segment
473  * @rate: A pointer to the rate of the segment
474  * @format: A pointer to the format of the newsegment values
475  * @start_value: A pointer to store the start value in
476  * @stop_value: A pointer to store the stop value in
477  * @stream_time: A pointer to store the stream time in
478  *
479  * Get the start, stop and format in the newsegment event.
480  */
481 void
482 gst_event_parse_new_segment (GstEvent * event, gboolean * update,
483     gdouble * rate, GstFormat * format, gint64 * start_value,
484     gint64 * stop_value, gint64 * stream_time)
485 {
486   const GstStructure *structure;
487
488   g_return_if_fail (GST_IS_EVENT (event));
489   g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT);
490
491   structure = gst_event_get_structure (event);
492   if (update)
493     *update =
494         g_value_get_boolean (gst_structure_get_value (structure, "update"));
495   if (rate)
496     *rate = g_value_get_double (gst_structure_get_value (structure, "rate"));
497   if (format)
498     *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
499   if (start_value)
500     *start_value =
501         g_value_get_int64 (gst_structure_get_value (structure, "start_val"));
502   if (stop_value)
503     *stop_value =
504         g_value_get_int64 (gst_structure_get_value (structure, "stop_val"));
505   if (stream_time)
506     *stream_time =
507         g_value_get_int64 (gst_structure_get_value (structure, "stream_time"));
508 }
509
510 /**
511  * gst_event_new_tag:
512  * @taglist: metadata list
513  *
514  * Generates a metadata tag event from the given @taglist.
515  *
516  * Returns: a new #GstEvent
517  */
518 GstEvent *
519 gst_event_new_tag (GstTagList * taglist)
520 {
521   g_return_val_if_fail (taglist != NULL, NULL);
522
523   return gst_event_new_custom (GST_EVENT_TAG, (GstStructure *) taglist);
524 }
525
526 /**
527  * gst_event_parse_tag:
528  * @event: a tag event
529  * @taglist: pointer to metadata list
530  *
531  * Parses a tag @event and stores the results in the given @taglist location.
532  */
533 void
534 gst_event_parse_tag (GstEvent * event, GstTagList ** taglist)
535 {
536   g_return_if_fail (GST_IS_EVENT (event));
537   g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TAG);
538
539   if (taglist)
540     *taglist = (GstTagList *) event->structure;
541 }
542
543 /* buffersize event */
544 /**
545  * gst_event_new_buffer_size:
546  * @format: buffer format
547  * @minsize: minimum buffer size
548  * @maxsize: maximum buffer size
549  * @async: thread behavior
550  *
551  * Create a new buffersize event. The event is sent downstream and notifies
552  * elements that they should provide a buffer of the specified dimensions.
553  *
554  * When the async flag is set, a thread boundary is prefered.
555  *
556  * Returns: a new #GstEvent
557  */
558 GstEvent *
559 gst_event_new_buffer_size (GstFormat format, gint64 minsize,
560     gint64 maxsize, gboolean async)
561 {
562   GST_CAT_INFO (GST_CAT_EVENT,
563       "creating buffersize format %d, minsize %" G_GINT64_FORMAT
564       ", maxsize %" G_GINT64_FORMAT ", async %d", format,
565       minsize, maxsize, async);
566
567   return gst_event_new_custom (GST_EVENT_BUFFERSIZE,
568       gst_structure_new ("GstEventBufferSize",
569           "format", GST_TYPE_FORMAT, format,
570           "minsize", G_TYPE_INT64, minsize,
571           "maxsize", G_TYPE_INT64, maxsize,
572           "async", G_TYPE_BOOLEAN, async, NULL));
573 }
574
575 /**
576  * gst_event_parse_buffer_size:
577  * @event: The event to query
578  * @format: A pointer to store the format in
579  * @minsize: A pointer to store the minsize in
580  * @maxsize: A pointer to store the maxsize in
581  * @async: A pointer to store the async-flag in
582  *
583  * Get the format, minsize, maxsize and async-flag in the buffersize event.
584  */
585 void
586 gst_event_parse_buffer_size (GstEvent * event, GstFormat * format,
587     gint64 * minsize, gint64 * maxsize, gboolean * async)
588 {
589   const GstStructure *structure;
590
591   g_return_if_fail (GST_IS_EVENT (event));
592   g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_BUFFERSIZE);
593
594   structure = gst_event_get_structure (event);
595   if (format)
596     *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
597   if (minsize)
598     *minsize =
599         g_value_get_int64 (gst_structure_get_value (structure, "minsize"));
600   if (maxsize)
601     *maxsize =
602         g_value_get_int64 (gst_structure_get_value (structure, "maxsize"));
603   if (async)
604     *async = g_value_get_boolean (gst_structure_get_value (structure, "async"));
605 }
606
607 /**
608  * gst_event_new_qos:
609  * @proportion: the proportion of the qos message
610  * @diff: The time difference of the last Clock sync
611  * @timestamp: The timestamp of the buffer
612  *
613  * Allocate a new qos event with the given values.
614  * The QOS event is generated in an element that wants an upstream
615  * element to either reduce or increase its rate because of
616  * high/low CPU load.
617  *
618  * proportion is the requested adjustment in datarate, 1.0 is the normal
619  * datarate, 0.75 means increase datarate by 75%, 1.5 is 150%. Negative
620  * values request a slow down, so -0.75 means a decrease by 75%.
621  *
622  * diff is the difference against the clock in stream time of the last
623  * buffer that caused the element to generate the QOS event.
624  *
625  * timestamp is the timestamp of the last buffer that cause the element
626  * to generate the QOS event.
627  *
628  * Returns: A new QOS event.
629  */
630 GstEvent *
631 gst_event_new_qos (gdouble proportion, GstClockTimeDiff diff,
632     GstClockTime timestamp)
633 {
634   GST_CAT_INFO (GST_CAT_EVENT,
635       "creating qos proportion %lf, diff %" GST_TIME_FORMAT
636       ", timestamp %" GST_TIME_FORMAT, proportion,
637       GST_TIME_ARGS (diff), GST_TIME_ARGS (timestamp));
638
639   return gst_event_new_custom (GST_EVENT_QOS,
640       gst_structure_new ("GstEventQOS",
641           "proportion", G_TYPE_DOUBLE, proportion,
642           "diff", G_TYPE_INT64, diff,
643           "timestamp", G_TYPE_UINT64, timestamp, NULL));
644 }
645
646 /**
647  * gst_event_parse_qos:
648  * @event: The event to query
649  * @proportion: A pointer to store the proportion in
650  * @diff: A pointer to store the diff in
651  * @timestamp: A pointer to store the timestamp in
652  *
653  * Get the proportion, diff and timestamp in the qos event.
654  */
655 void
656 gst_event_parse_qos (GstEvent * event, gdouble * proportion,
657     GstClockTimeDiff * diff, GstClockTime * timestamp)
658 {
659   const GstStructure *structure;
660
661   g_return_if_fail (GST_IS_EVENT (event));
662   g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_QOS);
663
664   structure = gst_event_get_structure (event);
665   if (proportion)
666     *proportion =
667         g_value_get_double (gst_structure_get_value (structure, "proportion"));
668   if (diff)
669     *diff = g_value_get_int64 (gst_structure_get_value (structure, "diff"));
670   if (timestamp)
671     *timestamp =
672         g_value_get_uint64 (gst_structure_get_value (structure, "timestamp"));
673 }
674
675 /**
676  * gst_event_new_seek:
677  * @rate: The new playback rate
678  * @format: The format of the seek values
679  * @flags: The optional seek flags
680  * @cur_type: The type and flags for the new current position
681  * @cur: The value of the new current position
682  * @stop_type: The type and flags for the new stop position
683  * @stop: The value of the new stop position
684  *
685  * Allocate a new seek event with the given parameters.
686  *
687  * The seek event configures playback of the pipeline from
688  * @cur to @stop at the speed given in @rate, also called a segment.
689  * The @cur and @stop values are expressed in format @format.
690  *
691  * A @rate of 1.0 means normal playback rate, 2.0 means double speed.
692  * Negatives values means backwards playback. A value of 0.0 for the
693  * rate is not allowed.
694  *
695  * @cur_type and @stop_type specify how to adjust the current and stop
696  * time, relative or absolute. A type of #GST_SEEK_TYPE_NONE means that
697  * the position should not be updated. The currently configured playback
698  * segment can be queried with #GST_QUERY_SEGMENT.
699  *
700  * Note that updating the @cur position will actually move the current
701  * playback pointer to that new position. It is not possible to seek 
702  * relative to the current playing position, to do this, pause the pipeline,
703  * get the current position and perform a GST_SEEK_TYPE_SET to the desired
704  * position.
705  *
706  * Returns: A new seek event.
707  */
708 GstEvent *
709 gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags,
710     GstSeekType cur_type, gint64 cur, GstSeekType stop_type, gint64 stop)
711 {
712   if (format == GST_FORMAT_TIME) {
713     GST_CAT_INFO (GST_CAT_EVENT,
714         "creating seek rate %lf, format TIME, flags %d, "
715         "cur_type %d, cur %" GST_TIME_FORMAT ", "
716         "stop_type %d, stop %" GST_TIME_FORMAT,
717         rate, flags, cur_type, GST_TIME_ARGS (cur),
718         stop_type, GST_TIME_ARGS (stop));
719   } else {
720     GST_CAT_INFO (GST_CAT_EVENT,
721         "creating seek rate %lf, format %d, flags %d, "
722         "cur_type %d, cur %" G_GINT64_FORMAT ", "
723         "stop_type %d, stop %" G_GINT64_FORMAT,
724         rate, format, flags, cur_type, cur, stop_type, stop);
725   }
726
727   return gst_event_new_custom (GST_EVENT_SEEK,
728       gst_structure_new ("GstEventSeek", "rate", G_TYPE_DOUBLE, rate,
729           "format", GST_TYPE_FORMAT, format,
730           "flags", GST_TYPE_SEEK_FLAGS, flags,
731           "cur_type", GST_TYPE_SEEK_TYPE, cur_type,
732           "cur", G_TYPE_INT64, cur,
733           "stop_type", GST_TYPE_SEEK_TYPE, stop_type,
734           "stop", G_TYPE_INT64, stop, NULL));
735 }
736
737 /**
738  * gst_event_parse_seek:
739  * @event: a seek event
740  * @rate: result location for the rate
741  * @format: result location for the stream format
742  * @flags:  result location for the #GstSeekFlags
743  * @cur_type: result location for the #GstSeekType of the current position
744  * @cur: result location for the current postion expressed in @format
745  * @stop_type:  result location for the #GstSeekType of the stop position
746  * @stop: result location for the stop postion expressed in @format
747  *
748  * Parses a seek @event and stores the results in the given result locations.
749  */
750 void
751 gst_event_parse_seek (GstEvent * event, gdouble * rate, GstFormat * format,
752     GstSeekFlags * flags,
753     GstSeekType * cur_type, gint64 * cur,
754     GstSeekType * stop_type, gint64 * stop)
755 {
756   const GstStructure *structure;
757
758   g_return_if_fail (GST_IS_EVENT (event));
759   g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_SEEK);
760
761   structure = gst_event_get_structure (event);
762   if (rate)
763     *rate = g_value_get_double (gst_structure_get_value (structure, "rate"));
764   if (format)
765     *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
766   if (flags)
767     *flags = g_value_get_flags (gst_structure_get_value (structure, "flags"));
768   if (cur_type)
769     *cur_type =
770         g_value_get_enum (gst_structure_get_value (structure, "cur_type"));
771   if (cur)
772     *cur = g_value_get_int64 (gst_structure_get_value (structure, "cur"));
773   if (stop_type)
774     *stop_type =
775         g_value_get_enum (gst_structure_get_value (structure, "stop_type"));
776   if (stop)
777     *stop = g_value_get_int64 (gst_structure_get_value (structure, "stop"));
778 }
779
780 /**
781  * gst_event_new_navigation:
782  * @structure: description of the event
783  *
784  * Create a new navigation event from the given description.
785  *
786  * Returns: a new #GstEvent
787  */
788 GstEvent *
789 gst_event_new_navigation (GstStructure * structure)
790 {
791   g_return_val_if_fail (structure != NULL, NULL);
792
793   return gst_event_new_custom (GST_EVENT_NAVIGATION, structure);
794 }