Beispiel #1
0
static void
configure_test_element (GstBin * bin, const gchar * capsfilter)
{
  GstElement *filter;
  GstElement *identity;
  GstPad *pad, *ghostpad;
  GstPadTemplate *test_static_templ;

  filter = gst_element_factory_make ("capsfilter", NULL);
  fail_unless (filter != NULL);
  gst_util_set_object_arg (G_OBJECT (filter), "caps", capsfilter);

  identity = gst_element_factory_make ("identity", NULL);
  fail_unless (identity != NULL);

  gst_bin_add_many (bin, filter, identity, NULL);
  fail_unless (gst_element_link_many (filter, identity, NULL) == TRUE);


  test_static_templ = gst_static_pad_template_get (&sink_factory);
  pad = gst_element_get_static_pad (filter, "sink");
  ghostpad = gst_ghost_pad_new_from_template ("sink", pad, test_static_templ);
  gst_element_add_pad (GST_ELEMENT_CAST (bin), ghostpad);
  gst_object_unref (pad);
  gst_object_unref (test_static_templ);

  test_static_templ = gst_static_pad_template_get (&src_factory);
  pad = gst_element_get_static_pad (identity, "src");
  ghostpad = gst_ghost_pad_new_from_template ("src", pad, test_static_templ);
  gst_element_add_pad (GST_ELEMENT_CAST (bin), ghostpad);
  gst_object_unref (pad);
  gst_object_unref (test_static_templ);
}
static void
gst_video_parse_init (GstVideoParse * vp)
{
  GstPad *inner_pad;
  GstPad *ghostpad;

  vp->rawvideoparse =
      gst_element_factory_make ("rawvideoparse", "inner_rawvideoparse");
  g_assert (vp->rawvideoparse != NULL);

  gst_bin_add (GST_BIN (vp), vp->rawvideoparse);

  inner_pad = gst_element_get_static_pad (vp->rawvideoparse, "sink");
  ghostpad =
      gst_ghost_pad_new_from_template ("sink", inner_pad,
      gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (vp), "sink"));
  gst_element_add_pad (GST_ELEMENT (vp), ghostpad);
  gst_object_unref (GST_OBJECT (inner_pad));

  inner_pad = gst_element_get_static_pad (vp->rawvideoparse, "src");
  ghostpad =
      gst_ghost_pad_new_from_template ("src", inner_pad,
      gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (vp), "src"));
  gst_element_add_pad (GST_ELEMENT (vp), ghostpad);
  gst_object_unref (GST_OBJECT (inner_pad));
}
Beispiel #3
0
static void
gst_vt_h264_enc_bin_init (GstVTH264EncBin * self, GstVTH264EncBinClass * gclass)
{
  GstVTH264EncBinPrivate *priv;
  GstPad *encoder_sinkpad, *parser_srcpad, *ghost_pad;

  self->priv = priv = TAA_VT_H264_ENC_BIN_GET_PRIVATE (self);

  priv->encoder = gst_element_factory_make ("vtenc_h264", "encoder");
  priv->parser = gst_element_factory_make ("h264parse", "parser");
  gst_bin_add_many (GST_BIN_CAST (self), priv->encoder, priv->parser, NULL);
  gst_element_link (priv->encoder, priv->parser);

  encoder_sinkpad = gst_element_get_static_pad (priv->encoder, "sink");
  ghost_pad = gst_ghost_pad_new_from_template ("sink", encoder_sinkpad,
      gst_static_pad_template_get (&vth264encbin_sink_template));
  gst_object_unref (encoder_sinkpad);
  gst_element_add_pad (GST_ELEMENT_CAST (self), ghost_pad);

  parser_srcpad = gst_element_get_static_pad (priv->parser, "src");
  ghost_pad = gst_ghost_pad_new_from_template ("src", parser_srcpad,
      gst_static_pad_template_get (&vth264encbin_src_template));
  gst_object_unref (parser_srcpad);
  gst_element_add_pad (GST_ELEMENT_CAST (self), ghost_pad);

  g_object_set (priv->encoder, "usage", 6, NULL);

  g_object_set (priv->parser,
      "output-format", H264PARSE_OUTPUT_FORMAT_BYTE_STREAM,
      "split-packetized", TRUE, NULL);
}
static void
gst_unaligned_audio_parse_init (GstUnalignedAudioParse * unaligned_audio_parse)
{
  GstPad *inner_pad;
  GstPad *ghostpad;

  unaligned_audio_parse->inner_parser =
      gst_element_factory_make ("rawaudioparse", "inner_parser");
  g_assert (unaligned_audio_parse->inner_parser != NULL);

  g_object_set (G_OBJECT (unaligned_audio_parse->inner_parser),
      "use-sink-caps", TRUE, NULL);

  gst_bin_add (GST_BIN (unaligned_audio_parse),
      unaligned_audio_parse->inner_parser);

  inner_pad =
      gst_element_get_static_pad (unaligned_audio_parse->inner_parser, "sink");
  ghostpad =
      gst_ghost_pad_new_from_template ("sink", inner_pad,
      gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS
          (unaligned_audio_parse), "sink"));
  gst_element_add_pad (GST_ELEMENT (unaligned_audio_parse), ghostpad);
  gst_object_unref (GST_OBJECT (inner_pad));

  inner_pad = gst_element_get_static_pad (unaligned_audio_parse->inner_parser,
      "src");
  ghostpad =
      gst_ghost_pad_new_from_template ("src", inner_pad,
      gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS
          (unaligned_audio_parse), "src"));
  gst_element_add_pad (GST_ELEMENT (unaligned_audio_parse), ghostpad);
  gst_object_unref (GST_OBJECT (inner_pad));
}
Beispiel #5
0
static GstPad *
kms_hub_port_generate_sink_pad (GstElement * element,
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps,
    GstElement * output)
{
  GstPad *output_pad, *pad;

  output_pad = gst_element_get_static_pad (output, "sink");
  pad = gst_ghost_pad_new_from_template (name, output_pad, templ);
  g_object_unref (output_pad);

  if (GST_STATE (element) >= GST_STATE_PAUSED
      || GST_STATE_PENDING (element) >= GST_STATE_PAUSED
      || GST_STATE_TARGET (element) >= GST_STATE_PAUSED) {
    gst_pad_set_active (pad, TRUE);
  }

  if (gst_element_add_pad (element, pad))
    return pad;

  GST_ERROR_OBJECT (element, "Cannot add pad %" GST_PTR_FORMAT, pad);
  g_object_unref (pad);

  return NULL;
}
Beispiel #6
0
static void owr_inter_src_init(OwrInterSrc *self)
{
    GstPad *srcpad, *sinkpad;

    GST_OBJECT_FLAG_SET(self, GST_ELEMENT_FLAG_SOURCE);

    self->queue = gst_element_factory_make("queue", NULL);
    gst_bin_add(GST_BIN(self), self->queue);

    srcpad = gst_element_get_static_pad(self->queue, "src");
    self->srcpad = gst_ghost_pad_new_from_template("src", srcpad, gst_static_pad_template_get(&src_template));
    gst_object_unref(srcpad);

    gst_element_add_pad(GST_ELEMENT(self), self->srcpad);

    /* Just to allow linking... */
    self->dummy_sinkpad = gst_pad_new("dummy_sinkpad", GST_PAD_SINK);
    gst_object_set_parent(GST_OBJECT(self->dummy_sinkpad), GST_OBJECT(self));

    self->internal_srcpad = gst_pad_new("internal_src", GST_PAD_SRC);
    gst_object_set_parent(GST_OBJECT(self->internal_srcpad), GST_OBJECT(self->dummy_sinkpad));
    gst_pad_set_event_function(self->internal_srcpad, owr_inter_src_internal_src_event);
    gst_pad_set_query_function(self->internal_srcpad, owr_inter_src_internal_src_query);

    sinkpad = gst_element_get_static_pad(self->queue, "sink");
    gst_pad_link(self->internal_srcpad, sinkpad);
    gst_object_unref(sinkpad);
}
static GstPad *
kms_element_generate_sink_pad (KmsElement * element, const gchar * name,
    GstElement ** target, GstPadTemplate * templ)
{
  GstElement *valve = *target;
  GstPad *sink, *ret_pad;

  if (valve != NULL)
    return NULL;

  valve = gst_element_factory_make ("valve", NULL);
  *target = valve;
  g_object_set (valve, "drop", TRUE, NULL);
  gst_bin_add (GST_BIN (element), valve);
  gst_element_sync_state_with_parent (valve);

  if (target == &element->priv->audio_valve) {
    KMS_ELEMENT_GET_CLASS (element)->audio_valve_added (element, valve);
  } else {
    KMS_ELEMENT_GET_CLASS (element)->video_valve_added (element, valve);
  }

  sink = gst_element_get_static_pad (valve, "sink");
  ret_pad = gst_ghost_pad_new_from_template (name, sink, templ);
  g_object_unref (sink);

  return ret_pad;
}
static gboolean
kms_base_hub_create_and_link_ghost_pad (KmsBaseHub * mixer,
    GstPad * src_pad, const gchar * gp_name, const gchar * gp_template_name,
    GstPad * target)
{
  GstPadTemplate *templ;
  GstPad *gp;
  gboolean ret;

  templ =
      gst_element_class_get_pad_template (GST_ELEMENT_CLASS
      (G_OBJECT_GET_CLASS (mixer)), gp_template_name);
  gp = gst_ghost_pad_new_from_template (gp_name, target, templ);

  if (GST_STATE (mixer) >= GST_STATE_PAUSED
      || GST_STATE_PENDING (mixer) >= GST_STATE_PAUSED
      || GST_STATE_TARGET (mixer) >= GST_STATE_PAUSED) {
    gst_pad_set_active (gp, TRUE);
  }

  ret = gst_element_add_pad (GST_ELEMENT (mixer), gp);

  if (ret) {
    gst_pad_link (src_pad, gp);
  } else {
    g_object_unref (gp);
  }

  return ret;
}
Beispiel #9
0
static void
kms_hub_port_start_media_type (KmsElement * self, KmsElementPadType type,
    GstPadTemplate * templ, const gchar * pad_name)
{
  GstElement *capsfilter = gst_element_factory_make ("capsfilter", NULL);
  GstPad *src = gst_element_get_static_pad (capsfilter, "src");
  GstPad *internal_src;

  gst_bin_add (GST_BIN (self), capsfilter);
  gst_element_sync_state_with_parent (capsfilter);

  internal_src = gst_ghost_pad_new_from_template (pad_name, src, templ);

  g_object_set_qdata_full (G_OBJECT (internal_src), key_elem_data_quark (),
      g_object_ref (capsfilter), g_object_unref);
  g_object_set_qdata (G_OBJECT (internal_src), key_type_data_quark (),
      GINT_TO_POINTER (type));

  g_signal_connect (internal_src, "linked",
      G_CALLBACK (kms_hub_port_internal_src_pad_linked), NULL);

  if (GST_STATE (self) >= GST_STATE_PAUSED
      || GST_STATE_PENDING (self) >= GST_STATE_PAUSED
      || GST_STATE_TARGET (self) >= GST_STATE_PAUSED) {
    gst_pad_set_active (internal_src, TRUE);
  }

  gst_element_add_pad (GST_ELEMENT (self), internal_src);
  g_object_unref (src);
}
static GstPad *
gst_hls_sink2_request_new_pad (GstElement * element, GstPadTemplate * templ,
    const gchar * name, const GstCaps * caps)
{
  GstHlsSink2 *sink = GST_HLS_SINK2_CAST (element);
  GstPad *pad, *peer;
  gboolean is_audio;

  g_return_val_if_fail (strcmp (templ->name_template, "audio") == 0
      || strcmp (templ->name_template, "video") == 0, NULL);
  g_return_val_if_fail (strcmp (templ->name_template, "audio") != 0
      || !sink->audio_sink, NULL);
  g_return_val_if_fail (strcmp (templ->name_template, "video") != 0
      || !sink->video_sink, NULL);

  is_audio = strcmp (templ->name_template, "audio") == 0;

  peer =
      gst_element_get_request_pad (sink->splitmuxsink,
      is_audio ? "audio_0" : "video");
  if (!peer)
    return NULL;

  pad = gst_ghost_pad_new_from_template (templ->name_template, peer, templ);
  gst_pad_set_active (pad, TRUE);
  gst_element_add_pad (element, pad);
  gst_object_unref (peer);

  if (is_audio)
    sink->audio_sink = pad;
  else
    sink->video_sink = pad;

  return pad;
}
static void
gst_rg_volume_init (GstRgVolume * self)
{
  GObjectClass *volume_class;
  GstPad *volume_pad, *ghost_pad;

  self->album_mode = DEFAULT_ALBUM_MODE;
  self->headroom = DEFAULT_HEADROOM;
  self->pre_amp = DEFAULT_PRE_AMP;
  self->fallback_gain = DEFAULT_FALLBACK_GAIN;
  self->target_gain = 0.0;
  self->result_gain = 0.0;

  self->volume_element = gst_element_factory_make ("volume", "rgvolume-volume");
  if (G_UNLIKELY (self->volume_element == NULL)) {
    GstMessage *msg;

    GST_WARNING_OBJECT (self, "could not create volume element");
    msg = gst_missing_element_message_new (GST_ELEMENT_CAST (self), "volume");
    gst_element_post_message (GST_ELEMENT_CAST (self), msg);

    /* Nothing else to do, we will refuse the state change from NULL to READY to
     * indicate that something went very wrong.  It is doubtful that someone
     * attempts changing our state though, since we end up having no pads! */
    return;
  }

  volume_class = G_OBJECT_GET_CLASS (G_OBJECT (self->volume_element));
  self->max_volume = G_PARAM_SPEC_DOUBLE
      (g_object_class_find_property (volume_class, "volume"))->maximum;

  GST_BIN_CLASS (parent_class)->add_element (GST_BIN_CAST (self),
      self->volume_element);

  volume_pad = gst_element_get_static_pad (self->volume_element, "sink");
  ghost_pad = gst_ghost_pad_new_from_template ("sink", volume_pad,
      gst_pad_get_pad_template (volume_pad));
  gst_object_unref (volume_pad);
  gst_pad_set_event_function (ghost_pad, gst_rg_volume_sink_event);
  gst_element_add_pad (GST_ELEMENT_CAST (self), ghost_pad);

  volume_pad = gst_element_get_static_pad (self->volume_element, "src");
  ghost_pad = gst_ghost_pad_new_from_template ("src", volume_pad,
      gst_pad_get_pad_template (volume_pad));
  gst_object_unref (volume_pad);
  gst_element_add_pad (GST_ELEMENT_CAST (self), ghost_pad);
}
static void
gst_vaapi_decode_bin_init (GstVaapiDecodeBin * vaapidecbin)
{
  GstPad *pad, *ghostpad;

  vaapidecbin->deinterlace_method = DEFAULT_DEINTERLACE_METHOD;
  vaapidecbin->disable_vpp = (g_getenv ("GST_VAAPI_DISABLE_VPP") != NULL);

  /* create the decoder */
  vaapidecbin->decoder =
      g_object_new (g_type_from_name ("GstVaapiDecode"), NULL);
  g_assert (vaapidecbin->decoder);

  /* create the queue */
  vaapidecbin->queue = gst_element_factory_make ("queue", "vaapi-queue");
  if (!vaapidecbin->queue) {
    g_clear_object (&vaapidecbin->decoder);
    post_missing_element_message (vaapidecbin, "queue");
    return;
  }

  gst_bin_add_many (GST_BIN (vaapidecbin), vaapidecbin->decoder,
      vaapidecbin->queue, NULL);

  if (!gst_element_link (vaapidecbin->decoder, vaapidecbin->queue)) {
    g_clear_object (&vaapidecbin->decoder);
    g_clear_object (&vaapidecbin->queue);
    g_critical ("failed to link decoder and queue");
    return;
  }

  /* create ghost pad sink */
  pad = gst_element_get_static_pad (vaapidecbin->decoder, "sink");
  ghostpad = gst_ghost_pad_new_from_template ("sink", pad,
      GST_PAD_PAD_TEMPLATE (pad));
  gst_object_unref (pad);
  if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad))
    g_critical ("failed to add decoder sink pad to bin");

  /* create ghost pad src */
  pad = gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->queue), "src");
  ghostpad = gst_ghost_pad_new_from_template ("src", pad,
      GST_PAD_PAD_TEMPLATE (pad));
  gst_object_unref (pad);
  if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad))
    g_critical ("failed to add queue source pad to bin");
}
static gboolean
kms_base_hub_link_src_pad (KmsBaseHub * mixer, const gchar * gp_name,
    const gchar * template_name, GstElement * internal_element,
    const gchar * pad_name, gboolean remove_on_unlink)
{
  GstPad *gp, *target;
  gboolean ret;

  if (GST_OBJECT_PARENT (internal_element) != GST_OBJECT (mixer)) {
    GST_ERROR_OBJECT (mixer, "Cannot link %" GST_PTR_FORMAT " wrong hierarchy",
        internal_element);
    return FALSE;
  }

  target = gst_element_get_static_pad (internal_element, pad_name);
  if (target == NULL) {
    target = gst_element_get_request_pad (internal_element, pad_name);

    if (target != NULL && remove_on_unlink) {
      g_signal_connect (G_OBJECT (target), "unlinked",
          G_CALLBACK (remove_unlinked_pad), NULL);
    }
  }

  if (target == NULL) {
    GST_ERROR_OBJECT (mixer, "Cannot get target pad");
    return FALSE;
  }

  gp = gst_element_get_static_pad (GST_ELEMENT (mixer), gp_name);

  if (gp == NULL) {
    GstPadTemplate *templ;

    templ =
        gst_element_class_get_pad_template (GST_ELEMENT_CLASS
        (G_OBJECT_GET_CLASS (mixer)), template_name);
    gp = gst_ghost_pad_new_from_template (gp_name, target, templ);

    if (GST_STATE (mixer) >= GST_STATE_PAUSED
        || GST_STATE_PENDING (mixer) >= GST_STATE_PAUSED
        || GST_STATE_TARGET (mixer) >= GST_STATE_PAUSED) {
      gst_pad_set_active (gp, TRUE);
    }

    ret = gst_element_add_pad (GST_ELEMENT (mixer), gp);
    if (!ret) {
      g_object_unref (gp);
    }
  } else {
    ret = set_target (gp, target);
    g_object_unref (gp);
  }

  g_object_unref (target);

  return ret;
}
GstPad* webkitGstGhostPadFromStaticTemplate(GstStaticPadTemplate* staticPadTemplate, const gchar* name, GstPad* target)
{
    GstPad* pad;
    GstPadTemplate* padTemplate = gst_static_pad_template_get(staticPadTemplate);

    if (target)
        pad = gst_ghost_pad_new_from_template(name, target, padTemplate);
    else
        pad = gst_ghost_pad_new_no_target_from_template(name, padTemplate);

    gst_object_unref(padTemplate);

    return pad;
}
Beispiel #15
0
static GstPad *
kms_element_generate_src_pad (KmsElement * element, const gchar * name,
    GstElement * agnosticbin, GstPadTemplate * templ)
{
  GstPad *agnostic_pad;
  GstPad *ret_pad;

  if (agnosticbin == NULL)
    return NULL;

  agnostic_pad = gst_element_get_request_pad (agnosticbin, "src_%u");
  ret_pad = gst_ghost_pad_new_from_template (name, agnostic_pad, templ);
  g_object_unref (agnostic_pad);

  return ret_pad;
}
Beispiel #16
0
static void
kms_agnostic_bin2_init (KmsAgnosticBin2 * self)
{
  GstPadTemplate *templ;
  GstElement *tee, *fakesink;
  GstPad *target, *sink;

  self->priv = KMS_AGNOSTIC_BIN2_GET_PRIVATE (self);

  tee = gst_element_factory_make ("tee", NULL);
  self->priv->input_tee = tee;
  fakesink = gst_element_factory_make ("fakesink", NULL);

  g_object_set (fakesink, "async", FALSE, "sync", FALSE, NULL);

  gst_bin_add_many (GST_BIN (self), tee, fakesink, NULL);
  gst_element_link_many (tee, fakesink, NULL);

  target = gst_element_get_static_pad (tee, "sink");
  templ = gst_static_pad_template_get (&sink_factory);
  self->priv->sink = gst_ghost_pad_new_from_template ("sink", target, templ);
  gst_pad_set_query_function (self->priv->sink, kms_agnostic_bin2_sink_query);
  gst_pad_set_chain_function (self->priv->sink, kms_agnostic_bin2_sink_chain);
  gst_pad_set_chain_list_function (self->priv->sink,
      kms_agnostic_bin2_sink_chain_list);
  kms_utils_manage_gaps (self->priv->sink);
  g_object_unref (templ);
  g_object_unref (target);

  sink = gst_element_get_static_pad (fakesink, "sink");
  gst_pad_add_probe (sink, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
      kms_agnostic_bin2_sink_caps_probe, self, NULL);
  g_object_unref (sink);

  gst_element_add_pad (GST_ELEMENT (self), self->priv->sink);

  self->priv->started = FALSE;
  self->priv->remove_pool =
      g_thread_pool_new (remove_on_unlinked_async, NULL, -1, FALSE, NULL);
  self->priv->bins =
      g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
  g_rec_mutex_init (&self->priv->thread_mutex);
  self->priv->min_bitrate = MIN_BITRATE_DEFAULT;
  self->priv->max_bitrate = MAX_BITRATE_DEFAULT;
  self->priv->bitrate_unlimited = FALSE;
}
static gboolean
kms_base_mixer_link_src_pad (KmsBaseMixer * mixer, const gchar * gp_name,
    const gchar * template_name, GstElement * internal_element,
    const gchar * pad_name)
{
  GstPad *gp, *target;
  gboolean ret;

  if (GST_OBJECT_PARENT (internal_element) != GST_OBJECT (mixer)) {
    GST_ERROR_OBJECT (mixer, "Cannot link %" GST_PTR_FORMAT " wrong hierarchy",
        internal_element);
    return FALSE;
  }

  target = gst_element_get_static_pad (internal_element, pad_name);
  if (target == NULL) {
    target = gst_element_get_request_pad (internal_element, pad_name);
  }

  if (target == NULL) {
    GST_ERROR_OBJECT (mixer, "Cannot get target pad");
    return FALSE;
  }

  gp = gst_element_get_static_pad (GST_ELEMENT (mixer), gp_name);

  if (gp == NULL) {
    GstPadTemplate *templ;

    templ =
        gst_element_class_get_pad_template (GST_ELEMENT_CLASS
        (G_OBJECT_GET_CLASS (mixer)), template_name);
    gp = gst_ghost_pad_new_from_template (gp_name, target, templ);
    ret = gst_element_add_pad (GST_ELEMENT (mixer), gp);
    if (!ret) {
      g_object_unref (gp);
    }
  } else {
    ret = gst_ghost_pad_set_target (GST_GHOST_PAD (gp), target);
    g_object_unref (gp);
  }

  g_object_unref (target);

  return ret;
}
static void
kms_mixer_endpoint_valve_added (KmsElement * self, GstElement * valve,
    GstPadTemplate * templ, const gchar * pad_name)
{
  GstPad *src = gst_element_get_static_pad (valve, "src");
  GstPad *internal_src = gst_ghost_pad_new_from_template (pad_name, src, templ);

  g_object_set_data_full (G_OBJECT (internal_src), KEY_VALVE_DATA,
      g_object_ref (valve), g_object_unref);

  g_signal_connect (internal_src, "linked",
      G_CALLBACK (kms_mixer_end_point_internal_src_pad_linked), NULL);
  internal_src->unlinkfunc =
      GST_DEBUG_FUNCPTR (kms_mixer_end_point_internal_src_pad_unlinked);

  gst_element_add_pad (GST_ELEMENT (self), internal_src);
  g_object_unref (src);
}
static GstPad *
kms_mixer_endpoint_generate_sink_pad (GstElement * element,
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps,
    GstElement * agnosticbin)
{
  GstPad *agnostic_pad, *pad;

  agnostic_pad = gst_element_get_static_pad (agnosticbin, "sink");
  pad = gst_ghost_pad_new_from_template (name, agnostic_pad, templ);
  g_object_unref (agnostic_pad);

  if (gst_element_add_pad (element, pad))
    return pad;

  GST_ERROR_OBJECT (element, "Cannot add pad %" GST_PTR_FORMAT, pad);
  g_object_unref (pad);

  return NULL;
}
Beispiel #20
0
GstPad *
kms_element_connect_sink_target_full (KmsElement * self, GstPad * target,
    KmsElementPadType type, const gchar * description)
{
  GstPad *pad;
  gchar *pad_name;
  GstPadTemplate *templ;

  templ = gst_static_pad_template_get (&sink_factory);

  pad_name = get_pad_name (type, description);

  pad = gst_ghost_pad_new_from_template (pad_name, target, templ);
  g_free (pad_name);
  g_object_unref (templ);

  if (type == KMS_ELEMENT_PAD_TYPE_VIDEO) {
    kms_utils_drop_until_keyframe (pad, TRUE);
    kms_utils_manage_gaps (pad);
  }

  gst_pad_set_query_function (pad, kms_element_pad_query);
  gst_pad_add_probe (pad,
      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_EVENT_FLUSH,
      accept_eos_probe, self, NULL);
  g_signal_connect (G_OBJECT (pad), "unlinked",
      G_CALLBACK (send_flush_on_unlink), NULL);

  if (GST_STATE (self) >= GST_STATE_PAUSED
      || GST_STATE_PENDING (self) >= GST_STATE_PAUSED
      || GST_STATE_TARGET (self) >= GST_STATE_PAUSED) {
    gst_pad_set_active (pad, TRUE);
  }

  if (gst_element_add_pad (GST_ELEMENT (self), pad)) {
    kms_element_set_sink_input_stats (self, pad, type);
    return pad;
  }

  g_object_unref (pad);

  return NULL;
}
static void
gst_vaapi_decode_bin_init (GstVaapiDecodeBin * vaapidecbin)
{
  GstPad *element_pad, *ghost_pad;

  /* let's assume we have VPP until we prove the opposite */
  vaapidecbin->has_vpp = TRUE;

  if (!gst_vaapi_decode_bin_configure (vaapidecbin))
    return;

  /* create ghost pad sink */
  element_pad =
      gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->decoder), "sink");
  ghost_pad =
      gst_ghost_pad_new_from_template ("sink", element_pad,
      GST_PAD_PAD_TEMPLATE (element_pad));
  gst_object_unref (element_pad);
  gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghost_pad);
}
static void
gst_insert_bin_init (GstInsertBin * self)
{
  GstProxyPad *internal;

  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INSERT_BIN,
      GstInsertBinPrivate);

  g_queue_init (&self->priv->change_queue);

  self->priv->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink",
      gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (self),
          "sink"));
  gst_element_add_pad (GST_ELEMENT (self), self->priv->sinkpad);

  internal = gst_proxy_pad_get_internal (GST_PROXY_PAD (self->priv->sinkpad));
  self->priv->srcpad = gst_ghost_pad_new_from_template ("src",
      GST_PAD (internal),
      gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (self), "src"));
  gst_object_unref (internal);
  gst_element_add_pad (GST_ELEMENT (self), self->priv->srcpad);
}
static gboolean
kms_base_mixer_create_and_link_ghost_pad (KmsBaseMixer * mixer,
    GstPad * src_pad, const gchar * gp_name, const gchar * gp_template_name,
    GstPad * target)
{
  GstPadTemplate *templ;
  GstPad *gp;
  gboolean ret;

  templ =
      gst_element_class_get_pad_template (GST_ELEMENT_CLASS
      (G_OBJECT_GET_CLASS (mixer)), gp_template_name);
  gp = gst_ghost_pad_new_from_template (gp_name, target, templ);
  ret = gst_element_add_pad (GST_ELEMENT (mixer), gp);

  if (ret) {
    gst_pad_link (src_pad, gp);
  } else {
    g_object_unref (gp);
  }

  return ret;
}
Beispiel #24
0
gboolean
fs_rtp_sub_stream_add_output_ghostpad_unlock (FsRtpSubStream *substream,
    GError **error)
{
  GstPad *valve_srcpad;
  gchar *padname = NULL;
  GstPad *ghostpad = NULL;
  FsCodec *codec = NULL;

  if (fs_rtp_sub_stream_has_stopped_enter (substream))
  {
    FS_RTP_SESSION_UNLOCK (substream->priv->session);
    return TRUE;
  }

  if (substream->priv->adding_output_ghostpad)
  {
    FS_RTP_SESSION_UNLOCK (substream->priv->session);
    goto out;
  }

  g_assert (substream->priv->output_ghostpad == NULL);

  substream->priv->adding_output_ghostpad = TRUE;

  padname = g_strdup_printf ("src_%u_%u_%d", substream->priv->session->id,
      substream->ssrc,
      substream->pt);

  FS_RTP_SESSION_UNLOCK (substream->priv->session);

  valve_srcpad = gst_element_get_static_pad (substream->priv->output_valve,
      "src");
  g_assert (valve_srcpad);

  ghostpad = gst_ghost_pad_new_from_template (padname, valve_srcpad,
      gst_element_class_get_pad_template (
          GST_ELEMENT_GET_CLASS (substream->priv->conference),
          "src_%d_%d_%d"));

  gst_object_unref (valve_srcpad);
  g_free (padname);

  if (!ghostpad)
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
        "Could not build ghostpad src_%u_%u_%d", substream->priv->session->id,
        substream->ssrc, substream->pt);
    goto error;
  }

  if (!gst_pad_set_active (ghostpad, TRUE))
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
        "Could not activate the src_%u_%u_%d", substream->priv->session->id,
        substream->ssrc, substream->pt);
    gst_object_unref (ghostpad);
    goto error;
  }

  if (!gst_element_add_pad (GST_ELEMENT (substream->priv->conference),
          ghostpad))
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
        "Could add build ghostpad src_%u_%u_%d to the conference",
        substream->priv->session->id, substream->ssrc, substream->pt);
    gst_object_unref (ghostpad);
    goto error;
  }

  FS_RTP_SESSION_LOCK (substream->priv->session);
  substream->priv->output_ghostpad = ghostpad;

  GST_DEBUG ("Src pad added on substream for ssrc:%X pt:%u " FS_CODEC_FORMAT,
      substream->ssrc, substream->pt,
      FS_CODEC_ARGS (substream->codec));

  codec = fs_codec_copy (substream->codec);

  FS_RTP_SESSION_UNLOCK (substream->priv->session);

  g_signal_emit (substream, signals[SRC_PAD_ADDED], 0,
                 ghostpad, codec);
  g_signal_emit (substream, signals[CODEC_CHANGED], 0);

  fs_codec_destroy (codec);

  g_object_set (substream->priv->output_valve, "drop", FALSE, NULL);

 out:

  fs_rtp_sub_stream_has_stopped_exit (substream);
  return TRUE;

 error:

  substream->priv->adding_output_ghostpad = FALSE;
  fs_rtp_sub_stream_has_stopped_exit (substream);
  return FALSE;
}
static void
kms_webrtc_data_session_bin_init (KmsWebRtcDataSessionBin * self)
{
  GstPadTemplate *pad_template;
  GstPad *pad, *target;
  gchar *name;

  self->priv = KMS_WEBRTC_DATA_SESSION_BIN_GET_PRIVATE (self);

  g_rec_mutex_init (&self->priv->mutex);

  self->priv->data_channels = g_hash_table_new (g_direct_hash, g_direct_equal);
  self->priv->channels =
      g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
      g_object_unref);
  self->priv->assoc_id = get_sctp_association_id ();
  self->priv->session_established = FALSE;
  self->priv->even_id = 0;
  self->priv->odd_id = 1;
  self->priv->pool =
      g_thread_pool_new (reset_stream_async, self, -1, FALSE, NULL);

  name = get_decoder_name (self->priv->assoc_id);
  self->priv->sctpdec = gst_element_factory_make ("sctpdec", name);
  g_free (name);

  name = get_encoder_name (self->priv->assoc_id);
  self->priv->sctpenc = gst_element_factory_make ("sctpenc", name);
  g_free (name);

  g_object_set (self->priv->sctpdec, "sctp-association-id",
      self->priv->assoc_id, NULL);
  g_object_set (self->priv->sctpenc, "sctp-association-id",
      self->priv->assoc_id, "use-sock-stream", TRUE, NULL);

  g_object_bind_property (self, "sctp-local-port", self->priv->sctpdec,
      "local-sctp-port", G_BINDING_SYNC_CREATE);

  g_object_bind_property (self, "sctp-remote-port", self->priv->sctpenc,
      "remote-sctp-port", G_BINDING_SYNC_CREATE);

  g_signal_connect (self->priv->sctpdec, "pad-added",
      G_CALLBACK (kms_webrtc_data_session_bin_pad_added), self);
  g_signal_connect (self->priv->sctpdec, "pad-removed",
      G_CALLBACK (kms_webrtc_data_session_bin_pad_removed), self);
  g_signal_connect (self->priv->sctpenc, "sctp-association-established",
      G_CALLBACK (kms_webrtc_data_session_bin_association_established), self);

  gst_bin_add_many (GST_BIN (self), self->priv->sctpdec, self->priv->sctpenc,
      NULL);

  target = gst_element_get_static_pad (self->priv->sctpdec, "sink");
  pad_template = gst_static_pad_template_get (&sink_template);
  pad = gst_ghost_pad_new_from_template ("sink", target, pad_template);
  g_object_unref (pad_template);
  g_object_unref (target);

  gst_element_add_pad (GST_ELEMENT (self), pad);

  target = gst_element_get_static_pad (self->priv->sctpenc, "src");
  pad_template = gst_static_pad_template_get (&src_template);
  pad = gst_ghost_pad_new_from_template ("src", target, pad_template);
  g_object_unref (pad_template);
  g_object_unref (target);

  gst_element_add_pad (GST_ELEMENT (self), pad);

  gst_element_sync_state_with_parent (self->priv->sctpdec);
  gst_element_sync_state_with_parent (self->priv->sctpenc);
}
Beispiel #26
0
static gboolean
create_elements (RsnDvdBin * dvdbin)
{
  GstPadTemplate *src_templ = NULL;
  GstPad *src = NULL;
  GstPad *sink = NULL;
  RsnDvdBinPadBlockCtx *bctx = NULL;

  if (!try_create_piece (dvdbin, DVD_ELEM_SOURCE, NULL,
          RESIN_TYPE_DVDSRC, "dvdsrc", "DVD source")) {
    return FALSE;
  }

  /* FIXME: Locking */
  if (dvdbin->device) {
    g_object_set (G_OBJECT (dvdbin->pieces[DVD_ELEM_SOURCE]),
        "device", dvdbin->device, NULL);
  }

  if (!try_create_piece (dvdbin, DVD_ELEM_DEMUX,
          NULL, GST_TYPE_FLUPS_DEMUX, "dvddemux", "DVD demuxer"))
    return FALSE;

  if (gst_element_link (dvdbin->pieces[DVD_ELEM_SOURCE],
          dvdbin->pieces[DVD_ELEM_DEMUX]) == FALSE)
    goto failed_connect;

  /* Listen for new pads from the demuxer */
  g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_DEMUX]), "pad-added",
      G_CALLBACK (demux_pad_added), dvdbin);

  g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_DEMUX]), "no-more-pads",
      G_CALLBACK (demux_no_more_pads), dvdbin);

  if (!try_create_piece (dvdbin, DVD_ELEM_MQUEUE, "multiqueue", 0, "mq",
          "multiqueue"))
    return FALSE;

  g_object_set (dvdbin->pieces[DVD_ELEM_MQUEUE],
      "max-size-time", (7 * GST_SECOND / 10), "max-size-bytes", 0,
      "max-size-buffers", 0, NULL);

  /* Decodebin will throw a missing element message to find an MPEG decoder */
  if (!try_create_piece (dvdbin, DVD_ELEM_VIDDEC, NULL, RSN_TYPE_VIDEODEC,
          "viddec", "video decoder"))
    return FALSE;

  if (!try_create_piece (dvdbin, DVD_ELEM_PARSET, NULL, RSN_TYPE_RSNPARSETTER,
          "rsnparsetter", "Aspect ratio adjustment"))
    return FALSE;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDDEC], "src");
  sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_PARSET], "sink");
  if (src == NULL || sink == NULL)
    goto failed_viddec_connect;
  if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
    goto failed_viddec_connect;
  gst_object_unref (src);
  gst_object_unref (sink);
  src = sink = NULL;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_PARSET], "src");
  if (src == NULL)
    goto failed_video_ghost;
  src_templ = gst_static_pad_template_get (&video_src_template);
  dvdbin->video_pad = gst_ghost_pad_new_from_template ("video", src, src_templ);
  gst_object_unref (src_templ);
  if (dvdbin->video_pad == NULL)
    goto failed_video_ghost;
  gst_pad_set_active (dvdbin->video_pad, TRUE);
  bctx = g_slice_new (RsnDvdBinPadBlockCtx);
  bctx->dvdbin = gst_object_ref (dvdbin);
  bctx->pad = gst_object_ref (dvdbin->video_pad);
  gst_pad_set_blocked_async_full (src, TRUE,
      (GstPadBlockCallback) dvdbin_pad_blocked_cb, bctx, (GDestroyNotify)
      _pad_block_destroy_notify);
  gst_object_unref (src);
  src = NULL;

  if (!try_create_piece (dvdbin, DVD_ELEM_SPU_SELECT, NULL,
          RSN_TYPE_STREAM_SELECTOR, "subpselect", "Subpicture stream selector"))
    return FALSE;

  /* Add a single standalone queue to hold a single buffer of SPU data */
  if (!try_create_piece (dvdbin, DVD_ELEM_SPUQ, "queue", 0, "spu_q",
          "subpicture decoder buffer"))
    return FALSE;
  g_object_set (dvdbin->pieces[DVD_ELEM_SPUQ],
      "max-size-time", G_GUINT64_CONSTANT (0), "max-size-bytes", 0,
      "max-size-buffers", 1, NULL);

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT], "src");
  sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPUQ], "sink");
  if (src == NULL || sink == NULL)
    goto failed_spuq_connect;
  if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
    goto failed_spuq_connect;
  gst_object_unref (src);
  gst_object_unref (sink);
  src = sink = NULL;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPUQ], "src");
  if (src == NULL)
    goto failed_spu_ghost;
  src_templ = gst_static_pad_template_get (&subpicture_src_template);
  dvdbin->subpicture_pad =
      gst_ghost_pad_new_from_template ("subpicture", src, src_templ);
  gst_object_unref (src_templ);
  if (dvdbin->subpicture_pad == NULL)
    goto failed_spu_ghost;
  gst_pad_set_active (dvdbin->subpicture_pad, TRUE);
  bctx = g_slice_new (RsnDvdBinPadBlockCtx);
  bctx->dvdbin = gst_object_ref (dvdbin);
  bctx->pad = gst_object_ref (dvdbin->subpicture_pad);
  gst_pad_set_blocked_async_full (src, TRUE,
      (GstPadBlockCallback) dvdbin_pad_blocked_cb, bctx, (GDestroyNotify)
      _pad_block_destroy_notify);
  gst_object_unref (src);
  src = NULL;

  if (!try_create_piece (dvdbin, DVD_ELEM_AUD_SELECT, NULL,
          RSN_TYPE_STREAM_SELECTOR, "audioselect", "Audio stream selector"))
    return FALSE;

  if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, NULL,
          RSN_TYPE_AUDIODEC, "auddec", "audio decoder"))
    return FALSE;

  /* rsnaudiomunge goes after the audio decoding to regulate the stream */
  if (!try_create_piece (dvdbin, DVD_ELEM_AUD_MUNGE, NULL,
          RSN_TYPE_AUDIOMUNGE, "audiomunge", "Audio output filter"))
    return FALSE;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "src");
  sink =
      gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "sink");
  if (src == NULL || sink == NULL)
    goto failed_aud_connect;
  if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
    goto failed_aud_connect;
  gst_object_unref (sink);
  gst_object_unref (src);
  src = sink = NULL;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT], "src");
  sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "sink");
  if (src == NULL || sink == NULL)
    goto failed_aud_connect;
  if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
    goto failed_aud_connect;
  gst_object_unref (sink);
  gst_object_unref (src);
  src = sink = NULL;

  /* ghost audio munge output pad onto bin */
  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_MUNGE], "src");
  if (src == NULL)
    goto failed_aud_ghost;
  src_templ = gst_static_pad_template_get (&audio_src_template);
  dvdbin->audio_pad = gst_ghost_pad_new_from_template ("audio", src, src_templ);
  gst_object_unref (src_templ);
  if (dvdbin->audio_pad == NULL)
    goto failed_aud_ghost;
  gst_pad_set_active (dvdbin->audio_pad, TRUE);
  bctx = g_slice_new (RsnDvdBinPadBlockCtx);
  bctx->dvdbin = gst_object_ref (dvdbin);
  bctx->pad = gst_object_ref (dvdbin->audio_pad);
  gst_pad_set_blocked_async_full (src, TRUE,
      (GstPadBlockCallback) dvdbin_pad_blocked_cb, bctx, (GDestroyNotify)
      _pad_block_destroy_notify);
  gst_object_unref (src);
  src = NULL;

  if (dvdbin->video_added && (dvdbin->audio_added || dvdbin->audio_broken)
      && dvdbin->subpicture_added) {
    GST_DEBUG_OBJECT (dvdbin, "Firing no more pads");
    gst_element_no_more_pads (GST_ELEMENT (dvdbin));
  }

  return TRUE;

failed_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD source and demuxer elements"));
  goto error_out;
failed_viddec_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD video decoder and aspect ratio adjuster"));
  goto error_out;
failed_video_ghost:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not ghost video output pad"));
  goto error_out;
failed_spuq_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD subpicture selector and buffer elements"));
  goto error_out;
failed_spu_ghost:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not ghost SPU output pad"));
  goto error_out;
failed_aud_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD audio decoder"));
  goto error_out;
failed_aud_ghost:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not ghost audio output pad"));
  goto error_out;
error_out:
  if (src != NULL)
    gst_object_unref (src);
  if (sink != NULL)
    gst_object_unref (sink);
  return FALSE;
}
static gboolean
gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin)
{
  gchar *missing_factory = NULL;
  GstPad *pad, *ghostpad;
  GstPadTemplate *tmpl;

  /* create the decoder */
  vaapidecbin->decoder =
      gst_element_factory_make ("vaapidecode", "vaapidecode");
  if (!vaapidecbin->decoder) {
    missing_factory = "vaapidecode";
    goto error_element_missing;
  }
  /* create the queue */
  vaapidecbin->queue = gst_element_factory_make ("queue", "queue");
  if (!vaapidecbin->queue) {
    missing_factory = "queue";
    goto error_element_missing;
  }

  g_object_set (G_OBJECT (vaapidecbin->queue),
      "max-size-bytes", vaapidecbin->max_size_bytes,
      "max-size-buffers", vaapidecbin->max_size_buffers,
      "max-size-time", vaapidecbin->max_size_time, NULL);

  gst_bin_add_many (GST_BIN (vaapidecbin), vaapidecbin->decoder,
      vaapidecbin->queue, NULL);

  if (!gst_element_link_many (vaapidecbin->decoder, vaapidecbin->queue, NULL))
    goto error_link_pad;

  /* create ghost pad sink */
  pad = gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->decoder), "sink");
  ghostpad = gst_ghost_pad_new_from_template ("sink", pad,
      GST_PAD_PAD_TEMPLATE (pad));
  gst_object_unref (pad);
  if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad))
    goto error_adding_pad;

  /* create ghost pad src */
  pad = gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->queue), "src");
  tmpl = gst_static_pad_template_get (&gst_vaapi_decode_bin_src_factory);
  ghostpad = gst_ghost_pad_new_from_template ("src", pad, tmpl);
  gst_object_unref (pad);
  gst_object_unref (tmpl);
  if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad))
    goto error_adding_pad;

  return TRUE;

error_element_missing:
  {
    post_missing_element_message (vaapidecbin, missing_factory);
    return FALSE;
  }
error_link_pad:
  {
    GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD, (NULL),
        ("Failed to configure the vaapidecodebin."));
    return FALSE;
  }
error_adding_pad:
  {
    GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD, (NULL),
        ("Failed to adding pads."));
    return FALSE;
  }
}
static GstPad *
gst_sctp_base_sink_request_new_pad (GstElement * element,
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
{
  GstSCTPBaseSink *self = GST_SCTP_BASE_SINK (element);
  GstPad *sinkpad, *ghostpad;
  GstElement *sctpclientsink;
  gchar *padname;
  gchar *pad_id;
  gint64 val;
  guint16 id;

  GST_SCTP_BASE_SINK_LOCK (self);
  if (self->priv->num_ostreams < self->priv->streams) {
    GST_SCTP_BASE_SINK_UNLOCK (self);
    GST_WARNING ("No more available streams");
    return NULL;
  }

  pad_id = get_stream_id_from_padname (name);
  if (pad_id == NULL) {
    GST_SCTP_BASE_SINK_UNLOCK (self);
    GST_WARNING
        ("Link of elements without using pad names is not yet supported");
    return NULL;
  }

  val = g_ascii_strtoll (pad_id, NULL, 10);
  g_free (pad_id);

  if (val > G_MAXUINT32) {
    GST_SCTP_BASE_SINK_UNLOCK (self);
    GST_ERROR ("SCTP stream id %" G_GINT64_FORMAT " is not valid", val);
    return NULL;
  }

  id = val;

  sctpclientsink = gst_element_factory_make ("sctpclientsink", NULL);
  sinkpad = gst_element_get_static_pad (sctpclientsink, "sink");
  if (sinkpad == NULL) {
    GST_SCTP_BASE_SINK_UNLOCK (self);
    GST_ERROR_OBJECT (sctpclientsink, "Can not get sink pad");
    gst_object_unref (sctpclientsink);
    return NULL;
  }

  g_object_set (sctpclientsink, "stream-id", id, "socket", self->priv->socket,
      NULL);

  gst_bin_add (GST_BIN (element), sctpclientsink);
  gst_element_sync_state_with_parent (sctpclientsink);

  padname = g_strdup_printf ("sink_%u", id);
  ghostpad = gst_ghost_pad_new_from_template (padname, sinkpad, templ);

  g_object_unref (sinkpad);
  g_free (padname);

  if (GST_STATE (element) >= GST_STATE_PAUSED
      || GST_STATE_PENDING (element) >= GST_STATE_PAUSED
      || GST_STATE_TARGET (element) >= GST_STATE_PAUSED)
    gst_pad_set_active (ghostpad, TRUE);

  gst_element_add_pad (element, ghostpad);

  self->priv->streams++;
  GST_SCTP_BASE_SINK_UNLOCK (self);

  return ghostpad;
}
static gboolean
create_elements (RsnDvdBin * dvdbin)
{
  GstPadTemplate *src_templ = NULL;
  GstPad *src = NULL;
  GstPad *sink = NULL;
  RsnDvdBinPadBlockCtx *bctx = NULL;

  if (!try_create_piece (dvdbin, DVD_ELEM_SOURCE, NULL,
          RESIN_TYPE_DVDSRC, "dvdsrc", "DVD source")) {
    return FALSE;
  }

  /* FIXME: Locking */
  if (dvdbin->device) {
    g_object_set (G_OBJECT (dvdbin->pieces[DVD_ELEM_SOURCE]),
        "device", dvdbin->device, NULL);
  }

  /* FIXME: Import and use local copy of mpeg PS demuxer */
  if (!try_create_piece (dvdbin, DVD_ELEM_DEMUX,
          NULL, GST_TYPE_FLUPS_DEMUX, "dvddemux", "DVD demuxer"))
    return FALSE;

  if (gst_element_link (dvdbin->pieces[DVD_ELEM_SOURCE],
          dvdbin->pieces[DVD_ELEM_DEMUX]) == FALSE)
    goto failed_connect;

  /* Listen for new pads from the demuxer */
  g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_DEMUX]), "pad-added",
      G_CALLBACK (demux_pad_added), dvdbin);

  g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_DEMUX]), "no-more-pads",
      G_CALLBACK (demux_no_more_pads), dvdbin);

  if (!try_create_piece (dvdbin, DVD_ELEM_MQUEUE, "multiqueue", 0, "rsnmq",
          "multiqueue"))
    return FALSE;

  g_object_set (dvdbin->pieces[DVD_ELEM_MQUEUE],
      "max-size-time", (7 * GST_SECOND / 10), "max-size-bytes", 0,
      "max-size-buffers", 0, NULL);

  if (!try_create_piece (dvdbin, DVD_ELEM_VIDPARSE, "mpegvideoparse", 0,
          "rsnvidparse", "video parser"))
    return FALSE;

  /* Decodebin will throw a missing element message to find an MPEG decoder */
  if (!try_create_piece (dvdbin, DVD_ELEM_VIDDEC, NULL, RSN_TYPE_VIDEODEC,
          "rsnviddec", "video decoder"))
    return FALSE;

  /* FIXME: Replace identity */
  if (!try_create_piece (dvdbin, DVD_ELEM_PARSET, NULL, RSN_TYPE_RSNPARSETTER,
          "rsnparsetter", "Aspect ratio adjustment"))
    return FALSE;

  if (!try_link_pieces (dvdbin->pieces[DVD_ELEM_VIDPARSE], "src",
          dvdbin->pieces[DVD_ELEM_VIDDEC], "sink"))
    goto failed_vidparse_connect;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDDEC], "src");
  sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_PARSET], "sink");
  if (src == NULL || sink == NULL)
    goto failed_viddec_connect;
  if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
    goto failed_viddec_connect;
  gst_object_unref (src);
  gst_object_unref (sink);
  src = sink = NULL;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_PARSET], "src");
  if (src == NULL)
    goto failed_video_ghost;
  src_templ = gst_static_pad_template_get (&video_src_template);
  dvdbin->video_pad = gst_ghost_pad_new_from_template ("video", src, src_templ);
  gst_object_unref (src_templ);
  if (dvdbin->video_pad == NULL)
    goto failed_video_ghost;
  gst_pad_set_active (dvdbin->video_pad, TRUE);
  bctx = g_slice_new (RsnDvdBinPadBlockCtx);
  bctx->dvdbin = gst_object_ref (dvdbin);
  bctx->pad = gst_object_ref (dvdbin->video_pad);
  bctx->pad_block_id =
      gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
      (GstPadProbeCallback) dvdbin_pad_blocked_cb, bctx, (GDestroyNotify)
      _pad_block_destroy_notify);
  gst_object_unref (src);
  src = NULL;

#if DEBUG_TIMING
  gst_pad_add_probe (dvdbin->video_pad,
      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_BUFFER |
      GST_PAD_PROBE_TYPE_EVENT_FLUSH,
      (GstPadProbeCallback) dvdbin_dump_timing_info, NULL, NULL);
#endif

  /* FIXME: Merge stream-selection logic to core and switch back */
  if (!try_create_piece (dvdbin, DVD_ELEM_SPU_SELECT, NULL,
          RSN_TYPE_INPUT_SELECTOR, "subpselect", "Subpicture stream selector"))
    return FALSE;

  g_object_set (G_OBJECT (dvdbin->pieces[DVD_ELEM_SPU_SELECT]),
      "sync-streams", FALSE, NULL);

  /* Add a single standalone queue to hold a single buffer of SPU data */
  if (!try_create_piece (dvdbin, DVD_ELEM_SPUQ, "queue", 0, "spu_q",
          "subpicture decoder buffer"))
    return FALSE;
  /* Allow a lot more while pre-rolling */
  g_object_set (dvdbin->pieces[DVD_ELEM_SPUQ],
      "max-size-time", G_GUINT64_CONSTANT (0), "max-size-bytes", 0,
      "max-size-buffers", 100, NULL);

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT], "src");
  sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPUQ], "sink");
  if (src == NULL || sink == NULL)
    goto failed_spuq_connect;
  if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
    goto failed_spuq_connect;
  gst_object_unref (src);
  gst_object_unref (sink);
  src = sink = NULL;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPUQ], "src");
  if (src == NULL)
    goto failed_spu_ghost;
  src_templ = gst_static_pad_template_get (&subpicture_src_template);
  dvdbin->subpicture_pad =
      gst_ghost_pad_new_from_template ("subpicture", src, src_templ);
  gst_object_unref (src_templ);
  if (dvdbin->subpicture_pad == NULL)
    goto failed_spu_ghost;
  gst_pad_set_active (dvdbin->subpicture_pad, TRUE);
  bctx = g_slice_new (RsnDvdBinPadBlockCtx);
  bctx->dvdbin = gst_object_ref (dvdbin);
  bctx->pad = gst_object_ref (dvdbin->subpicture_pad);
  bctx->pad_block_id =
      gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
      (GstPadProbeCallback) dvdbin_pad_blocked_cb, bctx, (GDestroyNotify)
      _pad_block_destroy_notify);
  gst_object_unref (src);
  src = NULL;

  if (!try_create_piece (dvdbin, DVD_ELEM_AUD_SELECT, NULL,
          RSN_TYPE_INPUT_SELECTOR, "audioselect", "Audio stream selector"))
    return FALSE;
  g_object_set (G_OBJECT (dvdbin->pieces[DVD_ELEM_AUD_SELECT]),
      "sync-streams", FALSE, NULL);

  if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, NULL,
          RSN_TYPE_AUDIODEC, "auddec", "audio decoder"))
    return FALSE;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUD_SELECT], "src");
  sink = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "sink");
  if (src == NULL || sink == NULL)
    goto failed_aud_connect;
  if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
    goto failed_aud_connect;
  gst_object_unref (sink);
  gst_object_unref (src);
  src = sink = NULL;

  /* ghost audio munge output pad onto bin */
  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_AUDDEC], "src");
  if (src == NULL)
    goto failed_aud_ghost;
  src_templ = gst_static_pad_template_get (&audio_src_template);
  dvdbin->audio_pad = gst_ghost_pad_new_from_template ("audio", src, src_templ);
  gst_object_unref (src_templ);
  if (dvdbin->audio_pad == NULL)
    goto failed_aud_ghost;
  gst_pad_set_active (dvdbin->audio_pad, TRUE);
  bctx = g_slice_new (RsnDvdBinPadBlockCtx);
  bctx->dvdbin = gst_object_ref (dvdbin);
  bctx->pad = gst_object_ref (dvdbin->audio_pad);
  bctx->pad_block_id =
      gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
      (GstPadProbeCallback) dvdbin_pad_blocked_cb, bctx, (GDestroyNotify)
      _pad_block_destroy_notify);
  gst_object_unref (src);
  src = NULL;

  if (dvdbin->video_added && (dvdbin->audio_added || dvdbin->audio_broken)
      && dvdbin->subpicture_added) {
    rsn_dvdbin_no_more_pads (dvdbin);
  }

  return TRUE;

failed_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD source and demuxer elements"));
  goto error_out;
failed_vidparse_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD video parser and video decoder"));
  goto error_out;
failed_viddec_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD video decoder and aspect ratio adjuster"));
  goto error_out;
failed_video_ghost:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not ghost video output pad"));
  goto error_out;
failed_spuq_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD subpicture selector and buffer elements"));
  goto error_out;
failed_spu_ghost:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not ghost SPU output pad"));
  goto error_out;
failed_aud_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD audio decoder"));
  goto error_out;
failed_aud_ghost:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not ghost audio output pad"));
  goto error_out;
error_out:
  if (src != NULL)
    gst_object_unref (src);
  if (sink != NULL)
    gst_object_unref (sink);
  return FALSE;
}