Move files from gst-plugins-ugly into the "subprojects/gst-plugins-ugly/" subdir
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-ugly / tests / check / elements / x264enc.c
1 /* GStreamer
2  *
3  * unit test for x264enc
4  *
5  * Copyright (C) <2008> Mark Nauwelaerts <mnauw@users.sf.net>
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #include <gst/check/gstcheck.h>
24 #include <gst/video/video.h>
25
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;
30
31 #define VIDEO_CAPS_STRING "video/x-raw, " \
32                            "width = (int) 384, " \
33                            "height = (int) 288, " \
34                            "framerate = (fraction) 25/1"
35
36 #define H264_CAPS_STRING "video/x-h264, " \
37                            "width = (int) 384, " \
38                            "height = (int) 288, " \
39                            "framerate = (fraction) 25/1"
40
41 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
42     GST_PAD_SRC,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS (VIDEO_CAPS_STRING));
45
46 static void cleanup_x264enc (GstElement * x264enc);
47
48 static GstElement *
49 setup_x264enc (const gchar * profile, const gchar * stream_format,
50     GstVideoFormat input_format)
51 {
52   GstPadTemplate *sink_tmpl, *tmpl;
53   GstElement *x264enc;
54   GstCaps *caps, *tmpl_caps;
55
56   GST_DEBUG ("setup_x264enc");
57
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);
63
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);
69
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);
73
74   tmpl = gst_element_get_pad_template (x264enc, "sink");
75   tmpl_caps = gst_pad_template_get_caps (tmpl);
76
77   if (gst_caps_can_intersect (caps, tmpl_caps)) {
78     gst_check_setup_events (mysrcpad, x264enc, caps, GST_FORMAT_TIME);
79   } else {
80     cleanup_x264enc (x264enc);
81     x264enc = NULL;
82   }
83
84   gst_caps_unref (tmpl_caps);
85   gst_caps_unref (caps);
86   gst_object_unref (sink_tmpl);
87
88   return x264enc;
89 }
90
91 static void
92 cleanup_x264enc (GstElement * x264enc)
93 {
94   GST_DEBUG ("cleanup_x264enc");
95   gst_element_set_state (x264enc, GST_STATE_NULL);
96
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);
102 }
103
104 static void
105 check_caps (GstCaps * caps, const gchar * profile, gint profile_id)
106 {
107   GstStructure *s;
108   const GValue *sf, *avcc, *pf;
109   const gchar *stream_format;
110   const gchar *caps_profile;
111
112   fail_unless (caps != NULL);
113
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) {
124     GstMapInfo map;
125     GstBuffer *buf;
126
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);
139   } else {
140     fail_if (TRUE, "unexpected stream-format in caps: %s", stream_format);
141   }
142
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));
149 }
150
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
154 };
155
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
162 };
163
164 static const GstVideoFormat formats_444[] =
165     { GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444_10LE,
166   GST_VIDEO_FORMAT_UNKNOWN
167 };
168 #else
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
174 };
175
176 static const GstVideoFormat formats_444[] =
177     { GST_VIDEO_FORMAT_Y444, GST_VIDEO_FORMAT_Y444_10BE,
178   GST_VIDEO_FORMAT_UNKNOWN
179 };
180 #endif
181
182 static void
183 test_video_profile (const gchar * profile, gint profile_id,
184     const GstVideoFormat input_formats[], gint input_format_index)
185 {
186   GstVideoFormat input_format = input_formats[input_format_index];
187   GstElement *x264enc;
188   GstBuffer *inbuffer, *outbuffer;
189   int i, num_buffers;
190   GstVideoInfo vinfo;
191   GstCaps *caps;
192
193   fail_unless (gst_video_info_set_format (&vinfo, input_format, 384, 288));
194
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));
199     return;
200   }
201
202   fail_unless (gst_element_set_state (x264enc,
203           GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
204       "could not set to playing");
205
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;
211     guint vlen, j = 0;
212
213     v = gst_structure_get_value (s, "format");
214
215     if (G_VALUE_TYPE (v) == G_TYPE_STRING) {
216       vlen = 1;
217       vi = v;
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);
222     } else {
223       fail ("Bad format in structure: %" GST_PTR_FORMAT, s);
224       g_assert_not_reached ();
225     }
226
227     while (TRUE) {
228       const gchar *str = g_value_get_string (vi);
229       GstVideoFormat format = gst_video_format_from_string (str);
230       int k;
231
232       for (k = 0;; k++) {
233         fail_unless (input_formats[k] != GST_VIDEO_FORMAT_UNKNOWN,
234             "Bad format: %s", str);
235         if (input_formats[k] == format)
236           break;
237       }
238
239       if (++j < vlen)
240         vi = gst_value_list_get_value (v, j);
241       else
242         break;
243     }
244   }
245   gst_caps_unref (caps);
246
247   /* corresponds to buffer for the size mentioned in the caps */
248   inbuffer = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (&vinfo));
249
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);
255
256   /* send eos to have all flushed if needed */
257   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE);
258
259   num_buffers = g_list_length (buffers);
260   fail_unless (num_buffers == 1);
261
262   /* check output caps */
263   {
264     GstCaps *outcaps;
265
266     outcaps = gst_pad_get_current_caps (mysinkpad);
267     check_caps (outcaps, profile, profile_id);
268     gst_caps_unref (outcaps);
269   }
270
271   /* validate buffers */
272   for (i = 0; i < num_buffers; ++i) {
273     outbuffer = GST_BUFFER (buffers->data);
274     fail_if (outbuffer == NULL);
275
276     switch (i) {
277       case 0:
278       {
279         gint nsize, npos, j, type, next_type;
280         GstMapInfo map;
281         const guint8 *data;
282         gsize size;
283
284         gst_buffer_map (outbuffer, &map, GST_MAP_READ);
285         data = map.data;
286         size = map.size;
287
288         npos = 0;
289         j = 0;
290         /* need SPS first */
291         next_type = 7;
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);
302             switch (type) {
303               case 7:
304                 /* SPS */
305                 next_type = 8;
306                 break;
307               case 8:
308                 /* PPS */
309                 next_type = 5;
310                 break;
311               default:
312                 break;
313             }
314             j++;
315           }
316           npos += nsize + 4;
317         }
318         gst_buffer_unmap (outbuffer, &map);
319         /* should have reached the exact end */
320         fail_unless (npos == size);
321         break;
322       }
323       default:
324         break;
325     }
326
327     buffers = g_list_remove (buffers, outbuffer);
328
329     ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
330     gst_buffer_unref (outbuffer);
331     outbuffer = NULL;
332   }
333
334   cleanup_x264enc (x264enc);
335   g_list_free (buffers);
336   buffers = NULL;
337 }
338
339 GST_START_TEST (test_video_baseline)
340 {
341   gint i;
342
343   for (i = 0; formats_420_8[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
344     test_video_profile ("constrained-baseline", 0x42, formats_420_8, i);
345 }
346
347 GST_END_TEST;
348
349 GST_START_TEST (test_video_main)
350 {
351   gint i;
352
353   for (i = 0; formats_420_8[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
354     test_video_profile ("main", 0x4d, formats_420_8, i);
355 }
356
357 GST_END_TEST;
358
359 GST_START_TEST (test_video_high)
360 {
361   gint i;
362
363   for (i = 0; formats_420_8[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
364     test_video_profile ("high", 0x64, formats_420_8, i);
365 }
366
367 GST_END_TEST;
368
369 GST_START_TEST (test_video_high10)
370 {
371   gint i;
372
373   for (i = 0; formats_420_10[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
374     test_video_profile ("high-10", 0x6e, formats_420_10, i);
375 }
376
377 GST_END_TEST;
378
379 GST_START_TEST (test_video_high422)
380 {
381   gint i;
382
383   for (i = 0; formats_422[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
384     test_video_profile ("high-4:2:2", 0x7A, formats_422, i);
385 }
386
387 GST_END_TEST;
388
389 GST_START_TEST (test_video_high444)
390 {
391   gint i;
392
393   for (i = 0; formats_444[i] != GST_VIDEO_FORMAT_UNKNOWN; i++)
394     test_video_profile ("high-4:4:4", 0xF4, formats_444, i);
395 }
396
397 GST_END_TEST;
398
399 Suite *
400 x264enc_suite (void)
401 {
402   Suite *s = suite_create ("x264enc");
403   TCase *tc_chain = tcase_create ("general");
404
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);
412
413   return s;
414 }
415
416 GST_CHECK_MAIN (x264enc);