tests: nvenc: Test runtime resolution change
[platform/upstream/gstreamer.git] / tests / check / elements / nvenc.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 #include <gst/check/gstcheck.h>
21 #include <gst/check/gstharness.h>
22
23 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
24     GST_PAD_SINK,
25     GST_PAD_ALWAYS,
26     GST_STATIC_CAPS ("video/x-h264, "
27         "width = (int) [1, MAX], "
28         "height = (int) [1, MAX], " "framerate = (fraction) [0, MAX]"));
29
30 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
31     GST_PAD_SRC,
32     GST_PAD_ALWAYS,
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]"));
37
38 static GstPad *sinkpad, *srcpad;
39
40 static GstElement *
41 setup_nvenc (const gchar * src_caps_str, GstCaps ** srccaps)
42 {
43   GstElement *nvenc;
44   GstCaps *caps = NULL;
45   GstBus *bus;
46
47   caps = gst_caps_from_string (src_caps_str);
48   fail_unless (caps != NULL);
49
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);
56
57   bus = gst_bus_new ();
58   gst_element_set_bus (nvenc, bus);
59
60   *srccaps = caps;
61
62   buffers = NULL;
63   return nvenc;
64 }
65
66 static void
67 cleanup_nvenc (GstElement * nvenc)
68 {
69   GstBus *bus;
70
71   /* Free parsed buffers */
72   gst_check_drop_buffers ();
73
74   bus = GST_ELEMENT_BUS (nvenc);
75   gst_bus_set_flushing (bus, TRUE);
76   gst_object_unref (bus);
77
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);
83 }
84
85 GST_START_TEST (test_encode_simple)
86 {
87   GstElement *nvenc;
88   GstBuffer *buffer;
89   gint i;
90   GList *iter;
91   GstCaps *outcaps, *sinkcaps, *srccaps;
92   GstSegment seg;
93
94   nvenc =
95       setup_nvenc
96       ("video/x-raw,format=(string)NV12,width=(int)320,height=(int)240,"
97       "framerate=(fraction)25/1,interlace-mode=(string)progressive", &srccaps);
98
99   ASSERT_SET_STATE (nvenc, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
100
101   gst_segment_init (&seg, GST_FORMAT_TIME);
102   seg.stop = gst_util_uint64_scale (10, GST_SECOND, 25);
103
104   gst_check_setup_events (srcpad, nvenc, srccaps, GST_FORMAT_TIME);
105   fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
106
107   buffer = gst_buffer_new_allocate (NULL, 320 * 240 + 2 * 160 * 120, NULL);
108   gst_buffer_memset (buffer, 0, 0, -1);
109
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);
114   }
115
116   gst_buffer_unref (buffer);
117
118   fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
119
120   /* All buffers must be there now */
121   fail_unless_equals_int (g_list_length (buffers), 10);
122
123   outcaps =
124       gst_caps_from_string
125       ("video/x-h264,width=(int)320,height=(int)240,framerate=(fraction)25/1");
126
127   for (iter = buffers; iter; iter = g_list_next (iter)) {
128     buffer = iter->data;
129
130     fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer),
131         gst_util_uint64_scale (1, GST_SECOND, 25));
132
133     sinkcaps = gst_pad_get_current_caps (sinkpad);
134     fail_unless (gst_caps_can_intersect (sinkcaps, outcaps));
135     gst_caps_unref (sinkcaps);
136   }
137
138   gst_caps_unref (outcaps);
139   gst_caps_unref (srccaps);
140
141   cleanup_nvenc (nvenc);
142 }
143
144 GST_END_TEST;
145
146
147 GST_START_TEST (test_reuse)
148 {
149   GstElement *nvenc;
150   GstBuffer *buffer;
151   gint i, loop;
152   GList *iter;
153   GstCaps *outcaps, *sinkcaps;
154   GstSegment seg;
155   GstCaps *srccaps;
156
157   nvenc =
158       setup_nvenc
159       ("video/x-raw,format=(string)NV12,width=(int)320,height=(int)240,"
160       "framerate=(fraction)25/1,interlace-mode=(string)progressive", &srccaps);
161
162   for (loop = 0; loop < 2; loop++) {
163     ASSERT_SET_STATE (nvenc, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
164
165     gst_segment_init (&seg, GST_FORMAT_TIME);
166     seg.stop = gst_util_uint64_scale (10, GST_SECOND, 25);
167
168     gst_check_setup_events (srcpad, nvenc, srccaps, GST_FORMAT_TIME);
169     fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
170
171     gst_segment_init (&seg, GST_FORMAT_TIME);
172     seg.stop = gst_util_uint64_scale (10, GST_SECOND, 25);
173
174     fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&seg)));
175
176     buffer = gst_buffer_new_allocate (NULL, 320 * 240 + 2 * 160 * 120, NULL);
177     gst_buffer_memset (buffer, 0, 0, -1);
178
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);
184     }
185
186     gst_buffer_unref (buffer);
187
188     fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
189
190     /* All buffers must be there now */
191     fail_unless_equals_int (g_list_length (buffers), 10);
192
193     outcaps =
194         gst_caps_from_string
195         ("video/x-h264,width=(int)320,height=(int)240,framerate=(fraction)25/1");
196
197     for (iter = buffers; iter; iter = g_list_next (iter)) {
198       buffer = iter->data;
199
200       fail_unless_equals_uint64 (GST_BUFFER_DURATION (buffer),
201           gst_util_uint64_scale (1, GST_SECOND, 25));
202
203       sinkcaps = gst_pad_get_current_caps (sinkpad);
204       fail_unless (gst_caps_can_intersect (sinkcaps, outcaps));
205       gst_caps_unref (sinkcaps);
206     }
207     gst_check_drop_buffers ();
208     gst_caps_unref (outcaps);
209
210     ASSERT_SET_STATE (nvenc, GST_STATE_READY, GST_STATE_CHANGE_SUCCESS);
211   }
212
213   gst_caps_unref (srccaps);
214
215   cleanup_nvenc (nvenc);
216 }
217
218 GST_END_TEST;
219
220 GST_START_TEST (test_caps_interlace_mode)
221 {
222   GstElement *nvenc;
223   GstBuffer *buffer;
224   GstCaps *caps, *srccaps;
225   GstSegment seg;
226
227   nvenc =
228       setup_nvenc
229       ("video/x-raw,format=(string)NV12,width=(int)320,height=(int)240,"
230       "framerate=(fraction)25/1", &srccaps);
231
232   ASSERT_SET_STATE (nvenc, GST_STATE_PLAYING, GST_STATE_CHANGE_SUCCESS);
233
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)));
237
238   buffer = gst_buffer_new_allocate (NULL, 320 * 240 + 2 * 160 * 120, NULL);
239   gst_buffer_memset (buffer, 0, 0, -1);
240
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);
245
246   /* always valid interlace mode */
247   caps =
248       gst_caps_from_string
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);
253
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);
257
258   /* not-supported interlace mode */
259   caps =
260       gst_caps_from_string
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);
265
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);
271
272   cleanup_nvenc (nvenc);
273 }
274
275 GST_END_TEST;
276
277 #define MAX_PUSH_BUFFER 64
278
279 static void
280 resolution_change_common (gint from_width, gint from_height, gint to_width,
281     gint to_height)
282 {
283   GstHarness *h;
284   GstCaps *caps;
285   GstEvent *event;
286   GstBuffer *in_buf, *out_buf = NULL;
287   GstFlowReturn ret;
288   gint i = 0;
289
290   h = gst_harness_new_parse ("nvh264enc ! h264parse");
291   fail_unless (h != NULL);
292
293   gst_harness_play (h);
294
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);
299
300   in_buf = gst_buffer_new_and_alloc ((from_width * from_height) * 3 / 2);
301   gst_buffer_memset (in_buf, 0, 0, -1);
302
303   GST_BUFFER_DURATION (in_buf) = GST_SECOND;
304   GST_BUFFER_DTS (in_buf) = GST_CLOCK_TIME_NONE;
305
306   /* Push buffers until get encoder output */
307   do {
308     fail_if (i > MAX_PUSH_BUFFER);
309
310     GST_BUFFER_PTS (in_buf) = i * GST_SECOND;
311
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));
315
316     out_buf = gst_harness_try_pull (h);
317     i++;
318   } while (out_buf == NULL);
319   gst_buffer_unref (out_buf);
320   gst_buffer_unref (in_buf);
321
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);
326
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);
331
332   GST_BUFFER_PTS (in_buf) = i * GST_SECOND;
333
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));
337
338   /* push EOS to drain all buffers */
339   fail_unless (gst_harness_push_event (h, gst_event_new_eos ()));
340
341   do {
342     gboolean term = FALSE;
343     event = gst_harness_pull_event (h);
344     /* wait until get EOS event */
345     if (event) {
346       if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)
347         term = TRUE;
348
349       gst_event_unref (event);
350
351       if (term)
352         break;
353     }
354   } while (out_buf == NULL);
355
356   /* check the last resolution from caps */
357   caps = gst_pad_get_current_caps (h->sinkpad);
358   fail_unless (caps != NULL);
359
360   GST_DEBUG ("last encoder src caps %" GST_PTR_FORMAT, caps);
361   {
362     gint val;
363     GstStructure *s;
364
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);
371   }
372   gst_caps_unref (caps);
373
374   gst_harness_teardown (h);
375 }
376
377 GST_START_TEST (test_resolution_change_to_larger)
378 {
379   resolution_change_common (64, 64, 128, 128);
380 }
381
382 GST_END_TEST;
383
384 GST_START_TEST (test_resolution_change_to_smaller)
385 {
386   resolution_change_common (128, 128, 64, 64);
387 }
388
389 GST_END_TEST;
390
391 static gboolean
392 check_nvenc_available (void)
393 {
394   gboolean ret = TRUE;
395   GstElement *nvenc;
396
397   nvenc = gst_element_factory_make ("nvh264enc", NULL);
398   if (!nvenc) {
399     GST_WARNING ("nvh264enc is not available, possibly driver load failure");
400     return FALSE;
401   }
402
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");
407     ret = FALSE;
408   }
409
410   gst_element_set_state (nvenc, GST_STATE_NULL);
411   gst_object_unref (nvenc);
412
413   return ret;
414 }
415
416 static Suite *
417 nvenc_suite (void)
418 {
419   Suite *s;
420   TCase *tc_chain;
421
422   /* HACK: cuda device init/deinit with fork seems to problematic */
423   g_setenv ("CK_FORK", "no", TRUE);
424
425   s = suite_create ("nvenc");
426   tc_chain = tcase_create ("general");
427
428   suite_add_tcase (s, tc_chain);
429
430   if (!check_nvenc_available ()) {
431     GST_DEBUG ("Skip nvenc test since cannot open device");
432     goto end;
433   }
434
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);
440
441 end:
442   return s;
443 }
444
445 GST_CHECK_MAIN (nvenc);