mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-28 03:45:39 +00:00
validate: media-check: Also check that segments are correct
This commit is contained in:
parent
7e2200d889
commit
3f668f3e80
6 changed files with 211 additions and 3 deletions
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 ("<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);
|
||||
}
|
||||
|
@ -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 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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue