/** * gst_event_set_seqnum: * @event: A #GstEvent. * @seqnum: A sequence number. * * Set the sequence number of a event. * * This function might be called by the creator of a event to indicate that the * event relates to other events or messages. See gst_event_get_seqnum() for * more information. * * MT safe. */ void gst_event_set_seqnum (GstEvent * event, guint32 seqnum) { g_return_if_fail (GST_IS_EVENT (event)); GST_EVENT_SEQNUM (event) = seqnum; }
/** * gst_event_get_seqnum: * @event: A #GstEvent. * * Retrieve the sequence number of a event. * * Events have ever-incrementing sequence numbers, which may also be set * explicitly via gst_event_set_seqnum(). Sequence numbers are typically used to * indicate that a event corresponds to some other set of events or messages, * for example an EOS event corresponding to a SEEK event. It is considered good * practice to make this correspondence when possible, though it is not * required. * * Note that events and messages share the same sequence number incrementor; * two events or messages will never have the same sequence number unless * that correspondence was made explicitly. * * Returns: The event's sequence number. * * MT safe. */ guint32 gst_event_get_seqnum (GstEvent * event) { g_return_val_if_fail (GST_IS_EVENT (event), -1); return GST_EVENT_SEQNUM (event); }
static void gst_event_init (GstEventImpl * event, GstEventType type) { gst_mini_object_init (GST_MINI_OBJECT_CAST (event), 0, _gst_event_type, (GstMiniObjectCopyFunction) _gst_event_copy, NULL, (GstMiniObjectFreeFunction) _gst_event_free); GST_EVENT_TYPE (event) = type; GST_EVENT_TIMESTAMP (event) = GST_CLOCK_TIME_NONE; GST_EVENT_SEQNUM (event) = gst_util_seqnum_next (); }
static GstEvent * _gst_event_copy (GstEvent * event) { GstEvent *copy; copy = (GstEvent *) gst_mini_object_new (GST_TYPE_EVENT); GST_EVENT_TYPE (copy) = GST_EVENT_TYPE (event); GST_EVENT_TIMESTAMP (copy) = GST_EVENT_TIMESTAMP (event); GST_EVENT_SEQNUM (copy) = GST_EVENT_SEQNUM (event); 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, ©->mini_object.refcount); } return copy; }
static GstPadProbeReturn sinkpad_event_probe (GstPad * sinkpad, GstEvent * event, CollectStructure * collect) { Segment *segment; GST_DEBUG_OBJECT (sinkpad, "event:%p (%s seqnum:%d) , collect:%p", event, GST_EVENT_TYPE_NAME (event), GST_EVENT_SEQNUM (event), collect); if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { fail_if (collect->expected_segments == NULL, "Received unexpected segment on pad: %s:%s", GST_DEBUG_PAD_NAME (sinkpad)); if (!collect->gotsegment) collect->seen_segments = g_list_append (NULL, GINT_TO_POINTER (GST_EVENT_SEQNUM (event))); else { fail_if (g_list_find (collect->seen_segments, GINT_TO_POINTER (GST_EVENT_SEQNUM (event))), "Got a segment event we already saw before !"); collect->seen_segments = g_list_append (collect->seen_segments, GINT_TO_POINTER (GST_EVENT_SEQNUM (event))); } segment = (Segment *) collect->expected_segments->data; if (compare_segments (collect, segment, event) && collect->keep_expected_segments == FALSE) { collect->expected_segments = g_list_remove (collect->expected_segments, segment); g_free (segment); } collect->gotsegment = TRUE; } return GST_PAD_PROBE_OK; }
static GstEvent * _gst_event_copy (GstEvent * event) { GstEventImpl *copy; GstStructure *s; copy = g_slice_new0 (GstEventImpl); gst_event_init (copy, GST_EVENT_TYPE (event)); GST_EVENT_TIMESTAMP (copy) = GST_EVENT_TIMESTAMP (event); GST_EVENT_SEQNUM (copy) = GST_EVENT_SEQNUM (event); s = GST_EVENT_STRUCTURE (event); if (s) { GST_EVENT_STRUCTURE (copy) = gst_structure_copy (s); gst_structure_set_parent_refcount (GST_EVENT_STRUCTURE (copy), ©->event.mini_object.refcount); } else { GST_EVENT_STRUCTURE (copy) = NULL; } return GST_EVENT_CAST (copy); }
static GstEvent * gst_event_new (GstEventType type) { GstEvent *event; event = (GstEvent *) gst_mini_object_new (GST_TYPE_EVENT); GST_CAT_DEBUG (GST_CAT_EVENT, "creating new event %p %s %d", event, gst_event_type_get_name (type), type); event->type = type; event->src = NULL; event->structure = NULL; GST_EVENT_SEQNUM (event) = gst_util_seqnum_next (); return event; }
gboolean mpegts_base_handle_seek_event (MpegTSBase * base, GstPad * pad, GstEvent * event) { MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); GstFlowReturn ret = GST_FLOW_ERROR; gdouble rate; gboolean flush; GstFormat format; GstSeekFlags flags; GstSeekType start_type, stop_type; gint64 start, stop; GstEvent *flush_event = NULL; gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); if (format != GST_FORMAT_TIME) return FALSE; if (GST_EVENT_SEQNUM (event) == base->last_seek_seqnum) { GST_DEBUG_OBJECT (base, "Skipping already handled seek"); return TRUE; } if (base->mode == BASE_MODE_PUSHING) { /* First try if upstream supports seeking in TIME format */ if (gst_pad_push_event (base->sinkpad, gst_event_ref (event))) { GST_DEBUG ("upstream handled SEEK event"); return TRUE; } /* If the subclass can seek, do that */ if (klass->seek) { ret = klass->seek (base, event); if (G_UNLIKELY (ret != GST_FLOW_OK)) GST_WARNING ("seeking failed %s", gst_flow_get_name (ret)); else { GstEvent *new_seek; if (GST_CLOCK_TIME_IS_VALID (base->seek_offset)) { base->mode = BASE_MODE_SEEKING; new_seek = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, GST_SEEK_TYPE_SET, base->seek_offset, GST_SEEK_TYPE_NONE, -1); gst_event_set_seqnum (new_seek, GST_EVENT_SEQNUM (event)); if (!gst_pad_push_event (base->sinkpad, new_seek)) ret = GST_FLOW_ERROR; else base->last_seek_seqnum = GST_EVENT_SEQNUM (event); } base->mode = BASE_MODE_PUSHING; } } else { GST_WARNING ("subclass has no seek implementation"); } return ret == GST_FLOW_OK; } if (!klass->seek) { GST_WARNING ("subclass has no seek implementation"); return FALSE; } if (rate <= 0.0) { GST_WARNING ("Negative rate not supported"); return FALSE; } GST_DEBUG ("seek event, rate: %f start: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop)); flush = flags & GST_SEEK_FLAG_FLUSH; /* stop streaming, either by flushing or by pausing the task */ base->mode = BASE_MODE_SEEKING; if (flush) { GST_DEBUG_OBJECT (base, "sending flush start"); flush_event = gst_event_new_flush_start (); gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event)); gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event)); GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event); } else gst_pad_pause_task (base->sinkpad); /* wait for streaming to finish */ GST_PAD_STREAM_LOCK (base->sinkpad); if (flush) { /* send a FLUSH_STOP for the sinkpad, since we need data for seeking */ GST_DEBUG_OBJECT (base, "sending flush stop"); flush_event = gst_event_new_flush_stop (TRUE); gst_event_set_seqnum (flush_event, GST_EVENT_SEQNUM (event)); /* ref for it to be reused later */ gst_pad_push_event (base->sinkpad, gst_event_ref (flush_event)); /* And actually flush our pending data but allow to preserve some info * to perform the seek */ mpegts_base_flush (base, FALSE); mpegts_packetizer_flush (base->packetizer, FALSE); } if (flags & (GST_SEEK_FLAG_SEGMENT)) { GST_WARNING ("seek flags 0x%x are not supported", (int) flags); goto done; } /* If the subclass can seek, do that */ ret = klass->seek (base, event); if (G_UNLIKELY (ret != GST_FLOW_OK)) GST_WARNING ("seeking failed %s", gst_flow_get_name (ret)); else base->last_seek_seqnum = GST_EVENT_SEQNUM (event); if (flush_event) { /* if we sent a FLUSH_START, we now send a FLUSH_STOP */ GST_DEBUG_OBJECT (base, "sending flush stop"); GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, flush_event); flush_event = NULL; } done: if (flush_event) gst_event_unref (flush_event); gst_pad_start_task (base->sinkpad, (GstTaskFunction) mpegts_base_loop, base, NULL); GST_PAD_STREAM_UNLOCK (base->sinkpad); return ret == GST_FLOW_OK; }