• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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