validate: Print actions directly from the scenario

Avoiding user to have to print them in each and every action type
implementation.

This requires adding some API to prepare actions before printing them.
Preparing action in that case mean parsing the values contained in the
GstStructure parsing equations and setting back the actual value
afterward

API:
  * GstValidatePrepateAction
  * gst_validate_action_type_set_prepare_function
This commit is contained in:
Thibault Saunier 2015-02-17 14:56:47 +01:00
parent 8b6c521bb1
commit 08afce235c
3 changed files with 115 additions and 36 deletions

View file

@ -506,6 +506,27 @@ gst_validate_printf (gpointer source, const gchar * format, ...)
va_end (var_args);
}
static gboolean
_append_value (GQuark field_id, const GValue * value, GString * string)
{
gchar *val_str = NULL;
if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME)
val_str = g_strdup_printf ("%" GST_TIME_FORMAT,
GST_TIME_ARGS (g_value_get_uint64 (value)));
else
val_str = gst_value_serialize (value);
g_string_append (string, g_quark_to_string (field_id));
g_string_append_len (string, "=", 1);
g_string_append (string, val_str);
g_string_append_len (string, " ", 1);
g_free (val_str);
return TRUE;
}
/**
* gst_validate_print_action:
* @action: (allow-none): The source object to log
@ -516,7 +537,22 @@ gst_validate_printf (gpointer source, const gchar * format, ...)
void
gst_validate_print_action (GstValidateAction * action, const gchar * message)
{
GString *string = NULL;
if (message == NULL) {
GString *string = g_string_new (gst_structure_get_name (action->structure));
g_string_append_len (string, ": ", 2);
gst_structure_foreach (action->structure,
(GstStructureForeachFunc) _append_value, string);
g_string_append_len (string, "\n", 1);
message = string->str;
}
gst_validate_printf (action, "%s", message);
if (string)
g_string_free (string, TRUE);
}
static void
@ -589,11 +625,11 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args)
if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) {
GstValidateAction *action = (GstValidateAction *) source;
g_string_printf (string,
"\n(Executing action: %s, number: %u at position: %" GST_TIME_FORMAT
" repeat: %i) | ", g_strcmp0 (action->name,
"") == 0 ? "Unnamed" : action->name, action->action_number,
GST_TIME_ARGS (action->playback_time), action->repeat);
if (action->printed)
return;
action->printed = TRUE;
g_string_printf (string, "Executing ");
} else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) {
gint i;

View file

@ -368,13 +368,24 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario,
{
gdouble val;
const gchar *strval;
const GValue *gvalue = gst_structure_get_value (action->structure, name);
if (gvalue == NULL) {
return -1;
}
if (G_VALUE_TYPE (gvalue) == GST_TYPE_CLOCK_TIME) {
*retval = g_value_get_uint64 (gvalue);
return TRUE;
}
if (!gst_structure_get_double (action->structure, name, &val)) {
gchar *error = NULL;
if (!(strval = gst_structure_get_string (action->structure, name))) {
GST_INFO_OBJECT (scenario, "Could not find %s", name);
return FALSE;
return -1;
}
val =
gst_validate_utils_parse_expression (strval, _set_variable_func,
@ -482,10 +493,6 @@ _execute_seek (GstValidateScenario * scenario, GstValidateAction * action)
gst_validate_action_get_clocktime (scenario, action, "stop", &stop);
gst_validate_printf (action, "seeking to: %" GST_TIME_FORMAT
" stop: %" GST_TIME_FORMAT " Rate %lf\n",
GST_TIME_ARGS (start), GST_TIME_ARGS (stop), rate);
return gst_validate_scenario_execute_seek (scenario, action, rate, format,
flags, start_type, start, stop_type, stop);
}
@ -525,8 +532,6 @@ _execute_set_state (GstValidateScenario * scenario, GstValidateAction * action)
scenario->priv->changing_state = TRUE;
scenario->priv->seeked_in_pause = FALSE;
gst_validate_printf (action, "Setting state to %s\n", str_state);
ret = gst_element_set_state (scenario->pipeline, state);
if (ret == GST_STATE_CHANGE_FAILURE) {
@ -553,9 +558,6 @@ _execute_pause (GstValidateScenario * scenario, GstValidateAction * action)
GstStateChangeReturn ret;
gst_structure_get_double (action->structure, "duration", &duration);
gst_validate_printf (action, "pausing for %" GST_TIME_FORMAT "\n",
GST_TIME_ARGS (duration * GST_SECOND));
gst_structure_set (action->structure, "state", G_TYPE_STRING, "paused", NULL);
GST_DEBUG ("Pausing for %" GST_TIME_FORMAT,
@ -606,8 +608,6 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action)
{
GstBus *bus = gst_element_get_bus (scenario->pipeline);
gst_validate_printf (action, "Stoping pipeline\n");
gst_bus_post (bus,
gst_message_new_request_state (GST_OBJECT_CAST (scenario),
GST_STATE_NULL));
@ -618,9 +618,6 @@ _execute_stop (GstValidateScenario * scenario, GstValidateAction * action)
static gboolean
_execute_eos (GstValidateScenario * scenario, GstValidateAction * action)
{
gst_validate_printf (action, "sending EOS at %" GST_TIME_FORMAT "\n",
GST_TIME_ARGS (action->playback_time));
GST_DEBUG ("Sending eos to pipeline at %" GST_TIME_FORMAT,
GST_TIME_ARGS (action->playback_time));
@ -808,10 +805,6 @@ _execute_switch_track (GstValidateScenario * scenario,
pad = find_nth_sink_pad (input_selector, index);
g_object_get (input_selector, "active-pad", &cpad, NULL);
gst_validate_printf (action, "Switching to track number: %i,"
" (from %s:%s to %s:%s)\n",
index, GST_DEBUG_PAD_NAME (cpad), GST_DEBUG_PAD_NAME (pad));
if (gst_element_get_state (scenario->pipeline, &state, &next, 0) &&
state == GST_STATE_PLAYING && next == GST_STATE_VOID_PENDING) {
srcpad = gst_element_get_static_pad (input_selector, "src");
@ -972,6 +965,17 @@ gst_validate_execute_action (GstValidateActionType * action_type,
g_return_val_if_fail (g_strcmp0 (action_type->name, action->type) == 0,
GST_VALIDATE_EXECUTE_ACTION_ERROR);
if (action_type->prepare) {
if (action_type->prepare (action) == FALSE) {
GST_ERROR_OBJECT (action->scenario, "Action %" GST_PTR_FORMAT
" could not be prepared", action->structure);
return GST_VALIDATE_EXECUTE_ACTION_ERROR;
}
}
gst_validate_print_action (action, NULL);
res = action_type->execute (action->scenario, action);
if (!gst_structure_has_field (action->structure, "sub-action")) {
@ -1212,9 +1216,6 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action)
}
duration *= wait_multiplier;
gst_validate_printf (action,
"Waiting for %" GST_TIME_FORMAT " (wait_multiplier: %f)\n",
GST_TIME_ARGS (duration), wait_multiplier);
SCENARIO_LOCK (scenario);
if (priv->get_pos_id) {
@ -1246,7 +1247,6 @@ _execute_dot_pipeline (GstValidateScenario * scenario,
else
dotname = g_strdup ("validate.action.unnamed");
gst_validate_printf (action, "Doting pipeline (name %s)\n", dotname);
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (scenario->pipeline),
details, dotname);
@ -1310,8 +1310,6 @@ _execute_set_property (GstValidateScenario * scenario,
property_value = gst_structure_get_value (action->structure,
"property-value");
gst_validate_printf (action, "Setting property %s to %s\n",
property, gst_value_serialize (property_value));
ret = _object_set_property (G_OBJECT (target), property, property_value);
gst_object_unref (target);
@ -1340,11 +1338,6 @@ _execute_set_debug_threshold (GstValidateScenario * scenario,
gst_structure_get_boolean (action->structure, "reset", &reset);
gst_validate_printf (action,
"%s -- Set debug threshold to '%s', %sreseting all\n",
gst_structure_to_string (action->structure), threshold_str,
reset ? "" : "NOT ");
gst_debug_set_threshold_from_string (threshold_str, reset);
if (str)
@ -1443,6 +1436,36 @@ _set_action_playback_time (GstValidateScenario * scenario,
return FALSE;
}
gst_structure_set (action->structure, "playback-time", GST_TYPE_CLOCK_TIME,
action->playback_time, NULL);
return TRUE;
}
static gboolean
gst_validate_action_default_prepare_func (GstValidateAction * action)
{
gulong i;
GstClockTime time;
const gchar *vars[] = { "duration", "start", "stop" };
for (i = 0; i < G_N_ELEMENTS (vars); i++) {
gint res =
gst_validate_action_get_clocktime (action->scenario, action, vars[i],
&time);
if (res == FALSE) {
GST_ERROR_OBJECT (action->scenario, "Could not get clocktime for"
" variable %s", vars[i]);
return FALSE;
} else if (res == -1) {
continue;
}
gst_structure_set (action->structure, vars[i], GST_TYPE_CLOCK_TIME,
time, NULL);
}
return TRUE;
}
@ -2446,6 +2469,7 @@ gst_validate_register_action_type_dynamic (GstPlugin * plugin,
sizeof (GstValidateActionParameter) * (n_params));
}
type->prepare = gst_validate_action_default_prepare_func;
type->execute = function;
type->name = g_strdup (type_name);
if (plugin)

View file

@ -65,6 +65,19 @@ enum
*/
typedef GstValidateExecuteActionReturn (*GstValidateExecuteAction) (GstValidateScenario * scenario, GstValidateAction * action);
/**
* GstValidatePrepareAction:
* @action: The #GstValidateAction to prepare before execution
*
* A function that prepares @action so it can be executed right after.
* Most of the time that function is used to parse and set field with
* equations in the action structure.
*
* Returns: a %TRUE if the action could be prepared and is ready to be run
* %FALSE otherwise
*/
typedef gboolean (*GstValidatePrepareAction) (GstValidateAction * action);
/**
* GstValidateAction:
@ -92,8 +105,9 @@ struct _GstValidateAction
gint repeat;
GstClockTime playback_time;
GstValidateExecuteActionReturn state; /* Actually ActionState */
gboolean printed;
gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint) - 2];
gpointer _gst_reserved[GST_PADDING_LARGE - sizeof (gint) - 2 - sizeof(gboolean)];
};
void gst_validate_action_set_done (GstValidateAction *action);
@ -144,6 +158,7 @@ struct _GstValidateActionType
gchar *name;
gchar *implementer_namespace;
GstValidatePrepareAction prepare;
GstValidateExecuteAction execute;
GstValidateActionParameter *parameters;
@ -244,6 +259,10 @@ gst_validate_register_action_type (const gchar *type_name,
const gchar *description,
GstValidateActionTypeFlags flags);
void
gst_validate_action_type_set_prepare_function (GstValidateActionType *type,
GstValidatePrepareAction prepare_action);
GstValidateActionType *
gst_validate_register_action_type_dynamic (GstPlugin *plugin,
const gchar * type_name,