diff --git a/validate/gst/validate/gst-validate-report.c b/validate/gst/validate/gst-validate-report.c index e67d5c522f..72f7749c05 100644 --- a/validate/gst/validate/gst-validate-report.c +++ b/validate/gst/validate/gst-validate-report.c @@ -361,6 +361,8 @@ gst_validate_report_load_issues (void) _("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, diff --git a/validate/gst/validate/gst-validate-report.h b/validate/gst/validate/gst-validate-report.h index 09db59893e..4c43aae664 100644 --- a/validate/gst/validate/gst-validate-report.h +++ b/validate/gst/validate/gst-validate-report.h @@ -104,6 +104,7 @@ typedef enum { #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") diff --git a/validate/gst/validate/media-descriptor-parser.c b/validate/gst/validate/media-descriptor-parser.c index 29d7849c66..c9b208a5b7 100644 --- a/validate/gst/validate/media-descriptor-parser.c +++ b/validate/gst/validate/media-descriptor-parser.c @@ -95,6 +95,43 @@ deserialize_streamnode (const gchar ** names, const gchar ** values) 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) { @@ -199,6 +236,13 @@ on_start_element_cb (GMarkupParseContext * context, * 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; diff --git a/validate/gst/validate/media-descriptor-writer.c b/validate/gst/validate/media-descriptor-writer.c index f666f5a81a..4c93f314e8 100644 --- a/validate/gst/validate/media-descriptor-writer.c +++ b/validate/gst/validate/media-descriptor-writer.c @@ -146,8 +146,15 @@ serialize_filenode (GstValidateMediaDescriptorWriter * writer) 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 (""); + for (tmp2 = snode->segments; tmp2; tmp2 = tmp2->next) + STR_APPEND4 (((GstValidateSegmentNode *) tmp2->data)->str_open); + STR_APPEND3 (""); + for (tmp2 = snode->frames; tmp2; tmp2 = tmp2->next) { STR_APPEND3 (((GstValidateMediaFrameNode *) tmp2->data)->str_open); } @@ -317,8 +324,28 @@ _uridecodebin_probe (GstPad * pad, GstPadProbeInfo * info, (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_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; } @@ -519,8 +546,10 @@ _run_frame_analysis (GstValidateMediaDescriptorWriter * writer, GstValidateRunner * runner, const gchar * uri) { GstBus *bus; + GList *tmp; GstStateChangeReturn sret; GstValidateMonitor *monitor; + GstValidateMediaFileNode *filenode; GstElement *uridecodebin = gst_element_factory_make ("uridecodebin", NULL); @@ -551,6 +580,15 @@ _run_frame_analysis (GstValidateMediaDescriptorWriter * writer, } 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; @@ -846,6 +884,7 @@ gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter gchar *checksum; guint id; GstValidateMediaFrameNode *fnode; + GstSegment * segment; g_return_val_if_fail (GST_IS_VALIDATE_MEDIA_DESCRIPTOR_WRITER (writer), FALSE); @@ -877,8 +916,11 @@ gst_validate_media_descriptor_writer_add_frame (GstValidateMediaDescriptorWriter 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); diff --git a/validate/gst/validate/media-descriptor.c b/validate/gst/validate/media-descriptor.c index b4cf758899..831812a6be 100644 --- a/validate/gst/validate/media-descriptor.c +++ b/validate/gst/validate/media-descriptor.c @@ -62,6 +62,15 @@ free_framenode (GstValidateMediaFrameNode * framenode) g_slice_free (GstValidateMediaFrameNode, framenode); } +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) { @@ -69,6 +78,7 @@ free_streamnode (GstValidateMediaStreamNode * streamnode) 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); @@ -337,6 +347,103 @@ stream_id_is_equal (const gchar * uri, const gchar * rid, const gchar * cid) return FALSE; } +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 * @@ -445,6 +552,8 @@ compare_streams (GstValidateMediaDescriptor * ref, /* 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; diff --git a/validate/gst/validate/media-descriptor.h b/validate/gst/validate/media-descriptor.h index 3079cfab7f..25c7c9ad34 100644 --- a/validate/gst/validate/media-descriptor.h +++ b/validate/gst/validate/media-descriptor.h @@ -82,7 +82,7 @@ typedef struct /* Attributes */ GstCaps *caps; - GstSegment segment; + GList * segments; gchar *id; gchar *padname; @@ -112,6 +112,16 @@ typedef struct 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);