Coverage Report

Created: 2025-09-05 06:29

/src/gstreamer/subprojects/gst-plugins-base/gst-libs/gst/audio/gstaudiometa.c
Line
Count
Source (jump to first uncovered line)
1
/* GStreamer
2
 * Copyright (C) <2011> Wim Taymans <wim.taymans@gmail.com>
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Library General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2 of the License, or (at your option) any later version.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Library General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Library General Public
15
 * License along with this library; if not, write to the
16
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17
 * Boston, MA 02110-1301, USA.
18
 */
19
20
/**
21
 * SECTION:gstaudiometa
22
 * @title: GstAudio meta
23
 * @short_description: Buffer metadata for audio downmix matrix handling
24
 *
25
 * #GstAudioDownmixMeta defines an audio downmix matrix to be send along with
26
 * audio buffers. These functions in this module help to create and attach the
27
 * meta as well as extracting it.
28
 */
29
#ifdef HAVE_CONFIG_H
30
#include "config.h"
31
#endif
32
33
#include "gstaudiometa.h"
34
35
#include <string.h>
36
#include <gst/base/base.h>
37
38
static gboolean
39
gst_audio_downmix_meta_init (GstMeta * meta, gpointer params,
40
    GstBuffer * buffer)
41
0
{
42
0
  GstAudioDownmixMeta *dmeta = (GstAudioDownmixMeta *) meta;
43
44
0
  dmeta->from_position = dmeta->to_position = NULL;
45
0
  dmeta->from_channels = dmeta->to_channels = 0;
46
0
  dmeta->matrix = NULL;
47
48
0
  return TRUE;
49
0
}
50
51
static void
52
gst_audio_downmix_meta_free (GstMeta * meta, GstBuffer * buffer)
53
0
{
54
0
  GstAudioDownmixMeta *dmeta = (GstAudioDownmixMeta *) meta;
55
56
0
  g_free (dmeta->from_position);
57
0
  if (dmeta->matrix) {
58
0
    g_free (*dmeta->matrix);
59
0
    g_free (dmeta->matrix);
60
0
  }
61
0
}
62
63
static gboolean
64
gst_audio_downmix_meta_transform (GstBuffer * dest, GstMeta * meta,
65
    GstBuffer * buffer, GQuark type, gpointer data)
66
0
{
67
0
  GstAudioDownmixMeta *smeta, *dmeta;
68
69
0
  smeta = (GstAudioDownmixMeta *) meta;
70
71
0
  if (GST_META_TRANSFORM_IS_COPY (type)) {
72
0
    dmeta = gst_buffer_add_audio_downmix_meta (dest, smeta->from_position,
73
0
        smeta->from_channels, smeta->to_position, smeta->to_channels,
74
0
        (const gfloat **) smeta->matrix);
75
0
    if (!dmeta)
76
0
      return FALSE;
77
0
  } else {
78
    /* return FALSE, if transform type is not supported */
79
0
    return FALSE;
80
0
  }
81
82
0
  return TRUE;
83
0
}
84
85
/**
86
 * gst_buffer_get_audio_downmix_meta_for_channels:
87
 * @buffer: a #GstBuffer
88
 * @to_position: (array length=to_channels): the channel positions of
89
 *   the destination
90
 * @to_channels: The number of channels of the destination
91
 *
92
 * Find the #GstAudioDownmixMeta on @buffer for the given destination
93
 * channel positions.
94
 *
95
 * Returns: (transfer none): the #GstAudioDownmixMeta on @buffer.
96
 */
97
GstAudioDownmixMeta *
98
gst_buffer_get_audio_downmix_meta_for_channels (GstBuffer * buffer,
99
    const GstAudioChannelPosition * to_position, gint to_channels)
100
0
{
101
0
  gpointer state = NULL;
102
0
  GstMeta *meta;
103
0
  const GstMetaInfo *info = GST_AUDIO_DOWNMIX_META_INFO;
104
105
0
  while ((meta = gst_buffer_iterate_meta (buffer, &state))) {
106
0
    if (meta->info->api == info->api) {
107
0
      GstAudioDownmixMeta *ameta = (GstAudioDownmixMeta *) meta;
108
0
      if (ameta->to_channels == to_channels &&
109
0
          memcmp (ameta->to_position, to_position,
110
0
              sizeof (GstAudioChannelPosition) * to_channels) == 0)
111
0
        return ameta;
112
0
    }
113
0
  }
114
0
  return NULL;
115
0
}
116
117
/**
118
 * gst_buffer_add_audio_downmix_meta:
119
 * @buffer: a #GstBuffer
120
 * @from_position: (array length=from_channels): the channel positions
121
 *   of the source
122
 * @from_channels: The number of channels of the source
123
 * @to_position: (array length=to_channels): the channel positions of
124
 *   the destination
125
 * @to_channels: The number of channels of the destination
126
 * @matrix: The matrix coefficients.
127
 *
128
 * Attaches #GstAudioDownmixMeta metadata to @buffer with the given parameters.
129
 *
130
 * @matrix is an two-dimensional array of @to_channels times @from_channels
131
 * coefficients, i.e. the i-th output channels is constructed by multiplicating
132
 * the input channels with the coefficients in @matrix[i] and taking the sum
133
 * of the results.
134
 *
135
 * Returns: (transfer none): the #GstAudioDownmixMeta on @buffer.
136
 */
137
GstAudioDownmixMeta *
138
gst_buffer_add_audio_downmix_meta (GstBuffer * buffer,
139
    const GstAudioChannelPosition * from_position, gint from_channels,
140
    const GstAudioChannelPosition * to_position, gint to_channels,
141
    const gfloat ** matrix)
142
0
{
143
0
  GstAudioDownmixMeta *meta;
144
0
  gint i;
145
146
0
  g_return_val_if_fail (from_position != NULL, NULL);
147
0
  g_return_val_if_fail (from_channels > 0, NULL);
148
0
  g_return_val_if_fail (to_position != NULL, NULL);
149
0
  g_return_val_if_fail (to_channels > 0, NULL);
150
0
  g_return_val_if_fail (matrix != NULL, NULL);
151
152
0
  meta =
153
0
      (GstAudioDownmixMeta *) gst_buffer_add_meta (buffer,
154
0
      GST_AUDIO_DOWNMIX_META_INFO, NULL);
155
156
0
  meta->from_channels = from_channels;
157
0
  meta->to_channels = to_channels;
158
159
0
  meta->from_position =
160
0
      g_new (GstAudioChannelPosition, meta->from_channels + meta->to_channels);
161
0
  meta->to_position = meta->from_position + meta->from_channels;
162
0
  memcpy (meta->from_position, from_position,
163
0
      sizeof (GstAudioChannelPosition) * meta->from_channels);
164
0
  memcpy (meta->to_position, to_position,
165
0
      sizeof (GstAudioChannelPosition) * meta->to_channels);
166
167
0
  meta->matrix = g_new (gfloat *, meta->to_channels);
168
0
  meta->matrix[0] = g_new (gfloat, meta->from_channels * meta->to_channels);
169
0
  memcpy (meta->matrix[0], matrix[0], sizeof (gfloat) * meta->from_channels);
170
0
  for (i = 1; i < meta->to_channels; i++) {
171
0
    meta->matrix[i] = meta->matrix[0] + i * meta->from_channels;
172
0
    memcpy (meta->matrix[i], matrix[i], sizeof (gfloat) * meta->from_channels);
173
0
  }
174
175
0
  return meta;
176
0
}
177
178
GType
179
gst_audio_downmix_meta_api_get_type (void)
180
0
{
181
0
  static GType type;
182
0
  static const gchar *tags[] =
183
0
      { GST_META_TAG_AUDIO_STR, GST_META_TAG_AUDIO_CHANNELS_STR, NULL };
184
185
0
  if (g_once_init_enter (&type)) {
186
0
    GType _type = gst_meta_api_type_register ("GstAudioDownmixMetaAPI", tags);
187
0
    g_once_init_leave (&type, _type);
188
0
  }
189
0
  return type;
190
0
}
191
192
const GstMetaInfo *
193
gst_audio_downmix_meta_get_info (void)
194
0
{
195
0
  static const GstMetaInfo *audio_downmix_meta_info = NULL;
196
197
0
  if (g_once_init_enter ((GstMetaInfo **) & audio_downmix_meta_info)) {
198
0
    const GstMetaInfo *meta =
199
0
        gst_meta_register (GST_AUDIO_DOWNMIX_META_API_TYPE,
200
0
        "GstAudioDownmixMeta", sizeof (GstAudioDownmixMeta),
201
0
        gst_audio_downmix_meta_init, gst_audio_downmix_meta_free,
202
0
        gst_audio_downmix_meta_transform);
203
0
    g_once_init_leave ((GstMetaInfo **) & audio_downmix_meta_info,
204
0
        (GstMetaInfo *) meta);
205
0
  }
206
0
  return audio_downmix_meta_info;
207
0
}
208
209
static gboolean
210
gst_audio_clipping_meta_init (GstMeta * meta, gpointer params,
211
    GstBuffer * buffer)
212
0
{
213
0
  GstAudioClippingMeta *cmeta = (GstAudioClippingMeta *) meta;
214
215
0
  cmeta->format = GST_FORMAT_UNDEFINED;
216
0
  cmeta->start = cmeta->end = 0;
217
218
0
  return TRUE;
219
0
}
220
221
static gboolean
222
gst_audio_clipping_meta_transform (GstBuffer * dest, GstMeta * meta,
223
    GstBuffer * buffer, GQuark type, gpointer data)
224
0
{
225
0
  GstAudioClippingMeta *smeta, *dmeta;
226
227
0
  smeta = (GstAudioClippingMeta *) meta;
228
229
0
  if (GST_META_TRANSFORM_IS_COPY (type)) {
230
0
    GstMetaTransformCopy *copy = data;
231
232
0
    if (copy->region)
233
0
      return FALSE;
234
235
0
    dmeta =
236
0
        gst_buffer_add_audio_clipping_meta (dest, smeta->format, smeta->start,
237
0
        smeta->end);
238
0
    if (!dmeta)
239
0
      return FALSE;
240
0
  } else {
241
    /* TODO: Could implement an automatic transform for resampling */
242
    /* return FALSE, if transform type is not supported */
243
0
    return FALSE;
244
0
  }
245
246
0
  return TRUE;
247
0
}
248
249
/**
250
 * gst_buffer_add_audio_clipping_meta:
251
 * @buffer: a #GstBuffer
252
 * @format: GstFormat of @start and @stop, GST_FORMAT_DEFAULT is samples
253
 * @start: Amount of audio to clip from start of buffer
254
 * @end: Amount of  to clip from end of buffer
255
 *
256
 * Attaches #GstAudioClippingMeta metadata to @buffer with the given parameters.
257
 *
258
 * Returns: (transfer none): the #GstAudioClippingMeta on @buffer.
259
 *
260
 * Since: 1.8
261
 */
262
GstAudioClippingMeta *
263
gst_buffer_add_audio_clipping_meta (GstBuffer * buffer,
264
    GstFormat format, guint64 start, guint64 end)
265
0
{
266
0
  GstAudioClippingMeta *meta;
267
268
0
  g_return_val_if_fail (format != GST_FORMAT_UNDEFINED, NULL);
269
270
0
  meta =
271
0
      (GstAudioClippingMeta *) gst_buffer_add_meta (buffer,
272
0
      GST_AUDIO_CLIPPING_META_INFO, NULL);
273
274
0
  meta->format = format;
275
0
  meta->start = start;
276
0
  meta->end = end;
277
278
0
  return meta;
279
0
}
280
281
GType
282
gst_audio_clipping_meta_api_get_type (void)
283
0
{
284
0
  static GType type;
285
0
  static const gchar *tags[] =
286
0
      { GST_META_TAG_AUDIO_STR, GST_META_TAG_AUDIO_RATE_STR, NULL };
287
288
0
  if (g_once_init_enter (&type)) {
289
0
    GType _type = gst_meta_api_type_register ("GstAudioClippingMetaAPI", tags);
290
0
    g_once_init_leave (&type, _type);
291
0
  }
292
0
  return type;
293
0
}
294
295
const GstMetaInfo *
296
gst_audio_clipping_meta_get_info (void)
297
0
{
298
0
  static const GstMetaInfo *audio_clipping_meta_info = NULL;
299
300
0
  if (g_once_init_enter ((GstMetaInfo **) & audio_clipping_meta_info)) {
301
0
    const GstMetaInfo *meta =
302
0
        gst_meta_register (GST_AUDIO_CLIPPING_META_API_TYPE,
303
0
        "GstAudioClippingMeta", sizeof (GstAudioClippingMeta),
304
0
        gst_audio_clipping_meta_init, NULL,
305
0
        gst_audio_clipping_meta_transform);
306
0
    g_once_init_leave ((GstMetaInfo **) & audio_clipping_meta_info,
307
0
        (GstMetaInfo *) meta);
308
0
  }
309
0
  return audio_clipping_meta_info;
310
0
}
311
312
313
static gboolean
314
gst_audio_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
315
0
{
316
0
  GstAudioMeta *ameta = (GstAudioMeta *) meta;
317
318
0
  gst_audio_info_init (&ameta->info);
319
0
  ameta->samples = 0;
320
0
  ameta->offsets = NULL;
321
322
0
  return TRUE;
323
0
}
324
325
static void
326
gst_audio_meta_free (GstMeta * meta, GstBuffer * buffer)
327
0
{
328
0
  GstAudioMeta *ameta = (GstAudioMeta *) meta;
329
330
0
  if (ameta->offsets && ameta->offsets != ameta->priv_offsets_arr)
331
0
    g_free (ameta->offsets);
332
0
}
333
334
static gboolean
335
gst_audio_meta_transform (GstBuffer * dest, GstMeta * meta,
336
    GstBuffer * buffer, GQuark type, gpointer data)
337
0
{
338
0
  GstAudioMeta *smeta, *dmeta;
339
340
0
  smeta = (GstAudioMeta *) meta;
341
342
0
  if (GST_META_TRANSFORM_IS_COPY (type)) {
343
0
    dmeta = gst_buffer_add_audio_meta (dest, &smeta->info, smeta->samples,
344
0
        smeta->offsets);
345
0
    if (!dmeta)
346
0
      return FALSE;
347
0
  } else {
348
    /* return FALSE, if transform type is not supported */
349
0
    return FALSE;
350
0
  }
351
352
0
  return TRUE;
353
0
}
354
355
static gboolean
356
gst_audio_meta_serialize (const GstMeta * meta, GstByteArrayInterface * data,
357
    guint8 * version)
358
0
{
359
0
  GstAudioMeta *ameta = (GstAudioMeta *) meta;
360
361
  /* Position is limited to 64 */
362
0
  gint n_position = ameta->info.channels > 64 ? 0 : ameta->info.channels;
363
364
0
  gsize size = 28 + n_position * 4 + ameta->info.channels * 8;
365
0
  guint8 *ptr = gst_byte_array_interface_append (data, size);
366
0
  if (ptr == NULL)
367
0
    return FALSE;
368
369
0
  GstByteWriter bw;
370
0
  gboolean success = TRUE;
371
0
  gst_byte_writer_init_with_data (&bw, ptr, size, FALSE);
372
0
  success &= gst_byte_writer_put_int32_le (&bw, ameta->info.finfo->format);
373
0
  success &= gst_byte_writer_put_int32_le (&bw, ameta->info.flags);
374
0
  success &= gst_byte_writer_put_int32_le (&bw, ameta->info.layout);
375
0
  success &= gst_byte_writer_put_int32_le (&bw, ameta->info.rate);
376
0
  success &= gst_byte_writer_put_int32_le (&bw, ameta->info.channels);
377
0
  for (int i = 0; i < n_position; i++)
378
0
    success &= gst_byte_writer_put_int32_le (&bw, ameta->info.position[i]);
379
0
  success &= gst_byte_writer_put_uint64_le (&bw, ameta->samples);
380
0
  for (int i = 0; i < ameta->info.channels; i++)
381
0
    success &= gst_byte_writer_put_uint64_le (&bw, ameta->offsets[i]);
382
0
  g_assert (success);
383
384
0
  return TRUE;
385
0
}
386
387
static GstMeta *
388
gst_audio_meta_deserialize (const GstMetaInfo * info, GstBuffer * buffer,
389
    const guint8 * data, gsize size, guint8 version)
390
0
{
391
0
  GstAudioMeta *ameta = NULL;
392
0
  gint32 format;
393
0
  gint32 flags;
394
0
  gint32 layout;
395
0
  gint32 rate;
396
0
  gint32 channels;
397
398
0
  if (version != 0)
399
0
    return NULL;
400
401
0
  GstByteReader br;
402
0
  gboolean success = TRUE;
403
0
  gst_byte_reader_init (&br, data, size);
404
0
  success &= gst_byte_reader_get_int32_le (&br, &format);
405
0
  success &= gst_byte_reader_get_int32_le (&br, &flags);
406
0
  success &= gst_byte_reader_get_int32_le (&br, &layout);
407
0
  success &= gst_byte_reader_get_int32_le (&br, &rate);
408
0
  success &= gst_byte_reader_get_int32_le (&br, &channels);
409
410
0
  if (!success)
411
0
    return NULL;
412
413
  /* Position is limited to 64 */
414
0
  gint n_position = channels > 64 ? 0 : channels;
415
0
  gint32 *position = g_new (gint32, n_position);
416
0
  guint64 *offsets64 = g_new (guint64, channels);
417
0
  guint64 samples = 0;
418
419
0
  for (int i = 0; i < n_position; i++)
420
0
    success &= gst_byte_reader_get_int32_le (&br, &position[i]);
421
0
  success &= gst_byte_reader_get_uint64_le (&br, &samples);
422
0
  for (int i = 0; i < channels; i++)
423
0
    success &= gst_byte_reader_get_uint64_le (&br, &offsets64[i]);
424
425
0
  if (!success) {
426
0
    g_free (position);
427
0
    g_free (offsets64);
428
0
    return NULL;
429
0
  }
430
#if GLIB_SIZEOF_SIZE_T != 8
431
  gsize *offsets = g_new (gsize, channels);
432
  for (int i = 0; i < channels; i++) {
433
    if (offsets64[i] > G_MAXSIZE) {
434
      g_free (offsets64);
435
      g_free (offsets);
436
      g_free (position);
437
      return NULL;
438
    }
439
    offsets[i] = offsets64[i];
440
  }
441
  g_free (offsets64);
442
#else
443
0
  gsize *offsets = (gsize *) offsets64;
444
0
#endif
445
446
0
  GstAudioInfo audio_info;
447
0
  gst_audio_info_set_format (&audio_info, format, rate, channels,
448
0
      (channels > 64) ? NULL : position);
449
0
  audio_info.flags = flags;
450
0
  audio_info.layout = layout;
451
452
0
  ameta = gst_buffer_add_audio_meta (buffer, &audio_info, samples, offsets);
453
454
0
  g_free (offsets);
455
0
  g_free (position);
456
457
0
  return (GstMeta *) ameta;
458
0
}
459
460
/**
461
 * gst_buffer_add_audio_meta:
462
 * @buffer: a #GstBuffer
463
 * @info: the audio properties of the buffer
464
 * @samples: the number of valid samples in the buffer
465
 * @offsets: (nullable): the offsets (in bytes) where each channel plane starts
466
 *   in the buffer or %NULL to calculate it (see below); must be %NULL also
467
 *   when @info->layout is %GST_AUDIO_LAYOUT_INTERLEAVED
468
 *
469
 * Allocates and attaches a #GstAudioMeta on @buffer, which must be writable
470
 * for that purpose. The fields of the #GstAudioMeta are directly populated
471
 * from the arguments of this function.
472
 *
473
 * When @info->layout is %GST_AUDIO_LAYOUT_NON_INTERLEAVED and @offsets is
474
 * %NULL, the offsets are calculated with a formula that assumes the planes are
475
 * tightly packed and in sequence:
476
 * offsets[channel] = channel * @samples * sample_stride
477
 *
478
 * It is not allowed for channels to overlap in memory,
479
 * i.e. for each i in [0, channels), the range
480
 * [@offsets[i], @offsets[i] + @samples * sample_stride) must not overlap
481
 * with any other such range. This function will assert if the parameters
482
 * specified cause this restriction to be violated.
483
 *
484
 * It is, obviously, also not allowed to specify parameters that would cause
485
 * out-of-bounds memory access on @buffer. This is also checked, which means
486
 * that you must add enough memory on the @buffer before adding this meta.
487
 *
488
 * Returns: (transfer none): the #GstAudioMeta that was attached on the @buffer
489
 *
490
 * Since: 1.16
491
 */
492
GstAudioMeta *
493
gst_buffer_add_audio_meta (GstBuffer * buffer, const GstAudioInfo * info,
494
    gsize samples, gsize offsets[])
495
0
{
496
0
  GstAudioMeta *meta;
497
0
  gint i;
498
0
  gsize plane_size;
499
500
0
  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
501
0
  g_return_val_if_fail (info != NULL, NULL);
502
0
  g_return_val_if_fail (GST_AUDIO_INFO_IS_VALID (info), NULL);
503
0
  g_return_val_if_fail (GST_AUDIO_INFO_FORMAT (info) !=
504
0
      GST_AUDIO_FORMAT_UNKNOWN, NULL);
505
0
  g_return_val_if_fail (info->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED
506
0
      || !offsets, NULL);
507
508
0
  meta =
509
0
      (GstAudioMeta *) gst_buffer_add_meta (buffer, GST_AUDIO_META_INFO, NULL);
510
511
0
  meta->info = *info;
512
0
  meta->samples = samples;
513
0
  plane_size = samples * info->finfo->width / 8;
514
515
0
  if (info->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
516
0
#ifndef G_DISABLE_CHECKS
517
0
    gsize max_offset = 0;
518
0
    gint j;
519
0
#endif
520
521
0
    if (G_UNLIKELY (info->channels > 8))
522
0
      meta->offsets = g_new (gsize, info->channels);
523
0
    else
524
0
      meta->offsets = meta->priv_offsets_arr;
525
526
0
    if (offsets) {
527
0
      for (i = 0; i < info->channels; i++) {
528
0
        meta->offsets[i] = offsets[i];
529
0
#ifndef G_DISABLE_CHECKS
530
0
        max_offset = MAX (max_offset, offsets[i]);
531
0
        for (j = 0; j < info->channels; j++) {
532
0
          if (i != j && !(offsets[j] + plane_size <= offsets[i]
533
0
                  || offsets[i] + plane_size <= offsets[j])) {
534
0
            g_critical ("GstAudioMeta properties would cause channel memory "
535
0
                "areas to overlap! offsets: %" G_GSIZE_FORMAT " (%d), %"
536
0
                G_GSIZE_FORMAT " (%d) with plane size %" G_GSIZE_FORMAT,
537
0
                offsets[i], i, offsets[j], j, plane_size);
538
0
            gst_buffer_remove_meta (buffer, (GstMeta *) meta);
539
0
            return NULL;
540
0
          }
541
0
        }
542
0
#endif
543
0
      }
544
0
    } else {
545
      /* default offsets assume channels are laid out sequentially in memory */
546
0
      for (i = 0; i < info->channels; i++)
547
0
        meta->offsets[i] = i * plane_size;
548
0
#ifndef G_DISABLE_CHECKS
549
0
      max_offset = meta->offsets[info->channels - 1];
550
0
#endif
551
0
    }
552
553
0
#ifndef G_DISABLE_CHECKS
554
0
    if (max_offset + plane_size > gst_buffer_get_size (buffer)) {
555
0
      g_critical ("GstAudioMeta properties would cause "
556
0
          "out-of-bounds memory access on the buffer: max_offset %"
557
0
          G_GSIZE_FORMAT ", samples %" G_GSIZE_FORMAT ", bps %u, buffer size %"
558
0
          G_GSIZE_FORMAT, max_offset, samples, info->finfo->width / 8,
559
0
          gst_buffer_get_size (buffer));
560
0
      gst_buffer_remove_meta (buffer, (GstMeta *) meta);
561
0
      return NULL;
562
0
    }
563
0
#endif
564
0
  }
565
566
0
  return meta;
567
0
}
568
569
GType
570
gst_audio_meta_api_get_type (void)
571
136
{
572
136
  static GType type;
573
136
  static const gchar *tags[] = {
574
136
    GST_META_TAG_AUDIO_STR, GST_META_TAG_AUDIO_CHANNELS_STR,
575
136
    GST_META_TAG_AUDIO_RATE_STR, NULL
576
136
  };
577
578
136
  if (g_once_init_enter (&type)) {
579
1
    GType _type = gst_meta_api_type_register ("GstAudioMetaAPI", tags);
580
1
    g_once_init_leave (&type, _type);
581
1
  }
582
136
  return type;
583
136
}
584
585
const GstMetaInfo *
586
gst_audio_meta_get_info (void)
587
0
{
588
0
  static const GstMetaInfo *audio_meta_info = NULL;
589
590
0
  if (g_once_init_enter ((GstMetaInfo **) & audio_meta_info)) {
591
0
    GstMetaInfo *info = gst_meta_info_new (GST_AUDIO_META_API_TYPE,
592
0
        "GstAudioMeta", sizeof (GstAudioMeta));
593
594
0
    info->init_func = gst_audio_meta_init;
595
0
    info->free_func = gst_audio_meta_free;
596
0
    info->transform_func = gst_audio_meta_transform;
597
0
    info->serialize_func = gst_audio_meta_serialize;
598
0
    info->deserialize_func = gst_audio_meta_deserialize;
599
0
    const GstMetaInfo *meta = gst_meta_info_register (info);
600
601
0
    g_once_init_leave ((GstMetaInfo **) & audio_meta_info,
602
0
        (GstMetaInfo *) meta);
603
0
  }
604
0
  return audio_meta_info;
605
0
}
606
607
/**
608
 * gst_audio_level_meta_api_get_type:
609
 *
610
 * Return the #GType associated with #GstAudioLevelMeta.
611
 *
612
 * Returns: a #GType
613
 *
614
 * Since: 1.20
615
 */
616
GType
617
gst_audio_level_meta_api_get_type (void)
618
0
{
619
0
  static GType type = 0;
620
0
  static const gchar *tags[] = { NULL };
621
622
0
  if (g_once_init_enter (&type)) {
623
0
    GType _type = gst_meta_api_type_register ("GstAudioLevelMetaAPI", tags);
624
0
    g_once_init_leave (&type, _type);
625
0
  }
626
0
  return type;
627
0
}
628
629
static gboolean
630
gst_audio_level_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
631
0
{
632
0
  GstAudioLevelMeta *dmeta = (GstAudioLevelMeta *) meta;
633
634
0
  dmeta->level = 127;
635
0
  dmeta->voice_activity = FALSE;
636
637
0
  return TRUE;
638
0
}
639
640
static gboolean
641
gst_audio_level_meta_transform (GstBuffer * dst, GstMeta * meta,
642
    GstBuffer * src, GQuark type, gpointer data)
643
0
{
644
0
  if (GST_META_TRANSFORM_IS_COPY (type)) {
645
0
    GstAudioLevelMeta *smeta = (GstAudioLevelMeta *) meta;
646
0
    GstAudioLevelMeta *dmeta;
647
648
0
    dmeta = gst_buffer_add_audio_level_meta (dst, smeta->level,
649
0
        smeta->voice_activity);
650
0
    if (dmeta == NULL)
651
0
      return FALSE;
652
0
  } else {
653
    /* return FALSE, if transform type is not supported */
654
0
    return FALSE;
655
0
  }
656
657
0
  return TRUE;
658
0
}
659
660
/**
661
 * gst_audio_level_meta_get_info:
662
 *
663
 * Return the #GstMetaInfo associated with #GstAudioLevelMeta.
664
 *
665
 * Returns: (transfer none): a #GstMetaInfo
666
 *
667
 * Since: 1.20
668
 */
669
const GstMetaInfo *
670
gst_audio_level_meta_get_info (void)
671
0
{
672
0
  static const GstMetaInfo *audio_level_meta_info = NULL;
673
674
0
  if (g_once_init_enter (&audio_level_meta_info)) {
675
0
    const GstMetaInfo *meta = gst_meta_register (GST_AUDIO_LEVEL_META_API_TYPE,
676
0
        "GstAudioLevelMeta",
677
0
        sizeof (GstAudioLevelMeta),
678
0
        gst_audio_level_meta_init,
679
0
        (GstMetaFreeFunction) NULL,
680
0
        gst_audio_level_meta_transform);
681
0
    g_once_init_leave (&audio_level_meta_info, meta);
682
0
  }
683
0
  return audio_level_meta_info;
684
0
}
685
686
/**
687
 * gst_buffer_add_audio_level_meta:
688
 * @buffer: a #GstBuffer
689
 * @level: the -dBov from 0-127 (127 is silence).
690
 * @voice_activity: whether the buffer contains voice activity.
691
 *
692
 * Attaches audio level information to @buffer. (RFC 6464)
693
 *
694
 * Returns: (transfer none) (nullable): the #GstAudioLevelMeta on @buffer.
695
 *
696
 * Since: 1.20
697
 */
698
GstAudioLevelMeta *
699
gst_buffer_add_audio_level_meta (GstBuffer * buffer, guint8 level,
700
    gboolean voice_activity)
701
0
{
702
0
  GstAudioLevelMeta *meta;
703
704
0
  g_return_val_if_fail (buffer != NULL, NULL);
705
706
0
  meta = (GstAudioLevelMeta *) gst_buffer_add_meta (buffer,
707
0
      GST_AUDIO_LEVEL_META_INFO, NULL);
708
0
  if (!meta)
709
0
    return NULL;
710
711
0
  meta->level = level;
712
0
  meta->voice_activity = voice_activity;
713
714
0
  return meta;
715
0
}
716
717
/**
718
 * gst_buffer_get_audio_level_meta:
719
 * @buffer: a #GstBuffer
720
 *
721
 * Find the #GstAudioLevelMeta on @buffer.
722
 *
723
 * Returns: (transfer none) (nullable): the #GstAudioLevelMeta or %NULL when
724
 * there is no such metadata on @buffer.
725
 *
726
 * Since: 1.20
727
 */
728
GstAudioLevelMeta *
729
gst_buffer_get_audio_level_meta (GstBuffer * buffer)
730
0
{
731
0
  return (GstAudioLevelMeta *) gst_buffer_get_meta (buffer,
732
0
      gst_audio_level_meta_api_get_type ());
733
0
}