2 * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
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.
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.
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.
25 #include <gst/video/video.h>
29 #define DEFAULT_VIDEO_SINK "autovideosink"
31 static GMainLoop *loop = NULL;
32 static gint width = 320;
33 static gint height = 240;
34 static gint bitrate = 2000;
39 GstElement *capsfilter;
48 restore_terminal (void)
50 gst_nvcodec_kb_set_key_handler (NULL, NULL);
54 print_keyboard_help (void)
58 const gchar *key_desc;
59 const gchar *key_help;
62 "q or ESC", "Quit"}, {
63 "right arrow", "Increase Width"}, {
64 "left arrow", "Decrease Width"}, {
65 "up arrow", "Increase Height"}, {
66 "down arrow", "Decrease Height"}, {
67 ">", "Increase encoding bitrate by 100 kbit/sec"}, {
68 "<", "Decrease encoding bitrate by 100 kbit/sec"}, {
69 "k", "show keyboard shortcuts"}
71 guint i, chars_to_pad, desc_len, max_desc_len = 0;
73 g_print ("\n\n%s\n\n", "Keyboard controls:");
75 for (i = 0; i < G_N_ELEMENTS (key_controls); ++i) {
76 desc_len = g_utf8_strlen (key_controls[i].key_desc, -1);
77 max_desc_len = MAX (max_desc_len, desc_len);
81 for (i = 0; i < G_N_ELEMENTS (key_controls); ++i) {
82 chars_to_pad = max_desc_len - g_utf8_strlen (key_controls[i].key_desc, -1);
83 g_print ("\t%s", key_controls[i].key_desc);
84 g_print ("%-*s: ", chars_to_pad, "");
85 g_print ("%s\n", key_controls[i].key_help);
91 keyboard_cb (const gchar * key_input, gpointer user_data)
93 TestCallbackData *data = (TestCallbackData *) user_data;
96 /* only want to switch/case on single char, not first char of string */
97 if (key_input[0] != '\0' && key_input[1] == '\0')
98 key = g_ascii_tolower (key_input[0]);
102 print_keyboard_help ();
106 gst_element_send_event (data->pipeline, gst_event_new_eos ());
107 g_main_loop_quit (loop);
110 if (key_input[1] == '\0') {
111 gst_element_send_event (data->pipeline, gst_event_new_eos ());
112 g_main_loop_quit (loop);
117 bitrate = MIN (bitrate, 2048000);
118 g_print ("Increase encoding bitrate to %d\n", bitrate);
119 g_object_set (G_OBJECT (data->nvenc), "bitrate", bitrate, NULL);
123 bitrate = MAX (bitrate, 100);
124 g_print ("Decrease encoding bitrate to %d\n", bitrate);
125 g_object_set (G_OBJECT (data->nvenc), "bitrate", bitrate, NULL);
128 if (strcmp (key_input, GST_NVCODEC_KB_ARROW_RIGHT) == 0) {
129 g_print ("Increase width to %d\n", ++width);
130 } else if (strcmp (key_input, GST_NVCODEC_KB_ARROW_LEFT) == 0) {
131 g_print ("Decrease width to %d\n", --width);
132 } else if (strcmp (key_input, GST_NVCODEC_KB_ARROW_UP) == 0) {
133 g_print ("Increase height to %d\n", ++height);
134 } else if (strcmp (key_input, GST_NVCODEC_KB_ARROW_DOWN) == 0) {
135 g_print ("Decrease height to %d\n", --height);
144 bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
146 TestCallbackData *data = (TestCallbackData *) user_data;
147 GstElement *pipeline = data->pipeline;
149 switch (GST_MESSAGE_TYPE (msg)) {
150 case GST_MESSAGE_STATE_CHANGED:
151 if (GST_MESSAGE_SRC (msg) == GST_OBJECT_CAST (pipeline)) {
152 gchar *state_transition_name;
153 GstState old, new, pending;
155 gst_message_parse_state_changed (msg, &old, &new, &pending);
157 state_transition_name = g_strdup_printf ("%s_%s",
158 gst_element_state_get_name (old), gst_element_state_get_name (new));
160 /* dump graph for (some) pipeline state changes */
162 gchar *dump_name = g_strconcat ("nvcodec.", state_transition_name,
164 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
165 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
168 g_free (state_transition_name);
171 case GST_MESSAGE_ERROR:{
175 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
176 GST_DEBUG_GRAPH_SHOW_ALL, "nvcodec.error");
178 gst_message_parse_error (msg, &err, &dbg);
179 g_printerr ("ERROR %s \n", err->message);
181 g_printerr ("ERROR debug information: %s\n", dbg);
182 g_clear_error (&err);
185 g_main_loop_quit (loop);
188 case GST_MESSAGE_ELEMENT:
190 GstNavigationMessageType mtype = gst_navigation_message_get_type (msg);
191 if (mtype == GST_NAVIGATION_MESSAGE_EVENT) {
194 if (gst_navigation_message_parse_event (msg, &ev)) {
195 GstNavigationEventType e_type = gst_navigation_event_get_type (ev);
196 if (e_type == GST_NAVIGATION_EVENT_KEY_PRESS) {
199 if (gst_navigation_event_parse_key_event (ev, &key)) {
200 GST_INFO ("Key press: %s", key);
202 if (strcmp (key, "Left") == 0)
203 key = GST_NVCODEC_KB_ARROW_LEFT;
204 else if (strcmp (key, "Right") == 0)
205 key = GST_NVCODEC_KB_ARROW_RIGHT;
206 else if (strcmp (key, "Up") == 0)
207 key = GST_NVCODEC_KB_ARROW_UP;
208 else if (strcmp (key, "Down") == 0)
209 key = GST_NVCODEC_KB_ARROW_DOWN;
210 else if (strlen (key) > 1)
213 keyboard_cb (key, user_data);
218 gst_event_unref (ev);
230 check_nvcodec_available (void)
235 elem = gst_element_factory_make ("nvh264enc", NULL);
237 GST_WARNING ("nvh264enc is not available, possibly driver load failure");
241 /* GST_STATE_READY is meaning that driver could be loaded */
242 if (gst_element_set_state (elem,
243 GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
244 GST_WARNING ("cannot open device");
248 gst_element_set_state (elem, GST_STATE_NULL);
249 gst_object_unref (elem);
252 elem = gst_element_factory_make ("nvh264dec", NULL);
254 GST_WARNING ("nvh264dec is not available, possibly driver load failure");
258 /* GST_STATE_READY is meaning that driver could be loaded */
259 if (gst_element_set_state (elem,
260 GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
261 GST_WARNING ("cannot open device");
265 gst_element_set_state (elem, GST_STATE_NULL);
266 gst_object_unref (elem);
272 static GstPadProbeReturn
273 resolution_change_probe (GstPad * pad, GstPadProbeInfo * info,
276 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
277 TestCallbackData *data = (TestCallbackData *) user_data;
279 if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info))) {
280 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
281 GstPad *peer = gst_pad_get_peer (pad);
282 GstFlowReturn flow_ret = GST_FLOW_OK;
284 ret = GST_PAD_PROBE_HANDLED;
287 flow_ret = gst_pad_chain (peer, buffer);
289 if (flow_ret != GST_FLOW_OK) {
290 gst_pad_remove_probe (pad, data->probe_id);
293 if (data->prev_width != width || data->prev_height != height) {
294 GstCaps *caps = NULL;
295 gint next_width, next_height;
298 next_height = height;
300 g_object_get (data->capsfilter, "caps", &caps, NULL);
301 caps = gst_caps_make_writable (caps);
302 gst_caps_set_simple (caps,
303 "width", G_TYPE_INT, next_width, "height", G_TYPE_INT,
305 g_object_set (data->capsfilter, "caps", caps, NULL);
306 gst_caps_unref (caps);
308 data->prev_width = next_width;
309 data->prev_height = next_height;
319 main (gint argc, gchar ** argv)
321 GstElement *pipeline, *src, *convert, *capsfilter, *queue, *sink, *parse;
322 GstElement *enc, *dec;
323 GstStateChangeReturn sret;
324 GError *error = NULL;
325 gboolean use_gl = FALSE;
327 GOptionContext *option_ctx;
329 TestCallbackData data = { 0, };
332 GOptionEntry options[] = {
333 {"use-gl", 0, 0, G_OPTION_ARG_NONE, &use_gl,
334 "Use OpenGL memory as input to the nvenc", NULL}
339 option_ctx = g_option_context_new ("nvcodec dynamic reconfigure example");
340 g_option_context_add_main_entries (option_ctx, options, NULL);
341 g_option_context_set_help_enabled (option_ctx, TRUE);
342 if (!g_option_context_parse (option_ctx, &argc, &argv, &error)) {
343 g_printerr ("option parsing failed: %s\n", error->message);
344 g_clear_error (&error);
348 g_option_context_free (option_ctx);
349 gst_init (NULL, NULL);
351 if (!check_nvcodec_available ()) {
352 g_printerr ("Cannot load nvcodec plugin");
356 /* prepare the pipeline */
357 loop = g_main_loop_new (NULL, FALSE);
359 pipeline = gst_pipeline_new ("nvcodec-example");
362 src = gst_element_factory_make ("gltestsrc", NULL);
364 src = gst_element_factory_make ("videotestsrc", NULL);
367 g_printerr ("%s element is not available\n",
368 use_gl ? "gltestsrc" : "videotestsrc");
372 gst_bin_add (GST_BIN (pipeline), src);
375 convert = gst_element_factory_make ("glcolorconvert", NULL);
377 convert = gst_element_factory_make ("videoconvert", NULL);
380 g_printerr ("%s element is not available\n",
381 use_gl ? "glcolorconvert" : "videoconvert");
385 gst_bin_add (GST_BIN (pipeline), convert);
388 sink = gst_element_factory_make ("glimagesink", NULL);
390 sink = gst_element_factory_make (DEFAULT_VIDEO_SINK, NULL);
394 g_printerr ("%s element is not available\n",
395 use_gl ? "glimagesink" : DEFAULT_VIDEO_SINK);
399 gst_bin_add (GST_BIN (pipeline), sink);
401 capsfilter = gst_element_factory_make ("capsfilter", NULL);
402 queue = gst_element_factory_make ("queue", NULL);
403 enc = gst_element_factory_make ("nvh264enc", NULL);
404 parse = gst_element_factory_make ("h264parse", NULL);
406 /* vbr with target bitrate */
407 g_object_set (G_OBJECT (enc), "rc-mode", 4, "bitrate", bitrate, NULL);
409 dec = gst_element_factory_make ("nvh264dec", NULL);
411 gst_bin_add_many (GST_BIN (pipeline), capsfilter, queue, enc, parse, dec,
415 GstElement *sink_convert = gst_element_factory_make ("videoconvert", NULL);
416 gst_bin_add (GST_BIN (pipeline), sink_convert);
418 gst_element_link_many (src,
419 convert, capsfilter, enc, parse, dec, queue, sink_convert, sink, NULL);
421 gst_element_link_many (src,
422 convert, capsfilter, enc, parse, dec, queue, sink, NULL);
425 caps = gst_caps_from_string ("video/x-raw,format=NV12");
428 gst_caps_set_features_simple (caps,
429 gst_caps_features_from_string ("memory:GLMemory"));
432 g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);
433 gst_caps_unref (caps);
435 data.pipeline = pipeline;
436 data.capsfilter = capsfilter;
439 pad = gst_element_get_static_pad (convert, "src");
440 data.probe_id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER,
441 (GstPadProbeCallback) resolution_change_probe, &data, NULL);
442 gst_object_unref (pad);
443 data.prev_width = width;
444 data.prev_height = height;
446 gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_msg, &data);
448 if (gst_nvcodec_kb_set_key_handler (keyboard_cb, &data)) {
449 g_print ("Press 'k' to see a list of keyboard shortcuts.\n");
450 atexit (restore_terminal);
453 /* run the pipeline */
454 sret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
455 if (sret == GST_STATE_CHANGE_FAILURE) {
456 g_printerr ("Pipeline doesn't want to playing\n");
458 g_main_loop_run (loop);
461 gst_element_set_state (pipeline, GST_STATE_NULL);
462 gst_bus_remove_watch (GST_ELEMENT_BUS (pipeline));
468 gst_object_unref (pipeline);
469 g_main_loop_unref (loop);