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