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