From 0dbfa44839c0623ea4f2644b184551026cae01a0 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Sat, 14 Jul 2018 15:55:34 -0400 Subject: [PATCH] validate:scenario: Add an action type to validate last sample checksum --- validate/gst/validate/gst-validate-pad-monitor.c | 5 +- validate/gst/validate/gst-validate-scenario.c | 206 +++++++++++++++++++++++ 2 files changed, 208 insertions(+), 3 deletions(-) diff --git a/validate/gst/validate/gst-validate-pad-monitor.c b/validate/gst/validate/gst-validate-pad-monitor.c index 1e29fa5..3dbcb97 100644 --- a/validate/gst/validate/gst-validate-pad-monitor.c +++ b/validate/gst/validate/gst-validate-pad-monitor.c @@ -1761,11 +1761,10 @@ _should_check_buffers (GstValidatePadMonitor * pad_monitor, GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking"); pad_monitor->check_buffers = FALSE; - } else - if (!gst_validate_media_descriptor_detects_frames + } else if (!gst_validate_media_descriptor_detects_frames (monitor->media_descriptor)) { GST_DEBUG_OBJECT (pad, - "No frame detection media descriptor => not buffer checking"); + "No frame detection media descriptor => no buffer checking"); pad_monitor->check_buffers = FALSE; } else if (pad_monitor->all_bufs == NULL && !gst_validate_media_descriptor_get_buffers (monitor->media_descriptor, diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 41ea07f..e6bdd5e 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -2,6 +2,7 @@ * * Copyright (C) 2013 Collabora Ltd. * Author: Thibault Saunier + * Copyright (C) 2018 Thibault Saunier * * gst-validate-scenario.c - Validate Scenario class * @@ -3592,6 +3593,172 @@ done: return res; } +static GstValidateExecuteActionReturn +_check_last_sample_checksum (GstValidateScenario * scenario, + GstValidateAction * action, GstElement * sink) +{ + GstSample *sample; + gchar *sum; + GstMapInfo map; + GstBuffer *buffer; + const gchar *target_sum; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + + target_sum = gst_validate_action_get_string (action, "checksum"); + g_object_get (sink, "last-sample", &sample, NULL); + if (sample == NULL) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not \"check-last-sample\" as %" GST_PTR_FORMAT + " 'last-sample' property is NULL" + ". MAKE SURE THE 'enable-last-sample' PROPERTY IS SET TO 'TRUE'!", + sink); + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + goto done; + } + + buffer = gst_sample_get_buffer (sample); + if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Last sample buffer could not be mapped, action can't run."); + goto done; + } + + sum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, map.data, map.size); + gst_buffer_unmap (buffer, &map); + + if (g_strcmp0 (sum, target_sum)) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Last buffer checksum '%s' is different than the expected one: '%s'", + sum, target_sum); + + res = GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + g_free (sum); + +done: + return res; +} + +static gboolean +_sink_matches_last_sample_specs (GstElement * sink, const gchar * name, + const gchar * fname, GstCaps * sinkpad_caps) +{ + GstCaps *tmpcaps; + GstPad *sinkpad; + GObjectClass *klass = G_OBJECT_GET_CLASS (sink); + GParamSpec *paramspec = g_object_class_find_property (klass, "last-sample"); + + if (!paramspec) + return FALSE; + + if (paramspec->value_type != GST_TYPE_SAMPLE) + return FALSE; + + if (!name && !fname && !sinkpad_caps) + return TRUE; + + if (name && !g_strcmp0 (GST_OBJECT_NAME (sink), name)) + return TRUE; + + if (fname + && !g_strcmp0 (GST_OBJECT_NAME (gst_element_get_factory (sink)), fname)) + return TRUE; + + if (!sinkpad_caps) + return FALSE; + + sinkpad = gst_element_get_static_pad (sink, "sink"); + if (!sinkpad) + return FALSE; + + tmpcaps = gst_pad_get_current_caps (sinkpad); + if (tmpcaps) { + gboolean res = gst_caps_can_intersect (tmpcaps, sinkpad_caps); + + GST_DEBUG_OBJECT (sink, "Matches caps: %" GST_PTR_FORMAT, tmpcaps); + gst_caps_unref (tmpcaps); + + return res; + } else { + GST_INFO_OBJECT (sink, "No caps set yet, can't check it."); + } + + return FALSE; +} + +static GstValidateExecuteActionReturn +_execute_check_last_sample (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstIterator *it; + GValue data = { 0, }; + gboolean done = FALSE; + GstCaps *caps = NULL; + GstElement *sink = NULL, *tmpelement; + const gchar *name = gst_structure_get_string (action->structure, "sink-name"), + *factory_name = + gst_structure_get_string (action->structure, "sink-factory-name"), + *caps_str = gst_structure_get_string (action->structure, "sinkpad-caps"); + DECLARE_AND_GET_PIPELINE (scenario, action); + + if (caps_str) { + caps = gst_caps_from_string (caps_str); + + g_assert (caps); + } + + it = gst_bin_iterate_recurse (GST_BIN (pipeline)); + while (!done) { + switch (gst_iterator_next (it, &data)) { + case GST_ITERATOR_OK: + tmpelement = g_value_get_object (&data); + if (_sink_matches_last_sample_specs (tmpelement, name, factory_name, + caps)) { + if (sink) { + + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not \"check-last-sample\" as several elements were found " + "from describing string: '%" GST_PTR_FORMAT + "' (%s and %s match)", action->structure, + GST_OBJECT_NAME (sink), GST_OBJECT_NAME (tmpelement)); + + gst_object_unref (sink); + } + + sink = gst_object_ref (tmpelement); + } + g_value_reset (&data); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (it); + g_clear_object (&sink); + break; + case GST_ITERATOR_ERROR: + /* Fallthrough */ + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (it); + if (caps) + gst_caps_unref (caps); + + if (!sink) { + GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR, + "Could not \"check-last-sample\" as no sink was found from description: '%" + GST_PTR_FORMAT "'", action->structure); + + goto error; + } + + return _check_last_sample_checksum (scenario, action, sink); + +error: + g_clear_object (&sink); + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; +} + static gboolean _action_set_done (GstValidateAction * action) { @@ -3622,6 +3789,7 @@ _action_set_done (GstValidateAction * action) ")\n", action->type, GST_TIME_ARGS (execution_duration)); action->priv->execution_time = GST_CLOCK_TIME_NONE; action->priv->state = _execute_sub_action_action (action); + if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) { GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC"); @@ -4352,6 +4520,44 @@ init_scenarios (void) }), "Disables a GstPlugin", GST_VALIDATE_ACTION_TYPE_NONE); + + REGISTER_ACTION_TYPE ("check-last-sample", _execute_check_last_sample, + ((GstValidateActionParameter []) { + { + .name = "sink-name", + .description = "The name of the sink element to check sample on.", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "sink-factory-name", + .description = "The name of the factory of the sink element to check sample on.", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "sinkpad-caps", + .description = "The caps (as string) of the sink to check.", + .mandatory = FALSE, + .types = "string", + NULL + }, + { + .name = "checksum", + .description = "The reference checksum of the buffer.", + .mandatory = TRUE, + .types = "string", + NULL + }, + {NULL} + }), + "Checks the last-sample checksum on declared Sink element." + " This allows checking the checksum of a buffer after a 'seek' or after a GESTimeline 'commit'" + " for example", + GST_VALIDATE_ACTION_TYPE_INTERLACED); + /* *INDENT-ON* */ for (tmp = gst_validate_plugin_get_config (NULL); tmp; tmp = tmp->next) { -- 2.7.4