Blame gst-libs/gst/audio/audio-buffer.c

Packit 0652a1
/* GStreamer
Packit 0652a1
 * Copyright (C) <2018> Collabora Ltd.
Packit 0652a1
 *   @author George Kiagiadakis <george.kiagiadakis@collabora.com>
Packit 0652a1
 *
Packit 0652a1
 * This library is free software; you can redistribute it and/or
Packit 0652a1
 * modify it under the terms of the GNU Library General Public
Packit 0652a1
 * License as published by the Free Software Foundation; either
Packit 0652a1
 * version 2 of the License, or (at your option) any later version.
Packit 0652a1
 *
Packit 0652a1
 * This library is distributed in the hope that it will be useful,
Packit 0652a1
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 0652a1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 0652a1
 * Library General Public License for more details.
Packit 0652a1
 *
Packit 0652a1
 * You should have received a copy of the GNU Library General Public
Packit 0652a1
 * License along with this library; if not, write to the
Packit 0652a1
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 0652a1
 * Boston, MA 02110-1301, USA.
Packit 0652a1
 */
Packit 0652a1
Packit 0652a1
#ifdef HAVE_CONFIG_H
Packit 0652a1
#  include "config.h"
Packit 0652a1
#endif
Packit 0652a1
Packit 0652a1
#include "audio-buffer.h"
Packit 0652a1
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_audio_buffer_unmap_internal (GstAudioBuffer * buffer, guint n_unmap)
Packit 0652a1
{
Packit 0652a1
  guint i;
Packit 0652a1
  for (i = 0; i < n_unmap; i++) {
Packit 0652a1
    gst_buffer_unmap (buffer->buffer, &buffer->map_infos[i]);
Packit 0652a1
  }
Packit 0652a1
  if (buffer->planes != buffer->priv_planes_arr)
Packit 0652a1
    g_slice_free1 (buffer->n_planes * sizeof (gpointer), buffer->planes);
Packit 0652a1
  if (buffer->map_infos != buffer->priv_map_infos_arr)
Packit 0652a1
    g_slice_free1 (buffer->n_planes * sizeof (GstMapInfo), buffer->map_infos);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_buffer_unmap:
Packit 0652a1
 * @buffer: the #GstAudioBuffer to unmap
Packit 0652a1
 *
Packit 0652a1
 * Unmaps an audio buffer that was previously mapped with
Packit 0652a1
 * gst_audio_buffer_map().
Packit 0652a1
 *
Packit 0652a1
 * Since: 1.16
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_buffer_unmap (GstAudioBuffer * buffer)
Packit 0652a1
{
Packit 0652a1
  gst_audio_buffer_unmap_internal (buffer, buffer->n_planes);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_buffer_map:
Packit 0652a1
 * @buffer: pointer to a #GstAudioBuffer
Packit 0652a1
 * @info: the audio properties of the buffer
Packit 0652a1
 * @gstbuffer: (transfer none): the #GstBuffer to be mapped
Packit 0652a1
 * @flags: the access mode for the memory
Packit 0652a1
 *
Packit 0652a1
 * Maps an audio @gstbuffer so that it can be read or written and stores the
Packit 0652a1
 * result of the map operation in @buffer.
Packit 0652a1
 *
Packit 0652a1
 * This is especially useful when the @gstbuffer is in non-interleaved (planar)
Packit 0652a1
 * layout, in which case this function will use the information in the
Packit 0652a1
 * @gstbuffer's attached #GstAudioMeta in order to map each channel in a
Packit 0652a1
 * separate "plane" in #GstAudioBuffer. If a #GstAudioMeta is not attached
Packit 0652a1
 * on the @gstbuffer, then it must be in interleaved layout.
Packit 0652a1
 *
Packit 0652a1
 * If a #GstAudioMeta is attached, then the #GstAudioInfo on the meta is checked
Packit 0652a1
 * against @info. Normally, they should be equal, but in case they are not,
Packit 0652a1
 * a g_critical will be printed and the #GstAudioInfo from the meta will be
Packit 0652a1
 * used.
Packit 0652a1
 *
Packit 0652a1
 * In non-interleaved buffers, it is possible to have each channel on a separate
Packit 0652a1
 * #GstMemory. In this case, each memory will be mapped separately to avoid
Packit 0652a1
 * copying their contents in a larger memory area. Do note though that it is
Packit 0652a1
 * not supported to have a single channel spanning over two or more different
Packit 0652a1
 * #GstMemory objects. Although the map operation will likely succeed in this
Packit 0652a1
 * case, it will be highly sub-optimal and it is recommended to merge all the
Packit 0652a1
 * memories in the buffer before calling this function.
Packit 0652a1
 *
Packit 0652a1
 * Note: The actual #GstBuffer is not ref'ed, but it is required to stay valid
Packit 0652a1
 * as long as it's mapped.
Packit 0652a1
 *
Packit 0652a1
 * Returns: %TRUE if the map operation succeeded or %FALSE on failure
Packit 0652a1
 *
Packit 0652a1
 * Since: 1.16
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_buffer_map (GstAudioBuffer * buffer, const GstAudioInfo * info,
Packit 0652a1
    GstBuffer * gstbuffer, GstMapFlags flags)
Packit 0652a1
{
Packit 0652a1
  GstAudioMeta *meta = NULL;
Packit 0652a1
  guint i = 0, idx, length;
Packit 0652a1
  gsize skip;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (buffer != NULL, FALSE);
Packit 0652a1
  g_return_val_if_fail (info != NULL, FALSE);
Packit 0652a1
  g_return_val_if_fail (GST_AUDIO_INFO_IS_VALID (info), FALSE);
Packit 0652a1
  g_return_val_if_fail (GST_AUDIO_INFO_FORMAT (info) !=
Packit 0652a1
      GST_AUDIO_FORMAT_UNKNOWN, FALSE);
Packit 0652a1
  g_return_val_if_fail (GST_IS_BUFFER (gstbuffer), FALSE);
Packit 0652a1
Packit 0652a1
  meta = gst_buffer_get_audio_meta (gstbuffer);
Packit 0652a1
Packit 0652a1
  /* be strict on the layout */
Packit 0652a1
  g_return_val_if_fail ((!meta && info->layout == GST_AUDIO_LAYOUT_INTERLEAVED)
Packit 0652a1
      || (meta && info->layout == meta->info.layout), FALSE);
Packit 0652a1
Packit 0652a1
  /* and not so strict on other fields */
Packit 0652a1
  if (G_UNLIKELY (meta && !gst_audio_info_is_equal (&meta->info, info))) {
Packit 0652a1
    g_critical ("the GstAudioInfo argument is not equal "
Packit 0652a1
        "to the GstAudioMeta's attached info");
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  if (meta) {
Packit 0652a1
    /* make sure that the meta doesn't imply having more samples than
Packit 0652a1
     * what's actually possible to store in this buffer */
Packit 0652a1
    g_return_val_if_fail (meta->samples <=
Packit 0652a1
        gst_buffer_get_size (gstbuffer) / GST_AUDIO_INFO_BPF (&meta->info),
Packit 0652a1
        FALSE);
Packit 0652a1
    buffer->n_samples = meta->samples;
Packit 0652a1
  } else {
Packit 0652a1
    buffer->n_samples =
Packit 0652a1
        gst_buffer_get_size (gstbuffer) / GST_AUDIO_INFO_BPF (info);
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  buffer->info = meta ? meta->info : *info;
Packit 0652a1
  buffer->buffer = gstbuffer;
Packit 0652a1
Packit 0652a1
  if (GST_AUDIO_BUFFER_LAYOUT (buffer) == GST_AUDIO_LAYOUT_INTERLEAVED) {
Packit 0652a1
    /* interleaved */
Packit 0652a1
    buffer->n_planes = 1;
Packit 0652a1
    buffer->planes = buffer->priv_planes_arr;
Packit 0652a1
    buffer->map_infos = buffer->priv_map_infos_arr;
Packit 0652a1
Packit 0652a1
    if (!gst_buffer_map (gstbuffer, &buffer->map_infos[0], flags))
Packit 0652a1
      return FALSE;
Packit 0652a1
Packit 0652a1
    buffer->planes[0] = buffer->map_infos[0].data;
Packit 0652a1
  } else {
Packit 0652a1
    /* non-interleaved */
Packit 0652a1
    buffer->n_planes = GST_AUDIO_BUFFER_CHANNELS (buffer);
Packit 0652a1
Packit 0652a1
    if (G_UNLIKELY (buffer->n_planes > 8)) {
Packit 0652a1
      buffer->planes = g_slice_alloc (buffer->n_planes * sizeof (gpointer));
Packit 0652a1
      buffer->map_infos =
Packit 0652a1
          g_slice_alloc (buffer->n_planes * sizeof (GstMapInfo));
Packit 0652a1
    } else {
Packit 0652a1
      buffer->planes = buffer->priv_planes_arr;
Packit 0652a1
      buffer->map_infos = buffer->priv_map_infos_arr;
Packit 0652a1
    }
Packit 0652a1
Packit 0652a1
    for (i = 0; i < buffer->n_planes; i++) {
Packit 0652a1
      if (!gst_buffer_find_memory (gstbuffer, meta->offsets[i],
Packit 0652a1
              GST_AUDIO_BUFFER_PLANE_SIZE (buffer), &idx, &length, &skip))
Packit 0652a1
        goto no_memory;
Packit 0652a1
Packit 0652a1
      if (!gst_buffer_map_range (gstbuffer, idx, length, &buffer->map_infos[i],
Packit 0652a1
              flags))
Packit 0652a1
        goto cannot_map;
Packit 0652a1
Packit 0652a1
      buffer->planes[i] = buffer->map_infos[i].data + skip;
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  return TRUE;
Packit 0652a1
Packit 0652a1
no_memory:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG ("plane %u, no memory at offset %" G_GSIZE_FORMAT, i,
Packit 0652a1
        meta->offsets[i]);
Packit 0652a1
    gst_audio_buffer_unmap_internal (buffer, i);
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
cannot_map:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG ("cannot map memory range %u-%u", idx, length);
Packit 0652a1
    gst_audio_buffer_unmap_internal (buffer, i);
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
}