• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  test-roi.c - Testsuite for Region of Interest
3  *
4  *  Copyright (C) 2019 Intel Corporation
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public License
8  *  as published by the Free Software Foundation; either version 2.1
9  *  of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301 USA
20  */
21 
22 #include <stdio.h>
23 #include <gst/gst.h>
24 #include <gst/video/navigation.h>
25 #include <gst/video/gstvideometa.h>
26 
27 typedef struct _CustomData
28 {
29   GstElement *pipeline;
30   GMainLoop *loop;
31   gboolean roi_enabled;
32   gboolean is_delta_qp;
33 } AppData;
34 
35 static void
send_eos_event(AppData * data)36 send_eos_event (AppData * data)
37 {
38   gst_element_send_event (data->pipeline, gst_event_new_eos ());
39 }
40 
41 static void
dispatch_keystroke(AppData * app,const gchar * str)42 dispatch_keystroke (AppData * app, const gchar * str)
43 {
44   switch (g_ascii_tolower (str[0])) {
45     case 'r':
46       app->roi_enabled = !app->roi_enabled;
47       gst_println ("ROI %s", app->roi_enabled ? "enabled" : "disabled");
48       break;
49     case 'd':
50       app->is_delta_qp = !app->is_delta_qp;
51       gst_println ("Use %s", app->is_delta_qp ? "delta QP" : "Priority");
52       break;
53     case 'q':
54       send_eos_event (app);
55       break;
56     default:
57       break;
58   }
59 
60   return;
61 }
62 
63 static void
cb_msg(GstBus * bus,GstMessage * msg,gpointer data)64 cb_msg (GstBus * bus, GstMessage * msg, gpointer data)
65 {
66   AppData *app = data;
67   GstNavigationMessageType mtype = gst_navigation_message_get_type (msg);
68   GstEvent *ev = NULL;
69   GstNavigationEventType type;
70   const gchar *key;
71 
72   if (mtype != GST_NAVIGATION_MESSAGE_EVENT)
73     return;
74   if (!gst_navigation_message_parse_event (msg, &ev))
75     goto bail;
76 
77   type = gst_navigation_event_get_type (ev);
78   if (type != GST_NAVIGATION_EVENT_KEY_PRESS)
79     goto bail;
80   if (!gst_navigation_event_parse_key_event (ev, &key))
81     goto bail;
82 
83   dispatch_keystroke (app, key);
84 
85 bail:
86   if (ev)
87     gst_event_unref (ev);
88 }
89 
90 static void
cb_msg_eos(GstBus * bus,GstMessage * msg,gpointer data)91 cb_msg_eos (GstBus * bus, GstMessage * msg, gpointer data)
92 {
93   AppData *app = data;
94   g_main_loop_quit (app->loop);
95 }
96 
97 
98 static void
cb_msg_error(GstBus * bus,GstMessage * msg,gpointer data)99 cb_msg_error (GstBus * bus, GstMessage * msg, gpointer data)
100 {
101   AppData *app = data;
102   gchar *debug = NULL;
103   GError *err = NULL;
104 
105   gst_message_parse_error (msg, &err, &debug);
106 
107   g_print ("Error: %s\n", err->message);
108   g_error_free (err);
109 
110   if (debug) {
111     g_print ("Debug details: %s\n", debug);
112     g_free (debug);
113   }
114 
115   g_main_loop_quit (app->loop);
116 }
117 
118 static GstPadProbeReturn
cb_add_roi(GstPad * pad,GstPadProbeInfo * info,gpointer data)119 cb_add_roi (GstPad * pad, GstPadProbeInfo * info, gpointer data)
120 {
121   AppData *app = data;
122   GstVideoRegionOfInterestMeta *rmeta;
123   GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
124   GstStructure *s;
125 
126   if (!app->roi_enabled)
127     return GST_PAD_PROBE_OK;
128 
129   buf = gst_buffer_make_writable (buf);
130 
131   rmeta =
132       gst_buffer_add_video_region_of_interest_meta (buf, "test", 0, 0, 320,
133       240);
134 
135   if (app->is_delta_qp)
136     s = gst_structure_new ("roi/msdk", "delta-qp", G_TYPE_INT, 20, NULL);
137   else
138     s = gst_structure_new ("roi/msdk", "priority", G_TYPE_INT, -3, NULL);
139   gst_video_region_of_interest_meta_add_param (rmeta, s);
140 
141   GST_PAD_PROBE_INFO_DATA (info) = buf;
142   return GST_PAD_PROBE_OK;
143 }
144 
145 /* Process keyboard input */
146 static gboolean
handle_keyboard(GIOChannel * source,GIOCondition cond,gpointer data)147 handle_keyboard (GIOChannel * source, GIOCondition cond, gpointer data)
148 {
149   AppData *app = data;
150   gchar *str = NULL;
151 
152   if (g_io_channel_read_line (source, &str, NULL, NULL,
153           NULL) != G_IO_STATUS_NORMAL) {
154     return TRUE;
155   }
156 
157   dispatch_keystroke (app, str);
158 
159   g_free (str);
160   return TRUE;
161 }
162 
163 /*
164  * This is an example pipeline to recognize difference between ROI and non-ROI.
165  * 1. Produce snow pattern with 320p
166  * 2. Encode and decode the raw data with 2 pipelines at same time.
167  *    2.1. Insert GstVideoRegionOfInterestMeta to the 2nd pipeline buffers to enable ROI.
168  * 3. Mix both streams in videomixer.
169  * 5. Output the result in one window.
170  *
171  * Note that the higher definition of original raw data, the easier we
172  * recognize.  So you can replace videotestsrc with your
173  * high-definition camera or other src elements.
174  */
175 
176 /*
177 .----------.  .---.     .--------.  .---.  .---.  .---.  .--------.  .----------.  .-----.
178 | videosrc |->|tee|->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->|videomixer|->|vsink|
179 '----------'  '---'     '--------'  '---'  '---'  '---'  '--------'  '----------'  '-----'
180                 ^                                                    ^
181                 |                                                    |
182                 |       .--------.  .---.  .---.  .---.  .--------.  |
183                 '--->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->'
184                      ^  '--------'  '---'  '---'  '---'  '--------'
185                      |
186                      '-- Insert GstVideoRegionOfInterestMeta width roi/msdk params on buffers
187 */
188 
189 int
main(int argc,char * argv[])190 main (int argc, char *argv[])
191 {
192   AppData data = { 0, };
193   GstStateChangeReturn ret;
194   GstElement *el;
195   GstPad *pad;
196   GError *err = NULL;
197   GIOChannel *io_stdin;
198   GstBus *bus;
199 
200   data.roi_enabled = TRUE;
201   data.is_delta_qp = TRUE;
202 
203   /* Initialize GStreamer */
204   gst_init (&argc, &argv);
205 
206   /* Print usage map */
207   g_print ("USAGE: 'r' to enable/disable ROI, "
208       "'d' to change ROI mode && 'q' to quit\n");
209 
210 #define SRC "videotestsrc pattern=snow ! " \
211             "video/x-raw, format=NV12, width=320, framerate=5/1"
212 #define ENCDEC "msdkh265enc rate-control=cqp ! msdkh265dec ! " \
213                "msdkvpp ! video/x-raw, width=640"
214 #define TEXT "textoverlay font-desc=\"Arial Bold 48\" "
215 
216   data.pipeline =
217       gst_parse_launch
218       ("videomixer name=mix ! msdkvpp ! glimagesink sync=false "
219       SRC " ! tee name=t ! queue ! " TEXT " text=\"non-ROI\" ! " ENCDEC
220       " ! videobox left=-640 ! mix. "
221       " t. ! queue name=roi ! " TEXT " text=\"ROI\" ! " ENCDEC
222       " ! videobox ! mix.", &err);
223 
224   if (err) {
225     g_printerr ("failed to parse pipeline: %s\n", err->message);
226     g_error_free (err);
227     return -1;
228   }
229 
230   bus = gst_pipeline_get_bus (GST_PIPELINE (data.pipeline));
231   gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
232   gst_bus_enable_sync_message_emission (bus);
233   g_signal_connect (bus, "message::error", G_CALLBACK (cb_msg_error), &data);
234   g_signal_connect (bus, "message::eos", G_CALLBACK (cb_msg_eos), &data);
235   g_signal_connect (bus, "message::element", G_CALLBACK (cb_msg), &data);
236   gst_object_unref (bus);
237 
238   el = gst_bin_get_by_name (GST_BIN (data.pipeline), "roi");
239   pad = gst_element_get_static_pad (el, "src");
240   gst_object_unref (el);
241   gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, cb_add_roi, &data, NULL);
242   gst_object_unref (pad);
243 
244   /* Add a keyboard watch so we get notified of keystrokes */
245   io_stdin = g_io_channel_unix_new (fileno (stdin));
246   g_io_add_watch (io_stdin, G_IO_IN, handle_keyboard, &data);
247 
248   /* Start playing */
249   ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
250   if (ret == GST_STATE_CHANGE_FAILURE) {
251     g_printerr ("Unable to set the pipeline to the playing state.\n");
252     gst_object_unref (data.pipeline);
253     return -1;
254   }
255 
256   /* Create a GLib Main Loop and set it to run */
257   data.loop = g_main_loop_new (NULL, FALSE);
258   g_main_loop_run (data.loop);
259 
260   /* Free resources */
261   g_main_loop_unref (data.loop);
262   gst_element_set_state (data.pipeline, GST_STATE_NULL);
263   gst_object_unref (data.pipeline);
264   g_io_channel_unref (io_stdin);
265 
266   return 0;
267 }
268