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.
20 #include <gst/check/gstcheck.h>
21 #include <gst/check/gstharness.h>
23 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
26 GST_STATIC_CAPS ("video/x-h264, "
27 "width = (int) [1, MAX], "
28 "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]"));
30 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
33 GST_STATIC_CAPS ("video/x-raw, "
34 "format = (string) NV12, "
35 "width = (int) [1, MAX], "
36 "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]"));
38 static GstPad *sinkpad, *srcpad;
41 setup_nvenc (const gchar * src_caps_str, GstCaps ** srccaps)
47 caps = gst_caps_from_string (src_caps_str);
48 fail_unless (caps != NULL);
50 nvenc = gst_check_setup_element ("nvh264enc");
51 fail_unless (nvenc != NULL);
52 srcpad = gst_check_setup_src_pad (nvenc, &srctemplate);
53 sinkpad = gst_check_setup_sink_pad (nvenc, &sinktemplate);
54 gst_pad_set_active (srcpad, TRUE);
55 gst_pad_set_active (sinkpad, TRUE);
58 gst_element_set_bus (nvenc, bus);
67 cleanup_nvenc (GstElement * nvenc)
71 /* Free parsed buffers */
72 gst_check_drop_buffers ();
74 bus = GST_ELEMENT_BUS (nvenc);
75 gst_bus_set_flushing (bus, TRUE);
76 gst_object_unref (bus);
78 gst_pad_set_active (srcpad, FALSE);
79 gst_pad_set_active (sinkpad, FALSE);
80 gst_check_teardown_src_pad (nvenc);
81 gst_check_teardown_sink_pad (nvenc);
82 gst_check_teardown_element (nvenc);
85 GST_START_TEST (test_encode_simple)
91 GstCaps *outcaps, *sinkcaps, *srccaps;
96 ("video/x-raw,format=(string)NV12,width=(int)320,height=(int)240,"
97 "framerate=(fraction)25/1,interlace-mode=(string)progressive", &srccaps);
99 ASSERT_SET_STATE (nvenc, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
101 gst_segment_init (&seg, GST_FORMAT_TIME);
102 seg.stop = gst_util_uint64_scale (10, GST_SECOND, 25);
104 gst_check_setup_events (srcpad, nvenc, srccaps, GST_FORMAT_TIME);
105 fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
107 buffer = gst_buffer_new_allocate (NULL, 320 * 240 + 2 * 160 * 120, NULL);
108 gst_buffer_memset (buffer, 0, 0, -1);
110 for (i = 0; i < 10; i++) {
111 GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (i, GST_SECOND, 25);
112 GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25);
113 fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK);
116 gst_buffer_unref (buffer);
118 fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
120 /* All buffers must be there now */
121 fail_unless_equals_int (g_list_length (buffers), 10);
125 ("video/x-h264,width=(int)320,height=(int)240,framerate=(fraction)25/1");
127 for (iter = buffers; iter; iter = g_list_next (iter)) {
130 fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer),
131 gst_util_uint64_scale (1, GST_SECOND, 25));
133 sinkcaps = gst_pad_get_current_caps (sinkpad);
134 fail_unless (gst_caps_can_intersect (sinkcaps, outcaps));
135 gst_caps_unref (sinkcaps);
138 gst_caps_unref (outcaps);
139 gst_caps_unref (srccaps);
141 cleanup_nvenc (nvenc);
147 GST_START_TEST (test_reuse)
153 GstCaps *outcaps, *sinkcaps;
159 ("video/x-raw,format=(string)NV12,width=(int)320,height=(int)240,"
160 "framerate=(fraction)25/1,interlace-mode=(string)progressive", &srccaps);
162 for (loop = 0; loop < 2; loop++) {
163 ASSERT_SET_STATE (nvenc, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
165 gst_segment_init (&seg, GST_FORMAT_TIME);
166 seg.stop = gst_util_uint64_scale (10, GST_SECOND, 25);
168 gst_check_setup_events (srcpad, nvenc, srccaps, GST_FORMAT_TIME);
169 fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
171 gst_segment_init (&seg, GST_FORMAT_TIME);
172 seg.stop = gst_util_uint64_scale (10, GST_SECOND, 25);
174 fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
176 buffer = gst_buffer_new_allocate (NULL, 320 * 240 + 2 * 160 * 120, NULL);
177 gst_buffer_memset (buffer, 0, 0, -1);
179 for (i = 0; i < 10; i++) {
180 GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (i, GST_SECOND, 25);
181 GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25);
182 fail_unless (gst_pad_push (srcpad,
183 gst_buffer_ref (buffer)) == GST_FLOW_OK);
186 gst_buffer_unref (buffer);
188 fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
190 /* All buffers must be there now */
191 fail_unless_equals_int (g_list_length (buffers), 10);
195 ("video/x-h264,width=(int)320,height=(int)240,framerate=(fraction)25/1");
197 for (iter = buffers; iter; iter = g_list_next (iter)) {
200 fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer),
201 gst_util_uint64_scale (1, GST_SECOND, 25));
203 sinkcaps = gst_pad_get_current_caps (sinkpad);
204 fail_unless (gst_caps_can_intersect (sinkcaps, outcaps));
205 gst_caps_unref (sinkcaps);
207 gst_check_drop_buffers ();
208 gst_caps_unref (outcaps);
210 ASSERT_SET_STATE (nvenc, GST_STATE_READY, GST_STATE_CHANGE_SUCCESS);
213 gst_caps_unref (srccaps);
215 cleanup_nvenc (nvenc);
220 GST_START_TEST (test_caps_interlace_mode)
224 GstCaps *caps, *srccaps;
229 ("video/x-raw,format=(string)NV12,width=(int)320,height=(int)240,"
230 "framerate=(fraction)25/1", &srccaps);
232 ASSERT_SET_STATE (nvenc, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
234 gst_check_setup_events (srcpad, nvenc, srccaps, GST_FORMAT_TIME);
235 gst_segment_init (&seg, GST_FORMAT_TIME);
236 fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
238 buffer = gst_buffer_new_allocate (NULL, 320 * 240 + 2 * 160 * 120, NULL);
239 gst_buffer_memset (buffer, 0, 0, -1);
241 /* empty interlace-mode */
242 GST_BUFFER_TIMESTAMP (buffer) = 0;
243 GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25);
244 fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK);
246 /* always valid interlace mode */
249 ("video/x-raw,format=(string)NV12,width=(int)320,height=(int)240,"
250 "framerate=(fraction)25/1,interlace-mode=(string)progressive");
251 fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps)));
252 gst_caps_unref (caps);
254 GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25);
255 GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25);
256 fail_unless (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK);
258 /* not-supported interlace mode */
261 ("video/x-raw,format=(string)NV12,width=(int)320,height=(int)240,"
262 "framerate=(fraction)25/1,interlace-mode=(string)alternate");
263 fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps)));
264 gst_caps_unref (caps);
266 GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (2, GST_SECOND, 25);
267 GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (1, GST_SECOND, 25);
268 fail_if (gst_pad_push (srcpad, gst_buffer_ref (buffer)) == GST_FLOW_OK);
269 gst_buffer_unref (buffer);
270 gst_caps_unref (srccaps);
272 cleanup_nvenc (nvenc);
277 #define MAX_PUSH_BUFFER 64
280 resolution_change_common (gint from_width, gint from_height, gint to_width,
286 GstBuffer *in_buf, *out_buf = NULL;
290 h = gst_harness_new_parse ("nvh264enc ! h264parse");
291 fail_unless (h != NULL);
293 gst_harness_play (h);
295 caps = gst_caps_from_string ("video/x-raw,format=NV12");
296 gst_caps_set_simple (caps, "width", G_TYPE_INT, from_width,
297 "height", G_TYPE_INT, from_height, NULL);
298 gst_harness_set_src_caps (h, caps);
300 in_buf = gst_buffer_new_and_alloc ((from_width * from_height) * 3 / 2);
301 gst_buffer_memset (in_buf, 0, 0, -1);
303 GST_BUFFER_DURATION (in_buf) = GST_SECOND;
304 GST_BUFFER_DTS (in_buf) = GST_CLOCK_TIME_NONE;
306 /* Push buffers until get encoder output */
308 fail_if (i > MAX_PUSH_BUFFER);
310 GST_BUFFER_PTS (in_buf) = i * GST_SECOND;
312 ret = gst_harness_push (h, gst_buffer_ref (in_buf));
313 fail_unless (ret == GST_FLOW_OK, "GstFlowReturn was %s",
314 gst_flow_get_name (ret));
316 out_buf = gst_harness_try_pull (h);
318 } while (out_buf == NULL);
319 gst_buffer_unref (out_buf);
320 gst_buffer_unref (in_buf);
322 /* change resolution */
323 caps = gst_caps_from_string ("video/x-raw,format=NV12");
324 gst_caps_set_simple (caps, "width", G_TYPE_INT, to_width,
325 "height", G_TYPE_INT, to_width, NULL);
327 GST_DEBUG ("Set new resolution %dx%d", to_width, to_height);
328 gst_harness_set_src_caps (h, caps);
329 in_buf = gst_buffer_new_and_alloc ((to_width * to_height) * 3 / 2);
330 gst_buffer_memset (in_buf, 0, 0, -1);
332 GST_BUFFER_PTS (in_buf) = i * GST_SECOND;
334 ret = gst_harness_push (h, gst_buffer_ref (in_buf));
335 fail_unless (ret == GST_FLOW_OK, "GstFlowReturn was %s",
336 gst_flow_get_name (ret));
338 /* push EOS to drain all buffers */
339 fail_unless (gst_harness_push_event (h, gst_event_new_eos ()));
342 gboolean term = FALSE;
343 event = gst_harness_pull_event (h);
344 /* wait until get EOS event */
346 if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)
349 gst_event_unref (event);
354 } while (out_buf == NULL);
356 /* check the last resolution from caps */
357 caps = gst_pad_get_current_caps (h->sinkpad);
358 fail_unless (caps != NULL);
360 GST_DEBUG ("last encoder src caps %" GST_PTR_FORMAT, caps);
365 s = gst_caps_get_structure (caps, 0);
366 fail_unless_equals_string (gst_structure_get_name (s), "video/x-h264");
367 fail_unless (gst_structure_get_int (s, "width", &val));
368 fail_unless_equals_int (val, to_width);
369 fail_unless (gst_structure_get_int (s, "height", &val));
370 fail_unless_equals_int (val, to_height);
372 gst_caps_unref (caps);
374 gst_harness_teardown (h);
377 GST_START_TEST (test_resolution_change_to_larger)
379 resolution_change_common (64, 64, 128, 128);
384 GST_START_TEST (test_resolution_change_to_smaller)
386 resolution_change_common (128, 128, 64, 64);
392 check_nvenc_available (void)
397 nvenc = gst_element_factory_make ("nvh264enc", NULL);
399 GST_WARNING ("nvh264enc is not available, possibly driver load failure");
403 /* GST_STATE_READY is meaning that driver could be loaded */
404 if (gst_element_set_state (nvenc,
405 GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
406 GST_WARNING ("cannot open device");
410 gst_element_set_state (nvenc, GST_STATE_NULL);
411 gst_object_unref (nvenc);
422 /* HACK: cuda device init/deinit with fork seems to problematic */
423 g_setenv ("CK_FORK", "no", TRUE);
425 s = suite_create ("nvenc");
426 tc_chain = tcase_create ("general");
428 suite_add_tcase (s, tc_chain);
430 if (!check_nvenc_available ()) {
431 GST_DEBUG ("Skip nvenc test since cannot open device");
435 tcase_add_test (tc_chain, test_encode_simple);
436 tcase_add_test (tc_chain, test_reuse);
437 tcase_add_test (tc_chain, test_caps_interlace_mode);
438 tcase_add_test (tc_chain, test_resolution_change_to_larger);
439 tcase_add_test (tc_chain, test_resolution_change_to_smaller);
445 GST_CHECK_MAIN (nvenc);