1 /* GStreamer
2 *
3 * unit test for GstBufferList
4 *
5 * Copyright (C) 2009 Axis Communications <dev-gstreamer at axis dot com>
6 * @author Jonas Holmberg <jonas dot holmberg at axis dot com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gst/check/gstcheck.h>
28 #include <gst/gstbufferlist.h>
29 #include <string.h>
30
31 static GstBufferList *list;
32
33 static void
setup(void)34 setup (void)
35 {
36 list = gst_buffer_list_new ();
37 }
38
39 static void
cleanup(void)40 cleanup (void)
41 {
42 gst_buffer_list_unref (list);
43 list = NULL;
44 }
45
GST_START_TEST(test_add_and_iterate)46 GST_START_TEST (test_add_and_iterate)
47 {
48 GstBuffer *buf1;
49 GstBuffer *buf2;
50
51 /* buffer list is initially empty */
52 fail_unless (gst_buffer_list_length (list) == 0);
53
54 ASSERT_CRITICAL (gst_buffer_list_insert (list, 0, NULL));
55 ASSERT_CRITICAL (gst_buffer_list_insert (NULL, 0, NULL));
56
57 buf1 = gst_buffer_new ();
58
59 /* add a group of 2 buffers */
60 fail_unless (gst_buffer_list_length (list) == 0);
61 ASSERT_CRITICAL (gst_buffer_list_insert (list, -1, NULL));
62 ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 1);
63 gst_buffer_list_add (list, buf1);
64 ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 1); /* list takes ownership */
65 fail_unless (gst_buffer_list_length (list) == 1);
66 buf2 = gst_buffer_new ();
67 gst_buffer_list_add (list, buf2);
68 ASSERT_BUFFER_REFCOUNT (buf2, "buf2", 1);
69 fail_unless (gst_buffer_list_length (list) == 2);
70 }
71
72 GST_END_TEST;
73
GST_START_TEST(test_remove)74 GST_START_TEST (test_remove)
75 {
76 GstBuffer *buf;
77
78 /* buffer list is initially empty */
79 fail_unless (gst_buffer_list_length (list) == 0);
80
81 buf = gst_buffer_new ();
82
83 /* add our own ref so it stays alive after removal from the list */
84 buf = gst_buffer_ref (buf);
85
86 /* add a buffer */
87 fail_unless (gst_buffer_list_length (list) == 0);
88 ASSERT_CRITICAL (gst_buffer_list_insert (list, -1, NULL));
89 ASSERT_BUFFER_REFCOUNT (buf, "buf", 2);
90 gst_buffer_list_add (list, buf);
91 ASSERT_BUFFER_REFCOUNT (buf, "buf", 2); /* list takes ownership */
92 fail_unless (gst_buffer_list_length (list) == 1);
93 gst_buffer_list_remove (list, 0, 1);
94 ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
95 gst_buffer_unref (buf);
96 fail_unless (gst_buffer_list_length (list) == 0);
97 }
98
99 GST_END_TEST;
100
GST_START_TEST(test_make_writable)101 GST_START_TEST (test_make_writable)
102 {
103 GstBufferList *wlist;
104 GstBuffer *buf1;
105 GstBuffer *buf2;
106 GstBuffer *buf3;
107 GstBuffer *buf;
108
109 /* add buffers to list */
110 buf1 = gst_buffer_new_allocate (NULL, 1, NULL);
111 gst_buffer_list_add (list, buf1);
112
113 buf2 = gst_buffer_new_allocate (NULL, 2, NULL);
114 buf3 = gst_buffer_new_allocate (NULL, 3, NULL);
115 gst_buffer_list_add (list, gst_buffer_append (buf2, buf3));
116
117 /* making it writable with refcount 1 returns the same list */
118 wlist = gst_buffer_list_make_writable (list);
119 fail_unless (wlist == list);
120 fail_unless_equals_int (gst_buffer_list_length (list), 2);
121 buf = gst_buffer_list_get (list, 0);
122 fail_unless (buf == buf1);
123 ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 1);
124 fail_unless_equals_int (gst_buffer_get_size (buf), 1);
125 buf = gst_buffer_list_get (list, 1);
126 fail_unless (buf == buf2);
127 ASSERT_BUFFER_REFCOUNT (buf2, "buf2", 1);
128 fail_unless_equals_int (gst_buffer_n_memory (buf), 2);
129
130 /* making it writable with refcount 2 returns a copy of the list with
131 * increased refcount on the buffers in the list */
132 gst_buffer_list_ref (list);
133 fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (list), 2);
134 wlist = gst_buffer_list_make_writable (list);
135 fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (list), 1);
136 fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (wlist), 1);
137 fail_unless (wlist != list);
138 /* check list */
139 fail_unless_equals_int (gst_buffer_list_length (list), 2);
140 buf = gst_buffer_list_get (list, 0);
141 fail_unless (buf == buf1);
142 ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 2);
143 fail_unless_equals_int (gst_buffer_get_size (buf), 1);
144 buf = gst_buffer_list_get (list, 1);
145 fail_unless (buf == buf2);
146 ASSERT_BUFFER_REFCOUNT (buf2, "buf2", 2);
147 fail_unless_equals_int (gst_buffer_n_memory (buf), 2);
148 /* check wlist */
149 fail_unless_equals_int (gst_buffer_list_length (wlist), 2);
150 buf = gst_buffer_list_get (wlist, 0);
151 fail_unless (buf == buf1);
152 ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 2);
153 fail_unless_equals_int (gst_buffer_get_size (buf), 1);
154 buf = gst_buffer_list_get (wlist, 1);
155 fail_unless (buf == buf2);
156 ASSERT_BUFFER_REFCOUNT (buf2, "buf2", 2);
157 fail_unless_equals_int (gst_buffer_n_memory (buf), 2);
158 gst_buffer_list_unref (wlist);
159 /* list will be unrefed in cleanup hook */
160 }
161
162 GST_END_TEST;
163
GST_START_TEST(test_copy)164 GST_START_TEST (test_copy)
165 {
166 GstBufferList *list_copy;
167 GstBuffer *buf1;
168 GstBuffer *buf2;
169 GstBuffer *buf3;
170 GstBuffer *buf;
171
172 /* add buffers to the list */
173 buf1 = gst_buffer_new_allocate (NULL, 1, NULL);
174 gst_buffer_list_add (list, buf1);
175
176 buf2 = gst_buffer_new_allocate (NULL, 2, NULL);
177 buf3 = gst_buffer_new_allocate (NULL, 3, NULL);
178 gst_buffer_list_add (list, gst_buffer_append (buf2, buf3));
179
180 /* make a copy */
181 list_copy = gst_buffer_list_copy (list);
182 fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (list) == 1);
183 fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (list_copy) == 1);
184 fail_unless (list_copy != list);
185 fail_unless_equals_int (gst_buffer_list_length (list_copy), 2);
186 buf = gst_buffer_list_get (list_copy, 0);
187 fail_unless (buf == buf1);
188 ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 2);
189 fail_unless_equals_int (gst_buffer_get_size (buf1), 1);
190 buf = gst_buffer_list_get (list_copy, 1);
191 fail_unless (buf == buf2);
192 ASSERT_BUFFER_REFCOUNT (buf2, "buf2", 2);
193 fail_unless_equals_int (gst_buffer_get_size (buf2), 5);
194 fail_unless_equals_int (gst_buffer_n_memory (buf2), 2);
195
196 gst_buffer_list_unref (list_copy);
197 }
198
199 GST_END_TEST;
200
GST_START_TEST(test_copy_deep)201 GST_START_TEST (test_copy_deep)
202 {
203 GstBufferList *list_copy;
204 GstMapInfo info, sinfo;
205 GstBuffer *buf1;
206 GstBuffer *buf2;
207 GstBuffer *buf_copy;
208
209 /* add buffers to the list */
210 buf1 = gst_buffer_new_allocate (NULL, 1, NULL);
211 gst_buffer_list_add (list, buf1);
212
213 buf2 = gst_buffer_new_allocate (NULL, 2, NULL);
214 gst_buffer_list_add (list, buf2);
215
216 /* make a copy */
217 list_copy = gst_buffer_list_copy_deep (list);
218 fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (list) == 1);
219 fail_unless (GST_MINI_OBJECT_REFCOUNT_VALUE (list_copy) == 1);
220 fail_unless (list_copy != list);
221 fail_unless_equals_int (gst_buffer_list_length (list_copy), 2);
222
223 buf_copy = gst_buffer_list_get (list_copy, 0);
224 /* each buffer in the list is copied and must point to different memory */
225 fail_unless (buf_copy != buf1);
226 ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 1);
227 fail_unless_equals_int (gst_buffer_get_size (buf1), 1);
228
229 buf_copy = gst_buffer_list_get (list_copy, 1);
230 fail_unless (buf_copy != buf2);
231 ASSERT_BUFFER_REFCOUNT (buf2, "buf2", 1);
232 fail_unless_equals_int (gst_buffer_get_size (buf2), 2);
233
234 fail_unless (gst_buffer_map (buf2, &info, GST_MAP_READ));
235 fail_unless (gst_buffer_map (buf_copy, &sinfo, GST_MAP_READ));
236
237 /* NOTE that data is refcounted */
238 fail_unless (info.size == sinfo.size);
239 /* copy_deep() forces new GstMemory to be used */
240 fail_unless (info.data != sinfo.data);
241
242 gst_buffer_unmap (buf_copy, &sinfo);
243 gst_buffer_unmap (buf2, &info);
244
245 gst_buffer_list_unref (list_copy);
246 }
247
248 GST_END_TEST;
249
250 typedef struct
251 {
252 GstBuffer *buf[2];
253 guint iter;
254 } ForeachData;
255
256 static gboolean
foreach_func1(GstBuffer ** buffer,guint idx,ForeachData * data)257 foreach_func1 (GstBuffer ** buffer, guint idx, ForeachData * data)
258 {
259 fail_unless (buffer != NULL);
260 fail_unless (GST_IS_BUFFER (*buffer));
261 fail_unless (*buffer == data->buf[idx]);
262
263 data->iter++;
264
265 return TRUE;
266 }
267
268 static gboolean
foreach_func3(GstBuffer ** buffer,guint idx,ForeachData * data)269 foreach_func3 (GstBuffer ** buffer, guint idx, ForeachData * data)
270 {
271 fail_unless (idx == 0);
272 fail_unless (buffer != NULL);
273 fail_unless (GST_IS_BUFFER (*buffer));
274 fail_unless (*buffer == data->buf[idx]);
275
276 data->iter++;
277
278 return FALSE;
279 }
280
281 static gboolean
foreach_func4(GstBuffer ** buffer,guint idx,ForeachData * data)282 foreach_func4 (GstBuffer ** buffer, guint idx, ForeachData * data)
283 {
284 fail_unless (idx == 0);
285 fail_unless (buffer != NULL);
286 fail_unless (GST_IS_BUFFER (*buffer));
287 fail_unless (*buffer == data->buf[data->iter]);
288
289 /* remove first */
290 if (*buffer == data->buf[0]) {
291 gst_buffer_unref (*buffer);
292 *buffer = NULL;
293 }
294
295 data->iter++;
296
297 return TRUE;
298 }
299
300 static gboolean
foreach_func5(GstBuffer ** buffer,guint idx,ForeachData * data)301 foreach_func5 (GstBuffer ** buffer, guint idx, ForeachData * data)
302 {
303 fail_unless (buffer != NULL);
304 fail_unless (GST_IS_BUFFER (*buffer));
305
306 data->iter++;
307
308 return TRUE;
309 }
310
GST_START_TEST(test_foreach)311 GST_START_TEST (test_foreach)
312 {
313 GstBuffer *buf2, *buf3;
314 ForeachData data;
315
316 /* add buffers to the list */
317 data.buf[0] = gst_buffer_new_allocate (NULL, 1, NULL);
318 gst_buffer_list_add (list, data.buf[0]);
319
320 buf2 = gst_buffer_new_allocate (NULL, 2, NULL);
321 buf3 = gst_buffer_new_allocate (NULL, 3, NULL);
322 data.buf[1] = gst_buffer_append (buf2, buf3);
323 gst_buffer_list_add (list, data.buf[1]);
324
325 fail_unless (gst_buffer_list_get (list, 0) == data.buf[0]);
326 fail_unless (gst_buffer_list_get (list, 1) == data.buf[1]);
327
328 /* iterate everything */
329 data.iter = 0;
330 gst_buffer_list_foreach (list, (GstBufferListFunc) foreach_func1, &data);
331 fail_unless (data.iter == 2);
332
333 /* iterate only the first buffer */
334 data.iter = 0;
335 gst_buffer_list_foreach (list, (GstBufferListFunc) foreach_func3, &data);
336 fail_unless (data.iter == 1);
337
338 /* remove the first buffer */
339 data.iter = 0;
340 gst_buffer_list_foreach (list, (GstBufferListFunc) foreach_func4, &data);
341 fail_unless (data.iter == 2);
342
343 fail_unless (gst_buffer_list_get (list, 0) == data.buf[1]);
344 fail_unless_equals_int (gst_buffer_list_length (list), 1);
345
346 /* iterate everything, just one more buffer now */
347 data.iter = 0;
348 gst_buffer_list_foreach (list, (GstBufferListFunc) foreach_func5, &data);
349 fail_unless (data.iter == 1);
350 }
351
352 GST_END_TEST;
353
354 /* make sure everything is fine if we exceed the pre-allocated size */
GST_START_TEST(test_expand_and_remove)355 GST_START_TEST (test_expand_and_remove)
356 {
357 GArray *arr;
358 GstBuffer *buf;
359 guint i, idx, num, counter = 0;
360
361 gst_buffer_list_unref (list);
362
363 arr = g_array_new (FALSE, FALSE, sizeof (guint));
364
365 list = gst_buffer_list_new_sized (1);
366
367 for (i = 0; i < 250; ++i) {
368 num = ++counter;
369 buf = gst_buffer_new_allocate (NULL, num, NULL);
370 gst_buffer_list_add (list, buf);
371 g_array_append_val (arr, num);
372 }
373
374 for (i = 0; i < 250; ++i) {
375 num = ++counter;
376 buf = gst_buffer_new_allocate (NULL, num, NULL);
377 idx = g_random_int_range (0, gst_buffer_list_length (list));
378 gst_buffer_list_insert (list, idx, buf);
379 g_array_insert_val (arr, idx, num);
380 }
381
382 /* make sure the list looks like it should */
383 fail_unless_equals_int (arr->len, gst_buffer_list_length (list));
384 for (i = 0; i < arr->len; ++i) {
385 buf = gst_buffer_list_get (list, i);
386 num = gst_buffer_get_size (buf);
387 fail_unless_equals_int (num, g_array_index (arr, guint, i));
388 }
389
390 for (i = 0; i < 44; ++i) {
391 num = g_random_int_range (1, 5);
392 idx = g_random_int_range (0, gst_buffer_list_length (list) - num);
393 gst_buffer_list_remove (list, idx, num);
394 g_array_remove_range (arr, idx, num);
395 }
396
397 /* make sure the list still looks like it should */
398 fail_unless_equals_int (arr->len, gst_buffer_list_length (list));
399 for (i = 0; i < arr->len; ++i) {
400 buf = gst_buffer_list_get (list, i);
401 num = gst_buffer_get_size (buf);
402 fail_unless_equals_int (num, g_array_index (arr, guint, i));
403 }
404
405 for (i = 0; i < 500; ++i) {
406 num = ++counter;
407 buf = gst_buffer_new_allocate (NULL, num, NULL);
408 gst_buffer_list_add (list, buf);
409 g_array_append_val (arr, num);
410 }
411
412 for (i = 0; i < 500; ++i) {
413 num = ++counter;
414 buf = gst_buffer_new_allocate (NULL, num, NULL);
415 idx = g_random_int_range (0, gst_buffer_list_length (list));
416 gst_buffer_list_insert (list, idx, buf);
417 g_array_insert_val (arr, idx, num);
418 }
419
420 /* make sure the list still looks like it should */
421 fail_unless_equals_int (arr->len, gst_buffer_list_length (list));
422 for (i = 0; i < arr->len; ++i) {
423 buf = gst_buffer_list_get (list, i);
424 num = gst_buffer_get_size (buf);
425 fail_unless_equals_int (num, g_array_index (arr, guint, i));
426 }
427
428 g_array_unref (arr);
429 }
430
431 GST_END_TEST;
432
GST_START_TEST(test_get_writable)433 GST_START_TEST (test_get_writable)
434 {
435 GstBuffer *buf, *writable_buf;
436
437 /* buffer list is initially empty */
438 fail_unless (gst_buffer_list_length (list) == 0);
439
440 /* Add 2 buffers */
441 buf = gst_buffer_new ();
442 ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
443 gst_buffer_list_add (list, buf);
444 ASSERT_BUFFER_REFCOUNT (buf, "buf", 1); /* list takes ownership */
445 fail_unless (gst_buffer_list_length (list) == 1);
446 fail_unless (buf == gst_buffer_list_get_writable (list, 0));
447 fail_unless (buf == gst_buffer_list_get (list, 0));
448
449 /* extra ref to make buffer no longer writable */
450 gst_buffer_ref (buf);
451 ASSERT_BUFFER_REFCOUNT (buf, "buf", 2);
452 fail_unless (buf == gst_buffer_list_get (list, 0));
453 ASSERT_BUFFER_REFCOUNT (buf, "buf", 2);
454
455 /* should make a copy to make it writable */
456 writable_buf = gst_buffer_list_get_writable (list, 0);
457 fail_if (buf == writable_buf);
458 ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
459 ASSERT_BUFFER_REFCOUNT (writable_buf, "writable_buf", 1);
460
461 gst_buffer_unref (buf);
462 }
463
464 GST_END_TEST;
465
GST_START_TEST(test_calc_size)466 GST_START_TEST (test_calc_size)
467 {
468 gst_buffer_list_add (list, gst_buffer_new_wrapped (g_strdup ("Hello"), 5));
469 gst_buffer_list_add (list, gst_buffer_new_wrapped (g_strdup (", "), 2));
470 gst_buffer_list_add (list, gst_buffer_new_wrapped (g_strdup ("world!"), 6));
471
472 fail_unless_equals_int (5 + 2 + 6, gst_buffer_list_calculate_size (list));
473 }
474
475 GST_END_TEST;
476
GST_START_TEST(test_new_sized_0)477 GST_START_TEST (test_new_sized_0)
478 {
479 GstBufferList *b = gst_buffer_list_new_sized (0);
480
481 gst_buffer_list_unref (b);
482 }
483
484 GST_END_TEST;
485
GST_START_TEST(test_multiple_mutable_buffer_references)486 GST_START_TEST (test_multiple_mutable_buffer_references)
487 {
488 GstBufferList *b = gst_buffer_list_new_sized (1);
489 GstBuffer *buf1, *buf2;
490
491 gst_buffer_list_add (b, gst_buffer_new ());
492 gst_buffer_list_ref (b);
493
494 buf1 = gst_buffer_list_get (b, 0);
495 buf2 = gst_buffer_list_get (b, 0);
496
497 fail_if (gst_buffer_list_is_writable (b));
498 fail_if (gst_buffer_is_writable (buf1));
499 fail_if (gst_buffer_is_writable (buf2));
500
501 /* Immutable operations that have optimizations for writable buffers
502 * will cause problems now, e.g. read-mapping the buffer and merging
503 * together all the memories and replacing them in the buffer */
504
505 gst_buffer_list_unref (b);
506 gst_buffer_list_unref (b);
507 }
508
509 GST_END_TEST;
510
511 static gboolean
foreach_replace_buffer(GstBuffer ** buffer,guint idx,gpointer user_data)512 foreach_replace_buffer (GstBuffer ** buffer, guint idx, gpointer user_data)
513 {
514 gst_buffer_unref (*buffer);
515 *buffer = gst_buffer_new ();
516
517 return TRUE;
518 }
519
GST_START_TEST(test_foreach_modify_non_writeable_list)520 GST_START_TEST (test_foreach_modify_non_writeable_list)
521 {
522 GstBufferList *b = gst_buffer_list_new_sized (1);
523 GstBuffer *buf;
524
525 buf = gst_buffer_new ();
526 gst_buffer_list_add (b, gst_buffer_ref (buf));
527 gst_buffer_list_ref (b);
528
529 fail_if (gst_buffer_list_is_writable (b));
530
531 ASSERT_CRITICAL (gst_buffer_list_foreach (b, foreach_replace_buffer, NULL));
532
533 fail_unless (gst_buffer_list_get (b, 0) == buf);
534
535 gst_buffer_list_unref (b);
536 gst_buffer_list_unref (b);
537 gst_buffer_unref (buf);
538 }
539
540 GST_END_TEST;
541
GST_START_TEST(test_foreach_modify_writeable_list)542 GST_START_TEST (test_foreach_modify_writeable_list)
543 {
544 GstBufferList *b = gst_buffer_list_new_sized (1);
545 GstBuffer *buf;
546
547 buf = gst_buffer_new ();
548 gst_buffer_list_add (b, gst_buffer_ref (buf));
549
550 fail_unless (gst_buffer_list_is_writable (b));
551
552 gst_buffer_list_foreach (b, foreach_replace_buffer, NULL);
553
554 gst_buffer_list_unref (b);
555 gst_buffer_unref (buf);
556 }
557
558 GST_END_TEST;
559
560 static Suite *
gst_buffer_list_suite(void)561 gst_buffer_list_suite (void)
562 {
563 Suite *s = suite_create ("GstBufferList");
564 TCase *tc_chain = tcase_create ("general");
565
566 suite_add_tcase (s, tc_chain);
567
568 tcase_add_checked_fixture (tc_chain, setup, cleanup);
569 tcase_add_test (tc_chain, test_add_and_iterate);
570 tcase_add_test (tc_chain, test_remove);
571 tcase_add_test (tc_chain, test_make_writable);
572 tcase_add_test (tc_chain, test_copy);
573 tcase_add_test (tc_chain, test_copy_deep);
574 tcase_add_test (tc_chain, test_foreach);
575 tcase_add_test (tc_chain, test_expand_and_remove);
576 tcase_add_test (tc_chain, test_get_writable);
577 tcase_add_test (tc_chain, test_calc_size);
578 tcase_add_test (tc_chain, test_new_sized_0);
579 tcase_add_test (tc_chain, test_multiple_mutable_buffer_references);
580 tcase_add_test (tc_chain, test_foreach_modify_non_writeable_list);
581 tcase_add_test (tc_chain, test_foreach_modify_writeable_list);
582
583 return s;
584 }
585
586 GST_CHECK_MAIN (gst_buffer_list);
587