_("detected tags are different than expected ones"), NULL);
REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_FRAMES_INCORRECT,
_("resulting file frames are not as expected"), NULL);
+ REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_SEGMENT_INCORRECT,
+ _("resulting segment is not as expected"), NULL);
REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_INFO,
_("the discoverer could not determine the stream info"), NULL);
REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_ID,
#define FILE_SEEKABLE_INCORRECT _QUARK("file-checking::seekable-incorrect")
#define FILE_PROFILE_INCORRECT _QUARK("file-checking::profile-incorrect")
#define FILE_FRAMES_INCORRECT _QUARK("file-checking::frames-incorrect")
+#define FILE_SEGMENT_INCORRECT _QUARK("file-checking::segment-incorrect")
#define ALLOCATION_FAILURE _QUARK("runtime::allocation-failure")
#define MISSING_PLUGIN _QUARK("runtime::missing-plugin")
return streamnode;
}
+static GstValidateSegmentNode *
+deserialize_segmentnode (const gchar ** names, const gchar ** values)
+{
+ gint i;
+ GstValidateSegmentNode *node = g_slice_new0 (GstValidateSegmentNode);
+
+ for (i = 0; names[i] != NULL; i++) {
+ if (!g_strcmp0 (names[i], "next-frame-id"))
+ node->next_frame_id = g_ascii_strtoull (values[i], NULL, 0);
+ else if (!g_strcmp0 (names[i], "flags"))
+ node->segment.flags = g_ascii_strtoull (values[i], NULL, 0);
+ else if (!g_strcmp0 (names[i], "rate"))
+ node->segment.rate = g_ascii_strtod (values[i], NULL);
+ else if (!g_strcmp0 (names[i], "applied-rate"))
+ node->segment.applied_rate = g_ascii_strtod (values[i], NULL);
+ else if (!g_strcmp0 (names[i], "format"))
+ node->segment.format = g_ascii_strtoull (values[i], NULL, 0);
+ else if (!g_strcmp0 (names[i], "base"))
+ node->segment.base = g_ascii_strtoull (values[i], NULL, 0);
+ else if (!g_strcmp0 (names[i], "offset"))
+ node->segment.offset = g_ascii_strtoull (values[i], NULL, 0);
+ else if (!g_strcmp0 (names[i], "start"))
+ node->segment.start = g_ascii_strtoull (values[i], NULL, 0);
+ else if (!g_strcmp0 (names[i], "stop"))
+ node->segment.stop = g_ascii_strtoull (values[i], NULL, 0);
+ else if (!g_strcmp0 (names[i], "time"))
+ node->segment.time = g_ascii_strtoull (values[i], NULL, 0);
+ else if (!g_strcmp0 (names[i], "position"))
+ node->segment.position = g_ascii_strtoull (values[i], NULL, 0);
+ else if (!g_strcmp0 (names[i], "duration"))
+ node->segment.duration = g_ascii_strtoull (values[i], NULL, 0);
+ }
+
+
+ return node;
+}
+
static GstValidateMediaTagsNode *
deserialize_tagsnode (const gchar ** names, const gchar ** values)
{
* node = deserialize_streamnode (attribute_names, attribute_values);
priv->in_stream = TRUE;
filenode->streams = g_list_prepend (filenode->streams, node);
+ } else if (g_strcmp0 (element_name, "segment") == 0) {
+ GstValidateMediaStreamNode *streamnode = filenode->streams->data;
+ GstValidateSegmentNode *node =
+ deserialize_segmentnode (attribute_names, attribute_values);
+
+ streamnode->segments = g_list_append (streamnode->segments, node);
+
} else if (g_strcmp0 (element_name, "frame") == 0) {
GstValidateMediaStreamNode *streamnode = filenode->streams->data;
GstValidateMediaStreamNode
* snode = ((GstValidateMediaStreamNode *) tmp->data);
+
STR_APPEND2 (snode->str_open);
+ /* Segment are always prepended, let's bring them back to the right order */
+ STR_APPEND3 ("<segments>");
+ for (tmp2 = snode->segments; tmp2; tmp2 = tmp2->next)
+ STR_APPEND4 (((GstValidateSegmentNode *) tmp2->data)->str_open);
+ STR_APPEND3 ("</segments>");
+
for (tmp2 = snode->frames; tmp2; tmp2 = tmp2->next) {
STR_APPEND3 (((GstValidateMediaFrameNode *) tmp2->data)->str_open);
}
(GstValidateMediaDescriptor *)
writer, pad);
if (streamnode) {
+ GstValidateSegmentNode *segment_node =
+ g_slice_new0 (GstValidateSegmentNode);
+
gst_event_parse_segment (event, &segment);
- gst_segment_copy_into (segment, &streamnode->segment);
+ gst_segment_copy_into (segment, &segment_node->segment);
+ segment_node->next_frame_id = g_list_length (streamnode->frames);
+
+ segment_node->str_open =
+ g_markup_printf_escaped ("<segment next-frame-id=\"%d\""
+ " flags=\"%d\" rate=\"%f\" applied-rate=\"%f\""
+ " format=\"%d\" base=\"%" G_GUINT64_FORMAT "\" offset=\"%"
+ G_GUINT64_FORMAT "\" start=\"%" G_GUINT64_FORMAT "\""
+ " stop=\"%" G_GUINT64_FORMAT "\" time=\"%" G_GUINT64_FORMAT
+ "\" position=\"%" G_GUINT64_FORMAT "\" duration=\"%"
+ G_GUINT64_FORMAT "\"/>", segment_node->next_frame_id,
+ segment->flags, segment->rate, segment->applied_rate,
+ segment->format, segment->base, segment->offset, segment->start,
+ segment->stop, segment->time, segment->position,
+ segment->duration);
+
+ streamnode->segments =
+ g_list_prepend (streamnode->segments, segment_node);
}
break;
}
GstValidateRunner * runner, const gchar * uri)
{
GstBus *bus;
+ GList *tmp;
GstStateChangeReturn sret;
GstValidateMonitor *monitor;
+ GstValidateMediaFileNode *filenode;
GstElement *uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
}
g_main_loop_run (writer->priv->loop);
+
+ filenode = ((GstValidateMediaDescriptor *) writer)->filenode;
+ /* Segment are always prepended, let's reorder them. */
+ for (tmp = filenode->streams; tmp; tmp = tmp->next) {
+ GstValidateMediaStreamNode
+ * snode = ((GstValidateMediaStreamNode *) tmp->data);
+ snode->segments = g_list_reverse (snode->segments);
+ }
+
gst_element_set_state (writer->priv->pipeline, GST_STATE_NULL);
gst_object_unref (writer->priv->pipeline);
writer->priv->pipeline = NULL;
gchar *checksum;
guint id;
GstValidateMediaFrameNode *fnode;
+ GstSegment * segment;
g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer),
FALSE);
fnode->duration = GST_BUFFER_DURATION (buf);
fnode->pts = GST_BUFFER_PTS (buf);
fnode->dts = GST_BUFFER_DTS (buf);
+
+ g_assert (streamnode->segments);
+ segment = &((GstValidateSegmentNode *)streamnode->segments->data)->segment;
fnode->running_time =
- gst_segment_to_running_time (&streamnode->segment, GST_FORMAT_TIME,
+ gst_segment_to_running_time (segment, GST_FORMAT_TIME,
GST_BUFFER_PTS (buf));
fnode->is_keyframe =
(GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) == FALSE);
}
static inline void
+free_segmentnode (GstValidateSegmentNode * segmentnode)
+{
+ g_free (segmentnode->str_open);
+ g_free (segmentnode->str_close);
+
+ g_slice_free (GstValidateSegmentNode, segmentnode);
+}
+
+static inline void
free_streamnode (GstValidateMediaStreamNode * streamnode)
{
if (streamnode->caps)
gst_caps_unref (streamnode->caps);
g_list_free_full (streamnode->frames, (GDestroyNotify) free_framenode);
+ g_list_free_full (streamnode->segments, (GDestroyNotify) free_segmentnode);
if (streamnode->pad)
gst_object_unref (streamnode->pad);
}
static gboolean
+compare_segments (GstValidateMediaDescriptor * ref,
+ gint i,
+ GstValidateMediaStreamNode * rstream,
+ GstValidateSegmentNode * rsegment, GstValidateSegmentNode * csegment)
+{
+ if (rsegment->next_frame_id != csegment->next_frame_id) {
+ GST_VALIDATE_REPORT (ref, FILE_SEGMENT_INCORRECT,
+ "Segment %" GST_SEGMENT_FORMAT
+ " didn't come before the same frame ID, expected to come before %d, came before %d",
+ &rsegment->segment, rsegment->next_frame_id, csegment->next_frame_id);
+ return FALSE;
+ }
+#define CHECK_SEGMENT_FIELD(fieldname, format) \
+ if (rsegment->segment.fieldname != csegment->segment.fieldname) { \
+ GST_ERROR ("Expected: %" GST_SEGMENT_FORMAT " got: %" GST_SEGMENT_FORMAT, \
+ &rsegment->segment, &csegment->segment); \
+ GST_VALIDATE_REPORT (ref, FILE_SEGMENT_INCORRECT, \
+ "Stream %s segment %d has " #fieldname \
+ " mismatch, Expected " format " got: " format , \
+ rstream->id, i, rsegment->segment.fieldname, \
+ csegment->segment.fieldname); \
+ return FALSE; \
+ }
+
+ CHECK_SEGMENT_FIELD (flags, "%d");
+ CHECK_SEGMENT_FIELD (rate, "%f");
+ CHECK_SEGMENT_FIELD (applied_rate, "%f");
+ CHECK_SEGMENT_FIELD (base, "%" G_GUINT64_FORMAT);
+ CHECK_SEGMENT_FIELD (offset, "%" G_GUINT64_FORMAT);
+ CHECK_SEGMENT_FIELD (start, "%" G_GUINT64_FORMAT);
+ CHECK_SEGMENT_FIELD (stop, "%" G_GUINT64_FORMAT);
+ CHECK_SEGMENT_FIELD (time, "%" G_GUINT64_FORMAT);
+ CHECK_SEGMENT_FIELD (position, "%" G_GUINT64_FORMAT);
+ CHECK_SEGMENT_FIELD (duration, "%" G_GUINT64_FORMAT);
+
+ return TRUE;
+}
+
+static void
+append_segment_diff (GString * diff, char diffsign, GList * segments)
+{
+ GList *tmp;
+
+ for (tmp = segments; tmp; tmp = tmp->next) {
+ gchar *ssegment =
+ gst_info_strdup_printf ("%c %" GST_SEGMENT_FORMAT "\n", diffsign,
+ &((GstValidateSegmentNode *) tmp->data)->segment);
+ g_string_append (diff, ssegment);
+ g_free (ssegment);
+
+ }
+}
+
+static gboolean
+compare_segment_list (GstValidateMediaDescriptor * ref,
+ GstValidateMediaStreamNode * rstream, GstValidateMediaStreamNode * cstream)
+{
+ gint i;
+ GList *rsegments, *csegments;
+
+ /* Keep compatibility with media stream files that do not have segments */
+ if (rstream->segments
+ && g_list_length (rstream->segments) !=
+ g_list_length (cstream->segments)) {
+ GString *diff = g_string_new (NULL);
+
+ append_segment_diff (diff, '-', rstream->segments);
+ append_segment_diff (diff, '+', cstream->segments);
+ GST_VALIDATE_REPORT (ref, FILE_SEGMENT_INCORRECT,
+ "Stream reference has %i segments, compared one has %i segments\n%s",
+ g_list_length (rstream->segments), g_list_length (cstream->segments),
+ diff->str);
+ g_string_free (diff, TRUE);
+ }
+
+ for (i = 0, rsegments = rstream->segments, csegments = cstream->segments;
+ rsegments;
+ rsegments = rsegments->next, csegments = csegments->next, i++) {
+ GstValidateSegmentNode *rsegment, *csegment;
+
+ if (csegment == NULL) {
+ /* The list was checked to be of the same size */
+ g_assert_not_reached ();
+ return FALSE;
+ }
+
+ rsegment = rsegments->data;
+ csegment = csegments->data;
+
+ if (!compare_segments (ref, i, rstream, rsegment, csegment))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
compare_frames (GstValidateMediaDescriptor * ref,
GstValidateMediaStreamNode *
rstream, GstValidateMediaFrameNode * rframe,
/* We ignore the return value on purpose as this is not critical */
compare_tags (ref, rstream, cstream);
+ compare_segment_list (ref, rstream, cstream);
+
if (compare_frames_list (ref, rstream, cstream))
return 1;
return 0;
/* Attributes */
GstCaps *caps;
- GstSegment segment;
+ GList * segments;
gchar *id;
gchar *padname;
gchar *str_close;
} GstValidateMediaFrameNode;
+typedef struct
+{
+ gint next_frame_id;
+
+ GstSegment segment;
+
+ gchar *str_open;
+ gchar *str_close;
+} GstValidateSegmentNode;
+
GST_VALIDATE_API
void gst_validate_filenode_free (GstValidateMediaFileNode *
filenode);