static GstCaps *
gst_inter_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter)
{
  GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
  GstCaps *caps;

  GST_DEBUG_OBJECT (interaudiosrc, "get_caps");

  if (!interaudiosrc->surface)
    return GST_BASE_SRC_CLASS (parent_class)->get_caps (src, filter);

  g_mutex_lock (&interaudiosrc->surface->mutex);
  if (interaudiosrc->surface->audio_info.finfo) {
    caps = gst_audio_info_to_caps (&interaudiosrc->surface->audio_info);
    if (filter) {
      GstCaps *tmp;

      tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
      gst_caps_unref (caps);
      caps = tmp;
    }
  } else {
    caps = NULL;
  }
  g_mutex_unlock (&interaudiosrc->surface->mutex);

  if (caps)
    return caps;
  else
    return GST_BASE_SRC_CLASS (parent_class)->get_caps (src, filter);
}
示例#2
0
static void
gst_deinterleave_add_new_pads (GstDeinterleave * self, GstCaps * caps)
{
  GstPad *pad;
  guint i;

  for (i = 0; i < GST_AUDIO_INFO_CHANNELS (&self->audio_info); i++) {
    gchar *name = g_strdup_printf ("src_%u", i);
    GstCaps *srccaps;
    GstAudioInfo info;
    GstAudioFormat format = GST_AUDIO_INFO_FORMAT (&self->audio_info);
    gint rate = GST_AUDIO_INFO_RATE (&self->audio_info);
    GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_MONO;
    CopyStickyEventsData data;

    /* Set channel position if we know it */
    if (self->keep_positions)
      position = GST_AUDIO_INFO_POSITION (&self->audio_info, i);

    gst_audio_info_init (&info);
    gst_audio_info_set_format (&info, format, rate, 1, &position);

    srccaps = gst_audio_info_to_caps (&info);

    pad = gst_pad_new_from_static_template (&src_template, name);
    g_free (name);

    gst_pad_use_fixed_caps (pad);
    gst_pad_set_query_function (pad,
        GST_DEBUG_FUNCPTR (gst_deinterleave_src_query));
    gst_pad_set_active (pad, TRUE);

    data.pad = pad;
    data.caps = srccaps;
    gst_pad_sticky_events_foreach (self->sink, copy_sticky_events, &data);
    if (data.caps)
      gst_pad_set_caps (pad, data.caps);
    gst_element_add_pad (GST_ELEMENT (self), pad);
    self->srcpads = g_list_prepend (self->srcpads, gst_object_ref (pad));

    gst_caps_unref (srccaps);
  }

  gst_element_no_more_pads (GST_ELEMENT (self));
  self->srcpads = g_list_reverse (self->srcpads);
}
示例#3
0
static void
gst_deinterleave_set_pads_caps (GstDeinterleave * self, GstCaps * caps)
{
  GList *l;
  gint i;

  for (l = self->srcpads, i = 0; l; l = l->next, i++) {
    GstPad *pad = GST_PAD (l->data);
    GstCaps *srccaps;
    GstAudioInfo info;

    gst_audio_info_from_caps (&info, caps);
    if (self->keep_positions)
      GST_AUDIO_INFO_POSITION (&info, 0) =
          GST_AUDIO_INFO_POSITION (&self->audio_info, i);

    srccaps = gst_audio_info_to_caps (&info);

    gst_pad_set_caps (pad, srccaps);
    gst_caps_unref (srccaps);
  }
}
/* Converts an AudioStreamBasicDescription to preferred caps.
 *
 * These caps will indicate the AU element's canonical format, which won't
 * make Core Audio resample nor convert.
 *
 * NOTE ON MULTI-CHANNEL AUDIO:
 *
 * If layout is not NULL, resulting caps will only include the subset
 * of channels supported by GStreamer. If the Core Audio layout contained
 * ANY positioned channels, then ONLY positioned channels will be included
 * in the resulting caps. Otherwise, resulting caps will be unpositioned,
 * and include only unpositioned channels.
 * (Channels with unsupported AudioChannelLabel will be skipped either way.)
 *
 * Naturally, the number of channels indicated by 'channels' can be lower
 * than the AU element's total number of channels.
 */
GstCaps *
gst_core_audio_asbd_to_caps (AudioStreamBasicDescription * asbd,
    AudioChannelLayout * layout)
{
  GstAudioInfo info;
  GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
  guint rate, channels, bps, endianness;
  guint64 channel_mask;
  gboolean sign, interleaved;
  GstAudioChannelPosition pos[GST_OSX_AUDIO_MAX_CHANNEL];

  if (asbd->mFormatID != kAudioFormatLinearPCM) {
    GST_WARNING ("Only linear PCM is supported");
    goto error;
  }

  if (!(asbd->mFormatFlags & kAudioFormatFlagIsPacked)) {
    GST_WARNING ("Only packed formats supported");
    goto error;
  }

  if (asbd->mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) {
    GST_WARNING ("Fixed point audio is unsupported");
    goto error;
  }

  rate = asbd->mSampleRate;
  if (rate == kAudioStreamAnyRate) {
    GST_WARNING ("No sample rate");
    goto error;
  }

  bps = asbd->mBitsPerChannel;
  endianness = asbd->mFormatFlags & kAudioFormatFlagIsBigEndian ?
      G_BIG_ENDIAN : G_LITTLE_ENDIAN;
  sign = asbd->mFormatID & kAudioFormatFlagIsSignedInteger ? TRUE : FALSE;
  interleaved = asbd->mFormatFlags & kAudioFormatFlagIsNonInterleaved ?
      TRUE : FALSE;

  if (asbd->mFormatFlags & kAudioFormatFlagIsFloat) {
    if (bps == 32) {
      if (endianness == G_LITTLE_ENDIAN)
        format = GST_AUDIO_FORMAT_F32LE;
      else
        format = GST_AUDIO_FORMAT_F32BE;

    } else if (bps == 64) {
      if (endianness == G_LITTLE_ENDIAN)
        format = GST_AUDIO_FORMAT_F64LE;
      else
        format = GST_AUDIO_FORMAT_F64BE;
    }
  } else {
    format = gst_audio_format_build_integer (sign, endianness, bps, bps);
  }

  if (format == GST_AUDIO_FORMAT_UNKNOWN) {
    GST_WARNING ("Unsupported sample format");
    goto error;
  }

  if (layout) {
    if (!gst_core_audio_parse_channel_layout (layout, &channels, &channel_mask,
            pos)) {
      GST_WARNING
          ("Failed to parse channel layout, best effort channels layout mapping will be used");
      layout = NULL;
    }
  }

  if (layout) {
    /* The AU can have arbitrary channel order, but we're using GstAudioInfo
     * which supports only the GStreamer channel order.
     * Also, we're eventually producing caps, which only have channel-mask
     * (whose implied order is the GStreamer channel order). */
    gst_audio_channel_positions_to_valid_order (pos, channels);

    gst_audio_info_set_format (&info, format, rate, channels, pos);
  } else {
    channels = MIN (asbd->mChannelsPerFrame, GST_OSX_AUDIO_MAX_CHANNEL);
    gst_audio_info_set_format (&info, format, rate, channels, NULL);
  }

  return gst_audio_info_to_caps (&info);

error:
  return NULL;
}
示例#5
0
static GstCaps *
gst_audio_parse_get_caps (GstRawParse * rp)
{
  GstAudioParse *ap = GST_AUDIO_PARSE (rp);
  GstCaps *caps, *ncaps;
  GstAudioInfo info;
  gint fps_n, fps_d;
  const GValue *val;

  if (ap->use_sink_caps) {
    gint rate;
    GstCaps *caps = gst_pad_get_current_caps (rp->sinkpad);
    gst_audio_info_from_caps (&info, caps);

    rate = GST_AUDIO_INFO_RATE (&info);
    gst_raw_parse_set_fps (GST_RAW_PARSE (ap), rate, 1);

    return caps;
  }

  gst_raw_parse_get_fps (rp, &fps_n, &fps_d);
  gst_audio_parse_setup_channel_positions (ap);

  /* yes, even when format not raw */
  gst_audio_info_init (&info);
  gst_audio_info_set_format (&info, ap->raw_format, fps_n, ap->channels,
      ap->channel_order);
  info.layout = ap->interleaved ? GST_AUDIO_LAYOUT_INTERLEAVED :
      GST_AUDIO_LAYOUT_NON_INTERLEAVED;
  caps = gst_audio_info_to_caps (&info);

  switch (ap->format) {
    case GST_AUDIO_PARSE_FORMAT_RAW:
      break;
    case GST_AUDIO_PARSE_FORMAT_ALAW:
      ncaps = gst_caps_new_simple ("audio/x-alaw",
          "rate", G_TYPE_INT, fps_n,
          "channels", G_TYPE_INT, ap->channels, NULL);
      /* pick mask stuff from faked raw format */
      val = gst_structure_get_value (gst_caps_get_structure (caps, 0),
          "channel-mask");
      if (val)
        gst_caps_set_value (ncaps, "channel-mask", val);
      gst_caps_unref (caps);
      caps = ncaps;
      break;
    case GST_AUDIO_PARSE_FORMAT_MULAW:
      ncaps = gst_caps_new_simple ("audio/x-mulaw",
          "rate", G_TYPE_INT, fps_n,
          "channels", G_TYPE_INT, ap->channels, NULL);
      /* pick mask stuff from faked raw format */
      val = gst_structure_get_value (gst_caps_get_structure (caps, 0),
          "channel-mask");
      if (val)
        gst_caps_set_value (ncaps, "channel-mask", val);
      gst_caps_unref (caps);
      caps = ncaps;
      break;
    default:
      caps = gst_caps_new_empty ();
      GST_ERROR_OBJECT (rp, "unexpected format %d", ap->format);
      break;
  }

  return caps;
}
static gboolean
gst_rtp_L16_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
{
  GstStructure *structure;
  GstRtpL16Depay *rtpL16depay;
  gint clock_rate, payload;
  gint channels;
  GstCaps *srccaps;
  gboolean res;
  const gchar *channel_order;
  const GstRTPChannelOrder *order;
  GstAudioInfo *info;

  rtpL16depay = GST_RTP_L16_DEPAY (depayload);

  structure = gst_caps_get_structure (caps, 0);

  payload = 96;
  gst_structure_get_int (structure, "payload", &payload);
  switch (payload) {
    case GST_RTP_PAYLOAD_L16_STEREO:
      channels = 2;
      clock_rate = 44100;
      break;
    case GST_RTP_PAYLOAD_L16_MONO:
      channels = 1;
      clock_rate = 44100;
      break;
    default:
      /* no fixed mapping, we need clock-rate */
      channels = 0;
      clock_rate = 0;
      break;
  }

  /* caps can overwrite defaults */
  clock_rate =
      gst_rtp_L16_depay_parse_int (structure, "clock-rate", clock_rate);
  if (clock_rate == 0)
    goto no_clockrate;

  channels =
      gst_rtp_L16_depay_parse_int (structure, "encoding-params", channels);
  if (channels == 0) {
    channels = gst_rtp_L16_depay_parse_int (structure, "channels", channels);
    if (channels == 0) {
      /* channels defaults to 1 otherwise */
      channels = 1;
    }
  }

  depayload->clock_rate = clock_rate;

  info = &rtpL16depay->info;
  gst_audio_info_init (info);
  info->finfo = gst_audio_format_get_info (GST_AUDIO_FORMAT_S16BE);
  info->rate = clock_rate;
  info->channels = channels;
  info->bpf = (info->finfo->width / 8) * channels;

  /* add channel positions */
  channel_order = gst_structure_get_string (structure, "channel-order");

  order = gst_rtp_channels_get_by_order (channels, channel_order);
  rtpL16depay->order = order;
  if (order) {
    memcpy (info->position, order->pos,
        sizeof (GstAudioChannelPosition) * channels);
    gst_audio_channel_positions_to_valid_order (info->position, info->channels);
  } else {
    GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE,
        (NULL), ("Unknown channel order '%s' for %d channels",
            GST_STR_NULL (channel_order), channels));
    /* create default NONE layout */
    gst_rtp_channels_create_default (channels, info->position);
  }

  srccaps = gst_audio_info_to_caps (info);
  res = gst_pad_set_caps (depayload->srcpad, srccaps);
  gst_caps_unref (srccaps);

  return res;

  /* ERRORS */
no_clockrate:
  {
    GST_ERROR_OBJECT (depayload, "no clock-rate specified");
    return FALSE;
  }
}
static GstCaps *
gst_dshowaudiosrc_getcaps_from_streamcaps (GstDshowAudioSrc * src, IPin * pin,
    IAMStreamConfig * streamcaps)
{
  GstCaps *caps = NULL;
  HRESULT hres = S_OK;
  int icount = 0;
  int isize = 0;
  AUDIO_STREAM_CONFIG_CAPS ascc;
  int i = 0;

  if (!streamcaps)
    return NULL;

  streamcaps->GetNumberOfCapabilities (&icount, &isize);

  if (isize != sizeof (ascc))
    return NULL;

  for (; i < icount; i++) {
    GstCapturePinMediaType *pin_mediatype = g_new0 (GstCapturePinMediaType, 1);

    pin->AddRef ();
    pin_mediatype->capture_pin = pin;

    hres = streamcaps->GetStreamCaps (i, &pin_mediatype->mediatype,
        (BYTE *) & ascc);
    if (hres == S_OK && pin_mediatype->mediatype) {
      GstCaps *mediacaps = NULL;

      if (!caps)
        caps = gst_caps_new_empty ();

      if (gst_dshow_check_mediatype (pin_mediatype->mediatype, MEDIASUBTYPE_PCM,
              FORMAT_WaveFormatEx)) {
	GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
        WAVEFORMATEX *wavformat =
            (WAVEFORMATEX *) pin_mediatype->mediatype->pbFormat;

	switch (wavformat->wFormatTag) {
            case WAVE_FORMAT_PCM:
	      format = gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, wavformat->wBitsPerSample, wavformat->wBitsPerSample);
	      break;
            default:
	      break;
	}

	if (format != GST_AUDIO_FORMAT_UNKNOWN) {
	  GstAudioInfo info;

	  gst_audio_info_init(&info);
	  gst_audio_info_set_format(&info,
				    format,
				    wavformat->nSamplesPerSec,
				    wavformat->nChannels,
				    NULL);
	  mediacaps = gst_audio_info_to_caps(&info);
	}

        if (mediacaps) {
          src->pins_mediatypes =
              g_list_append (src->pins_mediatypes, pin_mediatype);
          gst_caps_append (caps, mediacaps);
        } else {
          gst_dshow_free_pin_mediatype (pin_mediatype);
        }
      } else {
        gst_dshow_free_pin_mediatype (pin_mediatype);
      }
    } else {
      gst_dshow_free_pin_mediatype (pin_mediatype);
    }
  }

  if (caps && gst_caps_is_empty (caps)) {
    gst_caps_unref (caps);
    caps = NULL;
  }

  return caps;
}
示例#8
0
static gboolean
gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps ** caps)
{
  pa_channel_map channel_map;
  const pa_channel_map *m;
  GstStructure *s;
  gboolean need_channel_layout = FALSE;
  GstAudioRingBufferSpec spec;
  const gchar *name;

  s = gst_caps_get_structure (*caps, 0);
  gst_structure_get_int (s, "channels", &spec.info.channels);
  if (!gst_structure_has_field (s, "channel-mask")) {
    if (spec.info.channels == 1) {
      pa_channel_map_init_mono (&channel_map);
    } else if (spec.info.channels == 2) {
      gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
          GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
          GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT), NULL);
      pa_channel_map_init_stereo (&channel_map);
    } else {
      need_channel_layout = TRUE;
      gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
          G_GUINT64_CONSTANT (0), NULL);
    }
  }

  memset (&spec, 0, sizeof (GstAudioRingBufferSpec));
  spec.latency_time = GST_SECOND;
  if (!gst_audio_ring_buffer_parse_caps (&spec, *caps))
    goto invalid_caps;

  /* Keep the refcount of the caps at 1 to make them writable */
  gst_caps_unref (spec.caps);

  if (!need_channel_layout
      && !gst_pulse_gst_to_channel_map (&channel_map, &spec)) {
    need_channel_layout = TRUE;
    gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
        G_GUINT64_CONSTANT (0), NULL);
    memset (spec.info.position, 0xff, sizeof (spec.info.position));
  }

  if (!gst_pulse_fill_sample_spec (&spec, &pulsesrc->sample_spec))
    goto invalid_spec;

  pa_threaded_mainloop_lock (pulsesrc->mainloop);

  if (!pulsesrc->context)
    goto bad_context;

  name = "Record Stream";
  if (pulsesrc->proplist) {
    if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context,
                name, &pulsesrc->sample_spec,
                (need_channel_layout) ? NULL : &channel_map,
                pulsesrc->proplist)))
      goto create_failed;

  } else if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context,
              name, &pulsesrc->sample_spec,
              (need_channel_layout) ? NULL : &channel_map)))
    goto create_failed;

  m = pa_stream_get_channel_map (pulsesrc->stream);
  gst_pulse_channel_map_to_gst (m, &spec);
  gst_audio_channel_positions_to_valid_order (spec.info.position,
      spec.info.channels);
  gst_caps_unref (*caps);
  *caps = gst_audio_info_to_caps (&spec.info);

  GST_DEBUG_OBJECT (pulsesrc, "Caps are %" GST_PTR_FORMAT, *caps);

  pa_stream_set_state_callback (pulsesrc->stream, gst_pulsesrc_stream_state_cb,
      pulsesrc);
  pa_stream_set_read_callback (pulsesrc->stream, gst_pulsesrc_stream_request_cb,
      pulsesrc);
  pa_stream_set_underflow_callback (pulsesrc->stream,
      gst_pulsesrc_stream_underflow_cb, pulsesrc);
  pa_stream_set_overflow_callback (pulsesrc->stream,
      gst_pulsesrc_stream_overflow_cb, pulsesrc);
  pa_stream_set_latency_update_callback (pulsesrc->stream,
      gst_pulsesrc_stream_latency_update_cb, pulsesrc);

  pa_threaded_mainloop_unlock (pulsesrc->mainloop);

  return TRUE;

  /* ERRORS */
invalid_caps:
  {
    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS,
        ("Can't parse caps."), (NULL));
    goto fail;
  }
invalid_spec:
  {
    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS,
        ("Invalid sample specification."), (NULL));
    goto fail;
  }
bad_context:
  {
    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Bad context"), (NULL));
    goto unlock_and_fail;
  }
create_failed:
  {
    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
        ("Failed to create stream: %s",
            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
    goto unlock_and_fail;
  }
unlock_and_fail:
  {
    gst_pulsesrc_destroy_stream (pulsesrc);

    pa_threaded_mainloop_unlock (pulsesrc->mainloop);

  fail:
    return FALSE;
  }
}
示例#9
0
static gboolean
gst_raw_audio_parse_config_to_caps (GstRawAudioParse * raw_audio_parse,
    GstCaps ** caps, GstRawAudioParseConfig * config)
{
  gboolean ret = TRUE;
  GstAudioChannelPosition *channel_positions;

  g_assert (caps != NULL);

  if (config->bpf == 0) {
    GST_ERROR_OBJECT (raw_audio_parse,
        "cannot convert config to caps - config not filled with valid values");
    *caps = NULL;
    return FALSE;
  }

  channel_positions =
      config->needs_channel_reordering ? &(config->
      reordered_channel_positions[0]) : &(config->channel_positions[0]);

  switch (config->format) {
    case GST_RAW_AUDIO_PARSE_FORMAT_PCM:
    {
      GstAudioInfo info;
      gst_audio_info_init (&info);
      gst_audio_info_set_format (&info,
          config->pcm_format,
          config->sample_rate, config->num_channels, channel_positions);

      *caps = gst_audio_info_to_caps (&info);

      break;
    }

    case GST_RAW_AUDIO_PARSE_FORMAT_ALAW:
    case GST_RAW_AUDIO_PARSE_FORMAT_MULAW:
    {
      guint64 channel_mask;

      if (!gst_audio_channel_positions_to_mask (channel_positions,
              config->num_channels, TRUE, &channel_mask)) {
        GST_ERROR_OBJECT (raw_audio_parse, "invalid channel positions");
        ret = FALSE;
        break;
      }

      *caps = gst_caps_new_simple (
          (config->format ==
              GST_RAW_AUDIO_PARSE_FORMAT_ALAW) ? "audio/x-alaw" :
          "audio/x-mulaw", "rate", G_TYPE_INT, config->sample_rate, "channels",
          G_TYPE_INT, config->num_channels, "channel-mask", GST_TYPE_BITMASK,
          channel_mask, NULL);

      break;
    }

    default:
      g_assert_not_reached ();
      ret = FALSE;
  }

  if (!ret)
    *caps = NULL;

  return ret;
}
static GstFlowReturn
gst_inter_audio_src_create (GstBaseSrc * src, guint64 offset, guint size,
    GstBuffer ** buf)
{
  GstInterAudioSrc *interaudiosrc = GST_INTER_AUDIO_SRC (src);
  GstCaps *caps;
  GstBuffer *buffer;
  guint n, bpf;
  guint64 period_time;
  guint64 period_samples;

  GST_DEBUG_OBJECT (interaudiosrc, "create");

  buffer = NULL;
  caps = NULL;

  g_mutex_lock (&interaudiosrc->surface->mutex);
  if (interaudiosrc->surface->audio_info.finfo) {
    if (!gst_audio_info_is_equal (&interaudiosrc->surface->audio_info,
            &interaudiosrc->info)) {
      caps = gst_audio_info_to_caps (&interaudiosrc->surface->audio_info);
      interaudiosrc->timestamp_offset +=
          gst_util_uint64_scale (interaudiosrc->n_samples, GST_SECOND,
          interaudiosrc->info.rate);
      interaudiosrc->n_samples = 0;
    }
  }

  bpf = interaudiosrc->surface->audio_info.bpf;
  period_time = interaudiosrc->surface->audio_period_time;
  period_samples =
      gst_util_uint64_scale (period_time, interaudiosrc->info.rate, GST_SECOND);

  if (bpf > 0)
    n = gst_adapter_available (interaudiosrc->surface->audio_adapter) / bpf;
  else
    n = 0;

  if (n > period_samples)
    n = period_samples;
  if (n > 0) {
    buffer = gst_adapter_take_buffer (interaudiosrc->surface->audio_adapter,
        n * bpf);
  } else {
    buffer = gst_buffer_new ();
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_GAP);
  }
  g_mutex_unlock (&interaudiosrc->surface->mutex);

  if (caps) {
    gboolean ret = gst_base_src_set_caps (src, caps);
    gst_caps_unref (caps);
    if (!ret) {
      GST_ERROR_OBJECT (src, "Failed to set caps %" GST_PTR_FORMAT, caps);
      if (buffer)
        gst_buffer_unref (buffer);
      return GST_FLOW_NOT_NEGOTIATED;
    }
  }

  buffer = gst_buffer_make_writable (buffer);

  bpf = interaudiosrc->info.bpf;
  if (n < period_samples) {
    GstMapInfo map;
    GstMemory *mem;

    GST_DEBUG_OBJECT (interaudiosrc,
        "creating %" G_GUINT64_FORMAT " samples of silence",
        period_samples - n);
    mem = gst_allocator_alloc (NULL, (period_samples - n) * bpf, NULL);
    if (gst_memory_map (mem, &map, GST_MAP_WRITE)) {
      gst_audio_format_fill_silence (interaudiosrc->info.finfo, map.data,
          map.size);
      gst_memory_unmap (mem, &map);
    }
    gst_buffer_prepend_memory (buffer, mem);
  }
  n = period_samples;

  GST_BUFFER_OFFSET (buffer) = interaudiosrc->n_samples;
  GST_BUFFER_OFFSET_END (buffer) = interaudiosrc->n_samples + n;
  GST_BUFFER_TIMESTAMP (buffer) = interaudiosrc->timestamp_offset +
      gst_util_uint64_scale (interaudiosrc->n_samples, GST_SECOND,
      interaudiosrc->info.rate);
  GST_DEBUG_OBJECT (interaudiosrc, "create ts %" GST_TIME_FORMAT,
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
  GST_BUFFER_DURATION (buffer) = interaudiosrc->timestamp_offset +
      gst_util_uint64_scale (interaudiosrc->n_samples + n, GST_SECOND,
      interaudiosrc->info.rate) - GST_BUFFER_TIMESTAMP (buffer);
  GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
  if (interaudiosrc->n_samples == 0) {
    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
  }
  interaudiosrc->n_samples += n;

  *buf = buffer;

  return GST_FLOW_OK;
}
static gpointer
push_abuffers (gpointer data)
{
  GstSegment segment;
  GstPad *pad = data;
  gint i, j, k;
  GstClockTime timestamp = 0;
  GstAudioInfo info;
  GstCaps *caps;
  guint buf_size = 1000;

  if (audiodelay)
    g_usleep (2000);

  if (early_video)
    timestamp = 50 * GST_MSECOND;

  gst_pad_send_event (pad, gst_event_new_stream_start ("test"));

  gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S8, buf_size, channels,
      NULL);
  caps = gst_audio_info_to_caps (&info);
  gst_pad_send_event (pad, gst_event_new_caps (caps));
  gst_caps_unref (caps);

  gst_segment_init (&segment, GST_FORMAT_TIME);
  gst_pad_send_event (pad, gst_event_new_segment (&segment));

  for (i = 0; i < n_abuffers; i++) {
    GstBuffer *buf = gst_buffer_new_and_alloc (channels * buf_size);

    if (per_channel) {
      GstMapInfo map;
      guint8 *in_data;

      gst_buffer_map (buf, &map, GST_MAP_WRITE);
      in_data = map.data;

      for (j = 0; j < buf_size; j++) {
        for (k = 0; k < channels; k++) {
          in_data[j * channels + k] = fill_value_per_channel[k];
        }
      }

      gst_buffer_unmap (buf, &map);
    } else {
      gst_buffer_memset (buf, 0, fill_value, channels * buf_size);
    }

    GST_BUFFER_TIMESTAMP (buf) = timestamp;
    timestamp += 1 * GST_SECOND;
    if (audio_drift)
      timestamp += 50 * GST_MSECOND;
    else if (i == 4 && audio_nondiscont)
      timestamp += 30 * GST_MSECOND;
    GST_BUFFER_DURATION (buf) = timestamp - GST_BUFFER_TIMESTAMP (buf);

    fail_unless (gst_pad_chain (pad, buf) == GST_FLOW_OK);
  }
  gst_pad_send_event (pad, gst_event_new_eos ());

  return NULL;
}