static void
gst_interleave_release_pad (GstElement * element, GstPad * pad)
{
  GstInterleave *self = GST_INTERLEAVE (element);
  GList *l;
  GstAudioChannelPosition position;

  g_return_if_fail (GST_IS_INTERLEAVE_PAD (pad));

  /* Take lock to make sure we're not changing this when processing buffers */
  GST_OBJECT_LOCK (self->collect);

  g_atomic_int_add (&self->channels, -1);

  if (gst_pad_has_current_caps (pad))
    g_atomic_int_add (&self->configured_sinkpads_counter, -1);

  position = GST_INTERLEAVE_PAD_CAST (pad)->channel;
  g_value_array_remove (self->input_channel_positions, position);

  /* Update channel numbers */
  GST_OBJECT_LOCK (self);
  for (l = GST_ELEMENT_CAST (self)->sinkpads; l != NULL; l = l->next) {
    GstInterleavePad *ipad = GST_INTERLEAVE_PAD (l->data);

    if (GST_INTERLEAVE_PAD_CAST (pad)->channel < ipad->channel)
      ipad->channel--;
  }
  GST_OBJECT_UNLOCK (self);

  /* Update the src caps if we already have them */
  if (self->sinkcaps) {
    if (self->channels > 0) {
      GstCaps *srccaps;
      GstStructure *s;

      srccaps = gst_caps_copy (self->sinkcaps);
      s = gst_caps_get_structure (srccaps, 0);

      gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
      gst_interleave_set_channel_positions (self, s);

      gst_pad_set_active (self->src, TRUE);
      gst_pad_set_caps (self->src, srccaps);
      gst_caps_unref (srccaps);
    } else {
      gst_caps_replace (&self->sinkcaps, NULL);
    }
  }

  GST_OBJECT_UNLOCK (self->collect);

  gst_collect_pads_remove_pad (self->collect, pad);
  gst_element_remove_pad (element, pad);
}
static gboolean
gst_interleave_sink_setcaps (GstInterleave * self, GstPad * pad,
    const GstCaps * caps, const GstAudioInfo * info)
{
  g_return_val_if_fail (GST_IS_INTERLEAVE_PAD (pad), FALSE);

  /* TODO: handle caps changes */
  if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps)) {
    goto cannot_change_caps;
  } else {
    GstCaps *srccaps;
    GstStructure *s;
    gboolean res;

    self->width = GST_AUDIO_INFO_WIDTH (info);
    self->rate = GST_AUDIO_INFO_RATE (info);

    gst_interleave_set_process_function (self);

    srccaps = gst_caps_copy (caps);
    s = gst_caps_get_structure (srccaps, 0);

    gst_structure_remove_field (s, "channel-mask");

    gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
    gst_interleave_set_channel_positions (self, s);

    gst_pad_set_active (self->src, TRUE);
    res = gst_pad_set_caps (self->src, srccaps);
    gst_caps_unref (srccaps);

    if (!res)
      goto src_did_not_accept;
  }

  if (!self->sinkcaps) {
    GstCaps *sinkcaps = gst_caps_copy (caps);
    GstStructure *s = gst_caps_get_structure (sinkcaps, 0);

    gst_structure_remove_field (s, "channel-mask");

    GST_DEBUG_OBJECT (self, "setting sinkcaps %" GST_PTR_FORMAT, sinkcaps);

    gst_caps_replace (&self->sinkcaps, sinkcaps);

    gst_caps_unref (sinkcaps);
  }

  return TRUE;

cannot_change_caps:
  {
    GST_WARNING_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't "
        "change", self->sinkcaps);
    return FALSE;
  }
src_did_not_accept:
  {
    GST_WARNING_OBJECT (self, "src did not accept setcaps()");
    return FALSE;
  }
}
static GstPad *
gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
    const gchar * req_name, const GstCaps * caps)
{
  GstInterleave *self = GST_INTERLEAVE (element);
  GstPad *new_pad;
  gchar *pad_name;
  gint channels, padnumber;
  GValue val = { 0, };

  if (templ->direction != GST_PAD_SINK)
    goto not_sink_pad;

  padnumber = g_atomic_int_add (&self->padcounter, 1);
  if (self->channel_positions_from_input)
    channels = g_atomic_int_add (&self->channels, 1);
  else
    channels = padnumber;

  pad_name = g_strdup_printf ("sink_%u", padnumber);
  new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD,
          "name", pad_name, "direction", templ->direction,
          "template", templ, NULL));
  GST_INTERLEAVE_PAD_CAST (new_pad)->channel = channels;
  GST_DEBUG_OBJECT (self, "requested new pad %s", pad_name);
  g_free (pad_name);

  gst_pad_use_fixed_caps (new_pad);

  gst_collect_pads_add_pad (self->collect, new_pad, sizeof (GstCollectData),
      NULL, TRUE);

  gst_collect_pads_set_event_function (self->collect,
      (GstCollectPadsEventFunction)
      GST_DEBUG_FUNCPTR (gst_interleave_sink_event), self);

  if (!gst_element_add_pad (element, new_pad))
    goto could_not_add;

  g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
  g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_NONE);
  self->input_channel_positions =
      g_value_array_append (self->input_channel_positions, &val);
  g_value_unset (&val);

  /* Update the src caps if we already have them */
  if (self->sinkcaps) {
    GstCaps *srccaps;
    GstStructure *s;

    /* Take lock to make sure processing finishes first */
    GST_OBJECT_LOCK (self->collect);

    srccaps = gst_caps_copy (self->sinkcaps);
    s = gst_caps_get_structure (srccaps, 0);

    gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
    gst_interleave_set_channel_positions (self, s);

    /* FIXME: send caps event after stream-start event */
    gst_pad_set_active (self->src, TRUE);
    gst_pad_set_caps (self->src, srccaps);
    gst_caps_unref (srccaps);

    GST_OBJECT_UNLOCK (self->collect);
  }

  return new_pad;

  /* errors */
not_sink_pad:
  {
    g_warning ("interleave: requested new pad that is not a SINK pad\n");
    return NULL;
  }
could_not_add:
  {
    GST_DEBUG_OBJECT (self, "could not add pad %s", GST_PAD_NAME (new_pad));
    gst_collect_pads_remove_pad (self->collect, new_pad);
    gst_object_unref (new_pad);
    return NULL;
  }
}
示例#4
0
static gboolean
gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps)
{
  GstInterleave *self;

  g_return_val_if_fail (GST_IS_INTERLEAVE_PAD (pad), FALSE);

  self = GST_INTERLEAVE (gst_pad_get_parent (pad));

  /* First caps that are set on a sink pad are used as output caps */
  /* TODO: handle caps changes */
  if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps)) {
    goto cannot_change_caps;
  } else {
    GstCaps *srccaps;

    GstStructure *s;

    gboolean res;

    s = gst_caps_get_structure (caps, 0);

    if (!gst_structure_get_int (s, "width", &self->width))
      goto no_width;

    if (!gst_structure_get_int (s, "rate", &self->rate))
      goto no_rate;

    gst_interleave_set_process_function (self);

    if (gst_structure_has_field (s, "channel-positions")) {
      const GValue *pos_array;

      pos_array = gst_structure_get_value (s, "channel-positions");
      if (GST_VALUE_HOLDS_ARRAY (pos_array)
          && gst_value_array_get_size (pos_array) == 1) {
        const GValue *pos = gst_value_array_get_value (pos_array, 0);

        GValue *apos = g_value_array_get_nth (self->input_channel_positions,
            GST_INTERLEAVE_PAD_CAST (pad)->channel);

        g_value_set_enum (apos, g_value_get_enum (pos));
      }
    }

    srccaps = gst_caps_copy (caps);
    s = gst_caps_get_structure (srccaps, 0);

    gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
    gst_interleave_set_channel_positions (self, s);

    res = gst_pad_set_caps (self->src, srccaps);
    gst_caps_unref (srccaps);

    if (!res)
      goto src_did_not_accept;
  }

  if (!self->sinkcaps) {
    GstCaps *sinkcaps = gst_caps_copy (caps);

    GstStructure *s = gst_caps_get_structure (sinkcaps, 0);

    gst_structure_remove_field (s, "channel-positions");

    gst_caps_replace (&self->sinkcaps, sinkcaps);

    gst_caps_unref (sinkcaps);
  }

  gst_object_unref (self);

  return TRUE;

cannot_change_caps:
  {
    GST_DEBUG_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't "
        "change", self->sinkcaps);
    gst_object_unref (self);
    return FALSE;
  }
src_did_not_accept:
  {
    GST_DEBUG_OBJECT (self, "src did not accept setcaps()");
    gst_object_unref (self);
    return FALSE;
  }
no_width:
  {
    GST_WARNING_OBJECT (self, "caps did not have width: %" GST_PTR_FORMAT,
        caps);
    gst_object_unref (self);
    return FALSE;
  }
no_rate:
  {
    GST_WARNING_OBJECT (self, "caps did not have rate: %" GST_PTR_FORMAT, caps);
    gst_object_unref (self);
    return FALSE;
  }
}