Some docs updates

Original commit message from CVS:
* 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.
This commit is contained in:
Wim Taymans 2005-07-27 18:33:03 +00:00
parent 4795d25721
commit 66d7070ef1
28 changed files with 944 additions and 926 deletions

View file

@ -17,7 +17,7 @@ Changes in the 0.9 version
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.

View file

@ -1,3 +1,71 @@
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),

View file

@ -8,7 +8,8 @@
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

View file

@ -10,15 +10,47 @@ others don't.
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
@ -57,67 +89,39 @@ the EOS event is received in the PAUSED state, it is queued until the element
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
----
@ -149,7 +153,7 @@ the STREAM_LOCK so that the streaming thread and the seek gets serialized.
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
@ -162,9 +166,9 @@ The general flow of executing the seek with FLUSH is as follows:
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.
@ -173,29 +177,6 @@ More information about the different seek types can be found in
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
----------

View file

@ -468,11 +468,17 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
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;
@ -483,6 +489,7 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
GST_TIME_ARGS (basesink->discont_start),
GST_TIME_ARGS (basesink->discont_stop));
break;
}
default:
break;
}
@ -664,7 +671,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
GST_STREAM_UNLOCK (pad);
break;
}
case GST_EVENT_DISCONTINUOUS:
case GST_EVENT_NEWSEGMENT:
{
GstFlowReturn ret;
@ -674,39 +681,44 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
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;

View file

@ -362,9 +362,9 @@ gst_base_src_send_discont (GstBaseSrc * src)
{
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);
}
@ -372,10 +372,14 @@ gst_base_src_send_discont (GstBaseSrc * src)
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)
@ -385,11 +389,10 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
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);
@ -397,35 +400,35 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
/* 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;
@ -471,25 +474,11 @@ gst_base_src_event_handler (GstPad * pad, GstEvent * event)
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;
@ -695,7 +684,7 @@ eos:
{
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:
@ -707,7 +696,7 @@ 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;
}
@ -717,7 +706,7 @@ error:
("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;
}
}

View file

@ -497,11 +497,11 @@ gst_base_transform_event (GstPad * pad, GstEvent * event)
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);

View file

@ -273,13 +273,20 @@ static gboolean
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");
}

View file

@ -291,48 +291,23 @@ gst_file_sink_event (GstBaseSink * sink, GstEvent * event)
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),

View file

@ -48,14 +48,14 @@ typedef struct _GstBufferClass GstBufferClass;
#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)
@ -138,12 +138,12 @@ G_STMT_START { \
} 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))

View file

@ -1160,15 +1160,17 @@ gst_element_send_event (GstElement * element, GstEvent * event)
* 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;

View file

@ -302,11 +302,10 @@ GstIterator * gst_element_iterate_sink_pads (GstElement * element);
/* 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);

View file

@ -25,12 +25,10 @@
#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);
@ -101,298 +99,400 @@ 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);
if (GST_EVENT_SRC (event)) {
GST_EVENT_SRC (copy) = gst_object_ref (GST_EVENT_SRC (event));
}
memcpy (&copy->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 (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)
{
g_return_val_if_fail (mask != NULL, FALSE);
if (!masks)
return FALSE;
while (masks->type) {
if (masks->type == mask->type &&
(masks->flags & mask->flags) == mask->flags)
return TRUE;
masks++;
}
return FALSE;
}
/**
* gst_event_new:
* @type: The type of the new event
*
* Allocate a new event of the given type.
*
* Returns: A new event.
*/
GstEvent *
static GstEvent *
gst_event_new (GstEventType type)
{
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_CAT_INFO (GST_CAT_EVENT, "creating new event %p %d", event, type);
GST_EVENT_TYPE (event) = type;
event->type = type;
event->src = NULL;
event->structure = NULL;
return event;
}
/**
* 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.
*
* 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.
*
* 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_custom (GstEventType type, GstStructure * structure)
{
GstEvent *event;
event = gst_event_new (type);
if (structure) {
gst_structure_set_parent_refcount (structure, &event->mini_object.refcount);
event->structure = structure;
}
return event;
}
/**
* gst_event_get_structure:
* @event: The #GstEvent.
*
* Access the structure of the 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.
*/
const GstStructure *
gst_event_get_structure (GstEvent * event)
{
g_return_val_if_fail (GST_IS_EVENT (event), NULL);
return event->structure;
}
/**
* 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.
*
* This event is typically generated after a seek to minimize the latency
* after the seek.
*
* Returns: A new flush start event.
*/
GstEvent *
gst_event_new_flush_start (void)
{
return gst_event_new (GST_EVENT_FLUSH_START);
}
/**
* 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.
*
* Elements can process this event synchronized with the dataflow since
* the preceeding FLUSH_START event stopped the dataflow.
*
* This event is typically generated to complete a seek and to resume
* dataflow.
*
* Returns: A new flush stop event.
*/
GstEvent *
gst_event_new_flush_stop (void)
{
return gst_event_new (GST_EVENT_FLUSH_STOP);
}
/**
* gst_event_new_eos:
*
* 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.
*
* 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.
*/
GstEvent *
gst_event_new_eos (void)
{
return gst_event_new (GST_EVENT_EOS);
}
/**
* 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.
*
* The base time of the segment is used to convert the buffer timestamps
* into the stream time again.
*
* 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_newsegment (gdouble rate, GstFormat format,
gint64 start_val, gint64 stop_val, gint64 base)
{
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));
}
/**
* 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;
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"));
}
/* 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_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%.
*
* diff is the difference against the clock in stream time of the last
* buffer that caused the element to generate the QOS 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_qos (gdouble proportion, GstClockTimeDiff diff,
GstClockTime timestamp)
{
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_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;
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_seek:
* @type: The type of the seek event
* @offset: The offset of the 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.
*
* 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.
*
* @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_seek (GstSeekType type, gint64 offset)
gst_event_new_seek (gdouble rate, GstFormat format, GstSeekFlags flags,
GstSeekType cur_type, gint64 cur, GstSeekType stop_type, gint64 stop)
{
GstEvent *event;
event = gst_event_new (GST_EVENT_SEEK);
GST_EVENT_SEEK_TYPE (event) = type;
GST_EVENT_SEEK_OFFSET (event) = offset;
GST_EVENT_SEEK_ENDOFFSET (event) = -1;
return 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));
}
/**
* 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
*
* 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.
*
* Returns: A new discontinuous event.
*/
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;
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_discontinuous_valist (gdouble rate, GstFormat format1,
va_list var_args)
gst_event_new_navigation (GstStructure * structure)
{
GstEvent *event;
gint count = 0;
g_return_val_if_fail (structure != NULL, NULL);
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;
}
/**
* 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
*
* 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.
*
* Returns: A new discontinuous event.
*/
GstEvent *
gst_event_new_discontinuous (gdouble rate, GstFormat format1, ...)
{
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;
}
/**
* 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
*
* Get the start and end value for the given format in the discontinous event.
*
* Returns: TRUE if the discontinuous event carries the specified
* format/value pair.
*/
gboolean
gst_event_discont_get_value (GstEvent * event, GstFormat format,
gint64 * start_value, gint64 * end_value)
{
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;
}
/**
* gst_event_new_size:
* @format: The format of the size value
* @value: The value of the size event
*
* Create a new size event with the given values.
*
* Returns: The new size event.
*/
GstEvent *
gst_event_new_size (GstFormat format, gint64 value)
{
GstEvent *event;
event = gst_event_new (GST_EVENT_SIZE);
GST_EVENT_SIZE_FORMAT (event) = format;
GST_EVENT_SIZE_VALUE (event) = value;
return event;
}
/**
* 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
*
* Allocate a new segment seek event with the given parameters.
*
* Returns: A new segment seek event.
*/
GstEvent *
gst_event_new_segment_seek (GstSeekType type, gint64 start, gint64 stop)
{
GstEvent *event;
g_return_val_if_fail (start < stop || stop == -1, NULL);
event = gst_event_new (GST_EVENT_SEEK);
GST_EVENT_SEEK_TYPE (event) = type;
GST_EVENT_SEEK_OFFSET (event) = start;
GST_EVENT_SEEK_ENDOFFSET (event) = stop;
return event;
}
/**
* gst_event_new_flush:
* @done: Indicates the end of the flush
*
* Allocate a new flush event.
*
* Returns: A new flush event.
*/
GstEvent *
gst_event_new_flush (gboolean done)
{
GstEvent *event;
event = gst_event_new (GST_EVENT_FLUSH);
GST_EVENT_FLUSH_DONE (event) = done;
return event;
return gst_event_new_custom (GST_EVENT_NAVIGATION, structure);
}

View file

@ -1,6 +1,7 @@
/* 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
*
@ -27,122 +28,110 @@
#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
#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)
/**
* 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 {
GST_EVENT_FLAG_NONE = 0,
/* indicates negative rates are supported */
GST_RATE_FLAG_NEGATIVE = (1 << 1)
} GstEventFlag;
typedef struct
{
GstEventType type;
GstEventFlag flags;
} GstEventMask;
/* seek events, extends GstEventFlag */
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;
@ -152,32 +141,7 @@ struct _GstEvent {
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];
@ -193,39 +157,54 @@ struct _GstEventClass {
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

View file

@ -94,7 +94,7 @@ gst_message_init (GTypeInstance * instance, gpointer g_class)
{
GstMessage *message = GST_MESSAGE (instance);
message->timestamp = GST_CLOCK_TIME_NONE;
GST_MESSAGE_TIMESTAMP (message) = GST_CLOCK_TIME_NONE;
}
static void
@ -106,6 +106,7 @@ gst_message_finalize (GstMessage * message)
if (GST_MESSAGE_SRC (message)) {
gst_object_unref (GST_MESSAGE_SRC (message));
GST_MESSAGE_SRC (message) = NULL;
}
if (message->lock) {
@ -132,10 +133,10 @@ _gst_message_copy (GstMessage * message)
/* 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));
@ -150,16 +151,6 @@ _gst_message_copy (GstMessage * 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)
{
@ -386,7 +377,7 @@ gst_message_new_segment_done (GstObject * src, GstClockTime timestamp)
*
* 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.
*
@ -398,12 +389,12 @@ gst_message_new_custom (GstMessageType type, GstObject * src,
{
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;
}

View file

@ -3255,24 +3255,29 @@ gst_pad_send_event (GstPad * pad, GstEvent * event)
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",
@ -3303,6 +3308,14 @@ gst_pad_send_event (GstPad * pad, GstEvent * event)
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.",

View file

@ -491,32 +491,38 @@ gst_queue_handle_sink_event (GstPad * pad, GstEvent * event)
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:
@ -775,7 +781,7 @@ restart:
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);

View file

@ -804,48 +804,6 @@ gst_tag_list_foreach (GstTagList * list, GstTagForeachFunc func,
&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

View file

@ -24,7 +24,6 @@
#define __GST_TAG_H__
#include <gst/gststructure.h>
#include <gst/gstevent.h>
G_BEGIN_DECLS
@ -220,11 +219,6 @@ gboolean gst_tag_list_get_pointer_index (const GstTagList * list,
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:

View file

@ -804,48 +804,6 @@ gst_tag_list_foreach (GstTagList * list, GstTagForeachFunc func,
&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

View file

@ -24,7 +24,6 @@
#define __GST_TAG_H__
#include <gst/gststructure.h>
#include <gst/gstevent.h>
G_BEGIN_DECLS
@ -220,11 +219,6 @@ gboolean gst_tag_list_get_pointer_index (const GstTagList * list,
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:

View file

@ -468,11 +468,17 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
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;
@ -483,6 +489,7 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
GST_TIME_ARGS (basesink->discont_start),
GST_TIME_ARGS (basesink->discont_stop));
break;
}
default:
break;
}
@ -664,7 +671,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
GST_STREAM_UNLOCK (pad);
break;
}
case GST_EVENT_DISCONTINUOUS:
case GST_EVENT_NEWSEGMENT:
{
GstFlowReturn ret;
@ -674,39 +681,44 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
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;

View file

@ -362,9 +362,9 @@ gst_base_src_send_discont (GstBaseSrc * src)
{
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);
}
@ -372,10 +372,14 @@ gst_base_src_send_discont (GstBaseSrc * src)
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)
@ -385,11 +389,10 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
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);
@ -397,35 +400,35 @@ gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
/* 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;
@ -471,25 +474,11 @@ gst_base_src_event_handler (GstPad * pad, GstEvent * event)
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;
@ -695,7 +684,7 @@ eos:
{
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:
@ -707,7 +696,7 @@ 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;
}
@ -717,7 +706,7 @@ error:
("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;
}
}

View file

@ -497,11 +497,11 @@ gst_base_transform_event (GstPad * pad, GstEvent * event)
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);

View file

@ -321,8 +321,9 @@ gst_dp_packet_from_event (const GstEvent * event, GstDPHeaderFlag flags,
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;
@ -330,17 +331,17 @@ gst_dp_packet_from_event (const GstEvent * event, GstDPHeaderFlag flags,
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));
@ -472,29 +473,30 @@ gst_dp_event_from_packet (guint header_length, const guint8 * header,
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;
/*
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;
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));

View file

@ -273,13 +273,20 @@ static gboolean
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");
}

View file

@ -291,48 +291,23 @@ gst_file_sink_event (GstBaseSink * sink, GstEvent * event)
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),

View file

@ -491,32 +491,38 @@ gst_queue_handle_sink_event (GstPad * pad, GstEvent * event)
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:
@ -775,7 +781,7 @@ restart:
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);