tests: element: rewrite ROI test
Rewrote the ROI test to use GstVideoRegionOfInterest meta rather than injecting GstEvents. These meta are added as a pad probe in the queue src pad. Also * Use of navigation messages to control de test * Use signal watch for processing messages * Change to H265 rather than H264 since current intel-vaapi-driver only supports ROI on kabylake. TODO: add a parameter to change the encoder/decoder to test. https://bugzilla.gnome.org/show_bug.cgi?id=768248
This commit is contained in:
parent
c49a17ed15
commit
e82fafc482
@ -20,55 +20,129 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include <gst/video/navigation.h>
|
||||||
|
#include <gst/video/gstvideometa.h>
|
||||||
|
|
||||||
typedef struct _CustomData
|
typedef struct _CustomData
|
||||||
{
|
{
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
GstPad *src_pad;
|
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
|
gboolean roi_enabled;
|
||||||
} AppData;
|
} AppData;
|
||||||
|
|
||||||
static void
|
|
||||||
send_roi_event (AppData * data)
|
|
||||||
{
|
|
||||||
gboolean res = FALSE;
|
|
||||||
GstEvent *event;
|
|
||||||
gint value[2] = { 4, 0 };
|
|
||||||
static gint counter = 0;
|
|
||||||
|
|
||||||
event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB,
|
|
||||||
gst_structure_new ("GstVaapiEncoderRegionOfInterest",
|
|
||||||
"roi-x", G_TYPE_UINT, 0,
|
|
||||||
"roi-y", G_TYPE_UINT, 0,
|
|
||||||
"roi-width", G_TYPE_UINT, 320,
|
|
||||||
"roi-height", G_TYPE_UINT, 240,
|
|
||||||
"roi-value", G_TYPE_INT, value[counter++ % 2], NULL));
|
|
||||||
|
|
||||||
/* Send the event */
|
|
||||||
res = gst_pad_push_event (data->src_pad, event);
|
|
||||||
g_print ("Sending event %p done: %d\n", event, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
send_eos_event (AppData * data)
|
send_eos_event (AppData * data)
|
||||||
{
|
{
|
||||||
GstBus *bus;
|
|
||||||
GstMessage *msg;
|
|
||||||
|
|
||||||
bus = gst_element_get_bus (data->pipeline);
|
|
||||||
gst_element_send_event (data->pipeline, gst_event_new_eos ());
|
gst_element_send_event (data->pipeline, gst_event_new_eos ());
|
||||||
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS);
|
}
|
||||||
|
|
||||||
gst_message_unref (msg);
|
static void
|
||||||
gst_object_unref (bus);
|
dispatch_keystroke (AppData * app, const gchar * str)
|
||||||
|
{
|
||||||
|
switch (g_ascii_tolower (str[0])) {
|
||||||
|
case 'r':
|
||||||
|
app->roi_enabled = !app->roi_enabled;
|
||||||
|
gst_println ("ROI %s", app->roi_enabled ? "enabled" : "disabled");
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
send_eos_event (app);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cb_msg (GstBus * bus, GstMessage * msg, gpointer data)
|
||||||
|
{
|
||||||
|
AppData *app = data;
|
||||||
|
GstNavigationMessageType mtype = gst_navigation_message_get_type (msg);
|
||||||
|
GstEvent *ev = NULL;
|
||||||
|
GstNavigationEventType type;
|
||||||
|
const gchar *key;
|
||||||
|
|
||||||
|
if (mtype != GST_NAVIGATION_MESSAGE_EVENT)
|
||||||
|
return;
|
||||||
|
if (!gst_navigation_message_parse_event (msg, &ev))
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
type = gst_navigation_event_get_type (ev);
|
||||||
|
if (type != GST_NAVIGATION_EVENT_KEY_PRESS)
|
||||||
|
goto bail;
|
||||||
|
if (!gst_navigation_event_parse_key_event (ev, &key))
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
dispatch_keystroke (app, key);
|
||||||
|
|
||||||
|
bail:
|
||||||
|
if (ev)
|
||||||
|
gst_event_unref (ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cb_msg_eos (GstBus * bus, GstMessage * msg, gpointer data)
|
||||||
|
{
|
||||||
|
AppData *app = data;
|
||||||
|
g_main_loop_quit (app->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
cb_msg_error (GstBus * bus, GstMessage * msg, gpointer data)
|
||||||
|
{
|
||||||
|
AppData *app = data;
|
||||||
|
gchar *debug = NULL;
|
||||||
|
GError *err = NULL;
|
||||||
|
|
||||||
|
gst_message_parse_error (msg, &err, &debug);
|
||||||
|
|
||||||
|
g_print ("Error: %s\n", err->message);
|
||||||
|
g_error_free (err);
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
g_print ("Debug details: %s\n", debug);
|
||||||
|
g_free (debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_main_loop_quit (app->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstPadProbeReturn
|
||||||
|
cb_add_roi (GstPad * pad, GstPadProbeInfo * info, gpointer data)
|
||||||
|
{
|
||||||
|
AppData *app = data;
|
||||||
|
GstVideoRegionOfInterestMeta *rmeta;
|
||||||
|
GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
|
||||||
|
GstStructure *s;
|
||||||
|
|
||||||
|
if (!app->roi_enabled)
|
||||||
|
return GST_PAD_PROBE_OK;
|
||||||
|
|
||||||
|
buf = gst_buffer_make_writable (buf);
|
||||||
|
if (!buf)
|
||||||
|
return GST_PAD_PROBE_OK;
|
||||||
|
|
||||||
|
rmeta =
|
||||||
|
gst_buffer_add_video_region_of_interest_meta (buf, "test", 0, 0, 320,
|
||||||
|
240);
|
||||||
|
if (!rmeta)
|
||||||
|
return GST_PAD_PROBE_OK;
|
||||||
|
|
||||||
|
s = gst_structure_new ("roi/vaapi", "delta-qp", G_TYPE_INT, -10, NULL);
|
||||||
|
gst_video_region_of_interest_meta_add_param (rmeta, s);
|
||||||
|
|
||||||
|
GST_PAD_PROBE_INFO_DATA (info) = buf;
|
||||||
|
return GST_PAD_PROBE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process keyboard input */
|
/* Process keyboard input */
|
||||||
static gboolean
|
static gboolean
|
||||||
handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data)
|
handle_keyboard (GIOChannel * source, GIOCondition cond, gpointer data)
|
||||||
{
|
{
|
||||||
|
AppData *app = data;
|
||||||
gchar *str = NULL;
|
gchar *str = NULL;
|
||||||
|
|
||||||
if (g_io_channel_read_line (source, &str, NULL, NULL,
|
if (g_io_channel_read_line (source, &str, NULL, NULL,
|
||||||
@ -76,20 +150,9 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (g_ascii_tolower (str[0])) {
|
dispatch_keystroke (app, str);
|
||||||
case 'r':
|
|
||||||
send_roi_event (data);
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
send_eos_event (data);
|
|
||||||
g_main_loop_quit (data->loop);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (str);
|
g_free (str);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +160,7 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data)
|
|||||||
* This is an example pipeline to recognize difference between ROI and non-ROI.
|
* This is an example pipeline to recognize difference between ROI and non-ROI.
|
||||||
* 1. Produce snow pattern with 320p
|
* 1. Produce snow pattern with 320p
|
||||||
* 2. Encode and decode the raw data with 2 pipelines at same time.
|
* 2. Encode and decode the raw data with 2 pipelines at same time.
|
||||||
* 2.1. Inject a GstCustomEvent to the 2nd pipeline to enable ROI.
|
* 2.1. Insert GstVideoRegionOfInterestMeta to the 2nd pipeline buffers to enable ROI.
|
||||||
* 3. Mix both streams in videomixer.
|
* 3. Mix both streams in videomixer.
|
||||||
* 5. Output the result in one window.
|
* 5. Output the result in one window.
|
||||||
*
|
*
|
||||||
@ -116,37 +179,41 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data)
|
|||||||
'--->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->'
|
'--->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->'
|
||||||
^ '--------' '---' '---' '---' '--------'
|
^ '--------' '---' '---' '---' '--------'
|
||||||
|
|
|
|
||||||
'-- Injection of GstCustomEvent "GstVaapiEncoderRegionOfInterest"
|
'-- Insert GstVideoRegionOfInterestMeta width roit/vaapi params on buffers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
AppData data;
|
AppData data = { 0, };
|
||||||
GstStateChangeReturn ret;
|
GstStateChangeReturn ret;
|
||||||
GstElement *q;
|
GstElement *el;
|
||||||
GIOChannel *io_stdin;
|
GstPad *pad;
|
||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
|
GIOChannel *io_stdin;
|
||||||
|
GstBus *bus;
|
||||||
|
|
||||||
|
data.roi_enabled = TRUE;
|
||||||
|
|
||||||
/* Initialize GStreamer */
|
/* Initialize GStreamer */
|
||||||
gst_init (&argc, &argv);
|
gst_init (&argc, &argv);
|
||||||
|
|
||||||
/* Print usage map */
|
/* Print usage map */
|
||||||
g_print ("USAGE: Choose one of the following options, then press enter:\n"
|
g_print ("USAGE: 'r' to enable/disable ROI && 'q' to quit\n");
|
||||||
" 'r' to send ROI event \n" " 'q' to quit\n");
|
|
||||||
|
|
||||||
#define ENCDEC "vaapih264enc rate-control=cbr bitrate=2000 ! vaapih264dec ! vaapipostproc width=640 "
|
#define SRC "videotestsrc pattern=snow ! " \
|
||||||
#define TEXT "textoverlay font-desc=\"Arial Bold 48\" text="
|
"video/x-raw, format=NV12, width=320, framerate=5/1"
|
||||||
|
#define ENCDEC "vaapih265enc rate-control=cbr bitrate=2000 ! vaapih265dec ! " \
|
||||||
|
"vaapipostproc ! video/x-raw, width=640"
|
||||||
|
#define TEXT "textoverlay font-desc=\"Arial Bold 48\" "
|
||||||
|
|
||||||
data.pipeline =
|
data.pipeline =
|
||||||
gst_parse_launch
|
gst_parse_launch
|
||||||
("videomixer name=mix ! vaapipostproc ! vaapisink sync=false "
|
("videomixer name=mix ! vaapipostproc ! vaapisink sync=false "
|
||||||
"videotestsrc pattern=snow ! video/x-raw, width=320, framerate=5/1 "
|
SRC " ! tee name=t ! queue ! " TEXT " text=\"non-ROI\" ! " ENCDEC
|
||||||
"! tee name=t "
|
" ! videobox left=-640 ! mix. "
|
||||||
"t. ! queue ! " TEXT "\"non-ROI\" ! " ENCDEC
|
" t. ! queue name=roi ! " TEXT " text=\"ROI\" ! " ENCDEC
|
||||||
"! videobox left=-640 ! mix. "
|
" ! videobox ! mix.", &err);
|
||||||
"t. ! queue name=roi ! " TEXT "\"ROI\" ! " ENCDEC
|
|
||||||
"! videobox ! mix.", &err);
|
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
g_printerr ("failed to parse pipeline: %s\n", err->message);
|
g_printerr ("failed to parse pipeline: %s\n", err->message);
|
||||||
@ -154,13 +221,23 @@ main (int argc, char *argv[])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
q = gst_bin_get_by_name (GST_BIN (data.pipeline), "roi");
|
bus = gst_pipeline_get_bus (GST_PIPELINE (data.pipeline));
|
||||||
data.src_pad = gst_element_get_static_pad (q, "src");
|
gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
|
||||||
gst_object_unref (q);
|
gst_bus_enable_sync_message_emission (bus);
|
||||||
|
g_signal_connect (bus, "message::error", G_CALLBACK (cb_msg_error), &data);
|
||||||
|
g_signal_connect (bus, "message::eos", G_CALLBACK (cb_msg_eos), &data);
|
||||||
|
g_signal_connect (bus, "message::element", G_CALLBACK (cb_msg), &data);
|
||||||
|
gst_object_unref (bus);
|
||||||
|
|
||||||
|
el = gst_bin_get_by_name (GST_BIN (data.pipeline), "roi");
|
||||||
|
pad = gst_element_get_static_pad (el, "src");
|
||||||
|
gst_object_unref (el);
|
||||||
|
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, cb_add_roi, &data, NULL);
|
||||||
|
gst_object_unref (pad);
|
||||||
|
|
||||||
/* Add a keyboard watch so we get notified of keystrokes */
|
/* Add a keyboard watch so we get notified of keystrokes */
|
||||||
io_stdin = g_io_channel_unix_new (fileno (stdin));
|
io_stdin = g_io_channel_unix_new (fileno (stdin));
|
||||||
g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc) handle_keyboard, &data);
|
g_io_add_watch (io_stdin, G_IO_IN, handle_keyboard, &data);
|
||||||
|
|
||||||
/* Start playing */
|
/* Start playing */
|
||||||
ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
|
ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
|
||||||
@ -176,12 +253,9 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
/* Free resources */
|
/* Free resources */
|
||||||
g_main_loop_unref (data.loop);
|
g_main_loop_unref (data.loop);
|
||||||
g_io_channel_unref (io_stdin);
|
|
||||||
gst_element_set_state (data.pipeline, GST_STATE_NULL);
|
gst_element_set_state (data.pipeline, GST_STATE_NULL);
|
||||||
|
|
||||||
if (data.src_pad)
|
|
||||||
gst_object_unref (data.src_pad);
|
|
||||||
gst_object_unref (data.pipeline);
|
gst_object_unref (data.pipeline);
|
||||||
|
g_io_channel_unref (io_stdin);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user