rtsp-server:wfd: Fix build error for gcc upgrade
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / tests / examples / nvcodec / nvcodec.c
1 /* GStreamer
2  * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <gst/gst.h>
25 #include <gst/video/video.h>
26 #include <stdlib.h>
27
28 #include "../key-handler.h"
29
30 #define DEFAULT_VIDEO_SINK "autovideosink"
31
32 static GMainLoop *loop = NULL;
33 static gint width = 320;
34 static gint height = 240;
35 static gint bitrate = 2000;
36
37 typedef struct
38 {
39   GstElement *pipeline;
40   GstElement *capsfilter;
41   GstElement *nvenc;
42   gulong probe_id;
43
44   gint prev_width;
45   gint prev_height;
46 } TestCallbackData;
47
48 static void
49 print_keyboard_help (void)
50 {
51   /* *INDENT-OFF* */
52   static struct
53   {
54     const gchar *key_desc;
55     const gchar *key_help;
56   } key_controls[] = {
57     {
58     "q", "Quit"}, {
59     "right arrow", "Increase Width"}, {
60     "left arrow", "Decrease Width"}, {
61     "up arrow", "Increase Height"} , {
62     "down arrow", "Decrease Height"}, {
63     ">", "Increase encoding bitrate by 100 kbit/sec"}, {
64     "<", "Decrease encoding bitrate by 100 kbit/sec"}, {
65     "k", "show keyboard shortcuts"}
66   };
67   /* *INDENT-ON* */
68
69   guint i, chars_to_pad, desc_len, max_desc_len = 0;
70
71   g_print ("\n\n%s\n\n", "Keyboard controls:");
72
73   for (i = 0; i < G_N_ELEMENTS (key_controls); ++i) {
74     desc_len = g_utf8_strlen (key_controls[i].key_desc, -1);
75     max_desc_len = MAX (max_desc_len, desc_len);
76   }
77   ++max_desc_len;
78
79   for (i = 0; i < G_N_ELEMENTS (key_controls); ++i) {
80     chars_to_pad = max_desc_len - g_utf8_strlen (key_controls[i].key_desc, -1);
81     g_print ("\t%s", key_controls[i].key_desc);
82     g_print ("%-*s: ", chars_to_pad, "");
83     g_print ("%s\n", key_controls[i].key_help);
84   }
85   g_print ("\n");
86 }
87
88 static void
89 keyboard_cb (gchar input, gboolean is_ascii, gpointer user_data)
90 {
91   TestCallbackData *data = (TestCallbackData *) user_data;
92
93   if (is_ascii) {
94     switch (input) {
95       case 'k':
96         print_keyboard_help ();
97         break;
98       case 'q':
99       case 'Q':
100         gst_element_send_event (data->pipeline, gst_event_new_eos ());
101         g_main_loop_quit (loop);
102         break;
103       case '>':
104         bitrate += 100;
105         bitrate = MIN (bitrate, 2048000);
106         g_print ("Increase encoding bitrate to %d\n", bitrate);
107         g_object_set (G_OBJECT (data->nvenc), "bitrate", bitrate, NULL);
108         break;
109       case '<':
110         bitrate -= 100;
111         bitrate = MAX (bitrate, 100);
112         g_print ("Decrease encoding bitrate to %d\n", bitrate);
113         g_object_set (G_OBJECT (data->nvenc), "bitrate", bitrate, NULL);
114         break;
115       default:
116         break;
117     }
118
119     return;
120   }
121
122   switch (input) {
123     case KB_ARROW_RIGHT:
124       g_print ("Increase width to %d\n", ++width);
125       break;
126     case KB_ARROW_LEFT:
127       g_print ("Decrease width to %d\n", --width);
128       break;
129     case KB_ARROW_UP:
130       g_print ("Increase height to %d\n", ++height);
131       break;
132     case KB_ARROW_DOWN:
133       g_print ("Decrease height to %d\n", --height);
134       break;
135     default:
136       break;
137   }
138 }
139
140 static gboolean
141 bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
142 {
143   TestCallbackData *data = (TestCallbackData *) user_data;
144   GstElement *pipeline = data->pipeline;
145
146   switch (GST_MESSAGE_TYPE (msg)) {
147     case GST_MESSAGE_STATE_CHANGED:
148       if (GST_MESSAGE_SRC (msg) == GST_OBJECT_CAST (pipeline)) {
149         gchar *state_transition_name;
150         GstState old, new, pending;
151
152         gst_message_parse_state_changed (msg, &old, &new, &pending);
153
154         state_transition_name = g_strdup_printf ("%s_%s",
155             gst_element_state_get_name (old), gst_element_state_get_name (new));
156
157         /* dump graph for (some) pipeline state changes */
158         {
159           gchar *dump_name = g_strconcat ("nvcodec.", state_transition_name,
160               NULL);
161           GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
162               GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
163           g_free (dump_name);
164         }
165         g_free (state_transition_name);
166       }
167       break;
168     case GST_MESSAGE_ERROR:{
169       GError *err;
170       gchar *dbg;
171
172       GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
173           GST_DEBUG_GRAPH_SHOW_ALL, "nvcodec.error");
174
175       gst_message_parse_error (msg, &err, &dbg);
176       g_printerr ("ERROR %s \n", err->message);
177       if (dbg != NULL)
178         g_printerr ("ERROR debug information: %s\n", dbg);
179       g_clear_error (&err);
180       g_free (dbg);
181
182       g_main_loop_quit (loop);
183       break;
184     }
185     case GST_MESSAGE_ELEMENT:
186     {
187       GstNavigationMessageType mtype = gst_navigation_message_get_type (msg);
188       if (mtype == GST_NAVIGATION_MESSAGE_EVENT) {
189         GstEvent *ev = NULL;
190
191         if (gst_navigation_message_parse_event (msg, &ev)) {
192           GstNavigationEventType e_type = gst_navigation_event_get_type (ev);
193           if (e_type == GST_NAVIGATION_EVENT_KEY_PRESS) {
194             const gchar *key;
195             gchar val = 0;
196
197             if (gst_navigation_event_parse_key_event (ev, &key)) {
198               gboolean ascii = TRUE;
199
200               GST_INFO ("Key press: %s", key);
201
202               val = key[0];
203
204               if (g_strcmp0 (key, "Left") == 0) {
205                 val = KB_ARROW_LEFT;
206                 ascii = FALSE;
207               } else if (g_strcmp0 (key, "Right") == 0) {
208                 val = KB_ARROW_RIGHT;
209                 ascii = FALSE;
210               } else if (g_strcmp0 (key, "Up") == 0) {
211                 val = KB_ARROW_UP;
212                 ascii = FALSE;
213               } else if (g_strcmp0 (key, "Down") == 0) {
214                 val = KB_ARROW_DOWN;
215                 ascii = FALSE;
216               } else if (strlen (key) > 1) {
217                 break;
218               }
219
220               keyboard_cb (val, ascii, user_data);
221             }
222           }
223         }
224         if (ev)
225           gst_event_unref (ev);
226       }
227       break;
228     }
229     default:
230       break;
231   }
232
233   return TRUE;
234 }
235
236 static gboolean
237 check_nvcodec_available (const gchar * encoder_name)
238 {
239   gboolean ret = TRUE;
240   GstElement *elem;
241
242   elem = gst_element_factory_make (encoder_name, NULL);
243   if (!elem) {
244     GST_WARNING ("%s is not available, possibly driver load failure",
245         encoder_name);
246     return FALSE;
247   }
248
249   /* GST_STATE_READY is meaning that driver could be loaded */
250   if (gst_element_set_state (elem,
251           GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
252     GST_WARNING ("cannot open device");
253     ret = FALSE;
254   }
255
256   gst_element_set_state (elem, GST_STATE_NULL);
257   gst_object_unref (elem);
258
259   if (ret) {
260     elem = gst_element_factory_make ("nvh264dec", NULL);
261     if (!elem) {
262       GST_WARNING ("nvh264dec is not available, possibly driver load failure");
263       return FALSE;
264     }
265
266     /* GST_STATE_READY is meaning that driver could be loaded */
267     if (gst_element_set_state (elem,
268             GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
269       GST_WARNING ("cannot open device");
270       ret = FALSE;
271     }
272
273     gst_element_set_state (elem, GST_STATE_NULL);
274     gst_object_unref (elem);
275   }
276
277   return ret;
278 }
279
280 static GstPadProbeReturn
281 resolution_change_probe (GstPad * pad, GstPadProbeInfo * info,
282     gpointer user_data)
283 {
284   GstPadProbeReturn ret = GST_PAD_PROBE_OK;
285   TestCallbackData *data = (TestCallbackData *) user_data;
286
287   if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info))) {
288     GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
289     GstPad *peer = gst_pad_get_peer (pad);
290     GstFlowReturn flow_ret = GST_FLOW_OK;
291
292     ret = GST_PAD_PROBE_HANDLED;
293
294     if (peer) {
295       flow_ret = gst_pad_chain (peer, buffer);
296
297       if (flow_ret != GST_FLOW_OK) {
298         gst_pad_remove_probe (pad, data->probe_id);
299         data->probe_id = 0;
300       } else {
301         if (data->prev_width != width || data->prev_height != height) {
302           GstCaps *caps = NULL;
303           gint next_width, next_height;
304
305           next_width = width;
306           next_height = height;
307
308           g_object_get (data->capsfilter, "caps", &caps, NULL);
309           caps = gst_caps_make_writable (caps);
310           gst_caps_set_simple (caps,
311               "width", G_TYPE_INT, next_width, "height", G_TYPE_INT,
312               next_height, NULL);
313           g_object_set (data->capsfilter, "caps", caps, NULL);
314           gst_caps_unref (caps);
315
316           data->prev_width = next_width;
317           data->prev_height = next_height;
318         }
319       }
320     }
321   }
322
323   return ret;
324 }
325
326 gint
327 main (gint argc, gchar ** argv)
328 {
329   GstElement *pipeline, *src, *convert, *capsfilter, *queue, *sink, *parse;
330   GstElement *enc, *dec;
331   GstStateChangeReturn sret;
332   GError *error = NULL;
333   gboolean use_gl = FALSE;
334   gint exitcode = 1;
335   GOptionContext *option_ctx;
336   GstCaps *caps;
337   TestCallbackData data = { 0, };
338   GstPad *pad;
339   gchar *encoder_name = NULL;
340   /* *INDENT-OFF* */
341   GOptionEntry options[] = {
342     {"use-gl", 0, 0, G_OPTION_ARG_NONE, &use_gl,
343         "Use OpenGL memory as input to the nvenc", NULL},
344     {"encoder", 0, 0, G_OPTION_ARG_STRING, &encoder_name,
345         "NVENC encoder element to test, default: nvh264enc"},
346     {NULL}
347   };
348   /* *INDENT-ON* */
349
350   option_ctx = g_option_context_new ("nvcodec dynamic reconfigure example");
351   g_option_context_add_main_entries (option_ctx, options, NULL);
352   g_option_context_set_help_enabled (option_ctx, TRUE);
353   if (!g_option_context_parse (option_ctx, &argc, &argv, &error)) {
354     g_printerr ("option parsing failed: %s\n", error->message);
355     g_clear_error (&error);
356     exit (1);
357   }
358
359   g_option_context_free (option_ctx);
360   gst_init (NULL, NULL);
361
362   if (!encoder_name)
363     encoder_name = g_strdup ("nvh264enc");
364
365   if (!check_nvcodec_available (encoder_name)) {
366     g_printerr ("Cannot load nvcodec plugin");
367     exit (1);
368   }
369
370   /* prepare the pipeline */
371   loop = g_main_loop_new (NULL, FALSE);
372
373   pipeline = gst_pipeline_new ("nvcodec-example");
374
375   if (use_gl)
376     src = gst_element_factory_make ("gltestsrc", NULL);
377   else
378     src = gst_element_factory_make ("videotestsrc", NULL);
379
380   if (!src) {
381     g_printerr ("%s element is not available\n",
382         use_gl ? "gltestsrc" : "videotestsrc");
383     goto terminate;
384   }
385
386   gst_bin_add (GST_BIN (pipeline), src);
387
388   if (use_gl)
389     convert = gst_element_factory_make ("glcolorconvert", NULL);
390   else
391     convert = gst_element_factory_make ("videoconvert", NULL);
392
393   if (!convert) {
394     g_printerr ("%s element is not available\n",
395         use_gl ? "glcolorconvert" : "videoconvert");
396     goto terminate;
397   }
398
399   gst_bin_add (GST_BIN (pipeline), convert);
400
401   if (use_gl) {
402     sink = gst_element_factory_make ("glimagesink", NULL);
403   } else {
404     sink = gst_element_factory_make (DEFAULT_VIDEO_SINK, NULL);
405   }
406
407   if (!sink) {
408     g_printerr ("%s element is not available\n",
409         use_gl ? "glimagesink" : DEFAULT_VIDEO_SINK);
410     goto terminate;
411   }
412
413   gst_bin_add (GST_BIN (pipeline), sink);
414
415   capsfilter = gst_element_factory_make ("capsfilter", NULL);
416   queue = gst_element_factory_make ("queue", NULL);
417   enc = gst_element_factory_make (encoder_name, NULL);
418   parse = gst_element_factory_make ("h264parse", NULL);
419
420   g_object_set (G_OBJECT (enc), "bitrate", bitrate, NULL);
421
422   dec = gst_element_factory_make ("nvh264dec", NULL);
423
424   gst_bin_add_many (GST_BIN (pipeline), capsfilter, queue, enc, parse, dec,
425       NULL);
426
427   if (!use_gl) {
428     GstElement *sink_convert = gst_element_factory_make ("videoconvert", NULL);
429     gst_bin_add (GST_BIN (pipeline), sink_convert);
430
431     gst_element_link_many (src,
432         convert, capsfilter, enc, parse, dec, queue, sink_convert, sink, NULL);
433   } else {
434     gst_element_link_many (src,
435         convert, capsfilter, enc, parse, dec, queue, sink, NULL);
436   }
437
438   caps = gst_caps_from_string ("video/x-raw,format=NV12");
439
440   if (use_gl) {
441     gst_caps_set_features_simple (caps,
442         gst_caps_features_from_string ("memory:GLMemory"));
443   }
444
445   g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);
446   gst_caps_unref (caps);
447
448   data.pipeline = pipeline;
449   data.capsfilter = capsfilter;
450   data.nvenc = enc;
451
452   pad = gst_element_get_static_pad (convert, "src");
453   data.probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
454       (GstPadProbeCallback) resolution_change_probe, &data, NULL);
455   gst_object_unref (pad);
456   data.prev_width = width;
457   data.prev_height = height;
458
459   gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_msg, &data);
460
461   set_key_handler (keyboard_cb, &data);
462   g_print ("Press 'k' to see a list of keyboard shortcuts.\n");
463   atexit (unset_key_handler);
464
465   /* run the pipeline */
466   sret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
467   if (sret == GST_STATE_CHANGE_FAILURE) {
468     g_printerr ("Pipeline doesn't want to playing\n");
469   } else {
470     g_main_loop_run (loop);
471   }
472
473   gst_element_set_state (pipeline, GST_STATE_NULL);
474   gst_bus_remove_watch (GST_ELEMENT_BUS (pipeline));
475
476   exitcode = 0;
477
478 terminate:
479
480   gst_object_unref (pipeline);
481   g_main_loop_unref (loop);
482   g_free (encoder_name);
483
484   return exitcode;
485 }