1 /* GStreamer
2  * Copyright (C) 2018 Collabora Ltd.
3  *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include <gst/check/gstcheck.h>
22 #include <gst/audio/gstplanaraudioadapter.h>
23 
24 static GstBuffer *
generate_buffer(GstAudioInfo * info,gsize nsamples,gsize dummy_start,gsize dummy_end,gpointer * data_ret)25 generate_buffer (GstAudioInfo * info, gsize nsamples,
26     gsize dummy_start, gsize dummy_end, gpointer * data_ret)
27 {
28   gpointer data;
29   GstBuffer *buf;
30   gsize buf_sz;
31   gsize offsets[8];
32   gint c, bps;
33 
34   fail_unless (info->channels <= 8);
35 
36   bps = info->finfo->width / 8;
37   buf_sz = info->channels * (nsamples + dummy_start + dummy_end) * bps;
38   data = g_malloc (buf_sz);
39   fail_unless (data);
40   buf = gst_buffer_new_wrapped (data, buf_sz);
41   fail_unless (buf);
42 
43   for (c = 0; c < info->channels; c++) {
44     offsets[c] =
45         dummy_start * bps + c * (nsamples + dummy_start + dummy_end) * bps;
46 
47     /* dummy samples at the beginning of each channel plane */
48     gst_buffer_memset (buf, offsets[c] - dummy_start * bps, 0xBF,
49         dummy_start * bps);
50     /* valid channel samples */
51     gst_buffer_memset (buf, offsets[c], c | 0xF0, nsamples * bps);
52     /* dummy samples at the end of each channel plane */
53     gst_buffer_memset (buf, offsets[c] + nsamples * bps, 0xEF, dummy_end * bps);
54   }
55   gst_buffer_add_audio_meta (buf, info, nsamples, offsets);
56 
57   if (data_ret)
58     *data_ret = data;
59   return buf;
60 }
61 
62 static void
verify_buffer_contents(GstBuffer * buf,GstAudioInfo * info,gint expect_n_planes,gsize expect_plane_size,gpointer base,gsize real_plane_size,gsize expect_plane_start_offset)63 verify_buffer_contents (GstBuffer * buf, GstAudioInfo * info,
64     gint expect_n_planes, gsize expect_plane_size,
65     gpointer base, gsize real_plane_size, gsize expect_plane_start_offset)
66 {
67   GstAudioBuffer abuf;
68   gint i;
69   guint8 *byte;
70 
71   gst_audio_buffer_map (&abuf, info, buf, GST_MAP_READ);
72   fail_unless_equals_int (GST_AUDIO_BUFFER_N_PLANES (&abuf), expect_n_planes);
73   fail_unless_equals_int (GST_AUDIO_BUFFER_PLANE_SIZE (&abuf),
74       expect_plane_size);
75 
76   for (i = 0; i < GST_AUDIO_BUFFER_N_PLANES (&abuf); i++) {
77     if (base) {
78       /* if we have a base pointer, verify the plane pointer
79        * points to the right place */
80       fail_unless_equals_pointer (abuf.planes[i],
81           ((guint8 *) base) + i * real_plane_size + expect_plane_start_offset);
82     }
83 
84     /* verify all contents */
85     byte = abuf.planes[i];
86     while (byte < ((guint8 *) abuf.planes[i]) + expect_plane_size) {
87       GST_TRACE ("%d | %p", i, byte);
88       fail_unless_equals_int_hex (*byte, i | 0xF0);
89       ++byte;
90     }
91   }
92   gst_audio_buffer_unmap (&abuf);
93 }
94 
GST_START_TEST(test_retrieve_same)95 GST_START_TEST (test_retrieve_same)
96 {
97   GstPlanarAudioAdapter *adapter;
98   GstAudioInfo info;
99   GstBuffer *buf;
100 
101   adapter = gst_planar_audio_adapter_new ();
102 
103   gst_audio_info_init (&info);
104   gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S32, 100, 5, NULL);
105   info.layout = GST_AUDIO_LAYOUT_NON_INTERLEAVED;
106 
107   gst_planar_audio_adapter_configure (adapter, &info);
108   buf = generate_buffer (&info, 20, 0, 0, NULL);
109   gst_planar_audio_adapter_push (adapter, buf);
110   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 20);
111 
112   buf = generate_buffer (&info, 20, 10, 5, NULL);
113   gst_planar_audio_adapter_push (adapter, buf);
114   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 40);
115 
116   buf = gst_planar_audio_adapter_get_buffer (adapter, 20, GST_MAP_READ);
117   fail_unless (buf);
118   /* this buffer is shared between the adapter and us, we just ref'ed it */
119   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 2);
120   /* the adapter still has 40 samples */
121   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 40);
122   gst_planar_audio_adapter_flush (adapter, 20);
123   /* the adapter must have dropped this buffer internally */
124   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
125   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 20);
126   gst_buffer_unref (buf);
127 
128   buf = gst_planar_audio_adapter_take_buffer (adapter, 20, GST_MAP_READ);
129   fail_unless (buf);
130   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
131   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 0);
132   gst_buffer_unref (buf);
133 
134   g_object_unref (adapter);
135 }
136 
137 GST_END_TEST;
138 
GST_START_TEST(test_retrieve_smaller_for_read)139 GST_START_TEST (test_retrieve_smaller_for_read)
140 {
141   GstPlanarAudioAdapter *adapter;
142   GstAudioInfo info;
143   GstBuffer *buf;
144   gpointer data1, data2;
145 
146   adapter = gst_planar_audio_adapter_new ();
147 
148   gst_audio_info_init (&info);
149   gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, 100, 8, NULL);
150   info.layout = GST_AUDIO_LAYOUT_NON_INTERLEAVED;
151 
152   gst_planar_audio_adapter_configure (adapter, &info);
153   buf = generate_buffer (&info, 40, 0, 0, &data1);
154   gst_planar_audio_adapter_push (adapter, buf);
155   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 40);
156 
157   buf = generate_buffer (&info, 20, 10, 10, &data2);
158   gst_planar_audio_adapter_push (adapter, buf);
159   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 60);
160 
161   /* the the first 20 samples */
162 
163   buf = gst_planar_audio_adapter_take_buffer (adapter, 20, GST_MAP_READ);
164   fail_unless (buf);
165   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
166   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 40);
167   verify_buffer_contents (buf, &info, 8, 20 * sizeof (gint16),
168       data1, 40 * sizeof (gint16), 0);
169   gst_buffer_unref (buf);
170 
171   /* now the next 20 samples */
172 
173   buf = gst_planar_audio_adapter_take_buffer (adapter, 20, GST_MAP_READ);
174   fail_unless (buf);
175   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
176   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 20);
177   /* still the same memory, with a 20 sample offset on each plane */
178   verify_buffer_contents (buf, &info, 8, 20 * sizeof (gint16),
179       data1, 40 * sizeof (gint16), 20 * sizeof (gint16));
180   gst_buffer_unref (buf);
181 
182   /* 5 samples from the second buffer */
183 
184   buf = gst_planar_audio_adapter_take_buffer (adapter, 5, GST_MAP_READ);
185   fail_unless (buf);
186   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
187   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 15);
188   /* original buffer had an offset of 10 samples on its own and
189    * was 40 samples long, with only 20 samples valid */
190   verify_buffer_contents (buf, &info, 8, 5 * sizeof (gint16),
191       data2, 40 * sizeof (gint16), 10 * sizeof (gint16));
192   gst_buffer_unref (buf);
193 
194   /* and the last 15 samples */
195 
196   buf = gst_planar_audio_adapter_take_buffer (adapter, 15, GST_MAP_READ);
197   fail_unless (buf);
198   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
199   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 0);
200   verify_buffer_contents (buf, &info, 8, 15 * sizeof (gint16),
201       data2, 40 * sizeof (gint16), 15 * sizeof (gint16));
202   gst_buffer_unref (buf);
203 
204   g_object_unref (adapter);
205 }
206 
207 GST_END_TEST;
208 
GST_START_TEST(test_retrieve_smaller_for_write)209 GST_START_TEST (test_retrieve_smaller_for_write)
210 {
211   GstPlanarAudioAdapter *adapter;
212   GstAudioInfo info;
213   GstBuffer *buf;
214 
215   adapter = gst_planar_audio_adapter_new ();
216 
217   gst_audio_info_init (&info);
218   gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, 100, 8, NULL);
219   info.layout = GST_AUDIO_LAYOUT_NON_INTERLEAVED;
220 
221   gst_planar_audio_adapter_configure (adapter, &info);
222   buf = generate_buffer (&info, 40, 0, 0, NULL);
223   gst_planar_audio_adapter_push (adapter, buf);
224   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 40);
225 
226   buf = generate_buffer (&info, 20, 10, 10, NULL);
227   gst_planar_audio_adapter_push (adapter, buf);
228   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 60);
229 
230   /* the the first 20 samples */
231 
232   buf = gst_planar_audio_adapter_take_buffer (adapter, 20, GST_MAP_WRITE);
233   fail_unless (buf);
234   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
235   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 40);
236   verify_buffer_contents (buf, &info, 8, 20 * sizeof (gint16), NULL, 0, 0);
237   gst_buffer_unref (buf);
238 
239   /* now the next 20 samples */
240 
241   buf = gst_planar_audio_adapter_take_buffer (adapter, 20, GST_MAP_WRITE);
242   fail_unless (buf);
243   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
244   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 20);
245   verify_buffer_contents (buf, &info, 8, 20 * sizeof (gint16), NULL, 0, 0);
246   gst_buffer_unref (buf);
247 
248   /* 5 samples from the second buffer */
249 
250   buf = gst_planar_audio_adapter_take_buffer (adapter, 5, GST_MAP_WRITE);
251   fail_unless (buf);
252   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
253   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 15);
254   verify_buffer_contents (buf, &info, 8, 5 * sizeof (gint16), NULL, 0, 0);
255   gst_buffer_unref (buf);
256 
257   /* and the last 15 samples */
258 
259   buf = gst_planar_audio_adapter_take_buffer (adapter, 15, GST_MAP_WRITE);
260   fail_unless (buf);
261   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
262   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 0);
263   verify_buffer_contents (buf, &info, 8, 15 * sizeof (gint16), NULL, 0, 0);
264   gst_buffer_unref (buf);
265 
266   g_object_unref (adapter);
267 }
268 
269 GST_END_TEST;
270 
GST_START_TEST(test_retrieve_combined)271 GST_START_TEST (test_retrieve_combined)
272 {
273   GstPlanarAudioAdapter *adapter;
274   GstAudioInfo info;
275   GstBuffer *buf;
276   gpointer data2;
277 
278   adapter = gst_planar_audio_adapter_new ();
279 
280   gst_audio_info_init (&info);
281   gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_U24_32, 100, 4, NULL);
282   info.layout = GST_AUDIO_LAYOUT_NON_INTERLEAVED;
283 
284   gst_planar_audio_adapter_configure (adapter, &info);
285   buf = generate_buffer (&info, 20, 0, 0, NULL);
286   gst_planar_audio_adapter_push (adapter, buf);
287   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 20);
288 
289   buf = generate_buffer (&info, 20, 10, 15, NULL);
290   gst_planar_audio_adapter_push (adapter, buf);
291   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 40);
292 
293   buf = generate_buffer (&info, 80, 0, 5, &data2);
294   gst_planar_audio_adapter_push (adapter, buf);
295   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 120);
296 
297   /* take the first 60 samples - buffers are combined here */
298 
299   buf = gst_planar_audio_adapter_take_buffer (adapter, 60, GST_MAP_READ);
300   fail_unless (buf);
301   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
302   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 60);
303   verify_buffer_contents (buf, &info, 4, 60 * sizeof (gint32), NULL, 0, 0);
304   gst_buffer_unref (buf);
305 
306   /* now the next 60 samples, for reading */
307 
308   buf = gst_planar_audio_adapter_get_buffer (adapter, 60, GST_MAP_READ);
309   fail_unless (buf);
310   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
311   /* note we didn't take the buffer, the data is still in the adapter */
312   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 60);
313   verify_buffer_contents (buf, &info, 4, 60 * sizeof (gint32),
314       data2, 85 * sizeof (gint32), 20 * sizeof (gint32));
315   gst_buffer_unref (buf);
316 
317   /* flush a few */
318 
319   gst_planar_audio_adapter_flush (adapter, 10);
320   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 50);
321 
322   /* add some more */
323 
324   buf = generate_buffer (&info, 20, 10, 0, NULL);
325   gst_planar_audio_adapter_push (adapter, buf);
326   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 70);
327 
328   /* now take 60 again */
329 
330   buf = gst_planar_audio_adapter_take_buffer (adapter, 60, GST_MAP_READ);
331   fail_unless (buf);
332   fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (buf), 1);
333   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 10);
334   verify_buffer_contents (buf, &info, 4, 60 * sizeof (gint32), NULL, 0, 0);
335   gst_buffer_unref (buf);
336 
337   gst_planar_audio_adapter_clear (adapter);
338   fail_unless_equals_int (gst_planar_audio_adapter_available (adapter), 0);
339 
340   g_object_unref (adapter);
341 }
342 
343 GST_END_TEST;
344 
345 static Suite *
planar_audio_adapter_suite(void)346 planar_audio_adapter_suite (void)
347 {
348   Suite *s = suite_create ("GstPlanarAudioAdapter");
349 
350   TCase *tc_chain = tcase_create ("general");
351 
352   suite_add_tcase (s, tc_chain);
353   tcase_add_test (tc_chain, test_retrieve_same);
354   tcase_add_test (tc_chain, test_retrieve_smaller_for_read);
355   tcase_add_test (tc_chain, test_retrieve_smaller_for_write);
356   tcase_add_test (tc_chain, test_retrieve_combined);
357 
358   return s;
359 }
360 
361 GST_CHECK_MAIN (planar_audio_adapter);
362