mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-19 20:46:22 +00:00
scenario: Add an action that checks the "force-key-unit" event execution
This commit is contained in:
parent
10d1c4560e
commit
f8b4235e33
5 changed files with 289 additions and 11 deletions
|
@ -12,6 +12,7 @@ scenarios_DATA = simple_seeks.scenario \
|
|||
adaptive_video_size.scenario \
|
||||
adaptive_video_framerate.scenario \
|
||||
adaptive_video_framerate_size.scenario\
|
||||
force_key_unit.scenario\
|
||||
switch_audio_track.scenario
|
||||
|
||||
EXTRA_DIST = simple_seeks.scenario \
|
||||
|
@ -27,4 +28,5 @@ EXTRA_DIST = simple_seeks.scenario \
|
|||
adaptive_video_size.scenario \
|
||||
adaptive_video_framerate.scenario \
|
||||
adaptive_video_framerate_size.scenario\
|
||||
force_key_unit.scenario\
|
||||
switch_audio_track.scenario
|
||||
|
|
2
validate/data/force_key_unit.scenario
Normal file
2
validate/data/force_key_unit.scenario
Normal file
|
@ -0,0 +1,2 @@
|
|||
video-request-key-unit, playback_time=1.0, direction=upstream, running_time=-1.0, all-header=true, count=1
|
||||
eos, playback_time=2.0
|
|
@ -210,6 +210,9 @@ gst_validate_report_load_issues (void)
|
|||
REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED,
|
||||
_("All the actions were not executed before the program stoped"),
|
||||
NULL);
|
||||
REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR,
|
||||
_("The execution of an action did not properly happen"),
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -110,7 +110,8 @@ typedef enum {
|
|||
#define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_SUPERIOR_DURATION (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 1)
|
||||
#define GST_VALIDATE_ISSUE_ID_QUERY_POSITION_OUT_OF_SEGMENT (((GstValidateIssueId) GST_VALIDATE_AREA_QUERY) << GST_VALIDATE_ISSUE_ID_SHIFT | 2)
|
||||
|
||||
#define GST_VALIDATE_ISSUE_ID_SCENARIO_NOT_ENDED (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 1)
|
||||
#define GST_VALIDATE_ISSUE_ID_SCENARIO_NOT_ENDED (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 1)
|
||||
#define GST_VALIDATE_ISSUE_ID_SCENARIO_ACTION_EXECUTION_ERROR (((GstValidateIssueId) GST_VALIDATE_AREA_SCENARIO) << GST_VALIDATE_ISSUE_ID_SHIFT | 2)
|
||||
|
||||
#define GST_VALIDATE_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_VALIDATE_ISSUE_ID_SHIFT))
|
||||
|
||||
|
|
|
@ -29,9 +29,11 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <gst/validate/validate.h>
|
||||
#include <gst/pbutils/encoding-profile.h>
|
||||
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
#include <glib-unix.h>
|
||||
#endif
|
||||
|
@ -40,10 +42,34 @@
|
|||
|
||||
static gint ret = 0;
|
||||
static GMainLoop *mainloop;
|
||||
static GstElement *pipeline;
|
||||
static GstElement *pipeline, *encodebin;
|
||||
static GstEncodingProfile *encoding_profile = NULL;
|
||||
static gboolean eos_on_shutdown = FALSE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile gint refcount;
|
||||
|
||||
GstSegment segment; /* The currently configured segment */
|
||||
|
||||
/* FIXME Do we need a weak ref here? */
|
||||
GstValidateScenario *scenario;
|
||||
guint count_bufs;
|
||||
gboolean seen_event;
|
||||
GstClockTime running_time;
|
||||
|
||||
/* Make sure to remove all probes when we are done */
|
||||
gboolean done;
|
||||
|
||||
} KeyUnitProbeInfo;
|
||||
|
||||
/* This is used to
|
||||
* 1) Make sure we receive the event
|
||||
* 2) Count the number of frames that were not KF seen after the event
|
||||
*/
|
||||
#define FORCE_KF_DATA_NAME "force-key-unit"
|
||||
#define NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE 1
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
static gboolean
|
||||
intr_handler (gpointer user_data)
|
||||
|
@ -63,6 +89,238 @@ intr_handler (gpointer user_data)
|
|||
}
|
||||
#endif /* G_OS_UNIX */
|
||||
|
||||
static void
|
||||
key_unit_data_unref (KeyUnitProbeInfo *info)
|
||||
{
|
||||
if (G_UNLIKELY (g_atomic_int_dec_and_test (&info->refcount))) {
|
||||
g_slice_free (KeyUnitProbeInfo, info);
|
||||
}
|
||||
}
|
||||
|
||||
static KeyUnitProbeInfo *
|
||||
key_unit_data_ref (KeyUnitProbeInfo *info)
|
||||
{
|
||||
g_atomic_int_inc (&info->refcount);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static KeyUnitProbeInfo *
|
||||
key_unit_data_new (GstValidateScenario *scenario, GstClockTime running_time)
|
||||
{
|
||||
KeyUnitProbeInfo *info = g_slice_new0 (KeyUnitProbeInfo);
|
||||
info->refcount = 1;
|
||||
|
||||
info->scenario = scenario;
|
||||
info->running_time = running_time;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static GstPadProbeReturn
|
||||
_check_is_key_unit_cb (GstPad * pad, GstPadProbeInfo * info, KeyUnitProbeInfo *kuinfo)
|
||||
{
|
||||
if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) {
|
||||
if (gst_video_event_is_force_key_unit (GST_PAD_PROBE_INFO_DATA (info)))
|
||||
kuinfo->seen_event = TRUE;
|
||||
else if (GST_EVENT_TYPE (info->data) == GST_EVENT_SEGMENT &&
|
||||
GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
|
||||
const GstSegment *segment = NULL;
|
||||
|
||||
gst_event_parse_segment (info->data, &segment);
|
||||
kuinfo->segment = *segment;
|
||||
}
|
||||
} else if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info)) && kuinfo->seen_event) {
|
||||
|
||||
if (GST_CLOCK_TIME_IS_VALID (kuinfo->running_time)) {
|
||||
GstClockTime running_time = gst_segment_to_running_time (&kuinfo->segment,
|
||||
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (info->data));
|
||||
|
||||
if (running_time < kuinfo->running_time)
|
||||
return GST_PAD_PROBE_OK;
|
||||
}
|
||||
|
||||
if (GST_BUFFER_FLAG_IS_SET (GST_PAD_PROBE_INFO_BUFFER (info), GST_BUFFER_FLAG_DELTA_UNIT)) {
|
||||
if (kuinfo->count_bufs >= NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE) {
|
||||
GST_VALIDATE_REPORT (kuinfo->scenario,
|
||||
SCENARIO_ACTION_EXECUTION_ERROR,
|
||||
"Did not receive a key frame after requested one, "
|
||||
" at running_time %" GST_TIME_FORMAT " (with a %i "
|
||||
"frame tolerance)", GST_TIME_ARGS (kuinfo->running_time),
|
||||
NOT_KF_AFTER_FORCE_KF_EVT_TOLERANCE);
|
||||
|
||||
return GST_PAD_PROBE_REMOVE;
|
||||
}
|
||||
|
||||
kuinfo->count_bufs++;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (kuinfo->scenario,
|
||||
"Properly got keyframe after \"force-keyframe\" event "
|
||||
"with running_time %" GST_TIME_FORMAT " (latency %d frame(s))",
|
||||
GST_TIME_ARGS (kuinfo->running_time), kuinfo->count_bufs);
|
||||
|
||||
return GST_PAD_PROBE_REMOVE;
|
||||
}
|
||||
}
|
||||
|
||||
return GST_PAD_PROBE_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
_find_video_encoder (GValue * velement, gpointer udata)
|
||||
{
|
||||
GstElement *element = g_value_get_object (velement);
|
||||
|
||||
const gchar *klass = gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (element),
|
||||
GST_ELEMENT_METADATA_KLASS);
|
||||
|
||||
if (g_strstr_len (klass, -1, "Video") &&
|
||||
g_strstr_len (klass, -1, "Encoder")) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return !0;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
_execute_request_key_unit (GstValidateScenario * scenario,
|
||||
GstValidateAction * action)
|
||||
{
|
||||
guint count;
|
||||
GstIterator *iter;
|
||||
gboolean all_headers;
|
||||
|
||||
gboolean ret = TRUE;
|
||||
GValue result = { 0, };
|
||||
GstEvent *event = NULL;
|
||||
GstQuery *segment_query;
|
||||
KeyUnitProbeInfo *info = NULL;
|
||||
GstElement *video_encoder = NULL;
|
||||
GstPad *pad = NULL, *encoder_srcpad = NULL;
|
||||
GstClockTime running_time = GST_CLOCK_TIME_NONE;
|
||||
const gchar *direction = gst_structure_get_string (action->structure,
|
||||
"direction");
|
||||
|
||||
iter = gst_bin_iterate_recurse (GST_BIN (encodebin));
|
||||
if (!gst_iterator_find_custom (iter,
|
||||
(GCompareFunc) _find_video_encoder, &result,NULL)) {
|
||||
g_error ("Could not find any video encode");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
gst_iterator_free (iter);
|
||||
video_encoder = g_value_get_object (&result);
|
||||
encoder_srcpad = gst_element_get_static_pad (video_encoder, "src");
|
||||
|
||||
if (!encoder_srcpad) {
|
||||
GST_FIXME ("Implement weird encoder management");
|
||||
g_error ("We do not handle encoder with not static srcpad");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
gst_validate_action_get_clocktime (scenario, action,
|
||||
"running-time", &running_time);
|
||||
|
||||
if (gst_structure_get_boolean (action->structure, "all-headers",
|
||||
&all_headers)) {
|
||||
g_error ("Missing field: all-headers");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!gst_structure_get_uint (action->structure, "count", &count)) {
|
||||
if (!gst_structure_get_int (action->structure, "count", (gint *) & count)) {
|
||||
g_error ("Missing field: count");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
info = key_unit_data_new (scenario, running_time);
|
||||
if (g_strcmp0 (direction, "upstream") == 0) {
|
||||
event = gst_video_event_new_upstream_force_key_unit (running_time,
|
||||
all_headers, count);
|
||||
|
||||
pad = gst_element_get_static_pad (video_encoder, "src");
|
||||
gst_pad_add_probe (encoder_srcpad,
|
||||
GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
|
||||
(GstPadProbeCallback) _check_is_key_unit_cb,
|
||||
key_unit_data_ref (info),
|
||||
(GDestroyNotify) key_unit_data_unref);
|
||||
} else if (g_strcmp0 (direction, "downstream") == 0) {
|
||||
GstClockTime timestamp = GST_CLOCK_TIME_NONE,
|
||||
stream_time = GST_CLOCK_TIME_NONE;
|
||||
|
||||
pad = gst_element_get_static_pad (video_encoder, "sink");
|
||||
if (!pad) {
|
||||
GST_FIXME ("Implement weird encoder management");
|
||||
g_error ("We do not handle encoder with not static sinkpad");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
gst_validate_action_get_clocktime (scenario, action,
|
||||
"timestamp", ×tamp);
|
||||
|
||||
gst_validate_action_get_clocktime (scenario, action,
|
||||
"stream-time", &stream_time);
|
||||
|
||||
event = gst_video_event_new_downstream_force_key_unit (timestamp, stream_time,
|
||||
running_time, all_headers, count);
|
||||
|
||||
gst_pad_add_probe (pad,
|
||||
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
|
||||
(GstPadProbeCallback) _check_is_key_unit_cb,
|
||||
key_unit_data_ref (info),
|
||||
(GDestroyNotify) key_unit_data_unref);
|
||||
} else {
|
||||
g_error ("request keyunit direction %s invalide (should be in"
|
||||
" [downstrean, upstream]", direction);
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
g_print ("Sendings a \"force key unit\" event %s\n", direction);
|
||||
|
||||
segment_query = gst_query_new_segment (GST_FORMAT_TIME);
|
||||
gst_pad_query (encoder_srcpad, segment_query);
|
||||
|
||||
gst_query_parse_segment (segment_query, &(info->segment.rate),
|
||||
&(info->segment.format),
|
||||
(gint64*) &(info->segment.start),
|
||||
(gint64*) &(info->segment.stop));
|
||||
|
||||
gst_pad_add_probe (encoder_srcpad,
|
||||
GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
|
||||
(GstPadProbeCallback) _check_is_key_unit_cb, info,
|
||||
(GDestroyNotify) key_unit_data_unref);
|
||||
|
||||
|
||||
if (!gst_pad_send_event (pad, event)) {
|
||||
GST_VALIDATE_REPORT (scenario, SCENARIO_ACTION_EXECUTION_ERROR,
|
||||
"Could not send \"force key unit\" event %s", direction);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
done:
|
||||
if (video_encoder)
|
||||
gst_object_unref (video_encoder);
|
||||
if (pad)
|
||||
gst_object_unref (pad);
|
||||
if (encoder_srcpad)
|
||||
gst_object_unref (encoder_srcpad);
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_execute_set_restriction (GstValidateScenario * scenario,
|
||||
GstValidateAction * action)
|
||||
|
@ -275,24 +533,24 @@ pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstElement * encodebin)
|
|||
static void
|
||||
create_transcoding_pipeline (gchar * uri, gchar * outuri)
|
||||
{
|
||||
GstElement *src, *ebin, *sink;
|
||||
GstElement *src, *sink;
|
||||
|
||||
mainloop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
pipeline = gst_pipeline_new ("encoding-pipeline");
|
||||
src = gst_element_factory_make ("uridecodebin", NULL);
|
||||
|
||||
ebin = gst_element_factory_make ("encodebin", NULL);
|
||||
encodebin = gst_element_factory_make ("encodebin", NULL);
|
||||
sink = gst_element_make_from_uri (GST_URI_SINK, outuri, "sink", NULL);
|
||||
g_assert (sink);
|
||||
|
||||
g_object_set (src, "uri", uri, NULL);
|
||||
g_object_set (ebin, "profile", encoding_profile, NULL);
|
||||
g_object_set (encodebin, "profile", encoding_profile, NULL);
|
||||
|
||||
g_signal_connect (src, "pad-added", G_CALLBACK (pad_added_cb), ebin);
|
||||
g_signal_connect (src, "pad-added", G_CALLBACK (pad_added_cb), encodebin);
|
||||
|
||||
gst_bin_add_many (GST_BIN (pipeline), src, ebin, sink, NULL);
|
||||
gst_element_link (ebin, sink);
|
||||
gst_bin_add_many (GST_BIN (pipeline), src, encodebin, sink, NULL);
|
||||
gst_element_link (encodebin, sink);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -420,6 +678,20 @@ _parse_encoding_profile (const gchar * option_name, const gchar * value,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_register_actions (void)
|
||||
{
|
||||
const gchar *resize_video_mandatory_fields[] = { "restriction-caps", NULL };
|
||||
const gchar *force_key_unit_mandatory_fields[] = { "direction",
|
||||
"running-time", "all-headers", "count", NULL };
|
||||
|
||||
gst_validate_add_action_type ("set-restriction", _execute_set_restriction,
|
||||
resize_video_mandatory_fields, "Change the restriction caps on the fly");
|
||||
gst_validate_add_action_type ("video-request-key-unit",
|
||||
_execute_request_key_unit, force_key_unit_mandatory_fields,
|
||||
"Request a video key unit");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, gchar ** argv)
|
||||
{
|
||||
|
@ -438,7 +710,6 @@ main (int argc, gchar ** argv)
|
|||
gboolean want_help = FALSE;
|
||||
gboolean list_scenarios = FALSE;
|
||||
|
||||
const gchar *resize_video_mandatory_fields[] = { "restriction-caps", NULL };
|
||||
GOptionEntry options[] = {
|
||||
{"output-format", 'o', 0, G_OPTION_ARG_CALLBACK, &_parse_encoding_profile,
|
||||
"Set the properties to use for the encoding profile "
|
||||
|
@ -500,9 +771,8 @@ main (int argc, gchar ** argv)
|
|||
|
||||
gst_validate_init ();
|
||||
|
||||
gst_validate_add_action_type ("set-restriction", _execute_set_restriction,
|
||||
resize_video_mandatory_fields, "Change the restriction caps on the fly");
|
||||
|
||||
_register_actions ();
|
||||
if (argc != 3) {
|
||||
g_printerr ("%i arguments recived, 2 expected.\n"
|
||||
"You should run the test using:\n"
|
||||
|
|
Loading…
Reference in a new issue