1 /* GStreamer
2 *
3 * unit test for rawvideoparse
4 *
5 * Copyright (C) <2016> Carlos Rafael Giani <dv at pseudoterminal dot org>
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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <gst/check/gstcheck.h>
27 #include <gst/video/video.h>
28
29 /* The checks use as test data an 8x8 Y444 image, with 25 Hz framerate. In the
30 * sink caps configuration, the stride is 8 bytes, and the frames are tightly
31 * packed together. In the properties configuration, the stride is 10 bytes, the
32 * planes aren't tightly packed (there are 20 bytes between the planes), and the
33 * frames overall have padding between them (the overall frame size is
34 * stride (10) * height (8) * num-planes (3) + bytes-between-planes (20) * 2
35 * = 280 bytes, and the frame stride is 500 bytes, so there are 220 bytes of
36 * extra padding between frames).
37 *
38 * In the test 8x8 frame, the pixels are all set to #000000, except for two
39 * pixels: (xofs+1 yofs+0) is set to #8899AA, (xofs+0 yofs+1) is set to #112233.
40 * The first frame uses the offsets xofs=0 yofs=0. The second frame uses
41 * xofs=1 yofs=0 etc. For each configuration, there is a separate set of frames,
42 * each stored in the GstAdapter in the Context struct.
43 *
44 * During the tests, as part of the checks, the pixels are verified to have the
45 * right values. The pattern of the pixels was chosen to easily detect stride
46 * errors, incorrect plane offsets etc.
47 */
48
49 #define TEST_WIDTH 8
50 #define TEST_HEIGHT 8
51 #define TEST_FRAMERATE_N 25
52 #define TEST_FRAMERATE_D 1
53 #define TEST_FRAME_FORMAT GST_VIDEO_FORMAT_Y444
54 #define NUM_TEST_PLANES 3
55
56 #define PROP_CTX_PLANE_STRIDE 10
57 #define PROP_CTX_FRAME_SIZE 500
58 #define PROP_CTX_PLANE_PADDING 20
59 #define PROP_CTX_PLANE_SIZE (PROP_CTX_PLANE_STRIDE * TEST_HEIGHT + PROP_CTX_PLANE_PADDING)
60
61 GstElement *rawvideoparse;
62
63 /* For ease of programming we use globals to keep refs for our floating
64 * src and sink pads we create; otherwise we always have to do get_pad,
65 * get_peer, and then remove references in every test function */
66 static GstPad *mysrcpad, *mysinkpad;
67
68 typedef struct
69 {
70 GstAdapter *data;
71 guint plane_stride;
72 guint plane_size;
73 }
74 Context;
75
76 static Context properties_ctx, sinkcaps_ctx;
77
78 static void
set_pixel(Context const * ctx,guint8 * pixels,guint x,guint y,guint32 color)79 set_pixel (Context const *ctx, guint8 * pixels, guint x, guint y, guint32 color)
80 {
81 guint i;
82 guint ofs = y * ctx->plane_stride + x;
83 for (i = 0; i < NUM_TEST_PLANES; ++i)
84 pixels[ctx->plane_size * i + ofs] =
85 (color >> ((NUM_TEST_PLANES - 1 - i) * 8)) & 0xFF;
86 }
87
88 static guint32
get_pixel(Context const * ctx,const guint8 * pixels,guint x,guint y)89 get_pixel (Context const *ctx, const guint8 * pixels, guint x, guint y)
90 {
91 guint i;
92 guint ofs = y * ctx->plane_stride + x;
93 guint32 color = 0;
94 for (i = 0; i < NUM_TEST_PLANES; ++i)
95 color |=
96 ((guint32) (pixels[ctx->plane_size * i + ofs])) << ((NUM_TEST_PLANES -
97 1 - i) * 8);
98 return color;
99 }
100
101 static void
fill_test_pattern(Context const * ctx,GstBuffer * buffer,guint xofs,guint yofs)102 fill_test_pattern (Context const *ctx, GstBuffer * buffer, guint xofs,
103 guint yofs)
104 {
105 guint8 *pixels;
106 GstMapInfo map_info;
107
108 gst_buffer_map (buffer, &map_info, GST_MAP_WRITE);
109 pixels = map_info.data;
110
111 memset (pixels, 0, ctx->plane_size * NUM_TEST_PLANES);
112 set_pixel (ctx, pixels, 1 + xofs, 0 + yofs, 0x8899AA);
113 set_pixel (ctx, pixels, 0 + xofs, 1 + yofs, 0x112233);
114
115 gst_buffer_unmap (buffer, &map_info);
116 }
117
118 static void
check_test_pattern(Context const * ctx,GstBuffer * buffer,guint xofs,guint yofs)119 check_test_pattern (Context const *ctx, GstBuffer * buffer, guint xofs,
120 guint yofs)
121 {
122 guint x, y;
123 guint8 *pixels;
124 GstMapInfo map_info;
125
126 gst_buffer_map (buffer, &map_info, GST_MAP_READ);
127 pixels = map_info.data;
128
129 fail_unless_equals_uint64_hex (get_pixel (ctx, pixels, 1 + xofs, 0 + yofs),
130 0x8899AA);
131 fail_unless_equals_uint64_hex (get_pixel (ctx, pixels, 0 + xofs, 1 + yofs),
132 0x112233);
133
134 for (y = 0; y < TEST_HEIGHT; ++y) {
135 for (x = 0; x < TEST_WIDTH; ++x) {
136 if ((x == (1 + xofs) && y == (0 + yofs)) || (x == (0 + xofs)
137 && y == (1 + yofs)))
138 continue;
139
140 fail_unless_equals_uint64_hex (get_pixel (ctx, pixels, x, y), 0x000000);
141 }
142 }
143
144 gst_buffer_unmap (buffer, &map_info);
145 }
146
147
148 static void
setup_rawvideoparse(gboolean use_sink_caps,gboolean set_properties,GstCaps * incaps,GstFormat format)149 setup_rawvideoparse (gboolean use_sink_caps,
150 gboolean set_properties, GstCaps * incaps, GstFormat format)
151 {
152 guint i;
153
154
155 /* Setup the rawvideoparse element and the pads */
156
157 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
158 GST_PAD_SINK,
159 GST_PAD_ALWAYS,
160 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL))
161 );
162 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
163 GST_PAD_SRC,
164 GST_PAD_ALWAYS,
165 GST_STATIC_CAPS_ANY);
166
167 rawvideoparse = gst_check_setup_element ("rawvideoparse");
168
169 properties_ctx.plane_stride = PROP_CTX_PLANE_STRIDE;
170 properties_ctx.plane_size = PROP_CTX_PLANE_SIZE;
171 properties_ctx.data = gst_adapter_new ();
172
173 sinkcaps_ctx.plane_stride = TEST_WIDTH;
174 sinkcaps_ctx.plane_size = TEST_WIDTH * TEST_HEIGHT;
175 sinkcaps_ctx.data = gst_adapter_new ();
176
177 g_object_set (G_OBJECT (rawvideoparse), "use-sink-caps", use_sink_caps, NULL);
178 if (set_properties) {
179 GValue plane_offsets = G_VALUE_INIT;
180 GValue plane_strides = G_VALUE_INIT;
181 GValue val = G_VALUE_INIT;
182
183 g_value_init (&val, G_TYPE_INT);
184 g_value_init (&plane_offsets, GST_TYPE_ARRAY);
185 g_value_init (&plane_strides, GST_TYPE_ARRAY);
186
187 for (i = 0; i < NUM_TEST_PLANES; ++i) {
188 g_value_set_int (&val, properties_ctx.plane_size * i);
189 gst_value_array_append_value (&plane_offsets, &val);
190 }
191
192 for (i = 0; i < NUM_TEST_PLANES; ++i) {
193 g_value_set_int (&val, properties_ctx.plane_stride);
194 gst_value_array_append_value (&plane_strides, &val);
195 }
196
197 g_value_unset (&val);
198
199 g_object_set (G_OBJECT (rawvideoparse), "width", TEST_WIDTH, "height",
200 TEST_HEIGHT, "frame-size", PROP_CTX_FRAME_SIZE, "framerate",
201 TEST_FRAMERATE_N, TEST_FRAMERATE_D, "format", TEST_FRAME_FORMAT, NULL);
202 g_object_set_property (G_OBJECT (rawvideoparse), "plane-offsets",
203 &plane_offsets);
204 g_object_set_property (G_OBJECT (rawvideoparse), "plane-strides",
205 &plane_strides);
206
207 g_value_unset (&plane_offsets);
208 g_value_unset (&plane_strides);
209 }
210
211 /* Check that the plane stride/offset values are correct */
212 {
213 GValue plane_offsets_array = G_VALUE_INIT;
214 GValue plane_strides_array = G_VALUE_INIT;
215
216 /* By default, 320x240 i420 is used as format */
217 guint plane_offsets[3] = { 0, 76800, 96000 };
218 guint plane_strides[3] = { 320, 160, 160 };
219
220 g_value_init (&plane_offsets_array, GST_TYPE_ARRAY);
221 g_value_init (&plane_strides_array, GST_TYPE_ARRAY);
222
223 if (set_properties) {
224 /* When properties are explicitely set, we use Y444 as video format,
225 * so in that case, plane stride values are all the same */
226 plane_offsets[0] = properties_ctx.plane_size * 0;
227 plane_offsets[1] = properties_ctx.plane_size * 1;
228 plane_offsets[2] = properties_ctx.plane_size * 2;
229 plane_strides[0] = plane_strides[1] = plane_strides[2] =
230 properties_ctx.plane_stride;
231 }
232
233 g_object_get_property (G_OBJECT (rawvideoparse), "plane-offsets",
234 &plane_offsets_array);
235 g_object_get_property (G_OBJECT (rawvideoparse), "plane-strides",
236 &plane_strides_array);
237
238 fail_unless (gst_value_array_get_size (&plane_offsets_array) ==
239 gst_value_array_get_size (&plane_strides_array));
240
241 for (i = 0; i < gst_value_array_get_size (&plane_offsets_array); ++i) {
242 const GValue *gvalue;
243
244 gvalue = gst_value_array_get_value (&plane_offsets_array, i);
245 fail_unless (gvalue != NULL);
246 fail_unless_equals_uint64 (plane_offsets[i], g_value_get_int (gvalue));
247
248 gvalue = gst_value_array_get_value (&plane_strides_array, i);
249 fail_unless (gvalue != NULL);
250 fail_unless_equals_uint64 (plane_strides[i], g_value_get_int (gvalue));
251 }
252
253 g_value_unset (&plane_offsets_array);
254 g_value_unset (&plane_strides_array);
255 }
256
257 fail_unless (gst_element_set_state (rawvideoparse,
258 GST_STATE_PAUSED) == GST_STATE_CHANGE_SUCCESS,
259 "could not set to paused");
260
261 mysrcpad = gst_check_setup_src_pad (rawvideoparse, &srctemplate);
262 mysinkpad = gst_check_setup_sink_pad (rawvideoparse, &sinktemplate);
263
264 gst_pad_set_active (mysrcpad, TRUE);
265 gst_pad_set_active (mysinkpad, TRUE);
266
267 gst_check_setup_events (mysrcpad, rawvideoparse, incaps, format);
268 if (incaps)
269 gst_caps_unref (incaps);
270
271
272 /* Fill the adapters with test frames */
273
274 for (i = 0; i < 10; ++i) {
275 GstBuffer *buffer =
276 gst_buffer_new_allocate (NULL, PROP_CTX_FRAME_SIZE, NULL);
277 gst_buffer_memset (buffer, 0, 0xCC, gst_buffer_get_size (buffer));
278 fill_test_pattern (&properties_ctx, buffer, i, 0);
279 gst_adapter_push (properties_ctx.data, buffer);
280 }
281
282 for (i = 0; i < 10; ++i) {
283 GstBuffer *buffer =
284 gst_buffer_new_allocate (NULL, sinkcaps_ctx.plane_size * 3, NULL);
285 gst_buffer_memset (buffer, 0, 0xCC, gst_buffer_get_size (buffer));
286 fill_test_pattern (&sinkcaps_ctx, buffer, i, 0);
287 gst_adapter_push (sinkcaps_ctx.data, buffer);
288 }
289 }
290
291 static void
cleanup_rawvideoparse(void)292 cleanup_rawvideoparse (void)
293 {
294 int num_buffers, i;
295
296 gst_pad_set_active (mysrcpad, FALSE);
297 gst_pad_set_active (mysinkpad, FALSE);
298 gst_check_teardown_src_pad (rawvideoparse);
299 gst_check_teardown_sink_pad (rawvideoparse);
300 gst_check_teardown_element (rawvideoparse);
301
302 g_object_unref (G_OBJECT (properties_ctx.data));
303 g_object_unref (G_OBJECT (sinkcaps_ctx.data));
304
305 if (buffers != NULL) {
306 num_buffers = g_list_length (buffers);
307 for (i = 0; i < num_buffers; ++i) {
308 GstBuffer *buf = GST_BUFFER (buffers->data);
309 buffers = g_list_remove (buffers, buf);
310 gst_buffer_unref (buf);
311 }
312
313 g_list_free (buffers);
314 buffers = NULL;
315 }
316 }
317
318 static void
push_data_and_check_output(Context * ctx,gsize num_in_bytes,gsize expected_num_out_bytes,gint64 expected_pts,gint64 expected_dur,guint expected_num_buffers_in_list,guint buf_idx,guint xofs,guint yofs)319 push_data_and_check_output (Context * ctx, gsize num_in_bytes,
320 gsize expected_num_out_bytes, gint64 expected_pts, gint64 expected_dur,
321 guint expected_num_buffers_in_list, guint buf_idx, guint xofs, guint yofs)
322 {
323 GstBuffer *inbuf, *outbuf;
324 guint num_buffers;
325
326 /* Simulate upstream input by taking num_in_bytes bytes from the adapter */
327 inbuf = gst_adapter_take_buffer (ctx->data, num_in_bytes);
328 fail_unless (inbuf != NULL);
329
330 /* Push the input data and check that the output buffers list grew as
331 * expected */
332 fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK);
333 num_buffers = g_list_length (buffers);
334 fail_unless_equals_int (num_buffers, expected_num_buffers_in_list);
335
336 /* Take the output buffer */
337 outbuf = g_list_nth_data (buffers, buf_idx);
338 fail_unless (outbuf != NULL);
339
340 /* Verify size, PTS, duration of the output buffer */
341 fail_unless_equals_uint64 (expected_num_out_bytes,
342 gst_buffer_get_size (outbuf));
343 fail_unless_equals_uint64 (expected_pts, GST_BUFFER_PTS (outbuf));
344 fail_unless_equals_uint64 (expected_dur, GST_BUFFER_DURATION (outbuf));
345
346 /* Check that the pixels have the correct values */
347 check_test_pattern (ctx, outbuf, xofs, yofs);
348 }
349
350
GST_START_TEST(test_push_unaligned_data_properties_config)351 GST_START_TEST (test_push_unaligned_data_properties_config)
352 {
353 setup_rawvideoparse (FALSE, TRUE, NULL, GST_FORMAT_BYTES);
354
355 /* Send in data buffers that are not aligned to multiples of the
356 * frame size (= sample size * num_channels). This tests if rawvideoparse
357 * aligns output data properly.
358 *
359 * The second line sends a buffer with multiple frames inside.
360 * rawvideoparse will then parse this buffer repeatedly (and prepend
361 * leftover data from the earlier parse iteration), explaining why
362 * all of a sudden there are 4 output buffers, compared to just one
363 * earlier. The output data is expected to be 280 bytes large, since this
364 * is the size of the actual frame, without extra padding at the end.
365 */
366 push_data_and_check_output (&properties_ctx, 511, 280, GST_MSECOND * 0,
367 GST_MSECOND * 40, 1, 0, 0, 0);
368 push_data_and_check_output (&properties_ctx, 1940, 280, GST_MSECOND * 40,
369 GST_MSECOND * 40, 4, 1, 1, 0);
370 push_data_and_check_output (&properties_ctx, 10, 280, GST_MSECOND * 80,
371 GST_MSECOND * 40, 4, 2, 2, 0);
372
373 cleanup_rawvideoparse ();
374 }
375
376 GST_END_TEST;
377
GST_START_TEST(test_push_unaligned_data_sink_caps_config)378 GST_START_TEST (test_push_unaligned_data_sink_caps_config)
379 {
380 GstVideoInfo vinfo;
381 GstCaps *caps;
382
383 /* This test is essentially the same as test_push_unaligned_data_properties_config,
384 * except that rawvideoparse uses the sink caps config instead of the property config.
385 * Also, the input sizes are different, since the sink caps config does not use extra
386 * padding between planes and does use a stride that directly corresponds to the width,
387 * resulting in smaller frame size (192 bytes vs 280 bytes). */
388
389 gst_video_info_set_format (&vinfo, TEST_FRAME_FORMAT, TEST_WIDTH,
390 TEST_HEIGHT);
391 GST_VIDEO_INFO_FPS_N (&vinfo) = 25;
392 GST_VIDEO_INFO_FPS_D (&vinfo) = 1;
393 caps = gst_video_info_to_caps (&vinfo);
394
395 setup_rawvideoparse (TRUE, FALSE, caps, GST_FORMAT_BYTES);
396
397 push_data_and_check_output (&sinkcaps_ctx, 250, 192, GST_MSECOND * 0,
398 GST_MSECOND * 40, 1, 0, 0, 0);
399 push_data_and_check_output (&sinkcaps_ctx, 811, 192, GST_MSECOND * 40,
400 GST_MSECOND * 40, 5, 1, 1, 0);
401 push_data_and_check_output (&sinkcaps_ctx, 10, 192, GST_MSECOND * 80,
402 GST_MSECOND * 40, 5, 2, 2, 0);
403
404 cleanup_rawvideoparse ();
405 }
406
407 GST_END_TEST;
408
GST_START_TEST(test_config_switch)409 GST_START_TEST (test_config_switch)
410 {
411 GstVideoInfo vinfo;
412 GstCaps *caps;
413
414 /* Start processing with the properties config active, then mid-stream switch to
415 * the sink caps config. Since the sink caps config does not use padding, its
416 * frame size is smaller. The buffer duration stays the same (since it only depends
417 * on the framerate), but the expected output buffer size is different). */
418
419 gst_video_info_set_format (&vinfo, TEST_FRAME_FORMAT, TEST_WIDTH,
420 TEST_HEIGHT);
421 GST_VIDEO_INFO_FPS_N (&vinfo) = 25;
422 GST_VIDEO_INFO_FPS_D (&vinfo) = 1;
423 caps = gst_video_info_to_caps (&vinfo);
424
425 setup_rawvideoparse (FALSE, TRUE, caps, GST_FORMAT_BYTES);
426
427 /* Push in data with properties config active */
428 push_data_and_check_output (&properties_ctx, 500, 280, GST_MSECOND * 0,
429 GST_MSECOND * 40, 1, 0, 0, 0);
430 push_data_and_check_output (&properties_ctx, 500, 280, GST_MSECOND * 40,
431 GST_MSECOND * 40, 2, 1, 1, 0);
432
433 /* Perform the switch */
434 g_object_set (G_OBJECT (rawvideoparse), "use-sink-caps", TRUE, NULL);
435
436 /* Push in data with sink caps config active, expecting a different frame size */
437 push_data_and_check_output (&sinkcaps_ctx, 192, 192, GST_MSECOND * 80,
438 GST_MSECOND * 40, 3, 2, 0, 0);
439
440 cleanup_rawvideoparse ();
441 }
442
443 GST_END_TEST;
444
GST_START_TEST(test_push_with_no_framerate)445 GST_START_TEST (test_push_with_no_framerate)
446 {
447 /* Test the special case when no framerate is set. The parser is expected to
448 * still work then, but without setting duration or PTS/DTS (it cannot do that,
449 * because these require a nonzero framerate). The output buffers have PTS 0,
450 * all subsequent ones have no set PTS. */
451
452 setup_rawvideoparse (FALSE, TRUE, NULL, GST_FORMAT_BYTES);
453 g_object_set (G_OBJECT (rawvideoparse), "framerate", 0, 1, NULL);
454
455 push_data_and_check_output (&properties_ctx, 500, 280, 0, GST_CLOCK_TIME_NONE,
456 1, 0, 0, 0);
457 push_data_and_check_output (&properties_ctx, 500, 280, GST_CLOCK_TIME_NONE,
458 GST_CLOCK_TIME_NONE, 2, 1, 1, 0);
459
460 cleanup_rawvideoparse ();
461 }
462
463 GST_END_TEST;
464
GST_START_TEST(test_computed_plane_strides)465 GST_START_TEST (test_computed_plane_strides)
466 {
467 /* Test how plane strides & offsets are (re)computed if custom offsets/strides
468 * are disabled, and how they are preserved if they are enabled. */
469
470 GValue plane_offsets_array = G_VALUE_INIT;
471 GValue plane_strides_array = G_VALUE_INIT;
472 guint i;
473 guint const expected_comp_psize = TEST_WIDTH * TEST_HEIGHT;
474
475 g_value_init (&plane_offsets_array, GST_TYPE_ARRAY);
476 g_value_init (&plane_strides_array, GST_TYPE_ARRAY);
477
478 setup_rawvideoparse (FALSE, TRUE, NULL, GST_FORMAT_BYTES);
479
480 /* The setup set a custom set of plane offsets and strides together with
481 * width=TEST_WIDTH and height=TEST_HEIGHT. Check that the offsets & strides
482 * are preserved even after setting new, different width & height values. */
483
484 g_object_set (G_OBJECT (rawvideoparse), "width", TEST_WIDTH * 2,
485 "height", TEST_HEIGHT * 2, NULL);
486
487 g_object_get_property (G_OBJECT (rawvideoparse), "plane-offsets",
488 &plane_offsets_array);
489 g_object_get_property (G_OBJECT (rawvideoparse), "plane-strides",
490 &plane_strides_array);
491
492 for (i = 0; i < gst_value_array_get_size (&plane_offsets_array); ++i) {
493 const GValue *gvalue;
494
495 /* See setup_rawvideoparse() for how the offsets & strides are defined
496 * there. Offsets are set to plane_size*plane_index, and strides are
497 * set to the properties_ctx.plane_stride value. */
498
499 gvalue = gst_value_array_get_value (&plane_offsets_array, i);
500 fail_unless (gvalue != NULL);
501 fail_unless_equals_uint64 (properties_ctx.plane_size * i,
502 g_value_get_int (gvalue));
503
504 gvalue = gst_value_array_get_value (&plane_strides_array, i);
505 fail_unless (gvalue != NULL);
506 fail_unless_equals_uint64 (properties_ctx.plane_stride,
507 g_value_get_int (gvalue));
508 }
509
510 /* Discard the custom planes&offsets, re-enabling computed values. */
511 g_value_reset (&plane_offsets_array);
512 g_value_reset (&plane_strides_array);
513 g_object_set_property (G_OBJECT (rawvideoparse), "plane-offsets",
514 &plane_offsets_array);
515 g_object_set_property (G_OBJECT (rawvideoparse), "plane-strides",
516 &plane_strides_array);
517
518
519 /* The strides & offsets should have been recomputed by now. Since the Y444
520 * format is used, all strides are the same, and should equal the frame width
521 * (which was set to TEST_WIDTH*2 earlier). Plane offsets should be
522 * plane_size*plane_index, with plane_size set to (TEST_WIDTH*2 * TEST_HEIGHT*2),
523 * or TEST_WIDTH*TEST_HEIGHT*4 (-> expected_comp_psize*4). */
524
525 g_object_get_property (G_OBJECT (rawvideoparse), "plane-offsets",
526 &plane_offsets_array);
527 g_object_get_property (G_OBJECT (rawvideoparse), "plane-strides",
528 &plane_strides_array);
529
530 for (i = 0; i < gst_value_array_get_size (&plane_offsets_array); ++i) {
531 const GValue *gvalue;
532
533 gvalue = gst_value_array_get_value (&plane_offsets_array, i);
534 fail_unless (gvalue != NULL);
535 fail_unless_equals_uint64 (expected_comp_psize * 4 * i,
536 g_value_get_int (gvalue));
537
538 gvalue = gst_value_array_get_value (&plane_strides_array, i);
539 fail_unless (gvalue != NULL);
540 fail_unless_equals_uint64 (TEST_WIDTH * 2, g_value_get_int (gvalue));
541 }
542
543 g_value_reset (&plane_offsets_array);
544 g_value_reset (&plane_strides_array);
545
546
547 /* Again change the width & height values. width=TEST_WIDTH, height=TEST_HEIGHT.
548 * However, this time, offsets&strides are computed; the current values should
549 * not be preserved. Expected plane stride and offset values are similar to
550 * above, expect that no multiplications by 2 are present (since the TEST_WIDTH
551 * and TEST_HEIGHT values were passed without multiplying them). */
552
553 g_object_set (G_OBJECT (rawvideoparse), "width", TEST_WIDTH,
554 "height", TEST_HEIGHT, NULL);
555
556
557 g_object_get_property (G_OBJECT (rawvideoparse), "plane-offsets",
558 &plane_offsets_array);
559 g_object_get_property (G_OBJECT (rawvideoparse), "plane-strides",
560 &plane_strides_array);
561
562 for (i = 0; i < gst_value_array_get_size (&plane_offsets_array); ++i) {
563 const GValue *gvalue;
564
565 gvalue = gst_value_array_get_value (&plane_offsets_array, i);
566 fail_unless (gvalue != NULL);
567 fail_unless_equals_uint64 (expected_comp_psize * i,
568 g_value_get_int (gvalue));
569
570 gvalue = gst_value_array_get_value (&plane_strides_array, i);
571 fail_unless (gvalue != NULL);
572 fail_unless_equals_uint64 (TEST_WIDTH, g_value_get_int (gvalue));
573 }
574
575 g_value_unset (&plane_offsets_array);
576 g_value_unset (&plane_strides_array);
577
578 cleanup_rawvideoparse ();
579 }
580
581 GST_END_TEST;
582
GST_START_TEST(test_change_caps)583 GST_START_TEST (test_change_caps)
584 {
585 GstVideoInfo vinfo;
586 GstCaps *caps;
587
588 /* Start processing with the sink caps config active, using the
589 * default width/height/format and 25 Hz frame rate for the caps.
590 * Push some data, then change caps (25 Hz -> 50 Hz).
591 * Check that the changed caps are handled properly. */
592
593 gst_video_info_set_format (&vinfo, TEST_FRAME_FORMAT, TEST_WIDTH,
594 TEST_HEIGHT);
595 GST_VIDEO_INFO_FPS_N (&vinfo) = 25;
596 GST_VIDEO_INFO_FPS_D (&vinfo) = 1;
597 caps = gst_video_info_to_caps (&vinfo);
598
599 setup_rawvideoparse (TRUE, FALSE, caps, GST_FORMAT_BYTES);
600
601 /* Push in data with sink config active, expecting duration calculations
602 * to be based on the 25 Hz frame rate */
603 push_data_and_check_output (&sinkcaps_ctx, 192, 192, GST_MSECOND * 0,
604 GST_MSECOND * 40, 1, 0, 0, 0);
605 push_data_and_check_output (&sinkcaps_ctx, 192, 192, GST_MSECOND * 40,
606 GST_MSECOND * 40, 2, 1, 1, 0);
607
608 /* Change caps */
609 GST_VIDEO_INFO_FPS_N (&vinfo) = 50;
610 GST_VIDEO_INFO_FPS_D (&vinfo) = 1;
611 caps = gst_video_info_to_caps (&vinfo);
612 fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_caps (caps)));
613 gst_caps_unref (caps);
614
615 /* Push in data with sink config active, expecting duration calculations
616 * to be based on the 50 Hz frame rate */
617 push_data_and_check_output (&sinkcaps_ctx, 192, 192, GST_MSECOND * 80,
618 GST_MSECOND * 20, 3, 2, 2, 0);
619
620 cleanup_rawvideoparse ();
621 }
622
623 GST_END_TEST;
624
GST_START_TEST(test_incomplete_last_buffer)625 GST_START_TEST (test_incomplete_last_buffer)
626 {
627 GstVideoInfo vinfo;
628 GstCaps *caps;
629
630 /* Start processing with the sink caps config active, using the
631 * default width/height/format and 25 Hz frame rate for the caps.
632 * Push some data, then change caps (25 Hz -> 50 Hz).
633 * Check that the changed caps are handled properly. */
634
635 gst_video_info_set_format (&vinfo, TEST_FRAME_FORMAT, TEST_WIDTH,
636 TEST_HEIGHT);
637 GST_VIDEO_INFO_FPS_N (&vinfo) = 25;
638 GST_VIDEO_INFO_FPS_D (&vinfo) = 1;
639 caps = gst_video_info_to_caps (&vinfo);
640
641 setup_rawvideoparse (TRUE, FALSE, caps, GST_FORMAT_BYTES);
642
643 push_data_and_check_output (&sinkcaps_ctx, 192, 192, GST_MSECOND * 0,
644 GST_MSECOND * 40, 1, 0, 0, 0);
645 push_data_and_check_output (&sinkcaps_ctx, 192, 192, GST_MSECOND * 40,
646 GST_MSECOND * 40, 2, 1, 1, 0);
647 push_data_and_check_output (&sinkcaps_ctx, 100, 192, GST_MSECOND * 40,
648 GST_MSECOND * 40, 2, 1, 1, 0);
649 gst_pad_push_event (mysrcpad, gst_event_new_eos ());
650 fail_unless_equals_int (g_list_length (buffers), 2);
651
652 cleanup_rawvideoparse ();
653 }
654
655 GST_END_TEST;
656
657 static Suite *
rawvideoparse_suite(void)658 rawvideoparse_suite (void)
659 {
660 Suite *s = suite_create ("rawvideoparse");
661 TCase *tc_chain = tcase_create ("general");
662
663 suite_add_tcase (s, tc_chain);
664 tcase_add_test (tc_chain, test_push_unaligned_data_properties_config);
665 tcase_add_test (tc_chain, test_push_unaligned_data_sink_caps_config);
666 tcase_add_test (tc_chain, test_config_switch);
667 tcase_add_test (tc_chain, test_push_with_no_framerate);
668 tcase_add_test (tc_chain, test_computed_plane_strides);
669 tcase_add_test (tc_chain, test_change_caps);
670 tcase_add_test (tc_chain, test_incomplete_last_buffer);
671
672 return s;
673 }
674
675 GST_CHECK_MAIN (rawvideoparse);
676