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>
28 #include "../key-handler.h"
30 #define DEFAULT_VIDEO_SINK "autovideosink"
32 static GMainLoop *loop = NULL;
33 static gint width = 320;
34 static gint height = 240;
35 static gint bitrate = 2000;
40 GstElement *capsfilter;
49 print_keyboard_help (void)
54 const gchar *key_desc;
55 const gchar *key_help;
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"}
69 guint i, chars_to_pad, desc_len, max_desc_len = 0;
71 g_print ("\n\n%s\n\n", "Keyboard controls:");
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);
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);
89 keyboard_cb (gchar input, gboolean is_ascii, gpointer user_data)
91 TestCallbackData *data = (TestCallbackData *) user_data;
96 print_keyboard_help ();
100 gst_element_send_event (data->pipeline, gst_event_new_eos ());
101 g_main_loop_quit (loop);
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);
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);
124 g_print ("Increase width to %d\n", ++width);
127 g_print ("Decrease width to %d\n", --width);
130 g_print ("Increase height to %d\n", ++height);
133 g_print ("Decrease height to %d\n", --height);
141 bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
143 TestCallbackData *data = (TestCallbackData *) user_data;
144 GstElement *pipeline = data->pipeline;
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;
152 gst_message_parse_state_changed (msg, &old, &new, &pending);
154 state_transition_name = g_strdup_printf ("%s_%s",
155 gst_element_state_get_name (old), gst_element_state_get_name (new));
157 /* dump graph for (some) pipeline state changes */
159 gchar *dump_name = g_strconcat ("nvcodec.", state_transition_name,
161 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
162 GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
165 g_free (state_transition_name);
168 case GST_MESSAGE_ERROR:{
172 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
173 GST_DEBUG_GRAPH_SHOW_ALL, "nvcodec.error");
175 gst_message_parse_error (msg, &err, &dbg);
176 g_printerr ("ERROR %s \n", err->message);
178 g_printerr ("ERROR debug information: %s\n", dbg);
179 g_clear_error (&err);
182 g_main_loop_quit (loop);
185 case GST_MESSAGE_ELEMENT:
187 GstNavigationMessageType mtype = gst_navigation_message_get_type (msg);
188 if (mtype == GST_NAVIGATION_MESSAGE_EVENT) {
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) {
197 if (gst_navigation_event_parse_key_event (ev, &key)) {
198 gboolean ascii = TRUE;
200 GST_INFO ("Key press: %s", key);
204 if (g_strcmp0 (key, "Left") == 0) {
207 } else if (g_strcmp0 (key, "Right") == 0) {
208 val = KB_ARROW_RIGHT;
210 } else if (g_strcmp0 (key, "Up") == 0) {
213 } else if (g_strcmp0 (key, "Down") == 0) {
216 } else if (strlen (key) > 1) {
220 keyboard_cb (val, ascii, user_data);
225 gst_event_unref (ev);
237 check_nvcodec_available (const gchar * encoder_name)
242 elem = gst_element_factory_make (encoder_name, NULL);
244 GST_WARNING ("%s is not available, possibly driver load failure",
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");
256 gst_element_set_state (elem, GST_STATE_NULL);
257 gst_object_unref (elem);
260 elem = gst_element_factory_make ("nvh264dec", NULL);
262 GST_WARNING ("nvh264dec is not available, possibly driver load failure");
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");
273 gst_element_set_state (elem, GST_STATE_NULL);
274 gst_object_unref (elem);
280 static GstPadProbeReturn
281 resolution_change_probe (GstPad * pad, GstPadProbeInfo * info,
284 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
285 TestCallbackData *data = (TestCallbackData *) user_data;
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;
292 ret = GST_PAD_PROBE_HANDLED;
295 flow_ret = gst_pad_chain (peer, buffer);
297 if (flow_ret != GST_FLOW_OK) {
298 gst_pad_remove_probe (pad, data->probe_id);
301 if (data->prev_width != width || data->prev_height != height) {
302 GstCaps *caps = NULL;
303 gint next_width, next_height;
306 next_height = height;
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,
313 g_object_set (data->capsfilter, "caps", caps, NULL);
314 gst_caps_unref (caps);
316 data->prev_width = next_width;
317 data->prev_height = next_height;
327 main (gint argc, gchar ** argv)
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;
335 GOptionContext *option_ctx;
337 TestCallbackData data = { 0, };
339 gchar *encoder_name = NULL;
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"},
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);
359 g_option_context_free (option_ctx);
360 gst_init (NULL, NULL);
363 encoder_name = g_strdup ("nvh264enc");
365 if (!check_nvcodec_available (encoder_name)) {
366 g_printerr ("Cannot load nvcodec plugin");
370 /* prepare the pipeline */
371 loop = g_main_loop_new (NULL, FALSE);
373 pipeline = gst_pipeline_new ("nvcodec-example");
376 src = gst_element_factory_make ("gltestsrc", NULL);
378 src = gst_element_factory_make ("videotestsrc", NULL);
381 g_printerr ("%s element is not available\n",
382 use_gl ? "gltestsrc" : "videotestsrc");
386 gst_bin_add (GST_BIN (pipeline), src);
389 convert = gst_element_factory_make ("glcolorconvert", NULL);
391 convert = gst_element_factory_make ("videoconvert", NULL);
394 g_printerr ("%s element is not available\n",
395 use_gl ? "glcolorconvert" : "videoconvert");
399 gst_bin_add (GST_BIN (pipeline), convert);
402 sink = gst_element_factory_make ("glimagesink", NULL);
404 sink = gst_element_factory_make (DEFAULT_VIDEO_SINK, NULL);
408 g_printerr ("%s element is not available\n",
409 use_gl ? "glimagesink" : DEFAULT_VIDEO_SINK);
413 gst_bin_add (GST_BIN (pipeline), sink);
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);
420 g_object_set (G_OBJECT (enc), "bitrate", bitrate, NULL);
422 dec = gst_element_factory_make ("nvh264dec", NULL);
424 gst_bin_add_many (GST_BIN (pipeline), capsfilter, queue, enc, parse, dec,
428 GstElement *sink_convert = gst_element_factory_make ("videoconvert", NULL);
429 gst_bin_add (GST_BIN (pipeline), sink_convert);
431 gst_element_link_many (src,
432 convert, capsfilter, enc, parse, dec, queue, sink_convert, sink, NULL);
434 gst_element_link_many (src,
435 convert, capsfilter, enc, parse, dec, queue, sink, NULL);
438 caps = gst_caps_from_string ("video/x-raw,format=NV12");
441 gst_caps_set_features_simple (caps,
442 gst_caps_features_from_string ("memory:GLMemory"));
445 g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);
446 gst_caps_unref (caps);
448 data.pipeline = pipeline;
449 data.capsfilter = capsfilter;
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;
459 gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_msg, &data);
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);
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");
470 g_main_loop_run (loop);
473 gst_element_set_state (pipeline, GST_STATE_NULL);
474 gst_bus_remove_watch (GST_ELEMENT_BUS (pipeline));
480 gst_object_unref (pipeline);
481 g_main_loop_unref (loop);
482 g_free (encoder_name);