3 * unit test for x264enc
5 * Copyright (C) <2008> Mark Nauwelaerts <mnauw@users.sf.net>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
23 #include <gst/check/gstcheck.h>
24 #include <gst/video/video.h>
26 /* For ease of programming we use globals to keep refs for our floating
27 * src and sink pads we create; otherwise we always have to do get_pad,
28 * get_peer, and then remove references in every test function */
29 static GstPad *mysrcpad, *mysinkpad;
31 #define VIDEO_CAPS_STRING "video/x-raw, " \
32 "width = (int) 384, " \
33 "height = (int) 288, " \
34 "framerate = (fraction) 25/1"
36 #define H264_CAPS_STRING "video/x-h264, " \
37 "width = (int) 384, " \
38 "height = (int) 288, " \
39 "framerate = (fraction) 25/1"
41 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
44 GST_STATIC_CAPS (VIDEO_CAPS_STRING));
46 static void cleanup_x264enc (GstElement * x264enc);
49 setup_x264enc (const gchar * profile, const gchar * stream_format,
50 GstVideoFormat input_format)
52 GstPadTemplate *sink_tmpl, *tmpl;
54 GstCaps *caps, *tmpl_caps;
56 GST_DEBUG ("setup_x264enc");
58 caps = gst_caps_from_string (H264_CAPS_STRING);
59 gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile,
60 "stream-format", G_TYPE_STRING, stream_format, NULL);
61 sink_tmpl = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
62 gst_caps_unref (caps);
64 x264enc = gst_check_setup_element ("x264enc");
65 mysrcpad = gst_check_setup_src_pad (x264enc, &srctemplate);
66 mysinkpad = gst_check_setup_sink_pad_from_template (x264enc, sink_tmpl);
67 gst_pad_set_active (mysrcpad, TRUE);
68 gst_pad_set_active (mysinkpad, TRUE);
70 caps = gst_caps_from_string (VIDEO_CAPS_STRING);
71 gst_caps_set_simple (caps, "format", G_TYPE_STRING,
72 gst_video_format_to_string (input_format), NULL);
74 tmpl = gst_element_get_pad_template (x264enc, "sink");
75 tmpl_caps = gst_pad_template_get_caps (tmpl);
77 if (gst_caps_can_intersect (caps, tmpl_caps)) {
78 gst_check_setup_events (mysrcpad, x264enc, caps, GST_FORMAT_TIME);
80 cleanup_x264enc (x264enc);
84 gst_caps_unref (tmpl_caps);
85 gst_caps_unref (caps);
86 gst_object_unref (sink_tmpl);
92 cleanup_x264enc (GstElement * x264enc)
94 GST_DEBUG ("cleanup_x264enc");
95 gst_element_set_state (x264enc, GST_STATE_NULL);
97 gst_pad_set_active (mysrcpad, FALSE);
98 gst_pad_set_active (mysinkpad, FALSE);
99 gst_check_teardown_src_pad (x264enc);
100 gst_check_teardown_sink_pad (x264enc);
101 gst_check_teardown_element (x264enc);
105 check_caps (GstCaps * caps, const gchar * profile, gint profile_id)
108 const GValue *sf, *avcc, *pf;
109 const gchar *stream_format;
110 const gchar *caps_profile;
112 fail_unless (caps != NULL);
114 GST_INFO ("caps %" GST_PTR_FORMAT, caps);
115 s = gst_caps_get_structure (caps, 0);
116 fail_unless (s != NULL);
117 fail_if (!gst_structure_has_name (s, "video/x-h264"));
118 sf = gst_structure_get_value (s, "stream-format");
119 fail_unless (sf != NULL);
120 fail_unless (G_VALUE_HOLDS_STRING (sf));
121 stream_format = g_value_get_string (sf);
122 fail_unless (stream_format != NULL);
123 if (strcmp (stream_format, "avc") == 0) {
127 avcc = gst_structure_get_value (s, "codec_data");
128 fail_unless (avcc != NULL);
129 fail_unless (GST_VALUE_HOLDS_BUFFER (avcc));
130 buf = gst_value_get_buffer (avcc);
131 fail_unless (buf != NULL);
132 gst_buffer_map (buf, &map, GST_MAP_READ);
133 fail_unless_equals_int (map.data[0], 1);
134 fail_unless (map.data[1] == profile_id,
135 "Expected profile ID %#04x, got %#04x", profile_id, map.data[1]);
136 gst_buffer_unmap (buf, &map);
137 } else if (strcmp (stream_format, "byte-stream") == 0) {
138 fail_if (gst_structure_get_value (s, "codec_data") != NULL);
140 fail_if (TRUE, "unexpected stream-format in caps: %s", stream_format);
143 pf = gst_structure_get_value (s, "profile");
144 fail_unless (pf != NULL);
145 fail_unless (G_VALUE_HOLDS_STRING (pf));
146 caps_profile = g_value_get_string (pf);
147 fail_unless (caps_profile != NULL);
148 fail_unless (!strcmp (caps_profile, profile));
151 static const GstVideoFormat formats_420_8[] =
152 { GST_VIDEO_FORMAT_I420, GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_NV12,
153 GST_VIDEO_FORMAT_UNKNOWN
156 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
157 static const GstVideoFormat formats_420_10[] =
158 { GST_VIDEO_FORMAT_I420_10LE, GST_VIDEO_FORMAT_UNKNOWN };
159 static const GstVideoFormat formats_422[] =
160 { GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I422_10LE,
161 GST_VIDEO_FORMAT_UNKNOWN
164 static const GstVideoFormat formats_444[] =
165 { GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444_10LE,
166 GST_VIDEO_FORMAT_UNKNOWN
169 static const GstVideoFormat formats_420_10[] =
170 { GST_VIDEO_FORMAT_I420_10BE, GST_VIDEO_FORMAT_UNKNOWN };
171 static const GstVideoFormat formats_422[] =
172 { GST_VIDEO_FORMAT_Y42B, GST_VIDEO_FORMAT_I422_10BE,
173 GST_VIDEO_FORMAT_UNKNOWN
176 static const GstVideoFormat formats_444[] =
177 { GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444_10BE,
178 GST_VIDEO_FORMAT_UNKNOWN
183 test_video_profile (const gchar * profile, gint profile_id,
184 const GstVideoFormat input_formats[], gint input_format_index)
186 GstVideoFormat input_format = input_formats[input_format_index];
188 GstBuffer *inbuffer, *outbuffer;
193 fail_unless (gst_video_info_set_format (&vinfo, input_format, 384, 288));
195 x264enc = setup_x264enc (profile, "avc", input_format);
196 if (x264enc == NULL) {
197 g_printerr ("WARNING: input format '%s' not supported\n",
198 gst_video_format_to_string (input_format));
202 fail_unless (gst_element_set_state (x264enc,
203 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
204 "could not set to playing");
206 /* check that we only accept input formats compatible with the output caps */
207 caps = gst_pad_peer_query_caps (mysrcpad, NULL);
208 for (i = 0; i < gst_caps_get_size (caps); i++) {
209 GstStructure *s = gst_caps_get_structure (caps, i);
210 const GValue *v, *vi;
213 v = gst_structure_get_value (s, "format");
215 if (G_VALUE_TYPE (v) == G_TYPE_STRING) {
218 } else if (G_VALUE_TYPE (v) == GST_TYPE_LIST) {
219 vlen = gst_value_list_get_size (v);
220 fail_unless (vlen > 0, "Got empty format list");
221 vi = gst_value_list_get_value (v, 0);
223 fail ("Bad format in structure: %" GST_PTR_FORMAT, s);
224 g_assert_not_reached ();
228 const gchar *str = g_value_get_string (vi);
229 GstVideoFormat format = gst_video_format_from_string (str);
233 fail_unless (input_formats[k] != GST_VIDEO_FORMAT_UNKNOWN,
234 "Bad format: %s", str);
235 if (input_formats[k] == format)
240 vi = gst_value_list_get_value (v, j);
245 gst_caps_unref (caps);
247 /* corresponds to buffer for the size mentioned in the caps */
248 inbuffer = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (&vinfo));
250 /* makes valgrind's memcheck happier */
251 gst_buffer_memset (inbuffer, 0, 0, -1);
252 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
253 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
254 fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
256 /* send eos to have all flushed if needed */
257 fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE);
259 num_buffers = g_list_length (buffers);
260 fail_unless (num_buffers == 1);
262 /* check output caps */
266 outcaps = gst_pad_get_current_caps (mysinkpad);
267 check_caps (outcaps, profile, profile_id);
268 gst_caps_unref (outcaps);
271 /* validate buffers */
272 for (i = 0; i < num_buffers; ++i) {
273 outbuffer = GST_BUFFER (buffers->data);
274 fail_if (outbuffer == NULL);
279 gint nsize, npos, j, type, next_type;
284 gst_buffer_map (outbuffer, &map, GST_MAP_READ);
292 /* loop through NALs */
293 while (npos < size) {
294 fail_unless (size - npos >= 4);
295 nsize = GST_READ_UINT32_BE (data + npos);
296 fail_unless (nsize > 0);
297 fail_unless (npos + 4 + nsize <= size);
298 type = data[npos + 4] & 0x1F;
299 /* check the first NALs, disregard AU (9), SEI (6) */
300 if (type != 9 && type != 6) {
301 fail_unless (type == next_type);
318 gst_buffer_unmap (outbuffer, &map);
319 /* should have reached the exact end */
320 fail_unless (npos == size);
327 buffers = g_list_remove (buffers, outbuffer);
329 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
330 gst_buffer_unref (outbuffer);
334 cleanup_x264enc (x264enc);
335 g_list_free (buffers);
339 GST_START_TEST (test_video_baseline)
343 for (i = 0; formats_420_8[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
344 test_video_profile ("constrained-baseline", 0x42, formats_420_8, i);
349 GST_START_TEST (test_video_main)
353 for (i = 0; formats_420_8[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
354 test_video_profile ("main", 0x4d, formats_420_8, i);
359 GST_START_TEST (test_video_high)
363 for (i = 0; formats_420_8[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
364 test_video_profile ("high", 0x64, formats_420_8, i);
369 GST_START_TEST (test_video_high10)
373 for (i = 0; formats_420_10[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
374 test_video_profile ("high-10", 0x6e, formats_420_10, i);
379 GST_START_TEST (test_video_high422)
383 for (i = 0; formats_422[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
384 test_video_profile ("high-4:2:2", 0x7A, formats_422, i);
389 GST_START_TEST (test_video_high444)
393 for (i = 0; formats_444[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
394 test_video_profile ("high-4:4:4", 0xF4, formats_444, i);
402 Suite *s = suite_create ("x264enc");
403 TCase *tc_chain = tcase_create ("general");
405 suite_add_tcase (s, tc_chain);
406 tcase_add_test (tc_chain, test_video_baseline);
407 tcase_add_test (tc_chain, test_video_main);
408 tcase_add_test (tc_chain, test_video_high);
409 tcase_add_test (tc_chain, test_video_high10);
410 tcase_add_test (tc_chain, test_video_high422);
411 tcase_add_test (tc_chain, test_video_high444);
416 GST_CHECK_MAIN (x264enc);