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 /**
22 * SECTION:gstplanaraudioadapter
23 * @title: GstPlanarAudioAdapter
24 * @short_description: adapts incoming audio data on a sink pad into chunks of N samples
25 *
26 * This class is similar to GstAdapter, but it is made to work with
27 * non-interleaved (planar) audio buffers. Before using, an audio format
28 * must be configured with gst_planar_audio_adapter_configure()
29 */
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "gstplanaraudioadapter.h"
35
36 GST_DEBUG_CATEGORY_STATIC (gst_planar_audio_adapter_debug);
37 #define GST_CAT_DEFAULT gst_planar_audio_adapter_debug
38
39 struct _GstPlanarAudioAdapter
40 {
41 GObject object;
42
43 GstAudioInfo info;
44 GSList *buflist;
45 GSList *buflist_end;
46 gsize samples;
47 gsize skip;
48 guint count;
49
50 GstClockTime pts;
51 guint64 pts_distance;
52 GstClockTime dts;
53 guint64 dts_distance;
54 guint64 offset;
55 guint64 offset_distance;
56
57 GstClockTime pts_at_discont;
58 GstClockTime dts_at_discont;
59 guint64 offset_at_discont;
60
61 guint64 distance_from_discont;
62 };
63
64 struct _GstPlanarAudioAdapterClass
65 {
66 GObjectClass parent_class;
67 };
68
69 #define _do_init \
70 GST_DEBUG_CATEGORY_INIT (gst_planar_audio_adapter_debug, "planaraudioadapter", \
71 0, "object to splice and merge audio buffers to desired size")
72 #define gst_planar_audio_adapter_parent_class parent_class
73 G_DEFINE_TYPE_WITH_CODE (GstPlanarAudioAdapter, gst_planar_audio_adapter,
74 G_TYPE_OBJECT, _do_init);
75
76 static void gst_planar_audio_adapter_dispose (GObject * object);
77
78 static void
gst_planar_audio_adapter_class_init(GstPlanarAudioAdapterClass * klass)79 gst_planar_audio_adapter_class_init (GstPlanarAudioAdapterClass * klass)
80 {
81 GObjectClass *object = G_OBJECT_CLASS (klass);
82
83 object->dispose = gst_planar_audio_adapter_dispose;
84 }
85
86 static void
gst_planar_audio_adapter_init(GstPlanarAudioAdapter * adapter)87 gst_planar_audio_adapter_init (GstPlanarAudioAdapter * adapter)
88 {
89 adapter->pts = GST_CLOCK_TIME_NONE;
90 adapter->pts_distance = 0;
91 adapter->dts = GST_CLOCK_TIME_NONE;
92 adapter->dts_distance = 0;
93 adapter->offset = GST_BUFFER_OFFSET_NONE;
94 adapter->offset_distance = 0;
95 adapter->pts_at_discont = GST_CLOCK_TIME_NONE;
96 adapter->dts_at_discont = GST_CLOCK_TIME_NONE;
97 adapter->offset_at_discont = GST_BUFFER_OFFSET_NONE;
98 adapter->distance_from_discont = 0;
99 }
100
101 static void
gst_planar_audio_adapter_dispose(GObject * object)102 gst_planar_audio_adapter_dispose (GObject * object)
103 {
104 GstPlanarAudioAdapter *adapter = GST_PLANAR_AUDIO_ADAPTER (object);
105
106 gst_planar_audio_adapter_clear (adapter);
107
108 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
109 }
110
111 /**
112 * gst_planar_audio_adapter_new:
113 *
114 * Creates a new #GstPlanarAudioAdapter. Free with g_object_unref().
115 *
116 * Returns: (transfer full): a new #GstPlanarAudioAdapter
117 */
118 GstPlanarAudioAdapter *
gst_planar_audio_adapter_new(void)119 gst_planar_audio_adapter_new (void)
120 {
121 return g_object_new (GST_TYPE_PLANAR_AUDIO_ADAPTER, NULL);
122 }
123
124 /**
125 * gst_planar_audio_adapter_configure:
126 * @adapter: a #GstPlanarAudioAdapter
127 * @info: a #GstAudioInfo describing the format of the audio data
128 *
129 * Sets up the @adapter to handle audio data of the specified audio format.
130 * Note that this will internally clear the adapter and re-initialize it.
131 */
132 void
gst_planar_audio_adapter_configure(GstPlanarAudioAdapter * adapter,const GstAudioInfo * info)133 gst_planar_audio_adapter_configure (GstPlanarAudioAdapter * adapter,
134 const GstAudioInfo * info)
135 {
136 g_return_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter));
137 g_return_if_fail (info != NULL);
138 g_return_if_fail (GST_AUDIO_INFO_IS_VALID (info));
139 g_return_if_fail (info->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED);
140
141 gst_planar_audio_adapter_clear (adapter);
142 adapter->info = *info;
143 }
144
145 /**
146 * gst_planar_audio_adapter_clear:
147 * @adapter: a #GstPlanarAudioAdapter
148 *
149 * Removes all buffers from @adapter.
150 */
151 void
gst_planar_audio_adapter_clear(GstPlanarAudioAdapter * adapter)152 gst_planar_audio_adapter_clear (GstPlanarAudioAdapter * adapter)
153 {
154 g_return_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter));
155
156 g_slist_foreach (adapter->buflist, (GFunc) gst_mini_object_unref, NULL);
157 g_slist_free (adapter->buflist);
158 adapter->buflist = NULL;
159 adapter->buflist_end = NULL;
160 adapter->count = 0;
161 adapter->samples = 0;
162 adapter->skip = 0;
163
164 adapter->pts = GST_CLOCK_TIME_NONE;
165 adapter->pts_distance = 0;
166 adapter->dts = GST_CLOCK_TIME_NONE;
167 adapter->dts_distance = 0;
168 adapter->offset = GST_BUFFER_OFFSET_NONE;
169 adapter->offset_distance = 0;
170 adapter->pts_at_discont = GST_CLOCK_TIME_NONE;
171 adapter->dts_at_discont = GST_CLOCK_TIME_NONE;
172 adapter->offset_at_discont = GST_BUFFER_OFFSET_NONE;
173 adapter->distance_from_discont = 0;
174 }
175
176 static inline void
update_timestamps_and_offset(GstPlanarAudioAdapter * adapter,GstBuffer * buf)177 update_timestamps_and_offset (GstPlanarAudioAdapter * adapter, GstBuffer * buf)
178 {
179 GstClockTime pts, dts;
180 guint64 offset;
181
182 pts = GST_BUFFER_PTS (buf);
183 if (GST_CLOCK_TIME_IS_VALID (pts)) {
184 GST_LOG_OBJECT (adapter, "new pts %" GST_TIME_FORMAT, GST_TIME_ARGS (pts));
185 adapter->pts = pts;
186 adapter->pts_distance = 0;
187 }
188 dts = GST_BUFFER_DTS (buf);
189 if (GST_CLOCK_TIME_IS_VALID (dts)) {
190 GST_LOG_OBJECT (adapter, "new dts %" GST_TIME_FORMAT, GST_TIME_ARGS (dts));
191 adapter->dts = dts;
192 adapter->dts_distance = 0;
193 }
194 offset = GST_BUFFER_OFFSET (buf);
195 if (offset != GST_BUFFER_OFFSET_NONE) {
196 GST_LOG_OBJECT (adapter, "new offset %" G_GUINT64_FORMAT, offset);
197 adapter->offset = offset;
198 adapter->offset_distance = 0;
199 }
200
201 if (GST_BUFFER_IS_DISCONT (buf)) {
202 /* Take values as-is (might be NONE) */
203 adapter->pts_at_discont = pts;
204 adapter->dts_at_discont = dts;
205 adapter->offset_at_discont = offset;
206 adapter->distance_from_discont = 0;
207 }
208 }
209
210 /**
211 * gst_planar_audio_adapter_push:
212 * @adapter: a #GstPlanarAudioAdapter
213 * @buf: (transfer full): a #GstBuffer to queue in the adapter
214 *
215 * Adds the data from @buf to the data stored inside @adapter and takes
216 * ownership of the buffer.
217 */
218 void
gst_planar_audio_adapter_push(GstPlanarAudioAdapter * adapter,GstBuffer * buf)219 gst_planar_audio_adapter_push (GstPlanarAudioAdapter * adapter, GstBuffer * buf)
220 {
221 GstAudioMeta *meta;
222 gsize samples;
223
224 g_return_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter));
225 g_return_if_fail (GST_AUDIO_INFO_IS_VALID (&adapter->info));
226 g_return_if_fail (GST_IS_BUFFER (buf));
227
228 meta = gst_buffer_get_audio_meta (buf);
229 g_return_if_fail (meta != NULL);
230 g_return_if_fail (gst_audio_info_is_equal (&meta->info, &adapter->info));
231
232 samples = meta->samples;
233 adapter->samples += samples;
234
235 if (G_UNLIKELY (adapter->buflist == NULL)) {
236 GST_LOG_OBJECT (adapter, "pushing %p first %" G_GSIZE_FORMAT " samples",
237 buf, samples);
238 adapter->buflist = adapter->buflist_end = g_slist_append (NULL, buf);
239 update_timestamps_and_offset (adapter, buf);
240 } else {
241 /* Otherwise append to the end, and advance our end pointer */
242 GST_LOG_OBJECT (adapter, "pushing %p %" G_GSIZE_FORMAT " samples at end, "
243 "samples now %" G_GSIZE_FORMAT, buf, samples, adapter->samples);
244 adapter->buflist_end = g_slist_append (adapter->buflist_end, buf);
245 adapter->buflist_end = g_slist_next (adapter->buflist_end);
246 }
247 ++adapter->count;
248 }
249
250 static void
gst_planar_audio_adapter_flush_unchecked(GstPlanarAudioAdapter * adapter,gsize to_flush)251 gst_planar_audio_adapter_flush_unchecked (GstPlanarAudioAdapter * adapter,
252 gsize to_flush)
253 {
254 GSList *g = adapter->buflist;
255 gsize cur_samples;
256
257 /* clear state */
258 adapter->samples -= to_flush;
259
260 /* take skip into account */
261 to_flush += adapter->skip;
262 /* distance is always at least the amount of skipped samples */
263 adapter->pts_distance -= adapter->skip;
264 adapter->dts_distance -= adapter->skip;
265 adapter->offset_distance -= adapter->skip;
266 adapter->distance_from_discont -= adapter->skip;
267
268 g = adapter->buflist;
269 cur_samples = gst_buffer_get_audio_meta (g->data)->samples;
270 while (to_flush >= cur_samples) {
271 /* can skip whole buffer */
272 GST_LOG_OBJECT (adapter, "flushing out head buffer");
273 adapter->pts_distance += cur_samples;
274 adapter->dts_distance += cur_samples;
275 adapter->offset_distance += cur_samples;
276 adapter->distance_from_discont += cur_samples;
277 to_flush -= cur_samples;
278
279 gst_buffer_unref (g->data);
280 g = g_slist_delete_link (g, g);
281 --adapter->count;
282
283 if (G_UNLIKELY (g == NULL)) {
284 GST_LOG_OBJECT (adapter, "adapter empty now");
285 adapter->buflist_end = NULL;
286 break;
287 }
288 /* there is a new head buffer, update the timestamps */
289 update_timestamps_and_offset (adapter, g->data);
290 cur_samples = gst_buffer_get_audio_meta (g->data)->samples;
291 }
292 adapter->buflist = g;
293 /* account for the remaining bytes */
294 adapter->skip = to_flush;
295 adapter->pts_distance += to_flush;
296 adapter->dts_distance += to_flush;
297 adapter->offset_distance += to_flush;
298 adapter->distance_from_discont += to_flush;
299 }
300
301 /**
302 * gst_planar_audio_adapter_flush:
303 * @adapter: a #GstPlanarAudioAdapter
304 * @to_flush: the number of samples to flush
305 *
306 * Flushes the first @to_flush samples in the @adapter. The caller must ensure
307 * that at least this many samples are available.
308 */
309 void
gst_planar_audio_adapter_flush(GstPlanarAudioAdapter * adapter,gsize to_flush)310 gst_planar_audio_adapter_flush (GstPlanarAudioAdapter * adapter, gsize to_flush)
311 {
312 g_return_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter));
313 g_return_if_fail (to_flush <= adapter->samples);
314
315 /* flushing out 0 bytes will do nothing */
316 if (G_UNLIKELY (to_flush == 0))
317 return;
318
319 gst_planar_audio_adapter_flush_unchecked (adapter, to_flush);
320 }
321
322 /**
323 * gst_planar_audio_adapter_get_buffer:
324 * @adapter: a #GstPlanarAudioAdapter
325 * @nsamples: the number of samples to get
326 * @flags: hint the intended use of the returned buffer
327 *
328 * Returns a #GstBuffer containing the first @nsamples of the @adapter, but
329 * does not flush them from the adapter.
330 * Use gst_planar_audio_adapter_take_buffer() for flushing at the same time.
331 *
332 * The map @flags can be used to give an optimization hint to this function.
333 * When the requested buffer is meant to be mapped only for reading, it might
334 * be possible to avoid copying memory in some cases.
335 *
336 * Caller owns a reference to the returned buffer. gst_buffer_unref() after
337 * usage.
338 *
339 * Free-function: gst_buffer_unref
340 *
341 * Returns: (transfer full) (nullable): a #GstBuffer containing the first
342 * @nsamples of the adapter, or %NULL if @nsamples samples are not
343 * available. gst_buffer_unref() when no longer needed.
344 */
345 GstBuffer *
gst_planar_audio_adapter_get_buffer(GstPlanarAudioAdapter * adapter,gsize nsamples,GstMapFlags flags)346 gst_planar_audio_adapter_get_buffer (GstPlanarAudioAdapter * adapter,
347 gsize nsamples, GstMapFlags flags)
348 {
349 GstBuffer *buffer = NULL;
350 GstBuffer *cur;
351 gsize hsamples, skip;
352
353 g_return_val_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter), NULL);
354 g_return_val_if_fail (GST_AUDIO_INFO_IS_VALID (&adapter->info), NULL);
355 g_return_val_if_fail (nsamples > 0, NULL);
356
357 GST_LOG_OBJECT (adapter, "getting buffer of %" G_GSIZE_FORMAT " samples",
358 nsamples);
359
360 /* we don't have enough data, return NULL. This is unlikely
361 * as one usually does an _available() first instead of grabbing a
362 * random size. */
363 if (G_UNLIKELY (nsamples > adapter->samples))
364 return NULL;
365
366 cur = adapter->buflist->data;
367 skip = adapter->skip;
368 hsamples = gst_buffer_get_audio_meta (cur)->samples;
369
370
371 if (skip == 0 && hsamples == nsamples) {
372 /* our head buffer fits exactly the requirements */
373 GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " samples"
374 " as head buffer", nsamples);
375
376 buffer = gst_buffer_ref (cur);
377
378 } else if (hsamples >= nsamples + skip && !(flags & GST_MAP_WRITE)) {
379 /* return a buffer with the same data as our head buffer but with
380 * a modified GstAudioMeta that maps only the parts of the planes
381 * that should be made available to the caller. This is more efficient
382 * for reading (no mem copy), but will hit performance if the caller
383 * decides to map for writing or otherwise do a deep copy */
384 GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " samples"
385 " via copy region", nsamples);
386
387 buffer = gst_buffer_copy_region (cur, GST_BUFFER_COPY_ALL, 0, -1);
388 gst_audio_buffer_truncate (buffer, adapter->info.bpf, skip, nsamples);
389
390 } else {
391 gint c, bps;
392 GstAudioMeta *meta;
393
394 /* construct a buffer with concatenated memory chunks from the appropriate
395 * places. These memories will be copied into a single memory chunk
396 * as soon as the buffer is mapped */
397 GST_LOG_OBJECT (adapter, "providing buffer of %" G_GSIZE_FORMAT " samples"
398 " via memory concatenation", nsamples);
399
400 bps = adapter->info.finfo->width / 8;
401
402 for (c = 0; c < adapter->info.channels; c++) {
403 gsize need = nsamples;
404 gsize cur_skip = skip;
405 gsize take_from_cur;
406 GSList *cur_node = adapter->buflist;
407 while (cur_node && need > 0) {
408 cur = cur_node->data;
409 meta = gst_buffer_get_audio_meta (cur);
410 take_from_cur = need > (meta->samples - cur_skip) ?
411 meta->samples - cur_skip : need;
412
413 cur = gst_buffer_copy_region (cur, GST_BUFFER_COPY_MEMORY,
414 meta->offsets[c] + cur_skip * bps, take_from_cur * bps);
415
416 if (!buffer)
417 buffer = cur;
418 else
419 gst_buffer_append (buffer, cur);
420
421 need -= take_from_cur;
422 cur_skip = 0;
423 cur_node = g_slist_next (cur_node);
424 }
425 }
426
427 gst_buffer_add_audio_meta (buffer, &adapter->info, nsamples, NULL);
428 }
429
430 return buffer;
431 }
432
433 /**
434 * gst_planar_audio_adapter_take_buffer:
435 * @adapter: a #GstPlanarAudioAdapter
436 * @nsamples: the number of samples to take
437 * @flags: hint the intended use of the returned buffer
438 *
439 * Returns a #GstBuffer containing the first @nsamples bytes of the
440 * @adapter. The returned bytes will be flushed from the adapter.
441 *
442 * See gst_planar_audio_adapter_get_buffer() for more details.
443 *
444 * Caller owns a reference to the returned buffer. gst_buffer_unref() after
445 * usage.
446 *
447 * Free-function: gst_buffer_unref
448 *
449 * Returns: (transfer full) (nullable): a #GstBuffer containing the first
450 * @nsamples of the adapter, or %NULL if @nsamples samples are not
451 * available. gst_buffer_unref() when no longer needed.
452 */
453 GstBuffer *
gst_planar_audio_adapter_take_buffer(GstPlanarAudioAdapter * adapter,gsize nsamples,GstMapFlags flags)454 gst_planar_audio_adapter_take_buffer (GstPlanarAudioAdapter * adapter,
455 gsize nsamples, GstMapFlags flags)
456 {
457 GstBuffer *buffer;
458
459 buffer = gst_planar_audio_adapter_get_buffer (adapter, nsamples, flags);
460 if (buffer)
461 gst_planar_audio_adapter_flush_unchecked (adapter, nsamples);
462
463 return buffer;
464 }
465
466 /**
467 * gst_planar_audio_adapter_available:
468 * @adapter: a #GstPlanarAudioAdapter
469 *
470 * Gets the maximum amount of samples available, that is it returns the maximum
471 * value that can be supplied to gst_planar_audio_adapter_get_buffer() without
472 * that function returning %NULL.
473 *
474 * Returns: number of samples available in @adapter
475 */
476 gsize
gst_planar_audio_adapter_available(GstPlanarAudioAdapter * adapter)477 gst_planar_audio_adapter_available (GstPlanarAudioAdapter * adapter)
478 {
479 g_return_val_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter), 0);
480
481 return adapter->samples;
482 }
483
484 /**
485 * gst_planar_audio_adapter_get_distance_from_discont:
486 * @adapter: a #GstPlanarAudioAdapter
487 *
488 * Get the distance in samples since the last buffer with the
489 * %GST_BUFFER_FLAG_DISCONT flag.
490 *
491 * The distance will be reset to 0 for all buffers with
492 * %GST_BUFFER_FLAG_DISCONT on them, and then calculated for all other
493 * following buffers based on their size.
494 *
495 * Returns: The offset. Can be %GST_BUFFER_OFFSET_NONE.
496 */
497 guint64
gst_planar_audio_adapter_distance_from_discont(GstPlanarAudioAdapter * adapter)498 gst_planar_audio_adapter_distance_from_discont (GstPlanarAudioAdapter * adapter)
499 {
500 return adapter->distance_from_discont;
501 }
502
503 /**
504 * gst_planar_audio_adapter_offset_at_discont:
505 * @adapter: a #GstPlanarAudioAdapter
506 *
507 * Get the offset that was on the last buffer with the GST_BUFFER_FLAG_DISCONT
508 * flag, or GST_BUFFER_OFFSET_NONE.
509 *
510 * Returns: The offset at the last discont or GST_BUFFER_OFFSET_NONE.
511 */
512 guint64
gst_planar_audio_adapter_offset_at_discont(GstPlanarAudioAdapter * adapter)513 gst_planar_audio_adapter_offset_at_discont (GstPlanarAudioAdapter * adapter)
514 {
515 g_return_val_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter),
516 GST_BUFFER_OFFSET_NONE);
517
518 return adapter->offset_at_discont;
519 }
520
521 /**
522 * gst_planar_audio_adapter_pts_at_discont:
523 * @adapter: a #GstPlanarAudioAdapter
524 *
525 * Get the PTS that was on the last buffer with the GST_BUFFER_FLAG_DISCONT
526 * flag, or GST_CLOCK_TIME_NONE.
527 *
528 * Returns: The PTS at the last discont or GST_CLOCK_TIME_NONE.
529 */
530 GstClockTime
gst_planar_audio_adapter_pts_at_discont(GstPlanarAudioAdapter * adapter)531 gst_planar_audio_adapter_pts_at_discont (GstPlanarAudioAdapter * adapter)
532 {
533 g_return_val_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter),
534 GST_CLOCK_TIME_NONE);
535
536 return adapter->pts_at_discont;
537 }
538
539 /**
540 * gst_planar_audio_adapter_dts_at_discont:
541 * @adapter: a #GstPlanarAudioAdapter
542 *
543 * Get the DTS that was on the last buffer with the GST_BUFFER_FLAG_DISCONT
544 * flag, or GST_CLOCK_TIME_NONE.
545 *
546 * Returns: The DTS at the last discont or GST_CLOCK_TIME_NONE.
547 */
548 GstClockTime
gst_planar_audio_adapter_dts_at_discont(GstPlanarAudioAdapter * adapter)549 gst_planar_audio_adapter_dts_at_discont (GstPlanarAudioAdapter * adapter)
550 {
551 g_return_val_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter),
552 GST_CLOCK_TIME_NONE);
553
554 return adapter->dts_at_discont;
555 }
556
557 /**
558 * gst_planar_audio_adapter_prev_offset:
559 * @adapter: a #GstPlanarAudioAdapter
560 * @distance: (out) (allow-none): pointer to a location for distance, or %NULL
561 *
562 * Get the offset that was before the current sample in the adapter. When
563 * @distance is given, the amount of samples between the offset and the current
564 * position is returned.
565 *
566 * The offset is reset to GST_BUFFER_OFFSET_NONE and the distance is set to 0
567 * when the adapter is first created or when it is cleared. This also means that
568 * before the first sample with an offset is removed from the adapter, the
569 * offset and distance returned are GST_BUFFER_OFFSET_NONE and 0 respectively.
570 *
571 * Returns: The previous seen offset.
572 */
573 guint64
gst_planar_audio_adapter_prev_offset(GstPlanarAudioAdapter * adapter,guint64 * distance)574 gst_planar_audio_adapter_prev_offset (GstPlanarAudioAdapter * adapter,
575 guint64 * distance)
576 {
577 g_return_val_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter),
578 GST_BUFFER_OFFSET_NONE);
579
580 if (distance)
581 *distance = adapter->offset_distance;
582
583 return adapter->offset;
584 }
585
586 /**
587 * gst_planar_audio_adapter_prev_pts:
588 * @adapter: a #GstPlanarAudioAdapter
589 * @distance: (out) (allow-none): pointer to location for distance, or %NULL
590 *
591 * Get the pts that was before the current sample in the adapter. When
592 * @distance is given, the amount of samples between the pts and the current
593 * position is returned.
594 *
595 * The pts is reset to GST_CLOCK_TIME_NONE and the distance is set to 0 when
596 * the adapter is first created or when it is cleared. This also means that before
597 * the first sample with a pts is removed from the adapter, the pts
598 * and distance returned are GST_CLOCK_TIME_NONE and 0 respectively.
599 *
600 * Returns: The previously seen pts.
601 */
602 GstClockTime
gst_planar_audio_adapter_prev_pts(GstPlanarAudioAdapter * adapter,guint64 * distance)603 gst_planar_audio_adapter_prev_pts (GstPlanarAudioAdapter * adapter,
604 guint64 * distance)
605 {
606 g_return_val_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter),
607 GST_CLOCK_TIME_NONE);
608
609 if (distance)
610 *distance = adapter->pts_distance;
611
612 return adapter->pts;
613 }
614
615 /**
616 * gst_planar_audio_adapter_prev_dts:
617 * @adapter: a #GstPlanarAudioAdapter
618 * @distance: (out) (allow-none): pointer to location for distance, or %NULL
619 *
620 * Get the dts that was before the current sample in the adapter. When
621 * @distance is given, the amount of bytes between the dts and the current
622 * position is returned.
623 *
624 * The dts is reset to GST_CLOCK_TIME_NONE and the distance is set to 0 when
625 * the adapter is first created or when it is cleared. This also means that
626 * before the first sample with a dts is removed from the adapter, the dts
627 * and distance returned are GST_CLOCK_TIME_NONE and 0 respectively.
628 *
629 * Returns: The previously seen dts.
630 */
631 GstClockTime
gst_planar_audio_adapter_prev_dts(GstPlanarAudioAdapter * adapter,guint64 * distance)632 gst_planar_audio_adapter_prev_dts (GstPlanarAudioAdapter * adapter,
633 guint64 * distance)
634 {
635 g_return_val_if_fail (GST_IS_PLANAR_AUDIO_ADAPTER (adapter),
636 GST_CLOCK_TIME_NONE);
637
638 if (distance)
639 *distance = adapter->dts_distance;
640
641 return adapter->dts;
642 }
643