GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
FALSE)
+#define PAD_PARENT_IS_SINK(m) \
+ (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
+ GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_SINK ( \
+ GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
+ FALSE)
+
/*
* Locking the parent should always be done before locking the
} \
} G_STMT_END
+/* Structure used to store all seek-related information */
+struct _GstValidatePadSeekData
+{
+ guint32 seqnum;
+ gdouble rate;
+ GstFormat format;
+ GstSeekFlags flags;
+ GstSeekType start_type, stop_type;
+ gint64 start, stop;
+};
+
typedef struct
{
GstClockTime timestamp;
}
static void
+seek_data_free (GstValidatePadSeekData * data)
+{
+ g_slice_free (GstValidatePadSeekData, data);
+}
+
+static GstValidatePadSeekData *
+seek_data_for_seqnum (GstValidatePadMonitor * monitor, guint32 seqnum)
+{
+ GList *tmp;
+
+ for (tmp = monitor->seeks; tmp; tmp = tmp->next) {
+ GstValidatePadSeekData *data = (GstValidatePadSeekData *) tmp->data;
+ if (data->seqnum == seqnum)
+ return data;
+ }
+
+ return NULL;
+}
+
+static void
gst_validate_pad_monitor_dispose (GObject * object)
{
GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object);
gst_caps_replace (&monitor->last_caps, NULL);
gst_caps_replace (&monitor->last_query_res, NULL);
gst_caps_replace (&monitor->last_query_filter, NULL);
+ gst_caps_replace (&monitor->last_refused_caps, NULL);
+
+ g_list_free_full (monitor->seeks, (GDestroyNotify) seek_data_free);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
- pad_monitor->last_flow_return = GST_FLOW_OK;
-
pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
}
pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
- pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
-
if (pad_monitor->pending_setcaps_fields)
gst_structure_free (pad_monitor->pending_setcaps_fields);
pad_monitor->pending_setcaps_fields =
gst_structure_new_empty (PENDING_FIELDS);
+ if (pad_monitor->seeks)
+ g_list_free_full (pad_monitor->seeks, (GDestroyNotify) seek_data_free);
+ pad_monitor->current_seek = NULL;
+ pad_monitor->seeks = NULL;
/* FIXME : Why BYTES and not UNDEFINED ? */
gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
GstPad *otherpad;
GstPad *peerpad;
GstState state, pending;
- GstValidatePadMonitor *othermonitor;
GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
gboolean found_a_pad = FALSE;
GstPad *pad =
otherpad = g_value_get_object (&value);
peerpad = gst_pad_get_peer (otherpad);
if (peerpad) {
- othermonitor = _GET_PAD_MONITOR (peerpad);
- if (othermonitor) {
- found_a_pad = TRUE;
- GST_VALIDATE_MONITOR_LOCK (othermonitor);
- aggregated =
- _combine_flows (aggregated, othermonitor->last_flow_return);
- GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
- }
+ found_a_pad = TRUE;
+ aggregated =
+ _combine_flows (aggregated,
+ gst_pad_get_last_flow_return (peerpad));
gst_object_unref (peerpad);
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_START:
{
- if (pad_monitor->pending_flush_start_seqnum != GST_SEQNUM_INVALID) {
- if (seqnum == pad_monitor->pending_flush_start_seqnum) {
- pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
- } else {
+ if (pad_monitor->seeks) {
+ GstValidatePadSeekData *seekdata =
+ seek_data_for_seqnum (pad_monitor, seqnum);
+
+ if (!seekdata)
GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM,
- "Got: %u Expected: %u", seqnum,
- pad_monitor->pending_flush_start_seqnum);
+ "Got: %" G_GUINT32_FORMAT " Expected: %" G_GUINT32_FORMAT, seqnum,
+ ((GstValidatePadSeekData *) pad_monitor->seeks->data)->seqnum);
+ else {
+ if (!(seekdata->flags & GST_SEEK_FLAG_FLUSH)) {
+ GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
+ "Received flush-start for a non-flushing seek");
+ }
}
}
"Received flush-start from when flush-stop was expected");
}
pad_monitor->pending_flush_stop = TRUE;
+ /* Remove the current segment seekdata */
+ if (pad_monitor->current_seek) {
+ pad_monitor->seeks =
+ g_list_remove (pad_monitor->seeks, pad_monitor->current_seek);
+ seek_data_free (pad_monitor->current_seek);
+ pad_monitor->current_seek = NULL;
+ }
}
break;
case GST_EVENT_FLUSH_STOP:
{
- if (pad_monitor->pending_flush_stop_seqnum != GST_SEQNUM_INVALID) {
- if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
- pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
- } else {
- GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM,
- "Got: %u Expected: %u", seqnum,
- pad_monitor->pending_flush_stop_seqnum);
- }
+ if (pad_monitor->seeks && !seek_data_for_seqnum (pad_monitor, seqnum)) {
+ GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM,
+ "Got: %" G_GUINT32_FORMAT " Expected: %" G_GUINT32_FORMAT, seqnum,
+ ((GstValidatePadSeekData *) pad_monitor->seeks->data)->seqnum);
}
pad_monitor->pending_newsegment_seqnum = seqnum;
pad_monitor->current_buf = tmp;
}
+static void
+post_segment_message (GstValidatePadMonitor * pad_monitor, GstPad * pad,
+ const GstSegment * segment, guint32 seqnum)
+{
+ GstValidateMonitor *element_monitor =
+ GST_VALIDATE_MONITOR_GET_PARENT (pad_monitor);
+ GstElement *element;
+ GstStructure *structure;
+ GstMessage *msg;
+
+ if (element_monitor == NULL)
+ return;
+
+ element = gst_validate_monitor_get_element (element_monitor);
+ if (element == NULL)
+ return;
+
+ GST_DEBUG_OBJECT (pad,
+ "Posting application message for seqnum:%" G_GUINT32_FORMAT " %"
+ GST_SEGMENT_FORMAT, seqnum, segment);
+
+ structure =
+ gst_structure_new ("validate-segment", "segment", GST_TYPE_SEGMENT,
+ segment, NULL);
+ msg = gst_message_new_application ((GstObject *) element, structure);
+ gst_message_set_seqnum (msg, seqnum);
+ gst_element_post_message (element, msg);
+
+ gst_object_unref (element);
+
+ return;
+}
+
/* Checks whether a segment is just an update of another,
* That is to say that only the base and offset field differ and all
* other fields are identical */
pad_monitor->pending_buffer_discont = TRUE;
break;
case GST_EVENT_SEGMENT:
+ {
+ GstValidatePadSeekData *seekdata =
+ seek_data_for_seqnum (pad_monitor, seqnum);
+
/* parse segment data to be used if event is handled */
gst_event_parse_segment (event, &segment);
- GST_DEBUG_OBJECT (pad, "Got segment %" GST_SEGMENT_FORMAT, segment);
-
- /* Reset expected flush start/stop values, we have a segment */
- pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
- pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
+ GST_DEBUG_OBJECT (pad,
+ "Got segment seqnum:%" G_GUINT32_FORMAT " %" GST_SEGMENT_FORMAT,
+ seqnum, segment);
if (pad_monitor->pending_newsegment_seqnum != GST_SEQNUM_INVALID) {
- if (pad_monitor->pending_newsegment_seqnum == seqnum) {
- pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
- if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) {
- if (segment->time == pad_monitor->pending_seek_accurate_time) {
- pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
- } else {
- GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START,
- "After an accurate seek, got: %" GST_TIME_FORMAT
- " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time),
- GST_TIME_ARGS (pad_monitor->pending_seek_accurate_time));
- }
- }
- } else {
+ /* FIXME: Convert to more robust checks */
+ if (pad_monitor->pending_newsegment_seqnum != seqnum) {
GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM,
- "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
+ "Got: %u Expected: %u", seqnum,
+ pad_monitor->pending_newsegment_seqnum);
+ }
+ }
+
+ if (seekdata && seekdata != pad_monitor->current_seek) {
+ /* Check for accurate seeks */
+ if (seekdata->flags & GST_SEEK_FLAG_ACCURATE) {
+ if (segment->time != seekdata->start)
+ GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START,
+ "After an accurate seek, got: %" GST_TIME_FORMAT
+ " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time),
+ GST_TIME_ARGS (seekdata->start));
}
}
gst_event_replace (&pad_monitor->expected_segment, NULL);
}
}
+
+ /* Drop all expected seekdata from before this segment */
+ if (seekdata) {
+ while (pad_monitor->seeks && pad_monitor->seeks->data != seekdata) {
+ GstValidatePadSeekData *tmp =
+ (GstValidatePadSeekData *) pad_monitor->seeks->data;
+ pad_monitor->seeks =
+ g_list_delete_link (pad_monitor->seeks, pad_monitor->seeks);
+ seek_data_free (tmp);
+ }
+ }
+ pad_monitor->current_seek = seekdata;
+ }
break;
case GST_EVENT_CAPS:{
GstCaps *caps;
gst_segment_copy_into (segment, &pad_monitor->segment);
pad_monitor->has_segment = TRUE;
gst_validate_monitor_find_next_buffer (pad_monitor);
+ if (PAD_PARENT_IS_SINK (pad_monitor))
+ post_segment_message (pad_monitor, pad, segment, seqnum);
}
break;
case GST_EVENT_CAPS:{
return ret;
}
+static GstValidatePadSeekData *
+_store_seek_event_data (GstValidatePadMonitor * pad_monitor, GstEvent * event)
+{
+ GstValidatePadSeekData *data = g_slice_new0 (GstValidatePadSeekData);
+
+ data->seqnum = gst_event_get_seqnum (event);
+ gst_event_parse_seek (event, &data->rate, &data->format, &data->flags,
+ &data->start_type, &data->start, &data->stop_type, &data->stop);
+
+ pad_monitor->seeks = g_list_append (pad_monitor->seeks, data);
+
+ return data;
+}
+
static gboolean
gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
GstObject * parent, GstEvent * event, GstPadEventFunction handler)
{
gboolean ret = TRUE;
- gdouble rate;
- GstFormat format;
- gint64 start, stop;
- GstSeekFlags seek_flags;
- GstSeekType start_type, stop_type;
- guint32 seqnum = gst_event_get_seqnum (event);
GstPad *pad =
GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
(pad_monitor)));
gst_validate_pad_monitor_common_event_check (pad_monitor, event);
- /* pre checks */
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:
- {
- gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
- &start, &stop_type, &stop);
- /* upstream seek - store the seek event seqnum to check
- * flushes and newsegments share the same */
- }
- break;
- /* both flushes are handled by the common event handling function */
- case GST_EVENT_FLUSH_START:
- case GST_EVENT_FLUSH_STOP:
- case GST_EVENT_NAVIGATION:
- case GST_EVENT_LATENCY:
- case GST_EVENT_STEP:
- case GST_EVENT_QOS:
- default:
- break;
- }
-
if (handler) {
- GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
- /* Safely store pending accurate seek values */
- if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
- if (seek_flags & GST_SEEK_FLAG_ACCURATE && format == GST_FORMAT_TIME) {
- GST_DEBUG_OBJECT (pad,
- "Storing expected accurate seek time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (start));
- pad_monitor->pending_seek_accurate_time = start;
- }
- /* TODO we might need to use a list as multiple seeks can be sent
- * before the flushes arrive here */
- if (seek_flags & GST_SEEK_FLAG_FLUSH) {
- pad_monitor->pending_flush_start_seqnum = seqnum;
- pad_monitor->pending_flush_stop_seqnum = seqnum;
- }
- }
+ GstValidatePadSeekData *seekdata = NULL;
- gst_event_ref (event);
+ GST_DEBUG_OBJECT (pad, "event %" GST_PTR_FORMAT, event);
+
+ /* Safely store pending accurate seek values */
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK)
+ seekdata = _store_seek_event_data (pad_monitor, event);
+ GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
ret = pad_monitor->event_func (pad, parent, event);
- if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
- /* If the seek was already handled (same current seqnum), reset the
- * expected accurate seek value */
- if (ret && pad_monitor->has_segment
- && seqnum == pad_monitor->pending_eos_seqnum) {
- GST_DEBUG_OBJECT (pad,
- "Resetting expected accurate seek value, was already handled");
- pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
- } else if (!ret) {
- /* do not expect any of these events anymore */
- pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
- pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
- pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
- pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
- pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
- }
- }
GST_VALIDATE_MONITOR_LOCK (pad_monitor);
- }
- /* post checks */
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- case GST_EVENT_FLUSH_STOP:
- case GST_EVENT_QOS:
- case GST_EVENT_SEEK:
- case GST_EVENT_NAVIGATION:
- case GST_EVENT_LATENCY:
- case GST_EVENT_STEP:
- default:
- break;
+ if (seekdata && !ret) {
+ /* Remove failed seek from list */
+ GST_LOG_OBJECT (pad, "Failed seek, removing stored seek data");
+ pad_monitor->seeks = g_list_remove (pad_monitor->seeks, seekdata);
+ g_slice_free (GstValidatePadSeekData, seekdata);
+ }
}
- if (handler)
- gst_event_unref (event);
gst_object_unref (pad);
return ret;
}
GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
GST_VALIDATE_MONITOR_LOCK (pad_monitor);
- pad_monitor->last_flow_return = ret;
if (ret == GST_FLOW_EOS) {
mark_pads_eos (pad_monitor);
}
if (peer) {
GST_OBJECT_LOCK (peer);
task = GST_PAD_TASK (peer);
- if (task) {
+ if (task && GST_TASK_STATE (task) == GST_TASK_STARTED) {
GST_OBJECT_LOCK (task);
/* Only doing pointer comparison, no need to hold a ref */
thread = task->thread;
gpointer udata)
{
GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
+ guint32 seqnum = gst_event_get_seqnum (event);
GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
GST_VALIDATE_MONITOR_LOCK (monitor);
- GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
+ GST_DEBUG_OBJECT (pad, "event %p %s seqnum:%" G_GUINT32_FORMAT, event,
+ GST_EVENT_TYPE_NAME (event), seqnum);
if (GST_EVENT_IS_SERIALIZED (event)) {
gint i;