remains in this state.
- GMainLoop integration. Information on the state of the pipeline
- is now received in the mainloop.
+ is now received in the mainloop via the GstBus.
- Events move separate from the datastream, this allows for both
in and out of sync delivery of events.
+2005-07-27 Wim Taymans <wim@fluendo.com>
+
+ * CHANGES-0.9:
+ * docs/design/part-TODO.txt:
+ * docs/design/part-events.txt:
+ Some docs updates
+
+ * gst/base/gstbasesink.c: (gst_base_sink_handle_object),
+ (gst_base_sink_event), (gst_base_sink_do_sync),
+ (gst_base_sink_activate_push), (gst_base_sink_activate_pull):
+ * gst/base/gstbasesrc.c: (gst_base_src_send_discont),
+ (gst_base_src_do_seek), (gst_base_src_event_handler),
+ (gst_base_src_loop):
+ * gst/base/gstbasetransform.c: (gst_base_transform_transform_caps),
+ (gst_base_transform_configure_caps), (gst_base_transform_setcaps),
+ (gst_base_transform_get_size), (gst_base_transform_buffer_alloc),
+ (gst_base_transform_event), (gst_base_transform_handle_buffer),
+ (gst_base_transform_set_passthrough),
+ (gst_base_transform_is_passthrough):
+ * gst/elements/gstfakesink.c: (gst_fake_sink_event):
+ * gst/elements/gstfilesink.c: (gst_file_sink_event):
+ Event updates.
+
+ * gst/gstbuffer.h:
+ Use faster casts.
+
+ * gst/gstelement.c: (gst_element_seek):
+ * gst/gstelement.h:
+ Update gst_element_seek.
+
+ * gst/gstevent.c: (gst_event_finalize), (_gst_event_copy),
+ (gst_event_new), (gst_event_new_custom), (gst_event_get_structure),
+ (gst_event_new_flush_start), (gst_event_new_flush_stop),
+ (gst_event_new_eos), (gst_event_new_newsegment),
+ (gst_event_parse_newsegment), (gst_event_new_tag),
+ (gst_event_parse_tag), (gst_event_new_filler), (gst_event_new_qos),
+ (gst_event_parse_qos), (gst_event_new_seek),
+ (gst_event_parse_seek), (gst_event_new_navigation):
+ * gst/gstevent.h:
+ Make GstEvent use GstStructure. Add parsing code, make sure the
+ API is sufficiently generic.
+ Mark possible directions of events and serialization.
+
+ * gst/gstmessage.c: (gst_message_init), (gst_message_finalize),
+ (_gst_message_copy), (gst_message_new_segment_start),
+ (gst_message_new_segment_done), (gst_message_new_custom),
+ (gst_message_parse_segment_start),
+ (gst_message_parse_segment_done):
+ Small cleanups.
+
+ * gst/gstpad.c: (gst_pad_get_caps_unlocked), (gst_pad_accept_caps),
+ (gst_pad_set_caps), (gst_pad_send_event):
+ Update for new events.
+ Catch events sent in wrong directions.
+
+ * gst/gstqueue.c: (gst_queue_link_src),
+ (gst_queue_handle_sink_event), (gst_queue_chain), (gst_queue_loop),
+ (gst_queue_handle_src_query):
+ Event updates.
+
+ * gst/gsttag.c:
+ * gst/gsttag.h:
+ Remove event code from this file.
+
+ * libs/gst/dataprotocol/dataprotocol.c: (gst_dp_packet_from_event),
+ (gst_dp_event_from_packet):
+ Event updates.
+
2005-07-27 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* gst/base/gstbasetransform.c: (gst_base_transform_getcaps),
done by making the event contain a GstStructure with input/output values, similar
to GstMessage.
-- implement iterators for traversing elements upstream or dowstream.
+- implement iterators for traversing elements upstream or dowstream. Use more simple
+ algorithm using indegree topological sort.
- unlinking pads in the PAUSED state needs to make sure the stream thread is not
executing code. Can this be done with a flush to unlock all downstream chain
Different types of events exist to implement various functionalities.
+ GST_EVENT_FLUSH_START: data is to be discarded
+ GST_EVENT_FLUSH_STOP: data is allowed again
GST_EVENT_EOS: no more data is to be expected on a pad.
- GST_EVENT_FLUSH: data is to be discarded or allowed again
- GST_EVENT_DISCONTINUOUS: A new group of buffers with common start time
+ GST_EVENT_NEWSEGMENT: A new group of buffers with common start time
+ GST_EVENT_TAG: Stream metadata.
+ GST_EVENT_FILLER: Filler for sparse data streams
GST_EVENT_QOS: A notification of the quality of service of the stream
GST_EVENT_SEEK: A seek should be performed to a new position in the stream
- GST_EVENT_SIZE: Notification of suggested buffer size.
- GST_EVENT_RATE: Notification to change the processing speed of a stream
GST_EVENT_NAVIGATION: A navigation event.
- GST_EVENT_TAG: Stream metadata.
+
+
+FLUSH_START/STOP
+----------------
+
+A flush event is sent both downstream and upstream to clear any pending data
+from the pipeline. This might be needed to make the graph more responsive
+when the normal dataflow gets interrupted by for example a seek event.
+
+Flushing happens in two stages.
+
+ 1) a source filter sends the FLUSH_START event to the downstream peer element. The
+ downstream element starts rejecting buffers from the upstream elements. It
+ sends the flush event further downstream and discards any buffers it is
+ holding as well as return from the chain function as soon as possible.
+ This makes sure that all upstream elements get unblocked.
+ This event is not synchronized with the STREAM_LOCK and can be done in the
+ application thread.
+
+ 2) a source filter sends the FLUSH_STOP event to indicate
+ that the downstream element can accept buffers again. The downstream
+ element sends the flush event to its peer elements. After this step dataflow
+ continues. The FLUSH_STOP call is synchronized with the STREAM_LOCK so any
+ data used by the chain function can safely freed here if needed. Any
+ pending EOS events should be discarded too.
+
+After the flush completes the second stage, data is flowing again in the pipeline
+and all buffers are more recent than those before the flush.
+
+For elements that use the pullregion function, they send both flush events to
+the upstream pads in the same way top make sure that the pullregion function
+unlocks and any pending buffers are cleared in the upstream elements.
EOS
goes to PLAYING.
-FLUSH
------
-
-A flush event is sent both downstream and upstream to clear any pending data
-from the pipeline. This might be needed to make the graph more responsive
-when the normal dataflow gets interrupted by for example a seek event.
-
-Flushing happens in two stages.
-
- 1) a source filter sends the flush event to the downstream peer element. The
- downstream element starts rejecting buffers from the upstream elements. It
- sends the flush event further downstream and discards any buffers it is
- holding as well as return from the chain function as soon as possible.
- This makes sure that all upstream elements get unblocked.
- This event is not synchronized with the STREAM_LOCK and can be done in the
- application thread.
-
- 2) a source filter sends the flush event with the done flag set to indicate
- that the downstream element can accept buffers again. The downstream
- element sends the flush event to its peer elements. After this step dataflow
- continues. The endflush call is synchronized with the STREAM_LOCK so any
- data used by the chain function can safely freed here if needed. Any
- pending EOS events should be discarded too.
-
-After the flush completes the second stage, data is flowing again in the pipeline
-and all buffers are more recent than those before the flush.
-
-For elements that use the pullregion function, they send both flush events to
-the upstream pads in the same way top make sure that the pullregion function
-unlocks and any pending buffers are cleared in the upstream elements.
-
-
-DISCONTINUOUS
+NEWSEGMENT
-------------
-A discont event is sent downstream by an element to indicate that the following
-group of buffers start and end at the specified time. The discont event
+A newsegment event is sent downstream by an element to indicate that the following
+group of buffers start and end at the specified positions. The newsegment event
also contains the playback speed of the stream.
Since the stream time is always set to 0 at start and after a seek, a 0
point for all next buffer's timestamps has to be propagated through the
-pipeline using the DISCONT event.
+pipeline using the NEWSEGMENT event.
-Before sending buffers, an element must send a DISCONT event. An element is
-free to refuse buffers if they were not preceeded by a DISCONT event.
+Before sending buffers, an element must send a NEWSEGMENT event. An element is
+free to refuse buffers if they were not preceeded by a NEWSEGMENT event.
-Elements that sync to the clock should store the DISCONT start and end values
+Elements that sync to the clock should store the NEWSEGMENT start and end values
and substract the start value from the buffer timestamp before comparing
it against the stream time (see part-clocks.txt).
-An element is allowed to send out buffers with the DISCONT start time already
+An element is allowed to send out buffers with the NEWSEGMENT start time already
substracted from the timestamp. If it does so, it needs to send a corrected
-DISCONT downstream, ie, one with start time 0.
+NEWSEGMENT downstream, ie, one with start time 0.
-A DISCONT event should be generated as soon as possible in the pipeline and
+A NEWSEGMENT event should be generated as soon as possible in the pipeline and
is usually generated by a demuxer or source. The event is generated before
pushing the first buffer and after a seek, right before pushing the new buffer.
-The DISCONT event can be send from both the application and the streaming
+The NEWSEGMENT event can be send from both the application and the streaming
thread and should be serialized with the buffers.
+Buffers should be clipped within the range indicated by the newsegment event
+start and stop values. Sinks are allowed to drop buffers with timestamps out
+of the indicated newsegment range.
+
SEEK
----
The general flow of executing the seek with FLUSH is as follows:
1) unblock the streaming threads, they could be blocked in a chain
- function. This is done by sending a flush on all srcpads.
+ function. This is done by sending a FLUSH_START on all srcpads.
The flush will make sure that all downstream elements unlock and
that control will return to this element chain/loop function.
We cannot lock the STREAM_LOCK before doing this since it might
will wait for the seek to complete. Most likely, the stream thread
will pause because the peer elements are flushing.
- 4) send a flush event with the done flag set to allow streaming again.
+ 4) send a FLUSH_STOP event to all peer elements to allow streaming again.
- 5) send a DISCONT event to signal the new buffer timestamp base time.
+ 5) send a NEWSEGMENT event to signal the new buffer timestamp base time.
6) start stopped tasks and unlock the STREAM_LOCK, dataflow will continue
now from the new position.
part-seeking.txt.
-SIZE
-----
-
-Some demuxers know an optimal size for any downstream buffers. They can
-use this event to signal this fact. Similary an element can signal an
-upstream element for a prefered buffer size.
-
-
-RATE
-----
-
-When the application wants to change the playback rate of the stream, it
-issues a rate event on the sinks. A rate of 1.0 is the normal playback rate,
-2.0 plays at twice the speed and negative values play backwards.
-
-The rate event travels upstream. After the rate event reaches an element
-that can handle the rate event, it issues a flush and generates a new
-DISCONT event with the updated rate.
-
-Note that the clock speed does not change. More specific information about
-changing the playback rate are to be thought out and written down.
-
-
NAVIGATION
----------
basesink->preroll_queued++;
basesink->eos = TRUE;
break;
- case GST_EVENT_DISCONTINUOUS:
- /* the discont event is needed to bring the buffer timestamps to the
+ case GST_EVENT_NEWSEGMENT:
+ {
+ GstFormat format;
+ gdouble rate;
+
+ /* the newsegment event is needed to bring the buffer timestamps to the
* stream time */
- if (!gst_event_discont_get_value (event, GST_FORMAT_TIME,
- &basesink->discont_start, &basesink->discont_stop)) {
+ gst_event_parse_newsegment (event, &rate, &format,
+ &basesink->discont_start, &basesink->discont_stop, NULL);
+
+ if (format != GST_FORMAT_TIME) {
/* this means this sink will not be able to sync to the clock */
basesink->discont_start = 0;
basesink->discont_stop = 0;
GST_TIME_ARGS (basesink->discont_start),
GST_TIME_ARGS (basesink->discont_stop));
break;
+ }
default:
break;
}
GST_STREAM_UNLOCK (pad);
break;
}
- case GST_EVENT_DISCONTINUOUS:
+ case GST_EVENT_NEWSEGMENT:
{
GstFlowReturn ret;
GST_STREAM_UNLOCK (pad);
break;
}
- case GST_EVENT_FLUSH:
+ case GST_EVENT_FLUSH_START:
/* make sure we are not blocked on the clock also clear any pending
* eos state. */
if (bclass->event)
bclass->event (basesink, event);
- if (!GST_EVENT_FLUSH_DONE (event)) {
- GST_PREROLL_LOCK (pad);
- /* we need preroll after the flush */
- basesink->need_preroll = TRUE;
- /* unlock from a possible state change/preroll */
- gst_base_sink_preroll_queue_flush (basesink, pad);
+ GST_PREROLL_LOCK (pad);
+ /* we need preroll after the flush */
+ basesink->need_preroll = TRUE;
+ /* unlock from a possible state change/preroll */
+ gst_base_sink_preroll_queue_flush (basesink, pad);
- GST_LOCK (basesink);
- if (basesink->clock_id) {
- gst_clock_id_unschedule (basesink->clock_id);
- }
- GST_UNLOCK (basesink);
- GST_PREROLL_UNLOCK (pad);
-
- /* and we need to commit our state again on the next
- * prerolled buffer */
- GST_STATE_LOCK (basesink);
- GST_STREAM_LOCK (pad);
- gst_element_lost_state (GST_ELEMENT (basesink));
- GST_STREAM_UNLOCK (pad);
- GST_STATE_UNLOCK (basesink);
- } else {
- /* now we are completely unblocked and the _chain method
- * will return */
- GST_STREAM_LOCK (pad);
- GST_STREAM_UNLOCK (pad);
+ GST_LOCK (basesink);
+ if (basesink->clock_id) {
+ gst_clock_id_unschedule (basesink->clock_id);
}
+ GST_UNLOCK (basesink);
+ GST_PREROLL_UNLOCK (pad);
+
+ /* and we need to commit our state again on the next
+ * prerolled buffer */
+ GST_STATE_LOCK (basesink);
+ GST_STREAM_LOCK (pad);
+ gst_element_lost_state (GST_ELEMENT (basesink));
+ GST_STREAM_UNLOCK (pad);
+ GST_STATE_UNLOCK (basesink);
+ GST_DEBUG ("event unref %p %p", basesink, event);
+ gst_event_unref (event);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ if (bclass->event)
+ bclass->event (basesink, event);
+
+ /* now we are completely unblocked and the _chain method
+ * will return */
+ GST_STREAM_LOCK (pad);
+ GST_STREAM_UNLOCK (pad);
+
GST_DEBUG ("event unref %p %p", basesink, event);
gst_event_unref (event);
break;
{
GstEvent *event;
- event = gst_event_new_discontinuous (1.0,
+ event = gst_event_new_newsegment (1.0,
GST_FORMAT_BYTES,
- (gint64) src->segment_start, (gint64) src->segment_end, NULL);
+ (gint64) src->segment_start, (gint64) src->segment_end, (gint64) 0);
return gst_pad_push_event (src->srcpad, event);
}
static gboolean
gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
{
+ gdouble rate;
GstFormat format;
- gint64 offset;
+ GstSeekFlags flags;
+ GstSeekType cur_type, stop_type;
+ gint64 cur, stop;
- format = GST_EVENT_SEEK_FORMAT (event);
+ gst_event_parse_seek (event, &rate, &format, &flags,
+ &cur_type, &cur, &stop_type, &stop);
/* get seek format */
if (format == GST_FORMAT_DEFAULT)
return FALSE;
/* get seek positions */
- offset = GST_EVENT_SEEK_OFFSET (event);
- src->segment_loop = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
+ src->segment_loop = flags & GST_SEEK_FLAG_SEGMENT;
/* send flush start */
- gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
+ gst_pad_push_event (src->srcpad, gst_event_new_flush_start ());
/* unblock streaming thread */
gst_base_src_unlock (src);
/* grab streaming lock */
GST_STREAM_LOCK (src->srcpad);
- /* send flush end */
- gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
+ /* send flush stop */
+ gst_pad_push_event (src->srcpad, gst_event_new_flush_stop ());
/* perform the seek */
- switch (GST_EVENT_SEEK_METHOD (event)) {
- case GST_SEEK_METHOD_SET:
- if (offset < 0)
+ switch (cur_type) {
+ case GST_SEEK_TYPE_SET:
+ if (cur < 0)
goto error;
- src->offset = MIN (offset, src->size);
+ src->offset = MIN (cur, src->size);
src->segment_start = src->offset;
- src->segment_end = MIN (GST_EVENT_SEEK_ENDOFFSET (event), src->size);
+ src->segment_end = MIN (stop, src->size);
GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
src->offset);
break;
- case GST_SEEK_METHOD_CUR:
- offset += src->offset;
- src->offset = CLAMP (offset, 0, src->size);
+ case GST_SEEK_TYPE_CUR:
+ cur += src->offset;
+ src->offset = CLAMP (cur, 0, src->size);
src->segment_start = src->offset;
- src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
+ src->segment_end = stop;
GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
src->offset);
break;
- case GST_SEEK_METHOD_END:
- if (offset > 0)
+ case GST_SEEK_TYPE_END:
+ if (cur > 0)
goto error;
- offset = src->size + offset;
- src->offset = MAX (0, offset);
+ cur = src->size + cur;
+ src->offset = MAX (0, cur);
src->segment_start = src->offset;
- src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
+ src->segment_end = stop;
GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
src->offset);
break;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
return gst_base_src_do_seek (src, event);
- case GST_EVENT_SIZE:
- {
- GstFormat format;
-
- format = GST_EVENT_SIZE_FORMAT (event);
- if (format == GST_FORMAT_DEFAULT)
- format = GST_FORMAT_BYTES;
- /* we can only accept bytes */
- if (format != GST_FORMAT_BYTES)
- return FALSE;
-
- src->blocksize = GST_EVENT_SIZE_VALUE (event);
- g_object_notify (G_OBJECT (src), "blocksize");
- break;
- }
- case GST_EVENT_FLUSH:
+ case GST_EVENT_FLUSH_START:
/* cancel any blocking getrange */
- if (!GST_EVENT_FLUSH_DONE (event))
- gst_base_src_unlock (src);
+ gst_base_src_unlock (src);
+ break;
+ case GST_EVENT_FLUSH_STOP:
break;
default:
break;
{
GST_DEBUG_OBJECT (src, "going to EOS");
gst_pad_pause_task (pad);
- gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+ gst_pad_push_event (pad, gst_event_new_eos ());
return;
}
pause:
GST_ELEMENT_ERROR (src, STREAM, STOPPED,
("streaming stopped, reason %s", gst_flow_get_name (ret)),
("streaming stopped, reason %s", gst_flow_get_name (ret)));
- gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+ gst_pad_push_event (pad, gst_event_new_eos ());
}
return;
}
("internal: element returned NULL buffer"),
("internal: element returned NULL buffer"));
gst_pad_pause_task (pad);
- gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+ gst_pad_push_event (pad, gst_event_new_eos ());
return;
}
}
unlock = FALSE;
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH:
- if (GST_EVENT_FLUSH_DONE (event)) {
- GST_STREAM_LOCK (pad);
- unlock = TRUE;
- }
+ case GST_EVENT_FLUSH_START:
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ GST_STREAM_LOCK (pad);
+ unlock = TRUE;
break;
case GST_EVENT_EOS:
GST_STREAM_LOCK (pad);
gst_fake_sink_event (GstBaseSink * bsink, GstEvent * event)
{
GstFakeSink *sink = GST_FAKE_SINK (bsink);
+ const GstStructure *s;
if (!sink->silent) {
+ gchar *sstr;
+
g_free (sink->last_message);
+ s = gst_event_get_structure (event);
+ sstr = gst_structure_to_string (s);
+
sink->last_message =
- g_strdup_printf ("event ******* E (type: %d) %p",
- GST_EVENT_TYPE (event), event);
+ g_strdup_printf ("event ******* E (type: %d, %s) %p",
+ GST_EVENT_TYPE (event), sstr, event);
+ g_free (sstr);
g_object_notify (G_OBJECT (sink), "last_message");
}
filesink = GST_FILE_SINK (sink);
- type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
+ type = GST_EVENT_TYPE (event);
switch (type) {
- case GST_EVENT_SEEK:
- if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
- return FALSE;
- }
-
- if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
- if (fflush (filesink->file)) {
- GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
- (_("Error while writing to file \"%s\"."), filesink->filename),
- GST_ERROR_SYSTEM);
- return FALSE;
- }
- }
-
- switch (GST_EVENT_SEEK_METHOD (event)) {
- case GST_SEEK_METHOD_SET:
- fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_SET);
- break;
- case GST_SEEK_METHOD_CUR:
- fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_CUR);
- break;
- case GST_SEEK_METHOD_END:
- fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_END);
- break;
- default:
- g_warning ("unknown seek method!");
- break;
- }
- break;
- case GST_EVENT_DISCONTINUOUS:
+ case GST_EVENT_NEWSEGMENT:
{
gint64 soffset, eoffset;
+ GstFormat format;
- if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &soffset,
- &eoffset))
+ gst_event_parse_newsegment (event, NULL, &format, &soffset, &eoffset,
+ NULL);
+
+ if (format == GST_FORMAT_BYTES) {
fseek (filesink->file, soffset, SEEK_SET);
+ }
break;
}
- case GST_EVENT_FLUSH:
+ case GST_EVENT_EOS:
if (fflush (filesink->file)) {
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
(_("Error while writing to file \"%s\"."), filesink->filename),
#define GST_BUFFER_FLAG_SET(buf,flag) GST_MINI_OBJECT_FLAG_SET (buf, flag)
#define GST_BUFFER_FLAG_UNSET(buf,flag) GST_MINI_OBJECT_FLAG_UNSET (buf, flag)
-#define GST_BUFFER_DATA(buf) (GST_BUFFER(buf)->data)
-#define GST_BUFFER_SIZE(buf) (GST_BUFFER(buf)->size)
-#define GST_BUFFER_TIMESTAMP(buf) (GST_BUFFER(buf)->timestamp)
-#define GST_BUFFER_DURATION(buf) (GST_BUFFER(buf)->duration)
-#define GST_BUFFER_CAPS(buf) (GST_BUFFER(buf)->caps)
-#define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset)
-#define GST_BUFFER_OFFSET_END(buf) (GST_BUFFER(buf)->offset_end)
-#define GST_BUFFER_MALLOCDATA(buf) (GST_BUFFER(buf)->malloc_data)
+#define GST_BUFFER_DATA(buf) (GST_BUFFER_CAST(buf)->data)
+#define GST_BUFFER_SIZE(buf) (GST_BUFFER_CAST(buf)->size)
+#define GST_BUFFER_TIMESTAMP(buf) (GST_BUFFER_CAST(buf)->timestamp)
+#define GST_BUFFER_DURATION(buf) (GST_BUFFER_CAST(buf)->duration)
+#define GST_BUFFER_CAPS(buf) (GST_BUFFER_CAST(buf)->caps)
+#define GST_BUFFER_OFFSET(buf) (GST_BUFFER_CAST(buf)->offset)
+#define GST_BUFFER_OFFSET_END(buf) (GST_BUFFER_CAST(buf)->offset_end)
+#define GST_BUFFER_MALLOCDATA(buf) (GST_BUFFER_CAST(buf)->malloc_data)
#define GST_BUFFER_OFFSET_NONE ((guint64)-1)
} G_STMT_END
/* refcounting */
-#define gst_buffer_ref(buf) GST_BUFFER (gst_mini_object_ref (GST_MINI_OBJECT (buf)))
+#define gst_buffer_ref(buf) GST_BUFFER_CAST (gst_mini_object_ref (GST_MINI_OBJECT (buf)))
#define gst_buffer_unref(buf) gst_mini_object_unref (GST_MINI_OBJECT (buf))
/* copy buffer */
-#define gst_buffer_copy(buf) GST_BUFFER (gst_mini_object_copy (GST_MINI_OBJECT (buf)))
+#define gst_buffer_copy(buf) GST_BUFFER_CAST (gst_mini_object_copy (GST_MINI_OBJECT (buf)))
#define gst_buffer_is_writable(buf) gst_mini_object_is_writable (GST_MINI_OBJECT (buf))
-#define gst_buffer_make_writable(buf) GST_BUFFER (gst_mini_object_make_writable (GST_MINI_OBJECT (buf)))
+#define gst_buffer_make_writable(buf) GST_BUFFER_CAST (gst_mini_object_make_writable (GST_MINI_OBJECT (buf)))
#define gst_buffer_replace(obuf,nbuf) gst_mini_object_replace ((GstMiniObject **)(obuf), GST_MINI_OBJECT (nbuf))
* MT safe.
*/
gboolean
-gst_element_seek (GstElement * element, GstSeekType seek_method,
- GstFormat seek_format, GstSeekType seek_flags, guint64 offset)
+gst_element_seek (GstElement * element, gdouble rate, GstFormat format,
+ GstSeekFlags flags, GstSeekType cur_type, gint64 cur,
+ GstSeekType stop_type, gint64 stop)
{
GstEvent *event;
gboolean result;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
- event = gst_event_new_seek (seek_method | seek_format | seek_flags, offset);
+ event =
+ gst_event_new_seek (rate, format, flags, cur_type, cur, stop_type, stop);
result = gst_element_send_event (element, event);
return result;
/* event/query/format stuff */
gboolean gst_element_send_event (GstElement *element, GstEvent *event);
-gboolean gst_element_seek (GstElement *element,
- GstSeekType seek_method,
- GstFormat seek_format,
- GstSeekType seek_flags,
- guint64 offset);
+gboolean gst_element_seek (GstElement *element, gdouble rate,
+ GstFormat format, GstSeekFlags flags,
+ GstSeekType cur_type, gint64 cur,
+ GstSeekType stop_type, gint64 stop);
G_CONST_RETURN GstQueryType*
gst_element_get_query_types (GstElement *element);
gboolean gst_element_query (GstElement *element, GstQuery *query);
#include "gst_private.h"
#include "gstinfo.h"
-#include "gstmemchunk.h"
#include "gstevent.h"
-#include "gsttag.h"
+#include "gstenumtypes.h"
#include "gstutils.h"
-
static void gst_event_init (GTypeInstance * instance, gpointer g_class);
static void gst_event_class_init (gpointer g_class, gpointer class_data);
static void gst_event_finalize (GstEvent * event);
gst_object_unref (GST_EVENT_SRC (event));
GST_EVENT_SRC (event) = NULL;
}
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_TAG:
- if (GST_IS_TAG_LIST (event->event_data.structure.structure)) {
- gst_tag_list_free (event->event_data.structure.structure);
- } else {
- g_warning ("tag event %p didn't contain a valid tag list!", event);
- GST_ERROR ("tag event %p didn't contain a valid tag list!", event);
- }
- break;
- case GST_EVENT_NAVIGATION:
- gst_structure_free (event->event_data.structure.structure);
- break;
- default:
- break;
+ if (event->structure) {
+ gst_structure_set_parent_refcount (event->structure, NULL);
+ gst_structure_free (event->structure);
}
}
-
static GstEvent *
_gst_event_copy (GstEvent * event)
{
GstEvent *copy;
- copy = gst_event_new (event->type);
+ copy = (GstEvent *) gst_mini_object_new (GST_TYPE_EVENT);
- copy->timestamp = event->timestamp;
- if (event->src) {
- copy->src = gst_object_ref (event->src);
- }
+ GST_EVENT_TYPE (copy) = GST_EVENT_TYPE (event);
+ GST_EVENT_TIMESTAMP (copy) = GST_EVENT_TIMESTAMP (event);
- memcpy (©->event_data, &event->event_data, sizeof (event->event_data));
-
- /* FIXME copy/ref additional fields */
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_TAG:
- copy->event_data.structure.structure =
- gst_tag_list_copy ((GstTagList *) event->event_data.structure.
- structure);
- break;
- case GST_EVENT_NAVIGATION:
- copy->event_data.structure.structure =
- gst_structure_copy (event->event_data.structure.structure);
- default:
- break;
+ if (GST_EVENT_SRC (event)) {
+ GST_EVENT_SRC (copy) = gst_object_ref (GST_EVENT_SRC (event));
+ }
+ if (event->structure) {
+ copy->structure = gst_structure_copy (event->structure);
+ gst_structure_set_parent_refcount (copy->structure,
+ &event->mini_object.refcount);
}
-
return copy;
}
-/**
- * gst_event_masks_contains:
- * @masks: The eventmask array to search
- * @mask: the event mask to find
- *
- * See if the given eventmask is inside the eventmask array.
- *
- * Returns: TRUE if the eventmask is found inside the array
- */
-gboolean
-gst_event_masks_contains (const GstEventMask * masks, GstEventMask * mask)
+static GstEvent *
+gst_event_new (GstEventType type)
{
- g_return_val_if_fail (mask != NULL, FALSE);
+ GstEvent *event;
- if (!masks)
- return FALSE;
+ event = (GstEvent *) gst_mini_object_new (GST_TYPE_EVENT);
- while (masks->type) {
- if (masks->type == mask->type &&
- (masks->flags & mask->flags) == mask->flags)
- return TRUE;
+ GST_CAT_INFO (GST_CAT_EVENT, "creating new event %p %d", event, type);
- masks++;
- }
+ event->type = type;
+ event->src = NULL;
+ event->structure = NULL;
- return FALSE;
+ return event;
}
/**
- * gst_event_new:
+ * gst_event_new_custom:
* @type: The type of the new event
+ * @structure: The structure for the event. The event will take ownership of
+ * the structure.
*
- * Allocate a new event of the given type.
+ * Create a new custom-typed event. This can be used for anything not
+ * handled by other event-specific functions to pass an event to another
+ * element.
*
- * Returns: A new event.
+ * Make sure to allocate an event type with the #GST_EVENT_MAKE_TYPE macro,
+ * assigning a free number and filling in the correct direction and
+ * serialization flags.
+ *
+ * New custom events can also be created by subclassing the event type if
+ * needed.
+ *
+ * Returns: The new custom event.
*/
GstEvent *
-gst_event_new (GstEventType type)
+gst_event_new_custom (GstEventType type, GstStructure * structure)
{
GstEvent *event;
- event = (GstEvent *) gst_mini_object_new (GST_TYPE_EVENT);
-
- GST_CAT_INFO (GST_CAT_EVENT, "creating new event type %d: %p", type, event);
-
- GST_EVENT_TYPE (event) = type;
-
+ event = gst_event_new (type);
+ if (structure) {
+ gst_structure_set_parent_refcount (structure, &event->mini_object.refcount);
+ event->structure = structure;
+ }
return event;
}
/**
- * gst_event_new_seek:
- * @type: The type of the seek event
- * @offset: The offset of the seek
+ * gst_event_get_structure:
+ * @event: The #GstEvent.
*
- * Allocate a new seek event with the given parameters.
+ * Access the structure of the event.
*
- * Returns: A new seek event.
+ * Returns: The structure of the event. The structure is still
+ * owned by the event, which means that you should not free it and
+ * that the pointer becomes invalid when you free the event.
+ *
+ * MT safe.
*/
-GstEvent *
-gst_event_new_seek (GstSeekType type, gint64 offset)
+const GstStructure *
+gst_event_get_structure (GstEvent * event)
{
- GstEvent *event;
-
- event = gst_event_new (GST_EVENT_SEEK);
+ g_return_val_if_fail (GST_IS_EVENT (event), NULL);
- GST_EVENT_SEEK_TYPE (event) = type;
- GST_EVENT_SEEK_OFFSET (event) = offset;
- GST_EVENT_SEEK_ENDOFFSET (event) = -1;
-
- return event;
+ return event->structure;
}
/**
- * gst_event_new_discontinuous_valist:
- * @new_media: A flag indicating a new media type starts
- * @format1: The format of the discont value
- * @var_args: more discont values and formats
+ * gst_event_new_flush_start:
+ *
+ * Allocate a new flush start event. The flush start event can be send
+ * upstream and downstream and travels out-of-bounds with the dataflow.
+ * It marks pads as being in a WRONG_STATE to process more data.
+ *
+ * Elements unlock and blocking functions and exit their streaming functions
+ * as fast as possible.
*
- * Allocate a new discontinuous event with the given format/value pairs. Note
- * that the values are of type gint64 - you may not use simple integers such
- * as "0" when calling this function, always cast them like "(gint64) 0".
- * Terminate the list with #GST_FORMAT_UNDEFINED.
+ * This event is typically generated after a seek to minimize the latency
+ * after the seek.
*
- * Returns: A new discontinuous event.
+ * Returns: A new flush start event.
*/
GstEvent *
-gst_event_new_discontinuous_valist (gdouble rate, GstFormat format1,
- va_list var_args)
+gst_event_new_flush_start (void)
{
- GstEvent *event;
- gint count = 0;
-
- event = gst_event_new (GST_EVENT_DISCONTINUOUS);
- GST_EVENT_DISCONT_RATE (event) = rate;
-
- while (format1 != GST_FORMAT_UNDEFINED && count < 8) {
-
- GST_EVENT_DISCONT_OFFSET (event, count).format =
- format1 & GST_SEEK_FORMAT_MASK;
- GST_EVENT_DISCONT_OFFSET (event, count).start_value =
- va_arg (var_args, gint64);
- GST_EVENT_DISCONT_OFFSET (event, count).end_value =
- va_arg (var_args, gint64);
-
- format1 = va_arg (var_args, GstFormat);
-
- count++;
- }
-
- GST_EVENT_DISCONT_OFFSET_LEN (event) = count;
-
- return event;
+ return gst_event_new (GST_EVENT_FLUSH_START);
}
/**
- * gst_event_new_discontinuous:
- * @new_media: A flag indicating a new media type starts
- * @format1: The format of the discont value
- * @...: more discont values and formats
+ * gst_event_new_flush_stop:
+ *
+ * Allocate a new flush stop event. The flush start event can be send
+ * upstream and downstream and travels out-of-bounds with the dataflow.
+ * It is typically send after sending a FLUSH_START event to make the
+ * pads accept data again.
*
- * Allocate a new discontinuous event with the given format/value pairs. Note
- * that the values are of type gint64 - you may not use simple integers such
- * as "0" when calling this function, always cast them like "(gint64) 0".
- * Terminate the list with #GST_FORMAT_UNDEFINED.
+ * Elements can process this event synchronized with the dataflow since
+ * the preceeding FLUSH_START event stopped the dataflow.
*
- * Returns: A new discontinuous event.
+ * This event is typically generated to complete a seek and to resume
+ * dataflow.
+ *
+ * Returns: A new flush stop event.
*/
GstEvent *
-gst_event_new_discontinuous (gdouble rate, GstFormat format1, ...)
+gst_event_new_flush_stop (void)
{
- va_list var_args;
- GstEvent *event;
-
- va_start (var_args, format1);
-
- event = gst_event_new_discontinuous_valist (rate, format1, var_args);
-
- va_end (var_args);
-
- return event;
+ return gst_event_new (GST_EVENT_FLUSH_STOP);
}
/**
- * gst_event_discont_get_value:
- * @event: The event to query
- * @format: The format of the discontinuous value
- * @start_value: A pointer to store the end value in
- * @end_value: A pointer to store the end value in
+ * gst_event_new_eos:
*
- * Get the start and end value for the given format in the discontinous event.
+ * Create a new EOS event. The eos event can only travel downstream
+ * synchronized with the buffer flow. Elements that receive the EOS
+ * event on a pad can return UNEXPECTED as a GstFlowReturn when data
+ * after the EOS event arrives.
*
- * Returns: TRUE if the discontinuous event carries the specified
- * format/value pair.
+ * The EOS event will travel up to the sink elements in the pipeline
+ * which will then post the GST_MESSAGE_EOS on the bus.
+ *
+ * When all sinks have posted an EOS message, the EOS message is
+ * forwarded to the application.
+ *
+ * Returns: The new EOS event.
*/
-gboolean
-gst_event_discont_get_value (GstEvent * event, GstFormat format,
- gint64 * start_value, gint64 * end_value)
+GstEvent *
+gst_event_new_eos (void)
{
- gint i, n;
-
- g_return_val_if_fail (event != NULL, FALSE);
-
- n = GST_EVENT_DISCONT_OFFSET_LEN (event);
-
- for (i = 0; i < n; i++) {
- if (GST_EVENT_DISCONT_OFFSET (event, i).format == format) {
- if (start_value)
- *start_value = GST_EVENT_DISCONT_OFFSET (event, i).start_value;
- if (end_value)
- *end_value = GST_EVENT_DISCONT_OFFSET (event, i).end_value;
- return TRUE;
- }
- }
-
- return FALSE;
+ return gst_event_new (GST_EVENT_EOS);
}
-
/**
- * gst_event_new_size:
- * @format: The format of the size value
- * @value: The value of the size event
+ * gst_event_new_newsegment:
+ * @rate: a new rate for playback
+ * @format: The format of the segment values
+ * @start_val: the start value of the segment
+ * @stop_val: the stop value of the segment
+ * @base: base value for buffer timestamps.
+ *
+ * Allocate a new newsegment event with the given format/values tripplets.
+ *
+ * The newsegment event marks the range of buffers to be processed. All
+ * data not within the segment range is not to be processed.
*
- * Create a new size event with the given values.
+ * The base time of the segment is used to convert the buffer timestamps
+ * into the stream time again.
*
- * Returns: The new size event.
+ * After a newsegment event, the buffer stream time is calculated with:
+ *
+ * TIMESTAMP(buf) - start_time + base
+ *
+ * Returns: A new newsegment event.
*/
GstEvent *
-gst_event_new_size (GstFormat format, gint64 value)
+gst_event_new_newsegment (gdouble rate, GstFormat format,
+ gint64 start_val, gint64 stop_val, gint64 base)
{
- GstEvent *event;
+ return gst_event_new_custom (GST_EVENT_NEWSEGMENT,
+ gst_structure_new ("GstEventNewsegment", "rate", G_TYPE_DOUBLE, rate,
+ "format", GST_TYPE_FORMAT, format,
+ "start_val", G_TYPE_INT64, start_val,
+ "stop_val", G_TYPE_INT64, stop_val,
+ "base", G_TYPE_INT64, base, NULL));
+}
- event = gst_event_new (GST_EVENT_SIZE);
+/**
+ * gst_event_parse_newsegment:
+ * @event: The event to query
+ * @rate: A pointer to the rate of the segment
+ * @format: A pointer to the format of the newsegment values
+ * @start_value: A pointer to store the start value in
+ * @stop_value: A pointer to store the stop value in
+ * @base: A pointer to store the base time in
+ *
+ * Get the start, stop and format in the newsegment event.
+ */
+void
+gst_event_parse_newsegment (GstEvent * event, gdouble * rate,
+ GstFormat * format, gint64 * start_value, gint64 * stop_value,
+ gint64 * base)
+{
+ const GstStructure *structure;
- GST_EVENT_SIZE_FORMAT (event) = format;
- GST_EVENT_SIZE_VALUE (event) = value;
+ g_return_if_fail (GST_IS_EVENT (event));
+ g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT);
+
+ structure = gst_event_get_structure (event);
+ if (rate)
+ *rate = g_value_get_double (gst_structure_get_value (structure, "rate"));
+ if (format)
+ *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
+ if (start_value)
+ *start_value =
+ g_value_get_int64 (gst_structure_get_value (structure, "start_val"));
+ if (stop_value)
+ *stop_value =
+ g_value_get_int64 (gst_structure_get_value (structure, "stop_val"));
+ if (base)
+ *base = g_value_get_int64 (gst_structure_get_value (structure, "base"));
+}
- return event;
+/* tag event */
+GstEvent *
+gst_event_new_tag (GstTagList * taglist)
+{
+ g_return_val_if_fail (taglist != NULL, NULL);
+
+ return gst_event_new_custom (GST_EVENT_TAG, (GstStructure *) taglist);
}
+void
+gst_event_parse_tag (GstEvent * event, GstTagList ** taglist)
+{
+ g_return_if_fail (GST_IS_EVENT (event));
+ g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TAG);
+
+ if (taglist)
+ *taglist = (GstTagList *) event->structure;
+}
+
+/* filler event */
+GstEvent *
+gst_event_new_filler (void)
+{
+ return gst_event_new (GST_EVENT_FILLER);
+}
/**
- * gst_event_new_segment_seek:
- * @type: The type of the seek event
- * @start: The start offset of the seek
- * @stop: The stop offset of the seek
+ * gst_event_new_qos:
+ * @proportion: the proportion of the qos message
+ * @diff: The time difference of the last Clock sync
+ * @timestamp: The timestamp of the buffer
+ *
+ * Allocate a new qos event with the given values.
+ * The QOS event is generated in an element that wants an upstream
+ * element to either reduce or increase its rate because of
+ * high/low CPU load.
+ *
+ * proportion is the requested adjustment in datarate, 1.0 is the normal
+ * datarate, 0.75 means increase datarate by 75%, 1.5 is 150%. Negative
+ * values request a slow down, so -0.75 means a decrease by 75%.
*
- * Allocate a new segment seek event with the given parameters.
+ * diff is the difference against the clock in stream time of the last
+ * buffer that caused the element to generate the QOS event.
*
- * Returns: A new segment seek event.
+ * timestamp is the timestamp of the last buffer that cause the element
+ * to generate the QOS event.
+ *
+ * Returns: A new QOS event.
*/
GstEvent *
-gst_event_new_segment_seek (GstSeekType type, gint64 start, gint64 stop)
+gst_event_new_qos (gdouble proportion, GstClockTimeDiff diff,
+ GstClockTime timestamp)
{
- GstEvent *event;
-
- g_return_val_if_fail (start < stop || stop == -1, NULL);
-
- event = gst_event_new (GST_EVENT_SEEK);
+ return gst_event_new_custom (GST_EVENT_QOS,
+ gst_structure_new ("GstEventQOS",
+ "proportion", G_TYPE_DOUBLE, proportion,
+ "diff", G_TYPE_INT64, diff,
+ "timestamp", G_TYPE_UINT64, timestamp, NULL));
+}
- GST_EVENT_SEEK_TYPE (event) = type;
- GST_EVENT_SEEK_OFFSET (event) = start;
- GST_EVENT_SEEK_ENDOFFSET (event) = stop;
+/**
+ * gst_event_parse_qos:
+ * @event: The event to query
+ * @proportion: A pointer to store the proportion in
+ * @diff: A pointer to store the diff in
+ * @timestamp: A pointer to store the timestamp in
+ *
+ * Get the proportion, diff and timestamp in the qos event.
+ */
+void
+gst_event_parse_qos (GstEvent * event, gdouble * proportion,
+ GstClockTimeDiff * diff, GstClockTime * timestamp)
+{
+ const GstStructure *structure;
- return event;
+ g_return_if_fail (GST_IS_EVENT (event));
+ g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_QOS);
+
+ structure = gst_event_get_structure (event);
+ if (proportion)
+ *proportion =
+ g_value_get_double (gst_structure_get_value (structure, "proportion"));
+ if (diff)
+ *diff = g_value_get_int64 (gst_structure_get_value (structure, "diff"));
+ if (timestamp)
+ *timestamp =
+ g_value_get_uint64 (gst_structure_get_value (structure, "timestamp"));
}
/**
- * gst_event_new_flush:
- * @done: Indicates the end of the flush
+ * gst_event_new_seek:
+ * @rate: The new playback rate
+ * @format: The format of the seek values
+ * @flags: The optional seek flags.
+ * @cur_type: The type and flags for the new current position
+ * @cur: The value of the new current position
+ * @stop_type: The type and flags for the new stop position
+ * @stop: The value of the new stop position
+ *
+ * Allocate a new seek event with the given parameters.
+ *
+ * The seek event configures playback of the pipeline from
+ * @cur to @stop at the speed given in @rate.
+ * The @cur and @stop values are expressed in format @format.
*
- * Allocate a new flush event.
+ * A @rate of 1.0 means normal playback rate, 2.0 means double speed.
+ * Negatives values means backwards playback. A value of 0.0 for the
+ * rate is not allowed.
*
- * Returns: A new flush event.
+ * @cur_type and @stop_type specify how to adjust the current and stop
+ * time, relative or absolute. A type of #GST_EVENT_TYPE_NONE means that
+ * the position should not be updated.
+ *
+ * Returns: A new seek event.
*/
GstEvent *
-gst_event_new_flush (gboolean done)
+gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags,
+ GstSeekType cur_type, gint64 cur, GstSeekType stop_type, gint64 stop)
{
- GstEvent *event;
+ return gst_event_new_custom (GST_EVENT_SEEK,
+ gst_structure_new ("GstEventSeek", "rate", G_TYPE_DOUBLE, rate,
+ "format", GST_TYPE_FORMAT, format,
+ "flags", GST_TYPE_SEEK_FLAGS, flags,
+ "cur_type", GST_TYPE_SEEK_TYPE, cur_type,
+ "cur", G_TYPE_INT64, cur,
+ "stop_type", GST_TYPE_SEEK_TYPE, stop_type,
+ "stop", G_TYPE_INT64, stop, NULL));
+}
- event = gst_event_new (GST_EVENT_FLUSH);
- GST_EVENT_FLUSH_DONE (event) = done;
+void
+gst_event_parse_seek (GstEvent * event, gdouble * rate, GstFormat * format,
+ GstSeekFlags * flags,
+ GstSeekType * cur_type, gint64 * cur,
+ GstSeekType * stop_type, gint64 * stop)
+{
+ const GstStructure *structure;
- return event;
+ g_return_if_fail (GST_IS_EVENT (event));
+ g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_SEEK);
+
+ structure = gst_event_get_structure (event);
+ if (rate)
+ *rate = g_value_get_double (gst_structure_get_value (structure, "rate"));
+ if (format)
+ *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
+ if (flags)
+ *flags = g_value_get_flags (gst_structure_get_value (structure, "flags"));
+ if (cur_type)
+ *cur_type =
+ g_value_get_enum (gst_structure_get_value (structure, "cur_type"));
+ if (cur)
+ *cur = g_value_get_int64 (gst_structure_get_value (structure, "cur"));
+ if (stop_type)
+ *stop_type =
+ g_value_get_enum (gst_structure_get_value (structure, "stop_type"));
+ if (stop)
+ *stop = g_value_get_int64 (gst_structure_get_value (structure, "stop"));
+}
+
+/* navigation event */
+GstEvent *
+gst_event_new_navigation (GstStructure * structure)
+{
+ g_return_val_if_fail (structure != NULL, NULL);
+
+ return gst_event_new_custom (GST_EVENT_NAVIGATION, structure);
}
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
+ * 2005 Wim Taymans <wim@fluendo.com>
*
* gstevent.h: Header for GstEvent subsystem
*
#include <gst/gstminiobject.h>
#include <gst/gstformat.h>
#include <gst/gstobject.h>
+#include <gst/gstclock.h>
#include <gst/gststructure.h>
+#include <gst/gsttag.h>
G_BEGIN_DECLS
+/* bitmaks defining the direction */
+#define GST_EVDIR_US (1 << 0)
+#define GST_EVDIR_DS (1 << 1)
+#define GST_EVDIR_BOTH GST_EVDIR_US | GST_EVDIR_DS
+/* mask defining event is serialized with data */
+#define GST_EVSER (1 << 2)
+#define GST_EVSHIFT 4
+
+/* when making custom event types, use this macro with the num and
+ * the given flags */
+#define GST_EVENT_MAKE_TYPE(num,flags) (((num) << GST_EVSHIFT) | (flags))
+
/**
* GstEventType:
- * @GST_EVENT_UNKNOWN:
- * @GST_EVENT_EOS:
- * @GST_EVENT_FLUSH:
- * @GST_EVENT_DISCONTINUOUS:
- * @GST_EVENT_QOS:
- * @GST_EVENT_SEEK:
- * @GST_EVENT_SIZE:
- * @GST_EVENT_RATE:
- * @GST_EVENT_NAVIGATION:
- * @GST_EVENT_TAG:
+ * @GST_EVENT_UNKNOWN: unknown event.
+ * @GST_EVENT_FLUSH_START: start a flush operation
+ * @GST_EVENT_FLUSH_STOP: stop a flush operation
+ * @GST_EVENT_EOS: no more data is to be expected.
+ * @GST_EVENT_NEWSEGMENT: a new segment started
+ * @GST_EVENT_TAG: a new tag
+ * @GST_EVENT_FILLER: filler for sparse data streams.
+ * @GST_EVENT_QOS: a quality message
+ * @GST_EVENT_SEEK: a request for a new playback position and rate.
+ * @GST_EVENT_NAVIGATION: a navigation event
*/
typedef enum {
- GST_EVENT_UNKNOWN = 0,
- GST_EVENT_EOS = 1,
- GST_EVENT_FLUSH = 2,
- GST_EVENT_DISCONTINUOUS = 3,
- GST_EVENT_QOS = 4,
- GST_EVENT_SEEK = 5,
- GST_EVENT_SIZE = 8,
- GST_EVENT_RATE = 9,
- GST_EVENT_NAVIGATION = 10,
- GST_EVENT_TAG = 11
+ GST_EVENT_UNKNOWN = GST_EVENT_MAKE_TYPE (0, 0),
+ /* bidirectional events */
+ GST_EVENT_FLUSH_START = GST_EVENT_MAKE_TYPE (1, GST_EVDIR_BOTH),
+ GST_EVENT_FLUSH_STOP = GST_EVENT_MAKE_TYPE (2, GST_EVDIR_BOTH),
+ /* downstream serialized events */
+ GST_EVENT_EOS = GST_EVENT_MAKE_TYPE (3, GST_EVDIR_DS | GST_EVSER),
+ GST_EVENT_NEWSEGMENT = GST_EVENT_MAKE_TYPE (4, GST_EVDIR_DS | GST_EVSER),
+ GST_EVENT_TAG = GST_EVENT_MAKE_TYPE (5, GST_EVDIR_DS | GST_EVSER),
+ GST_EVENT_FILLER = GST_EVENT_MAKE_TYPE (6, GST_EVDIR_DS | GST_EVSER),
+ /* upstream events */
+ GST_EVENT_QOS = GST_EVENT_MAKE_TYPE (7, GST_EVDIR_US),
+ GST_EVENT_SEEK = GST_EVENT_MAKE_TYPE (8, GST_EVDIR_US),
+ GST_EVENT_NAVIGATION = GST_EVENT_MAKE_TYPE (9, GST_EVDIR_US),
+
+ /* custom events start here */
+ GST_EVENT_CUSTOM_START = 32
} GstEventType;
-#define GST_EVENT_ANY GST_EVENT_NAVIGATION
#define GST_EVENT_TRACE_NAME "GstEvent"
typedef struct _GstEvent GstEvent;
typedef struct _GstEventClass GstEventClass;
-#define GST_TYPE_EVENT (gst_event_get_type())
-#define GST_IS_EVENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EVENT))
-#define GST_IS_EVENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_EVENT))
-#define GST_EVENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_EVENT, GstEventClass))
-#define GST_EVENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EVENT, GstEvent))
-#define GST_EVENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_EVENT, GstEventClass))
+#define GST_TYPE_EVENT (gst_event_get_type())
+#define GST_IS_EVENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EVENT))
+#define GST_IS_EVENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_EVENT))
+#define GST_EVENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_EVENT, GstEventClass))
+#define GST_EVENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EVENT, GstEvent))
+#define GST_EVENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_EVENT, GstEventClass))
#define GST_EVENT_TYPE(event) (GST_EVENT(event)->type)
#define GST_EVENT_TIMESTAMP(event) (GST_EVENT(event)->timestamp)
#define GST_EVENT_SRC(event) (GST_EVENT(event)->src)
-#define GST_EVENT_IS_INTERRUPT(event) (GST_EVENT_TYPE (event) == GST_EVENT_INTERRUPT)
-
-#define GST_SEEK_FORMAT_SHIFT 0
-#define GST_SEEK_METHOD_SHIFT 16
-#define GST_SEEK_FLAGS_SHIFT 20
-#define GST_SEEK_FORMAT_MASK 0x0000ffff
-#define GST_SEEK_METHOD_MASK 0x000f0000
-#define GST_SEEK_FLAGS_MASK 0xfff00000
-
-typedef enum {
- GST_EVENT_FLAG_NONE = 0,
-
- /* indicates negative rates are supported */
- GST_RATE_FLAG_NEGATIVE = (1 << 1)
-} GstEventFlag;
-
-typedef struct
-{
- GstEventType type;
- GstEventFlag flags;
-} GstEventMask;
+#define GST_EVENT_IS_UPSTREAM(ev) !!(GST_EVENT_TYPE (ev) & GST_EVDIR_US)
+#define GST_EVENT_IS_DOWNSTREAM(ev) !!(GST_EVENT_TYPE (ev) & GST_EVDIR_DS)
+#define GST_EVENT_IS_SERIALIZED(ev) !!(GST_EVENT_TYPE (ev) & GST_EVSER)
-/* seek events, extends GstEventFlag */
+/**
+ * GstSeekType:
+ * @GST_SEEK_TYPE_NONE: no change in position is required
+ * @GST_SEEK_TYPE_CUR: change relative to current position
+ * @GST_SEEK_TYPE_SET: absolute position is requested
+ * @GST_SEEK_TYPE_END: relative position to duration is requested
+ */
typedef enum {
- /* | with some format */
- /* | with one of these */
- GST_SEEK_METHOD_CUR = (1 << (GST_SEEK_METHOD_SHIFT + 0)),
- GST_SEEK_METHOD_SET = (1 << (GST_SEEK_METHOD_SHIFT + 1)),
- GST_SEEK_METHOD_END = (1 << (GST_SEEK_METHOD_SHIFT + 2)),
-
- /* | with optional seek flags */
- /* seek flags */
- GST_SEEK_FLAG_FLUSH = (1 << (GST_SEEK_FLAGS_SHIFT + 0)),
- GST_SEEK_FLAG_ACCURATE = (1 << (GST_SEEK_FLAGS_SHIFT + 1)),
- GST_SEEK_FLAG_KEY_UNIT = (1 << (GST_SEEK_FLAGS_SHIFT + 2)),
- GST_SEEK_FLAG_SEGMENT_LOOP = (1 << (GST_SEEK_FLAGS_SHIFT + 3))
-
+ /* one of these */
+ GST_SEEK_TYPE_NONE = 0,
+ GST_SEEK_TYPE_CUR = 1,
+ GST_SEEK_TYPE_SET = 2,
+ GST_SEEK_TYPE_END = 3
} GstSeekType;
+/**
+ * GstSeekFlags:
+ * @GST_SEEK_FLAG_NONE: no flag
+ * @GST_SEEK_FLAG_FLUSH: flush pipeline
+ * @GST_SEEK_FLAG_ACCURATE: accurate position is requested, this might
+ * be slower for some formats.
+ * @GST_SEEK_FLAG_KEY_UNIT: seek to the nearest keyframe. This might be
+ * faster but less accurate.
+ * @GST_SEEK_FLAG_SEGMENT: perform a segment seek. After the playback
+ * of the segment completes, no EOS will be emmited but a
+ * SEGMENT_DONE message will be posted on the bus.
+ */
typedef enum {
- GST_SEEK_CERTAIN,
- GST_SEEK_FUZZY
-} GstSeekAccuracy;
-
-typedef struct
-{
- GstFormat format;
- gint64 start_value;
- gint64 end_value;
-} GstFormatValue;
-
-#define GST_EVENT_SEEK_TYPE(event) (GST_EVENT(event)->event_data.seek.type)
-#define GST_EVENT_SEEK_FORMAT(event) (GST_EVENT_SEEK_TYPE(event) & GST_SEEK_FORMAT_MASK)
-#define GST_EVENT_SEEK_METHOD(event) (GST_EVENT_SEEK_TYPE(event) & GST_SEEK_METHOD_MASK)
-#define GST_EVENT_SEEK_FLAGS(event) (GST_EVENT_SEEK_TYPE(event) & GST_SEEK_FLAGS_MASK)
-#define GST_EVENT_SEEK_OFFSET(event) (GST_EVENT(event)->event_data.seek.offset)
-#define GST_EVENT_SEEK_ENDOFFSET(event) (GST_EVENT(event)->event_data.seek.endoffset)
-#define GST_EVENT_SEEK_ACCURACY(event) (GST_EVENT(event)->event_data.seek.accuracy)
-
-#define GST_EVENT_DISCONT_RATE(event) (GST_EVENT(event)->event_data.discont.rate)
-#define GST_EVENT_DISCONT_OFFSET(event,i) (GST_EVENT(event)->event_data.discont.offsets[i])
-#define GST_EVENT_DISCONT_OFFSET_LEN(event) (GST_EVENT(event)->event_data.discont.noffsets)
-
-#define GST_EVENT_FLUSH_DONE(event) (GST_EVENT(event)->event_data.flush.done)
-
-#define GST_EVENT_SIZE_FORMAT(event) (GST_EVENT(event)->event_data.size.format)
-#define GST_EVENT_SIZE_VALUE(event) (GST_EVENT(event)->event_data.size.value)
-
-#define GST_EVENT_RATE_VALUE(event) (GST_EVENT(event)->event_data.rate.value)
+ GST_SEEK_FLAG_NONE = 0,
+ GST_SEEK_FLAG_FLUSH = (1 << 0),
+ GST_SEEK_FLAG_ACCURATE = (1 << 1),
+ GST_SEEK_FLAG_KEY_UNIT = (1 << 2),
+ GST_SEEK_FLAG_SEGMENT = (1 << 3)
+} GstSeekFlags;
struct _GstEvent {
GstMiniObject mini_object;
guint64 timestamp;
GstObject *src;
- union {
- struct {
- GstSeekType type;
- gint64 offset;
- gint64 endoffset;
- GstSeekAccuracy accuracy;
- } seek;
- struct {
- GstFormatValue offsets[8];
- gint noffsets;
- gdouble rate;
- } discont;
- struct {
- gboolean done;
- } flush;
- struct {
- GstFormat format;
- gint64 value;
- } size;
- struct {
- gdouble value;
- } rate;
- struct {
- GstStructure *structure;
- } structure;
- } event_data;
+ GstStructure *structure;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
void _gst_event_initialize (void);
GType gst_event_get_type (void);
-GstEvent* gst_event_new (GstEventType type);
-
/* refcounting */
#define gst_event_ref(ev) GST_EVENT (gst_mini_object_ref (GST_MINI_OBJECT (ev)))
#define gst_event_unref(ev) gst_mini_object_unref (GST_MINI_OBJECT (ev))
-/* copy buffer */
+/* copy event */
#define gst_event_copy(ev) GST_EVENT (gst_mini_object_copy (GST_MINI_OBJECT (ev)))
-gboolean gst_event_masks_contains (const GstEventMask *masks, GstEventMask *mask);
+/* custom event */
+GstEvent* gst_event_new_custom (GstEventType type, GstStructure *structure);
-/* seek event */
-GstEvent* gst_event_new_seek (GstSeekType type, gint64 offset);
-
-GstEvent* gst_event_new_segment_seek (GstSeekType type, gint64 start, gint64 stop);
-
-
-/* size events */
-GstEvent* gst_event_new_size (GstFormat format, gint64 value);
-
-/* discontinous event */
-GstEvent* gst_event_new_discontinuous (gdouble rate,
- GstFormat format1, ...);
-GstEvent* gst_event_new_discontinuous_valist (gdouble rate,
- GstFormat format1,
- va_list var_args);
-gboolean gst_event_discont_get_value (GstEvent *event, GstFormat format,
- gint64 *start_value, gint64 *end_value);
-
-#define gst_event_new_filler() gst_event_new(GST_EVENT_FILLER)
-#define gst_event_new_eos() gst_event_new(GST_EVENT_EOS)
+const GstStructure *
+ gst_event_get_structure (GstEvent *event);
/* flush events */
-GstEvent* gst_event_new_flush (gboolean done);
+GstEvent * gst_event_new_flush_start (void);
+GstEvent * gst_event_new_flush_stop (void);
+
+/* EOS event */
+GstEvent * gst_event_new_eos (void);
+
+/* newsegment events */
+GstEvent* gst_event_new_newsegment (gdouble rate,
+ GstFormat format, gint64 start_value, gint64 stop_value,
+ gint64 base);
+void gst_event_parse_newsegment (GstEvent *event, gdouble *rate, GstFormat *format,
+ gint64 *start_value, gint64 *end_value, gint64 *base);
+/* tag event */
+GstEvent* gst_event_new_tag (GstTagList *taglist);
+void gst_event_parse_tag (GstEvent *event, GstTagList **taglist);
+
+/* filler event */
+GstEvent * gst_event_new_filler (void);
+
+
+/* QOS events */
+GstEvent* gst_event_new_qos (gdouble proportion, GstClockTimeDiff diff,
+ GstClockTime timestamp);
+void gst_event_parse_qos (GstEvent *event, gdouble *proportion, GstClockTimeDiff *diff,
+ GstClockTime *timestamp);
+/* seek event */
+GstEvent* gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags,
+ GstSeekType cur_type, gint64 cur,
+ GstSeekType stop_type, gint64 stop);
+void gst_event_parse_seek (GstEvent *event, gdouble *rate, GstFormat *format,
+ GstSeekFlags *flags,
+ GstSeekType *cur_type, gint64 *cur,
+ GstSeekType *stop_type, gint64 *stop);
+/* navigation event */
+GstEvent* gst_event_new_navigation (GstStructure *structure);
G_END_DECLS
{
GstMessage *message = GST_MESSAGE (instance);
- message->timestamp = GST_CLOCK_TIME_NONE;
+ GST_MESSAGE_TIMESTAMP (message) = GST_CLOCK_TIME_NONE;
}
static void
if (GST_MESSAGE_SRC (message)) {
gst_object_unref (GST_MESSAGE_SRC (message));
+ GST_MESSAGE_SRC (message) = NULL;
}
if (message->lock) {
/* FIXME, need to copy relevant data from the miniobject. */
//memcpy (copy, message, sizeof (GstMessage));
- copy->lock = message->lock;
- copy->cond = message->cond;
- copy->type = message->type;
- copy->timestamp = message->timestamp;
+ GST_MESSAGE_GET_LOCK (copy) = GST_MESSAGE_GET_LOCK (message);
+ GST_MESSAGE_COND (copy) = GST_MESSAGE_COND (message);
+ GST_MESSAGE_TYPE (copy) = GST_MESSAGE_TYPE (message);
+ GST_MESSAGE_TIMESTAMP (copy) = GST_MESSAGE_TIMESTAMP (message);
if (GST_MESSAGE_SRC (message)) {
GST_MESSAGE_SRC (copy) = gst_object_ref (GST_MESSAGE_SRC (message));
return copy;
}
-/**
- * gst_message_new:
- * @type: The type of the new message
- *
- * Allocate a new message of the given type.
- *
- * Returns: A new message.
- *
- * MT safe.
- */
static GstMessage *
gst_message_new (GstMessageType type, GstObject * src)
{
*
* Create a new custom-typed message. This can be used for anything not
* handled by other message-specific functions to pass a message to the
- * app.
+ * app. The structure field can be NULL.
*
* Returns: The new message.
*
{
GstMessage *message;
- g_return_val_if_fail (GST_IS_STRUCTURE (structure), NULL);
-
message = gst_message_new (type, src);
- gst_structure_set_parent_refcount (structure, &message->mini_object.refcount);
- message->structure = structure;
-
+ if (structure) {
+ gst_structure_set_parent_refcount (structure,
+ &message->mini_object.refcount);
+ message->structure = structure;
+ }
return message;
}
GST_LOCK (pad);
+ if (GST_PAD_IS_SINK (pad) && !GST_EVENT_IS_DOWNSTREAM (event))
+ goto wrong_direction;
+ if (GST_PAD_IS_SRC (pad) && !GST_EVENT_IS_UPSTREAM (event))
+ goto wrong_direction;
+
if (GST_EVENT_SRC (event) == NULL)
GST_EVENT_SRC (event) = gst_object_ref (pad);
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH:
- GST_CAT_DEBUG (GST_CAT_EVENT, "have event type %d (FLUSH) on pad %s:%s",
+ case GST_EVENT_FLUSH_START:
+ GST_CAT_DEBUG (GST_CAT_EVENT,
+ "have event type %d (FLUSH_START) on pad %s:%s",
GST_EVENT_TYPE (event), GST_DEBUG_PAD_NAME (pad));
- if (GST_EVENT_FLUSH_DONE (event)) {
- GST_PAD_UNSET_FLUSHING (pad);
- GST_CAT_DEBUG (GST_CAT_EVENT, "cleared flush flag");
- } else {
- /* can't even accept a flush begin event when flushing */
- if (GST_PAD_IS_FLUSHING (pad))
- goto flushing;
- GST_PAD_SET_FLUSHING (pad);
- GST_CAT_DEBUG (GST_CAT_EVENT, "set flush flag");
- }
+ /* can't even accept a flush begin event when flushing */
+ if (GST_PAD_IS_FLUSHING (pad))
+ goto flushing;
+ GST_PAD_SET_FLUSHING (pad);
+ GST_CAT_DEBUG (GST_CAT_EVENT, "set flush flag");
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ GST_PAD_UNSET_FLUSHING (pad);
+ GST_CAT_DEBUG (GST_CAT_EVENT, "cleared flush flag");
break;
default:
GST_CAT_DEBUG (GST_CAT_EVENT, "have event type %d on pad %s:%s",
return result;
/* ERROR handling */
+wrong_direction:
+ {
+ g_warning ("pad %s:%s sending event in wrong direction",
+ GST_DEBUG_PAD_NAME (pad));
+ GST_UNLOCK (pad);
+ gst_event_unref (event);
+ return FALSE;
+ }
no_function:
{
g_warning ("pad %s:%s has no event handler, file a bug.",
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH:
- STATUS (queue, "received flush event");
+ case GST_EVENT_FLUSH_START:
+ STATUS (queue, "received flush start event");
/* forward event, re first as we're going to use it still */
gst_event_ref (event);
gst_pad_push_event (queue->srcpad, event);
- if (GST_EVENT_FLUSH_DONE (event)) {
- GST_QUEUE_MUTEX_LOCK (queue);
- gst_queue_locked_flush (queue);
- queue->srcresult = GST_FLOW_OK;
- gst_pad_start_task (queue->srcpad, (GstTaskFunction) gst_queue_loop,
- queue->srcpad);
- GST_QUEUE_MUTEX_UNLOCK (queue);
- STATUS (queue, "after flush");
- } else {
- /* now unblock the chain function */
- GST_QUEUE_MUTEX_LOCK (queue);
- queue->srcresult = GST_FLOW_WRONG_STATE;
- /* unblock the loop function */
- g_cond_signal (queue->item_add);
- GST_QUEUE_MUTEX_UNLOCK (queue);
+ /* now unblock the chain function */
+ GST_QUEUE_MUTEX_LOCK (queue);
+ queue->srcresult = GST_FLOW_WRONG_STATE;
+ /* unblock the loop function */
+ g_cond_signal (queue->item_add);
+ GST_QUEUE_MUTEX_UNLOCK (queue);
- /* make sure it pauses */
- gst_pad_pause_task (queue->srcpad);
- GST_CAT_LOG_OBJECT (queue_dataflow, queue, "loop stopped");
- }
+ /* make sure it pauses */
+ gst_pad_pause_task (queue->srcpad);
+ GST_CAT_LOG_OBJECT (queue_dataflow, queue, "loop stopped");
+ gst_event_unref (event);
+ goto done;
+ case GST_EVENT_FLUSH_STOP:
+ STATUS (queue, "received flush stop event");
+ /* forward event, re first as we're going to use it still */
+ gst_event_ref (event);
+ gst_pad_push_event (queue->srcpad, event);
+
+ GST_QUEUE_MUTEX_LOCK (queue);
+ gst_queue_locked_flush (queue);
+ queue->srcresult = GST_FLOW_OK;
+ gst_pad_start_task (queue->srcpad, (GstTaskFunction) gst_queue_loop,
+ queue->srcpad);
+ GST_QUEUE_MUTEX_UNLOCK (queue);
+
+ STATUS (queue, "after flush");
gst_event_unref (event);
goto done;
case GST_EVENT_EOS:
GST_ELEMENT_ERROR (queue, STREAM, STOPPED,
("streaming stopped, reason %s", flowname),
("streaming stopped, reason %s", flowname));
- gst_pad_push_event (queue->srcpad, gst_event_new (GST_EVENT_EOS));
+ gst_pad_push_event (queue->srcpad, gst_event_new_eos ());
}
GST_DEBUG ("pausing queue, reason %s", flowname);
gst_pad_pause_task (queue->srcpad);
&data);
}
-/***** tag events *****/
-
-/**
- * gst_event_new_tag:
- * @list: the tag list to put into the event or NULL for an empty list
- *
- * Creates a new tag event with the given list and takes ownership of it.
- *
- * Returns: a new tag event
- */
-GstEvent *
-gst_event_new_tag (GstTagList * list)
-{
- GstEvent *ret;
-
- g_return_val_if_fail (list == NULL || GST_IS_TAG_LIST (list), NULL);
-
- ret = gst_event_new (GST_EVENT_TAG);
- if (!list)
- list = gst_tag_list_new ();
- ret->event_data.structure.structure = (GstStructure *) list;
-
- return ret;
-}
-
-/**
- * gst_event_tag_get_list:
- * @tag_event: a tagging #GstEvent
- *
- * Gets the taglist from a given tagging event.
- *
- * Returns: The #GstTagList of the event
- */
-GstTagList *
-gst_event_tag_get_list (GstEvent * tag_event)
-{
- g_return_val_if_fail (GST_IS_EVENT (tag_event), NULL);
- g_return_val_if_fail (GST_EVENT_TYPE (tag_event) == GST_EVENT_TAG, NULL);
-
- return GST_TAG_LIST (tag_event->event_data.structure.structure);
-}
-
/**
* gst_tag_list_get_value_index:
* @list: a #GStTagList
#define __GST_TAG_H__
#include <gst/gststructure.h>
-#include <gst/gstevent.h>
G_BEGIN_DECLS
guint index,
gpointer * value);
-/* tag events */
-GstEvent * gst_event_new_tag (GstTagList * list);
-GstTagList * gst_event_tag_get_list (GstEvent * tag_event);
-
-
/* GStreamer core tags (need to be discussed) */
/**
* GST_TAG_TITLE:
&data);
}
-/***** tag events *****/
-
-/**
- * gst_event_new_tag:
- * @list: the tag list to put into the event or NULL for an empty list
- *
- * Creates a new tag event with the given list and takes ownership of it.
- *
- * Returns: a new tag event
- */
-GstEvent *
-gst_event_new_tag (GstTagList * list)
-{
- GstEvent *ret;
-
- g_return_val_if_fail (list == NULL || GST_IS_TAG_LIST (list), NULL);
-
- ret = gst_event_new (GST_EVENT_TAG);
- if (!list)
- list = gst_tag_list_new ();
- ret->event_data.structure.structure = (GstStructure *) list;
-
- return ret;
-}
-
-/**
- * gst_event_tag_get_list:
- * @tag_event: a tagging #GstEvent
- *
- * Gets the taglist from a given tagging event.
- *
- * Returns: The #GstTagList of the event
- */
-GstTagList *
-gst_event_tag_get_list (GstEvent * tag_event)
-{
- g_return_val_if_fail (GST_IS_EVENT (tag_event), NULL);
- g_return_val_if_fail (GST_EVENT_TYPE (tag_event) == GST_EVENT_TAG, NULL);
-
- return GST_TAG_LIST (tag_event->event_data.structure.structure);
-}
-
/**
* gst_tag_list_get_value_index:
* @list: a #GStTagList
#define __GST_TAG_H__
#include <gst/gststructure.h>
-#include <gst/gstevent.h>
G_BEGIN_DECLS
guint index,
gpointer * value);
-/* tag events */
-GstEvent * gst_event_new_tag (GstTagList * list);
-GstTagList * gst_event_tag_get_list (GstEvent * tag_event);
-
-
/* GStreamer core tags (need to be discussed) */
/**
* GST_TAG_TITLE:
basesink->preroll_queued++;
basesink->eos = TRUE;
break;
- case GST_EVENT_DISCONTINUOUS:
- /* the discont event is needed to bring the buffer timestamps to the
+ case GST_EVENT_NEWSEGMENT:
+ {
+ GstFormat format;
+ gdouble rate;
+
+ /* the newsegment event is needed to bring the buffer timestamps to the
* stream time */
- if (!gst_event_discont_get_value (event, GST_FORMAT_TIME,
- &basesink->discont_start, &basesink->discont_stop)) {
+ gst_event_parse_newsegment (event, &rate, &format,
+ &basesink->discont_start, &basesink->discont_stop, NULL);
+
+ if (format != GST_FORMAT_TIME) {
/* this means this sink will not be able to sync to the clock */
basesink->discont_start = 0;
basesink->discont_stop = 0;
GST_TIME_ARGS (basesink->discont_start),
GST_TIME_ARGS (basesink->discont_stop));
break;
+ }
default:
break;
}
GST_STREAM_UNLOCK (pad);
break;
}
- case GST_EVENT_DISCONTINUOUS:
+ case GST_EVENT_NEWSEGMENT:
{
GstFlowReturn ret;
GST_STREAM_UNLOCK (pad);
break;
}
- case GST_EVENT_FLUSH:
+ case GST_EVENT_FLUSH_START:
/* make sure we are not blocked on the clock also clear any pending
* eos state. */
if (bclass->event)
bclass->event (basesink, event);
- if (!GST_EVENT_FLUSH_DONE (event)) {
- GST_PREROLL_LOCK (pad);
- /* we need preroll after the flush */
- basesink->need_preroll = TRUE;
- /* unlock from a possible state change/preroll */
- gst_base_sink_preroll_queue_flush (basesink, pad);
+ GST_PREROLL_LOCK (pad);
+ /* we need preroll after the flush */
+ basesink->need_preroll = TRUE;
+ /* unlock from a possible state change/preroll */
+ gst_base_sink_preroll_queue_flush (basesink, pad);
- GST_LOCK (basesink);
- if (basesink->clock_id) {
- gst_clock_id_unschedule (basesink->clock_id);
- }
- GST_UNLOCK (basesink);
- GST_PREROLL_UNLOCK (pad);
-
- /* and we need to commit our state again on the next
- * prerolled buffer */
- GST_STATE_LOCK (basesink);
- GST_STREAM_LOCK (pad);
- gst_element_lost_state (GST_ELEMENT (basesink));
- GST_STREAM_UNLOCK (pad);
- GST_STATE_UNLOCK (basesink);
- } else {
- /* now we are completely unblocked and the _chain method
- * will return */
- GST_STREAM_LOCK (pad);
- GST_STREAM_UNLOCK (pad);
+ GST_LOCK (basesink);
+ if (basesink->clock_id) {
+ gst_clock_id_unschedule (basesink->clock_id);
}
+ GST_UNLOCK (basesink);
+ GST_PREROLL_UNLOCK (pad);
+
+ /* and we need to commit our state again on the next
+ * prerolled buffer */
+ GST_STATE_LOCK (basesink);
+ GST_STREAM_LOCK (pad);
+ gst_element_lost_state (GST_ELEMENT (basesink));
+ GST_STREAM_UNLOCK (pad);
+ GST_STATE_UNLOCK (basesink);
+ GST_DEBUG ("event unref %p %p", basesink, event);
+ gst_event_unref (event);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ if (bclass->event)
+ bclass->event (basesink, event);
+
+ /* now we are completely unblocked and the _chain method
+ * will return */
+ GST_STREAM_LOCK (pad);
+ GST_STREAM_UNLOCK (pad);
+
GST_DEBUG ("event unref %p %p", basesink, event);
gst_event_unref (event);
break;
{
GstEvent *event;
- event = gst_event_new_discontinuous (1.0,
+ event = gst_event_new_newsegment (1.0,
GST_FORMAT_BYTES,
- (gint64) src->segment_start, (gint64) src->segment_end, NULL);
+ (gint64) src->segment_start, (gint64) src->segment_end, (gint64) 0);
return gst_pad_push_event (src->srcpad, event);
}
static gboolean
gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
{
+ gdouble rate;
GstFormat format;
- gint64 offset;
+ GstSeekFlags flags;
+ GstSeekType cur_type, stop_type;
+ gint64 cur, stop;
- format = GST_EVENT_SEEK_FORMAT (event);
+ gst_event_parse_seek (event, &rate, &format, &flags,
+ &cur_type, &cur, &stop_type, &stop);
/* get seek format */
if (format == GST_FORMAT_DEFAULT)
return FALSE;
/* get seek positions */
- offset = GST_EVENT_SEEK_OFFSET (event);
- src->segment_loop = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
+ src->segment_loop = flags & GST_SEEK_FLAG_SEGMENT;
/* send flush start */
- gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
+ gst_pad_push_event (src->srcpad, gst_event_new_flush_start ());
/* unblock streaming thread */
gst_base_src_unlock (src);
/* grab streaming lock */
GST_STREAM_LOCK (src->srcpad);
- /* send flush end */
- gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
+ /* send flush stop */
+ gst_pad_push_event (src->srcpad, gst_event_new_flush_stop ());
/* perform the seek */
- switch (GST_EVENT_SEEK_METHOD (event)) {
- case GST_SEEK_METHOD_SET:
- if (offset < 0)
+ switch (cur_type) {
+ case GST_SEEK_TYPE_SET:
+ if (cur < 0)
goto error;
- src->offset = MIN (offset, src->size);
+ src->offset = MIN (cur, src->size);
src->segment_start = src->offset;
- src->segment_end = MIN (GST_EVENT_SEEK_ENDOFFSET (event), src->size);
+ src->segment_end = MIN (stop, src->size);
GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
src->offset);
break;
- case GST_SEEK_METHOD_CUR:
- offset += src->offset;
- src->offset = CLAMP (offset, 0, src->size);
+ case GST_SEEK_TYPE_CUR:
+ cur += src->offset;
+ src->offset = CLAMP (cur, 0, src->size);
src->segment_start = src->offset;
- src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
+ src->segment_end = stop;
GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
src->offset);
break;
- case GST_SEEK_METHOD_END:
- if (offset > 0)
+ case GST_SEEK_TYPE_END:
+ if (cur > 0)
goto error;
- offset = src->size + offset;
- src->offset = MAX (0, offset);
+ cur = src->size + cur;
+ src->offset = MAX (0, cur);
src->segment_start = src->offset;
- src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
+ src->segment_end = stop;
GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
src->offset);
break;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
return gst_base_src_do_seek (src, event);
- case GST_EVENT_SIZE:
- {
- GstFormat format;
-
- format = GST_EVENT_SIZE_FORMAT (event);
- if (format == GST_FORMAT_DEFAULT)
- format = GST_FORMAT_BYTES;
- /* we can only accept bytes */
- if (format != GST_FORMAT_BYTES)
- return FALSE;
-
- src->blocksize = GST_EVENT_SIZE_VALUE (event);
- g_object_notify (G_OBJECT (src), "blocksize");
- break;
- }
- case GST_EVENT_FLUSH:
+ case GST_EVENT_FLUSH_START:
/* cancel any blocking getrange */
- if (!GST_EVENT_FLUSH_DONE (event))
- gst_base_src_unlock (src);
+ gst_base_src_unlock (src);
+ break;
+ case GST_EVENT_FLUSH_STOP:
break;
default:
break;
{
GST_DEBUG_OBJECT (src, "going to EOS");
gst_pad_pause_task (pad);
- gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+ gst_pad_push_event (pad, gst_event_new_eos ());
return;
}
pause:
GST_ELEMENT_ERROR (src, STREAM, STOPPED,
("streaming stopped, reason %s", gst_flow_get_name (ret)),
("streaming stopped, reason %s", gst_flow_get_name (ret)));
- gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+ gst_pad_push_event (pad, gst_event_new_eos ());
}
return;
}
("internal: element returned NULL buffer"),
("internal: element returned NULL buffer"));
gst_pad_pause_task (pad);
- gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+ gst_pad_push_event (pad, gst_event_new_eos ());
return;
}
}
unlock = FALSE;
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH:
- if (GST_EVENT_FLUSH_DONE (event)) {
- GST_STREAM_LOCK (pad);
- unlock = TRUE;
- }
+ case GST_EVENT_FLUSH_START:
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ GST_STREAM_LOCK (pad);
+ unlock = TRUE;
break;
case GST_EVENT_EOS:
GST_STREAM_LOCK (pad);
g_free (h);
return FALSE;
case GST_EVENT_EOS:
- case GST_EVENT_FLUSH:
- case GST_EVENT_DISCONTINUOUS:
+ case GST_EVENT_FLUSH_START:
+ case GST_EVENT_FLUSH_STOP:
+ case GST_EVENT_NEWSEGMENT:
GST_WRITE_UINT64_BE (h + 8, GST_EVENT_TIMESTAMP (event));
pl_length = 0;
*payload = NULL;
case GST_EVENT_SEEK:
pl_length = 4 + 8 + 8 + 4;
*payload = g_malloc0 (pl_length);
- GST_WRITE_UINT32_BE (*payload, (guint32) GST_EVENT_SEEK_TYPE (event));
- GST_WRITE_UINT64_BE (*payload + 4,
- (guint64) GST_EVENT_SEEK_OFFSET (event));
- GST_WRITE_UINT64_BE (*payload + 12,
- (guint64) GST_EVENT_SEEK_ENDOFFSET (event));
- GST_WRITE_UINT32_BE (*payload + 20,
- (guint32) GST_EVENT_SEEK_ACCURACY (event));
+ /*
+ GST_WRITE_UINT32_BE (*payload, (guint32) GST_EVENT_SEEK_TYPE (event));
+ GST_WRITE_UINT64_BE (*payload + 4,
+ (guint64) GST_EVENT_SEEK_OFFSET (event));
+ GST_WRITE_UINT64_BE (*payload + 12,
+ (guint64) GST_EVENT_SEEK_ENDOFFSET (event));
+ GST_WRITE_UINT32_BE (*payload + 20,
+ (guint32) GST_EVENT_SEEK_ACCURACY (event));
+ */
break;
case GST_EVENT_QOS:
- case GST_EVENT_SIZE:
- case GST_EVENT_RATE:
case GST_EVENT_NAVIGATION:
case GST_EVENT_TAG:
g_warning ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));
g_warning ("Unknown event, ignoring");
return FALSE;
case GST_EVENT_EOS:
- case GST_EVENT_FLUSH:
- case GST_EVENT_DISCONTINUOUS:
- event = gst_event_new (type);
+ case GST_EVENT_FLUSH_START:
+ case GST_EVENT_FLUSH_STOP:
+ case GST_EVENT_NEWSEGMENT:
+ event = gst_event_new_custom (type, NULL);
GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
break;
case GST_EVENT_SEEK:
{
- GstSeekType type;
- gint64 offset, endoffset;
- GstSeekAccuracy accuracy;
-
- type = (GstSeekType) GST_READ_UINT32_BE (payload);
- offset = (gint64) GST_READ_UINT64_BE (payload + 4);
- endoffset = (gint64) GST_READ_UINT64_BE (payload + 12);
- accuracy = (GstSeekAccuracy) GST_READ_UINT32_BE (payload + 20);
- event = gst_event_new_segment_seek (type, offset, endoffset);
- GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
- GST_EVENT_SEEK_ACCURACY (event) = accuracy;
+ /*
+ GstSeekType type;
+ gint64 offset, endoffset;
+ GstSeekAccuracy accuracy;
+
+ type = (GstSeekType) GST_READ_UINT32_BE (payload);
+ offset = (gint64) GST_READ_UINT64_BE (payload + 4);
+ endoffset = (gint64) GST_READ_UINT64_BE (payload + 12);
+ accuracy = (GstSeekAccuracy) GST_READ_UINT32_BE (payload + 20);
+ event = gst_event_new_segment_seek (type, offset, endoffset);
+ GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
+ GST_EVENT_SEEK_ACCURACY (event) = accuracy;
+ */
break;
}
case GST_EVENT_QOS:
- case GST_EVENT_SIZE:
- case GST_EVENT_RATE:
case GST_EVENT_NAVIGATION:
case GST_EVENT_TAG:
g_warning ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));
gst_fake_sink_event (GstBaseSink * bsink, GstEvent * event)
{
GstFakeSink *sink = GST_FAKE_SINK (bsink);
+ const GstStructure *s;
if (!sink->silent) {
+ gchar *sstr;
+
g_free (sink->last_message);
+ s = gst_event_get_structure (event);
+ sstr = gst_structure_to_string (s);
+
sink->last_message =
- g_strdup_printf ("event ******* E (type: %d) %p",
- GST_EVENT_TYPE (event), event);
+ g_strdup_printf ("event ******* E (type: %d, %s) %p",
+ GST_EVENT_TYPE (event), sstr, event);
+ g_free (sstr);
g_object_notify (G_OBJECT (sink), "last_message");
}
filesink = GST_FILE_SINK (sink);
- type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
+ type = GST_EVENT_TYPE (event);
switch (type) {
- case GST_EVENT_SEEK:
- if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
- return FALSE;
- }
-
- if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
- if (fflush (filesink->file)) {
- GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
- (_("Error while writing to file \"%s\"."), filesink->filename),
- GST_ERROR_SYSTEM);
- return FALSE;
- }
- }
-
- switch (GST_EVENT_SEEK_METHOD (event)) {
- case GST_SEEK_METHOD_SET:
- fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_SET);
- break;
- case GST_SEEK_METHOD_CUR:
- fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_CUR);
- break;
- case GST_SEEK_METHOD_END:
- fseek (filesink->file, GST_EVENT_SEEK_OFFSET (event), SEEK_END);
- break;
- default:
- g_warning ("unknown seek method!");
- break;
- }
- break;
- case GST_EVENT_DISCONTINUOUS:
+ case GST_EVENT_NEWSEGMENT:
{
gint64 soffset, eoffset;
+ GstFormat format;
- if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &soffset,
- &eoffset))
+ gst_event_parse_newsegment (event, NULL, &format, &soffset, &eoffset,
+ NULL);
+
+ if (format == GST_FORMAT_BYTES) {
fseek (filesink->file, soffset, SEEK_SET);
+ }
break;
}
- case GST_EVENT_FLUSH:
+ case GST_EVENT_EOS:
if (fflush (filesink->file)) {
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
(_("Error while writing to file \"%s\"."), filesink->filename),
queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH:
- STATUS (queue, "received flush event");
+ case GST_EVENT_FLUSH_START:
+ STATUS (queue, "received flush start event");
/* forward event, re first as we're going to use it still */
gst_event_ref (event);
gst_pad_push_event (queue->srcpad, event);
- if (GST_EVENT_FLUSH_DONE (event)) {
- GST_QUEUE_MUTEX_LOCK (queue);
- gst_queue_locked_flush (queue);
- queue->srcresult = GST_FLOW_OK;
- gst_pad_start_task (queue->srcpad, (GstTaskFunction) gst_queue_loop,
- queue->srcpad);
- GST_QUEUE_MUTEX_UNLOCK (queue);
- STATUS (queue, "after flush");
- } else {
- /* now unblock the chain function */
- GST_QUEUE_MUTEX_LOCK (queue);
- queue->srcresult = GST_FLOW_WRONG_STATE;
- /* unblock the loop function */
- g_cond_signal (queue->item_add);
- GST_QUEUE_MUTEX_UNLOCK (queue);
+ /* now unblock the chain function */
+ GST_QUEUE_MUTEX_LOCK (queue);
+ queue->srcresult = GST_FLOW_WRONG_STATE;
+ /* unblock the loop function */
+ g_cond_signal (queue->item_add);
+ GST_QUEUE_MUTEX_UNLOCK (queue);
- /* make sure it pauses */
- gst_pad_pause_task (queue->srcpad);
- GST_CAT_LOG_OBJECT (queue_dataflow, queue, "loop stopped");
- }
+ /* make sure it pauses */
+ gst_pad_pause_task (queue->srcpad);
+ GST_CAT_LOG_OBJECT (queue_dataflow, queue, "loop stopped");
+ gst_event_unref (event);
+ goto done;
+ case GST_EVENT_FLUSH_STOP:
+ STATUS (queue, "received flush stop event");
+ /* forward event, re first as we're going to use it still */
+ gst_event_ref (event);
+ gst_pad_push_event (queue->srcpad, event);
+
+ GST_QUEUE_MUTEX_LOCK (queue);
+ gst_queue_locked_flush (queue);
+ queue->srcresult = GST_FLOW_OK;
+ gst_pad_start_task (queue->srcpad, (GstTaskFunction) gst_queue_loop,
+ queue->srcpad);
+ GST_QUEUE_MUTEX_UNLOCK (queue);
+
+ STATUS (queue, "after flush");
gst_event_unref (event);
goto done;
case GST_EVENT_EOS:
GST_ELEMENT_ERROR (queue, STREAM, STOPPED,
("streaming stopped, reason %s", flowname),
("streaming stopped, reason %s", flowname));
- gst_pad_push_event (queue->srcpad, gst_event_new (GST_EVENT_EOS));
+ gst_pad_push_event (queue->srcpad, gst_event_new_eos ());
}
GST_DEBUG ("pausing queue, reason %s", flowname);
gst_pad_pause_task (queue->srcpad);