audio.c 5.81 KB
Newer Older
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1
/* GStreamer
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
19 20 21 22 23 24
/**
 * SECTION:gstaudio
 * @short_description: Support library for audio elements
 *
 * This library contains some helper functions for audio elements.
 */
25

26 27 28 29
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

Wim Taymans's avatar
Wim Taymans committed
30 31
#include <string.h>

32
#include "audio.h"
33
#include "audio-enumtypes.h"
34

35 36
/**
 * gst_audio_buffer_clip:
Olivier Crête's avatar
Olivier Crête committed
37
 * @buffer: (transfer full): The buffer to clip.
Wim Taymans's avatar
Wim Taymans committed
38 39
 * @segment: Segment in %GST_FORMAT_TIME or %GST_FORMAT_DEFAULT to which
 *           the buffer should be clipped.
40
 * @rate: sample rate.
Wim Taymans's avatar
Wim Taymans committed
41 42
 * @bpf: size of one audio frame in bytes. This is the size of one sample
 * * channels.
43
 *
Piotr Fusik's avatar
Piotr Fusik committed
44
 * Clip the buffer to the given %GstSegment.
45
 *
Wim Taymans's avatar
Wim Taymans committed
46
 * After calling this function the caller does not own a reference to
47
 * @buffer anymore.
48
 *
Olivier Crête's avatar
Olivier Crête committed
49
 * Returns: (transfer full): %NULL if the buffer is completely outside the configured segment,
50 51
 * otherwise the clipped buffer is returned.
 *
52
 * If the buffer has no timestamp, it is assumed to be inside the segment and
Wim Taymans's avatar
Wim Taymans committed
53
 * is not clipped
54 55 56
 */
GstBuffer *
gst_audio_buffer_clip (GstBuffer * buffer, GstSegment * segment, gint rate,
Wim Taymans's avatar
Wim Taymans committed
57
    gint bpf)
58 59 60 61
{
  GstBuffer *ret;
  GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
  guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE;
62
  gsize trim, size, osize;
63 64 65 66 67 68
  gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end =
      TRUE;

  g_return_val_if_fail (segment->format == GST_FORMAT_TIME ||
      segment->format == GST_FORMAT_DEFAULT, buffer);
  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
69 70 71 72

  if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
    /* No timestamp - assume the buffer is completely in the segment */
    return buffer;
73 74 75 76 77

  /* Get copies of the buffer metadata to change later. 
   * Calculate the missing values for the calculations,
   * they won't be changed later though. */

Wim Taymans's avatar
Wim Taymans committed
78
  trim = 0;
79
  osize = size = gst_buffer_get_size (buffer);
80 81

  timestamp = GST_BUFFER_TIMESTAMP (buffer);
Wim Taymans's avatar
Wim Taymans committed
82
  GST_DEBUG ("timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
83 84 85 86
  if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
    duration = GST_BUFFER_DURATION (buffer);
  } else {
    change_duration = FALSE;
Wim Taymans's avatar
Wim Taymans committed
87
    duration = gst_util_uint64_scale (size / bpf, GST_SECOND, rate);
88 89 90 91 92 93 94 95 96 97 98 99 100
  }

  if (GST_BUFFER_OFFSET_IS_VALID (buffer)) {
    offset = GST_BUFFER_OFFSET (buffer);
  } else {
    change_offset = FALSE;
    offset = 0;
  }

  if (GST_BUFFER_OFFSET_END_IS_VALID (buffer)) {
    offset_end = GST_BUFFER_OFFSET_END (buffer);
  } else {
    change_offset_end = FALSE;
Wim Taymans's avatar
Wim Taymans committed
101
    offset_end = offset + size / bpf;
102 103 104 105 106
  }

  if (segment->format == GST_FORMAT_TIME) {
    /* Handle clipping for GST_FORMAT_TIME */

Wim Taymans's avatar
Wim Taymans committed
107
    guint64 start, stop, cstart, cstop, diff;
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124

    start = timestamp;
    stop = timestamp + duration;

    if (gst_segment_clip (segment, GST_FORMAT_TIME,
            start, stop, &cstart, &cstop)) {

      diff = cstart - start;
      if (diff > 0) {
        timestamp = cstart;

        if (change_duration)
          duration -= diff;

        diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
        if (change_offset)
          offset += diff;
Wim Taymans's avatar
Wim Taymans committed
125 126
        trim += diff * bpf;
        size -= diff * bpf;
127 128 129 130 131 132 133 134 135 136
      }

      diff = stop - cstop;
      if (diff > 0) {
        /* duration is always valid if stop is valid */
        duration -= diff;

        diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
        if (change_offset_end)
          offset_end -= diff;
Wim Taymans's avatar
Wim Taymans committed
137
        size -= diff * bpf;
138 139 140 141 142 143 144
      }
    } else {
      gst_buffer_unref (buffer);
      return NULL;
    }
  } else {
    /* Handle clipping for GST_FORMAT_DEFAULT */
Wim Taymans's avatar
Wim Taymans committed
145
    guint64 start, stop, cstart, cstop, diff;
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

    g_return_val_if_fail (GST_BUFFER_OFFSET_IS_VALID (buffer), buffer);

    start = offset;
    stop = offset_end;

    if (gst_segment_clip (segment, GST_FORMAT_DEFAULT,
            start, stop, &cstart, &cstop)) {

      diff = cstart - start;
      if (diff > 0) {
        offset = cstart;

        timestamp = gst_util_uint64_scale (cstart, GST_SECOND, rate);

        if (change_duration)
          duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);

Wim Taymans's avatar
Wim Taymans committed
164 165
        trim += diff * bpf;
        size -= diff * bpf;
166 167 168 169 170 171 172 173 174
      }

      diff = stop - cstop;
      if (diff > 0) {
        offset_end = cstop;

        if (change_duration)
          duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);

Wim Taymans's avatar
Wim Taymans committed
175
        size -= diff * bpf;
176 177 178 179 180 181 182
      }
    } else {
      gst_buffer_unref (buffer);
      return NULL;
    }
  }

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
  if (trim == 0 && size == osize) {
    /* nothing changed */
    ret = buffer;
  } else {
    /* Get a writable buffer and apply all changes */
    GST_DEBUG ("trim %" G_GSIZE_FORMAT " size %" G_GSIZE_FORMAT, trim, size);
    ret = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, trim, size);
    gst_buffer_unref (buffer);

    GST_DEBUG ("timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
    GST_BUFFER_TIMESTAMP (ret) = timestamp;

    if (change_duration)
      GST_BUFFER_DURATION (ret) = duration;
    if (change_offset)
      GST_BUFFER_OFFSET (ret) = offset;
    if (change_offset_end)
      GST_BUFFER_OFFSET_END (ret) = offset_end;
  }
202 203
  return ret;
}