Example #1
0
void GstPlayer::handleAddedPad(GstElement * upstream, GstPad * upstreamNewPad, GstElement * downstream) {

  GstPad *downstreamPad = gst_element_get_static_pad ( downstream, "sink");
  GstPadLinkReturn result;
  GstCaps * newPadCaps = NULL;
  GstStructure * newPadStruct = NULL;
  const gchar * newPadType = NULL;

  QLOG_TRACE() << "Got pad " << GST_PAD_NAME (upstreamNewPad) << " from " << GST_ELEMENT_NAME (upstream);

  if (gst_pad_is_linked (downstreamPad)) {
      QLOG_TRACE() << " Pad already connected to downstream.";
  }else{
      newPadCaps = gst_pad_get_caps (upstreamNewPad);
      newPadStruct = gst_caps_get_structure (newPadCaps, 0);
      newPadType = gst_structure_get_name (newPadStruct);

      if (!g_str_has_prefix (newPadType, "audio/x-raw")) {
          QLOG_TRACE() << "Pad is not of type is not raw audio but of type "<< newPadType <<". Can't connect.";
      }else{
          result = gst_pad_link (upstreamNewPad, downstreamPad);
          if (GST_PAD_LINK_FAILED (result)) {
              QLOG_TRACE() << "Failed to link.";
          } else {
              QLOG_TRACE() << "Link successful.";
          }
      }
    }

  if (newPadCaps != NULL)
    gst_caps_unref (newPadCaps);
  gst_object_unref (downstreamPad);
}
static void
new_decoded_pad (GstElement * dec, GstPad * new_pad, gboolean last,
    AppInfo * info)
{
  const gchar *sname;
  GstElement *csp, *scale, *filter;
  GstStructure *s;
  GstCaps *caps;
  GstPad *sinkpad;

  /* already found a video stream? */
  if (info->got_video)
    return;

  /* FIXME: is this racy or does decodebin2 make sure caps are always
   * negotiated at this point? */
  caps = gst_pad_get_caps (new_pad);
  g_return_if_fail (caps != NULL);

  s = gst_caps_get_structure (caps, 0);
  sname = gst_structure_get_name (s);
  if (!g_str_has_prefix (sname, "video/x-raw-"))
    goto not_video;

  csp = create_element ("ffmpegcolorspace");
  scale = create_element ("videoscale");
  filter = create_element ("capsfilter");
  info->sink = create_element ("gdkpixbufsink");
  g_object_set (info->sink, "qos", FALSE, "max-lateness", (gint64) - 1, NULL);

  gst_bin_add_many (GST_BIN (info->pipe), csp, scale, filter, info->sink, NULL);

  sinkpad = gst_element_get_static_pad (csp, "sink");
  if (GST_PAD_LINK_FAILED (gst_pad_link (new_pad, sinkpad)))
    g_error ("Can't link new decoded pad to ffmpegcolorspace's sink pad");
  gst_object_unref (sinkpad);

  if (!gst_element_link (csp, scale))
    g_error ("Can't link ffmpegcolorspace to videoscale");
  if (!gst_element_link (scale, filter))
    g_error ("Can't link videoscale to capsfilter");
  if (!gst_element_link (filter, info->sink))
    g_error ("Can't link capsfilter to gdkpixbufsink");

  gst_element_set_state (info->sink, GST_STATE_PAUSED);
  gst_element_set_state (filter, GST_STATE_PAUSED);
  gst_element_set_state (scale, GST_STATE_PAUSED);
  gst_element_set_state (csp, GST_STATE_PAUSED);

  info->got_video = TRUE;
  return;

not_video:
  {
    if (last) {
      g_error ("This file does not contain a video track, or you do not have "
          "the necessary decoder(s) installed");
    }
  }
}
static void
new_decoded_pad_cb(GstElement *demuxer,
                   GstPad *new_pad,
                   gpointer user_data)
{
   GstElement *decoder;
   GstPad *pad;
   GstCaps *caps;
   gchar *str;

   caps = gst_pad_get_caps(new_pad);
   str = gst_caps_to_string(caps);

   if (g_str_has_prefix(str, "video/"))
     {
        decoder = GST_ELEMENT(user_data);

        pad = gst_element_get_pad(decoder, "sink");
        if (GST_PAD_LINK_FAILED(gst_pad_link(new_pad, pad)))
          {
             g_warning("Failed to link %s:%s to %s:%s", GST_DEBUG_PAD_NAME(new_pad),
                       GST_DEBUG_PAD_NAME(pad));
          }
     }
   g_free(str);
   gst_caps_unref(caps);
}
Example #4
0
static void
stream_src_pad_added (FsStream *stream, GstPad *pad, FsCodec *codec,
    struct SimpleMsnConference *dat)
{
  GstElement *sink = gst_element_factory_make ("fakesink", NULL);
  GstPad *sinkpad;

  GST_DEBUG ("pad added");

  ts_fail_unless (sink != NULL);

  ts_fail_unless (gst_bin_add (GST_BIN (dat->pipeline), sink));

  sinkpad = gst_element_get_static_pad (sink, "sink");
  ts_fail_unless (sinkpad != NULL);

  gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (pad_probe_cb), dat);

  ts_fail_if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sinkpad)));

  gst_object_unref (sinkpad);

  ts_fail_if (gst_element_set_state (sink, GST_STATE_PLAYING) ==
      GST_STATE_CHANGE_FAILURE);

}
Example #5
0
void GstShow::newPad(GstElement *src,
                       GstPad     *new_pad,
                       gpointer    data)
{
    GstPad *sink_pad;
    GstElement *color = (GstElement *) data;
    GstPadLinkReturn ret;
    GstCaps *new_pad_caps = NULL;
    GstStructure *new_pad_struct = NULL;
    const gchar *new_pad_type = NULL;
    
    g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src));
    
    
    
    new_pad_caps = gst_pad_get_current_caps (new_pad);
    new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
    new_pad_type = gst_structure_get_name (new_pad_struct);
    
    g_print ("  It has type '%s'.\n", new_pad_type);
    
    sink_pad = gst_element_get_static_pad (color, "sink");
    if (!sink_pad){
        L_(lerror) << "Gstreamer: no pad named sink";
        return;
    }


    /* If our converter is already linked, we have nothing to do here */
    if (gst_pad_is_linked (sink_pad)) {
      g_print ("  We are already linked. Ignoring.\n");
      /* Unreference the new pad's caps, if we got them */
      if (new_pad_caps != NULL)
          gst_caps_unref (new_pad_caps);
      
      /* Unreference the sink pad */
      gst_object_unref (sink_pad);
      return;
    }
    
    /* Attempt the link */
    ret = gst_pad_link (new_pad, sink_pad);
    if (GST_PAD_LINK_FAILED (ret)) {
      g_print ("  Type is '%s' but link failed.\n", new_pad_type);
      /* Unreference the new pad's caps, if we got them */
      if (new_pad_caps != NULL)
          gst_caps_unref (new_pad_caps);
      
      /* Unreference the sink pad */
      gst_object_unref (sink_pad);
      return;    
    } else {
      g_print ("  Link succeeded (type '%s').\n", new_pad_type);
    }

}
/* This function will be called by the pad-added signal */
static void pad_added_handler(GstElement *src, GstPad *new_pad,
                              CustomData *data)
{
    GstPad *sink_pad = NULL;
    GstPadLinkReturn ret;
    GstCaps *new_pad_caps = NULL;
    GstStructure *new_pad_struct = NULL;
    const gchar *new_pad_type = NULL;

    g_print("Received new pad '%s' from '%s':\n", GST_PAD_NAME(new_pad),
            GST_ELEMENT_NAME(src));

    /* Check the new pad's type */
    new_pad_caps = gst_pad_get_caps(new_pad);
    new_pad_struct = gst_caps_get_structure(new_pad_caps, 0);
    new_pad_type = gst_structure_get_name(new_pad_struct);

    if (g_str_has_prefix(new_pad_type, "video/x-raw")) {
        sink_pad = gst_element_get_static_pad(data->vsink, "sink");
        if (gst_pad_is_linked(sink_pad)) {
            g_print("  We are already linked. Ignoring.\n");
            goto exit;
        }
    }

    if (g_str_has_prefix(new_pad_type, "audio/x-raw")) {
        sink_pad = gst_element_get_static_pad(data->convert, "sink");

        if (gst_pad_is_linked(sink_pad)) {
            g_print("  We are already linked. Ignoring.\n");
            goto exit;
        }
    }

    /* Attempt the link */
    ret = gst_pad_link(new_pad, sink_pad);

    if (GST_PAD_LINK_FAILED(ret)) {
        g_print("  Type is '%s' but link failed.\n", new_pad_type);
    }
    else {
        g_print("  Link succeeded (type '%s').\n", new_pad_type);
    }

exit:

    /* Unreference the new pad's caps, if we got them */
    if (new_pad_caps != NULL)
        gst_caps_unref(new_pad_caps);

    /* Unreference the sink pad */
    if (sink_pad != NULL)
        gst_object_unref(sink_pad);
}
Example #7
0
static void
_src_pad_added (FsStream *stream, GstPad *pad, FsCodec *codec,
    gpointer user_data)
{
  struct SimpleTestStream *st = user_data;
  GstElement *fakesink = gst_element_factory_make ("fakesink", NULL);
  GstPad *fakesink_pad = NULL;
  GstPadLinkReturn ret;
  FsCodec *codeccopy = fs_codec_copy (codec);
  gchar *str = NULL;

  g_assert (fakesink);

  g_object_set (fakesink,
      "signal-handoffs", TRUE,
      "sync", TRUE,
      "async", TRUE,
      NULL);

  ts_fail_if (codec->encoding_name == NULL,
      "Got invalid codec without an encoding_name with id %u"
      " and clock_rate %u", codec->id, codec->clock_rate);

  g_object_set_data (G_OBJECT (fakesink), "codec", codeccopy);
  g_object_weak_ref (G_OBJECT (fakesink),
      (GWeakNotify) fs_codec_destroy, codeccopy);

  g_signal_connect (fakesink, "handoff", st->handoff_handler, st);

  gst_bin_add (GST_BIN (st->dat->pipeline), fakesink);

  fakesink_pad = gst_element_get_static_pad (fakesink, "sink");
  ret = gst_pad_link (pad, fakesink_pad);
  gst_object_unref (fakesink_pad);

  ts_fail_if (GST_PAD_LINK_FAILED(ret), "Could not link fakesink");

  ts_fail_if (gst_element_set_state (fakesink, GST_STATE_PLAYING) ==
      GST_STATE_CHANGE_FAILURE, "Could not set the fakesink to playing");

  str = fs_codec_to_string (codec);
  GST_DEBUG ("%d:%d: Added Fakesink for codec %s", st->dat->id, st->target->id,
           str);
  g_free (str);

  if (max_src_pads > 1)
    ts_fail_unless (count_stream_pads (stream) <= max_src_pads);
  else
    ts_fail_unless (count_stream_pads (stream) == 1);
}
Example #8
0
/* This function will be called by the pad-added signal */
void pad_added_handler(GstElement *src, GstPad *new_pad, CustomData *data)
{
	GstPad *sink_pad = gst_element_get_static_pad(data->buffer, "sink");
	GstPadLinkReturn ret;
	GstCaps *new_pad_caps = NULL;
	GstStructure *new_pad_struct = NULL;
	const gchar *new_pad_type = NULL;

	GPlayerDEBUG("Received new pad '%s' from '%s':\n", GST_PAD_NAME(new_pad), GST_ELEMENT_NAME(src));

	/* If our converter is already linked, we have nothing to do here */
	if (gst_pad_is_linked(sink_pad))
	{
		GPlayerDEBUG("  We are already linked. Ignoring.\n");
		goto exit;
	}

	/* Check the new pad's type */
	new_pad_caps = gst_pad_query_caps(new_pad, NULL);
	new_pad_struct = gst_caps_get_structure(new_pad_caps, 0);
	new_pad_type = gst_structure_get_name(new_pad_struct);
	if (!g_str_has_prefix(new_pad_type, "audio/x-raw"))
	{
		GPlayerDEBUG("  It has type '%s' which is not raw audio. Ignoring.\n", new_pad_type);
		goto exit;
	}

	/* Attempt the link */
	ret = gst_pad_link(new_pad, sink_pad);
	if (GST_PAD_LINK_FAILED(ret))
	{
		GPlayerDEBUG("  Type is '%s' but link failed.\n", new_pad_type);
		gplayer_error(-1, data);
		data->target_state = GST_STATE_NULL;
		data->is_live = (gst_element_set_state(data->pipeline, data->target_state) == GST_STATE_CHANGE_NO_PREROLL);
	}
	else
	{
		GPlayerDEBUG("  Link succeeded (type '%s').\n", new_pad_type);
	}

	exit:
	/* Unreference the new pad's caps, if we got them */
	if (new_pad_caps != NULL)
		gst_caps_unref(new_pad_caps);

	/* Unreference the sink pad */
	kill_object(sink_pad);
}
Example #9
0
static void pad_added_handler (GstElement *src, GstPad *new_pad, gpointer data)
{
#if (TRANS_TYPE == TRANS_TYPE_TCP)
  GstPad *sink_pad = gst_element_get_static_pad (gst_data.convert, "sink");
#else
  GstPad *sink_pad = gst_element_get_static_pad (gst_data.tee, "sink");
#endif
  GstPadLinkReturn ret;
  GstCaps *new_pad_caps = NULL;
  GstStructure *new_pad_struct = NULL;
  const gchar *new_pad_type = NULL;
  guint caps_size = 0, i;

  g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src));
  g_print ("sink_pad: '%s'\n", GST_PAD_NAME (sink_pad));

  if (gst_pad_is_linked (sink_pad)) {
    g_print ("We are already linked. Ignoring.\n");
    goto exit;
  }

  new_pad_caps = gst_pad_get_current_caps(new_pad);
  caps_size = gst_caps_get_size(new_pad_caps);
  g_print ("caps_size : %d\n", caps_size);
  for (i = 0; i < caps_size; i++)
    {
      new_pad_struct = gst_caps_get_structure(new_pad_caps, i);
      new_pad_type = gst_structure_get_name(new_pad_struct);
      g_print ("new_pad_type %d: '%s'\n", i, new_pad_type);
      if (strstr(new_pad_type, "audio/x-raw"))
	{
	    ret = gst_pad_link (new_pad, sink_pad);
	    if (GST_PAD_LINK_FAILED (ret)) {
	      g_print ("Type is '%s' but link failed.\n", new_pad_type);
	    } else {
	      g_print ("Link succeeded (type '%s').\n", new_pad_type);
	    }
	    break;
	}
    }

exit:
  /* Unreference the new pad's caps, if we got them */
  if (new_pad_caps != NULL)
    gst_caps_unref (new_pad_caps);
   
  /* Unreference the sink pad */
  gst_object_unref (sink_pad);
}
static GstPadLinkReturn
gst_videodrop_link (GstPad * pad, const GstCaps * caps)
{
  GstVideodrop *videodrop;
  GstStructure *structure;
  gboolean ret;
  double fps;
  GstPad *otherpad;

  videodrop = GST_VIDEODROP (gst_pad_get_parent (pad));

  otherpad = (pad == videodrop->srcpad) ? videodrop->sinkpad :
      videodrop->srcpad;

  structure = gst_caps_get_structure (caps, 0);
  ret = gst_structure_get_double (structure, "framerate", &fps);
  if (!ret)
    return GST_PAD_LINK_REFUSED;

  if (pad == videodrop->srcpad) {
    videodrop->to_fps = fps;
  } else {
    videodrop->from_fps = fps;
  }

  if (gst_pad_is_negotiated (otherpad)) {
    /* 
     * Ensure that the other side talks the format we're trying to set
     */
    GstCaps *newcaps = gst_caps_copy (caps);

    if (pad == videodrop->srcpad) {
      gst_caps_set_simple (newcaps,
          "framerate", G_TYPE_DOUBLE, videodrop->from_fps, NULL);
    } else {
      gst_caps_set_simple (newcaps,
          "framerate", G_TYPE_DOUBLE, videodrop->to_fps, NULL);
    }
    ret = gst_pad_try_set_caps (otherpad, newcaps);
    if (GST_PAD_LINK_FAILED (ret)) {
      return GST_PAD_LINK_REFUSED;
    }
  }

  return GST_PAD_LINK_OK;
}
Example #11
0
static void pad_added_handler (GstElement *src, GstPad *new_pad, CustomData *data) {
    GstPad *sink_pad = gst_element_get_static_pad (data->audioconvert, "sink");
    GstPadLinkReturn ret;
    GstCaps *new_pad_caps = NULL;
    GstStructure *new_pad_struct = NULL;
    const gchar *new_pad_type = NULL;

    g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src));

    /* If our converter is already linked, we have nothing to do here */
    if (gst_pad_is_linked (sink_pad)) {
        g_print ("  We are already linked. Ignoring.\n");
        goto exit;
    }

    /* Check the new pad's type */
#if GST_VERSION_MAJOR == (0)
    new_pad_caps = gst_pad_get_caps (new_pad);
#else
    new_pad_caps = gst_pad_query_caps (new_pad, NULL);
#endif
    new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
    new_pad_type = gst_structure_get_name (new_pad_struct);
    if (!g_str_has_prefix (new_pad_type, "audio/x-raw")) {
        g_print ("  It has type '%s' which is not raw audio. Ignoring.\n", new_pad_type);
        goto exit;
    }

    /* Attempt the link */
    ret = gst_pad_link (new_pad, sink_pad);
    if (GST_PAD_LINK_FAILED (ret)) {
        g_print ("  Type is '%s' but link failed.\n", new_pad_type);
    } else {
        g_print ("  Link succeeded (type '%s').\n", new_pad_type);
    }

exit:
    /* Unreference the new pad's caps, if we got them */
    if (new_pad_caps != NULL)
        gst_caps_unref (new_pad_caps);

    /* Unreference the sink pad */
    gst_object_unref (sink_pad);
}
Example #12
0
static void vc_pad_added_handler (GstElement *src,
		GstPad *new_pad, vc_data *data) {
	GstPad *sink_pad = gst_element_get_static_pad (data->gst_data.depayloader, "sink");
	GstPadLinkReturn ret;
	GstCaps *new_pad_caps = NULL;
	GstStructure *new_pad_struct = NULL;
	const gchar *new_pad_type = NULL;

	g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src));

	/* Check the new pad's name */
	if (!g_str_has_prefix (GST_PAD_NAME (new_pad), "recv_rtp_src_")) {
		g_print ("  It is not the right pad.  Need recv_rtp_src_. Ignoring.\n");
		goto exit;
	}

	/* If our converter is already linked, we have nothing to do here */
	if (gst_pad_is_linked (sink_pad)) {
		g_print (" Sink pad from %s already linked. Ignoring.\n", GST_ELEMENT_NAME (src));
		goto exit;
	}

	/* Check the new pad's type */
	new_pad_caps = gst_pad_get_caps (new_pad);
	new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
	new_pad_type = gst_structure_get_name (new_pad_struct);

	/* Attempt the link */
	ret = gst_pad_link (new_pad, sink_pad);
	if (GST_PAD_LINK_FAILED (ret)) {
		g_print ("  Type is '%s' but link failed.\n", new_pad_type);
	} else {
		g_print ("  Link succeeded (type '%s').\n", new_pad_type);
	}

exit:
	/* Unreference the new pad's caps, if we got them */
	if (new_pad_caps != NULL)
		gst_caps_unref (new_pad_caps);

	/* Unreference the sink pad */
	gst_object_unref (sink_pad);
}
Example #13
0
static void
new_decoded_pad_cb (GstElement * decodebin, GstPad * new_pad, gboolean last,
    GstElement * pipeline)
{
  GstElement *fakesink;
  GstPad *sinkpad;

  fakesink = gst_element_factory_make ("fakesink", NULL);
  gst_bin_add (GST_BIN (pipeline), fakesink);

  sinkpad = gst_element_get_static_pad (fakesink, "sink");
  if (GST_PAD_LINK_FAILED (gst_pad_link (new_pad, sinkpad))) {
    g_warning ("Failed to link %s:%s to %s:%s", GST_DEBUG_PAD_NAME (new_pad),
        GST_DEBUG_PAD_NAME (sinkpad));
    gst_bin_remove (GST_BIN (pipeline), fakesink);
  } else {
    gst_element_set_state (fakesink, GST_STATE_PAUSED);
  }
}
Example #14
0
static gboolean
try_link_pieces (GstElement * e1, const gchar * pad1, GstElement * e2,
    const gchar * pad2)
{
  GstPad *src = gst_element_get_static_pad (e1, pad1);
  GstPad *sink = gst_element_get_static_pad (e2, pad2);
  gboolean ret = FALSE;

  if (src == NULL || sink == NULL)
    goto done;

  if (GST_PAD_LINK_FAILED (gst_pad_link (src, sink)))
    goto done;

  ret = TRUE;
done:
  if (src)
    gst_object_unref (src);
  if (sink)
    gst_object_unref (sink);
  return ret;
}
Example #15
0
static void
link_element_to_tee (GstElement * tee, GstElement * element)
{
  GstPad *tee_src = gst_element_get_request_pad (tee, "src_%u");
  GstPad *element_sink = gst_element_get_static_pad (element, "sink");
  GstPadLinkReturn ret;
  GstPadChainFunction old_func;

  /*
   * HACK Add a custom chain function that does not return error, this way
   * we avoid race conditions produced by reconnect events not using the stream
   * lock
   */
  old_func = GST_PAD_CHAINFUNC (element_sink);

  if (old_func != NULL) {
    if (old_func != no_fail_chain) {
      g_object_set_data (G_OBJECT (element_sink), OLD_CHAIN_KEY, old_func);
    }
    gst_pad_set_chain_function (element_sink, no_fail_chain);
  }

  remove_element_on_unlinked (element, "src", "sink");
  g_signal_connect (tee_src, "unlinked", G_CALLBACK (remove_tee_pad_on_unlink),
      NULL);

  gst_pad_add_probe (tee_src, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, tee_src_probe,
      NULL, NULL);

  ret = gst_pad_link_full (tee_src, element_sink, GST_PAD_LINK_CHECK_NOTHING);

  if (G_UNLIKELY (GST_PAD_LINK_FAILED (ret))) {
    GST_ERROR ("Linking %" GST_PTR_FORMAT " with %" GST_PTR_FORMAT " result %d",
        tee_src, element_sink, ret);
  }

  g_object_unref (element_sink);
  g_object_unref (tee_src);
}
Example #16
0
static void
link_element_to_tee (GstElement * tee, GstElement * element)
{
  GstPad *tee_src = gst_element_get_request_pad (tee, "src_%u");
  GstPad *element_sink = gst_element_get_static_pad (element, "sink");
  GstPadLinkReturn ret;

  remove_element_on_unlinked (element, "src", "sink");
  g_signal_connect (tee_src, "unlinked", G_CALLBACK (remove_tee_pad_on_unlink),
      NULL);

  gst_pad_add_probe (tee_src, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, tee_src_probe,
      NULL, NULL);

  ret = gst_pad_link_full (tee_src, element_sink, GST_PAD_LINK_CHECK_NOTHING);

  if (G_UNLIKELY (GST_PAD_LINK_FAILED (ret))) {
    GST_ERROR ("Linking %" GST_PTR_FORMAT " with %" GST_PTR_FORMAT " result %d",
        tee_src, element_sink, ret);
  }

  g_object_unref (element_sink);
  g_object_unref (tee_src);
}
Example #17
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 void
mex_telepathy_channel_on_content_added (TfChannel *channel,
                                        TfContent *content,
                                        gpointer   user_data)
{
  MexTelepathyChannel *self = MEX_TELEPATHY_CHANNEL (user_data);
  MexTelepathyChannelPrivate *priv = self->priv;
  GstPad *srcpad, *sinkpad;
  FsMediaType mtype;
  GstElement *element;
  GstStateChangeReturn ret;

  MEX_DEBUG ("Content added");

  g_object_get (content,
                "sink-pad", &sinkpad,
                "media-type", &mtype,
                NULL);

  switch (mtype)
    {
    case FS_MEDIA_TYPE_AUDIO:
      MEX_DEBUG ("Audio content added");
      element = gst_parse_bin_from_description (
        "autoaudiosrc ! audioresample ! audioconvert ! volume name=micvolume", TRUE, NULL);
      priv->outgoing_mic = element;
      priv->mic_volume = gst_bin_get_by_name (GST_BIN (priv->outgoing_mic), "micvolume");
      break;
    case FS_MEDIA_TYPE_VIDEO:
      MEX_DEBUG ("Video content added");
      element = mex_telepathy_channel_setup_video_source (self, content);
      break;
    default:
      MEX_WARNING ("Unknown media type");
      g_object_unref (sinkpad);
      return;
    }

  g_signal_connect (content, "src-pad-added",
                    G_CALLBACK (mex_telepathy_channel_on_src_pad_added), self);

  gst_bin_add (GST_BIN (priv->pipeline), element);
  srcpad = gst_element_get_pad (element, "src");

  if (GST_PAD_LINK_FAILED (gst_pad_link (srcpad, sinkpad)))
    {
      tp_channel_close_async (TP_CHANNEL (priv->channel), NULL, NULL);
      MEX_WARNING ("Couldn't link source pipeline !?");
      return;
    }

  ret = gst_element_set_state (element, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE)
    {
      tp_channel_close_async (TP_CHANNEL (priv->channel), NULL, NULL);
      MEX_WARNING ("source pipeline failed to start!?");
      return;
    }

  g_object_unref (srcpad);
  g_object_unref (sinkpad);
}
static GstElement *
mex_telepathy_channel_setup_video_source (MexTelepathyChannel *self,
                                          TfContent           *content)
{
  MexTelepathyChannelPrivate *priv = self->priv;
  GstElement *result, *input, *rate, *scaler, *colorspace, *capsfilter, *tee;
  GstCaps *caps;
  guint framerate = 0, width = 0, height = 0;
  GstPad *pad, *ghost, *teesink, *teesrc, *outsink;

  result = gst_bin_new ("video_input");
  input = gst_element_factory_make ("autovideosrc", NULL);
  rate = gst_element_factory_make ("videomaxrate", NULL);
  scaler = gst_element_factory_make ("videoscale", NULL);
  colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
  capsfilter = gst_element_factory_make ("capsfilter", NULL);

  g_assert (input && rate && scaler && colorspace && capsfilter);
  g_object_get (content,
                "framerate", &framerate,
                "width", &width,
                "height", &height,
                NULL);

  if (framerate == 0)
    framerate = 15;

  if (width == 0 || height == 0)
    {
      width = 320;
      height = 240;
    }

  priv->framerate = framerate;
  priv->width = width;
  priv->height = height;

  caps = gst_caps_new_simple ("video/x-raw-yuv",
                              "width", G_TYPE_INT, width,
                              "height", G_TYPE_INT, height,
                              "framerate", GST_TYPE_FRACTION, framerate, 1,
                              NULL);

  g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);

  gst_bin_add_many (GST_BIN (result), input, rate, scaler,
                    colorspace, capsfilter, NULL);
  g_assert (gst_element_link_many (input, rate, scaler,
                                   colorspace, capsfilter, NULL));

  pad = gst_element_get_static_pad (capsfilter, "src");
  g_assert (pad != NULL);

  tee = gst_element_factory_make("tee", NULL);
  if (!tee)
    {
      MEX_WARNING("Couldn't create tee element !?");
      return NULL;
    }

  teesink = gst_element_get_pad(tee, "sink");
  gst_bin_add (GST_BIN (result), tee);

  if (GST_PAD_LINK_FAILED (gst_pad_link (pad, teesink)))
    {
      MEX_WARNING ("Couldn't link source pipeline to tee !?");
      return NULL;
    }
  pad = gst_element_get_request_pad (tee, "src%d");

  // Link the tee to the preview widget.
  teesrc = gst_element_get_request_pad(tee, "src%d");
  outsink = gst_element_get_pad (self->priv->outgoing_sink, "sink");
  gst_bin_add (GST_BIN(result), self->priv->outgoing_sink);
  gst_pad_link (teesrc, outsink);

  ghost = gst_ghost_pad_new ("src", pad);
  gst_element_add_pad (result, ghost);

  g_object_unref (pad);

  priv->video_input = result;
  priv->video_capsfilter = capsfilter;

  g_signal_connect (content, "notify::framerate",
                    G_CALLBACK (
                      mex_telepathy_channel_on_video_framerate_changed),
                    self);

  g_signal_connect (content, "resolution-changed",
                    G_CALLBACK (
                      mex_telepathy_channel_on_video_resolution_changed),
                    self);

  return result;
}
static void
mex_telepathy_channel_on_src_pad_added (TfContent *content,
                                        TpHandle   handle,
                                        FsStream  *stream,
                                        GstPad    *pad,
                                        FsCodec   *codec,
                                        gpointer   user_data)
{
  MexTelepathyChannel *self = MEX_TELEPATHY_CHANNEL (user_data);
  MexTelepathyChannelPrivate *priv = self->priv;

  gchar *cstr = fs_codec_to_string (codec);
  FsMediaType mtype;
  GstPad *sinkpad;
  GstElement *element;
  GstStateChangeReturn ret;

  /* Upon pad added, clear the "in progress" box+padding */
  clutter_actor_hide (CLUTTER_ACTOR (priv->busy_box));
  clutter_actor_show (CLUTTER_ACTOR (priv->full_frame) );

  MEX_DEBUG ("New src pad: %s", cstr);
  g_object_get (content, "media-type", &mtype, NULL);

  switch (mtype)
    {
    case FS_MEDIA_TYPE_AUDIO:
      element = gst_parse_bin_from_description (
        "audioconvert ! audioresample ! audioconvert ! autoaudiosink",
        TRUE, NULL);
      break;
    case FS_MEDIA_TYPE_VIDEO:
      element = priv->incoming_sink;
      break;
    default:
      MEX_WARNING ("Unknown media type");
      return;
    }

  if (!gst_bin_add (GST_BIN (priv->pipeline), element))
    {
      MEX_WARNING ("Failed to add sink element to pipeline");
    }
  sinkpad = gst_element_get_pad (element, "sink");
  ret = gst_element_set_state (element, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE)
    {
      tp_channel_close_async (TP_CHANNEL (priv->channel), NULL, NULL);
      MEX_WARNING ("Failed to start tee sink pipeline !?");
      return;
    }

  if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sinkpad)))
    {
      tp_channel_close_async (TP_CHANNEL (priv->channel), NULL, NULL);
      MEX_WARNING ("Couldn't link sink pipeline !?");
      return;
    }

  g_object_unref (sinkpad);

  /* Start in FULL mode */
  mex_telepathy_channel_set_tool_mode (self, TOOL_MODE_FULL, 100);
}
Example #21
0
static gboolean
create_elements (RsnDvdBin * dvdbin)
{
  GstPad *src = NULL;
  GstPad *sink = 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);

  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, "decodebin", 0, "viddec",
          "video decoder"))
    return FALSE;

  g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_VIDDEC]),
      "new-decoded-pad", G_CALLBACK (viddec_pad_added), dvdbin);

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

#if USE_VIDEOQ
  /* Add a small amount of queueing after the video decoder. */
  if (!try_create_piece (dvdbin, DVD_ELEM_VIDQ, "queue", 0, "vid_q",
          "video decoder buffer"))
    return FALSE;
  g_object_set (dvdbin->pieces[DVD_ELEM_VIDQ],
      "max-size-time", G_GUINT64_CONSTANT (0), "max-size-bytes", 0,
      "max-size-buffers", 3, NULL);

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

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_VIDQ], "src");
#else
  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_PARSET], "src");
#endif
  if (src == NULL)
    goto failed_video_ghost;
  dvdbin->video_pad = gst_ghost_pad_new ("video", src);
  if (dvdbin->video_pad == NULL)
    goto failed_video_ghost;
  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;

  src = gst_element_get_static_pad (dvdbin->pieces[DVD_ELEM_SPU_SELECT], "src");
  if (src == NULL)
    goto failed_spu_ghost;
  dvdbin->subpicture_pad = gst_ghost_pad_new ("subpicture", src);
  if (dvdbin->subpicture_pad == NULL)
    goto failed_spu_ghost;
  gst_pad_set_active (dvdbin->subpicture_pad, TRUE);
  gst_pad_set_blocked_async (dvdbin->subpicture_pad, TRUE,
      (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin);
  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;

  /* 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;

#if DECODEBIN_AUDIO
  /* Decodebin will throw a missing element message to find a suitable
   * decoder */
  if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, "decodebin", 0, "auddec",
          "audio decoder"))
    return FALSE;

  g_signal_connect (G_OBJECT (dvdbin->pieces[DVD_ELEM_AUDDEC]),
      "new-decoded-pad", G_CALLBACK (auddec_pad_added), dvdbin);
#else
  if (!try_create_piece (dvdbin, DVD_ELEM_AUDDEC, "a52dec", 0, "auddec",
          "audio decoder"))
    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;
#endif

  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;
  dvdbin->audio_pad = gst_ghost_pad_new ("audio", src);
  if (dvdbin->audio_pad == NULL)
    goto failed_aud_ghost;
  gst_pad_set_active (dvdbin->audio_pad, TRUE);
  gst_pad_set_blocked_async (dvdbin->audio_pad, TRUE,
      (GstPadBlockCallback) dvdbin_pad_blocked_cb, dvdbin);
  gst_object_unref (src);
  src = NULL;

  return TRUE;

failed_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD source and demuxer elements"));
  goto error_out;
#if USE_VIDEOQ
failed_vidq_connect:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not connect DVD aspect ratio adjuster and video buffer elements"));
  goto error_out;
#endif
failed_video_ghost:
  GST_ELEMENT_ERROR (dvdbin, CORE, FAILED, (NULL),
      ("Could not ghost SPU output pad"));
  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 void
gst_insert_bin_do_change (GstInsertBin * self, GstPad * pad)
{
  struct ChangeData *data;

  GST_OBJECT_LOCK (self);

  if (!is_right_direction_for_block (pad)) {
    GST_WARNING_OBJECT (self, "Block pad does not have the expected direction");
    goto next;
  }

  while ((data = g_queue_pop_head (&self->priv->change_queue)) != NULL) {
    GstPad *peer = NULL;
    GstPad *other_peer = NULL;

    GST_OBJECT_UNLOCK (self);


    if (data->action == GST_INSERT_BIN_ACTION_ADD &&
        !validate_element (self, data->element))
      goto error;

    peer = gst_pad_get_peer (pad);

    if (peer == NULL) {
      GST_WARNING_OBJECT (self, "Blocked pad has no peer");
      goto error;
    }

    if (data->action == GST_INSERT_BIN_ACTION_ADD) {
      GstPad *srcpad = NULL, *sinkpad = NULL;
      GstPad *peersrcpad, *peersinkpad;

      /* First let's make sure we have the right pad */
      if (data->sibling) {
        GstElement *parent = NULL;
        GstPad *siblingpad;

        if ((gst_pad_get_direction (pad) == GST_PAD_SRC &&
                data->direction == DIRECTION_BEFORE) ||
            (gst_pad_get_direction (pad) == GST_PAD_SINK &&
                data->direction == DIRECTION_AFTER))
          siblingpad = peer;
        else
          siblingpad = pad;

        parent = gst_pad_get_parent_element (siblingpad);
        if (parent != NULL)
          gst_object_unref (parent);

        if (parent != data->sibling)
          goto retry;
      } else {
        GstObject *parent;
        GstPad *ghost;
        GstPad *proxypad;

        if (data->direction == DIRECTION_BEFORE) {
          ghost = self->priv->srcpad;
          if (gst_pad_get_direction (pad) == GST_PAD_SINK)
            proxypad = pad;
          else
            proxypad = peer;
        } else {
          ghost = self->priv->sinkpad;
          if (gst_pad_get_direction (pad) == GST_PAD_SINK)
            proxypad = peer;
          else
            proxypad = pad;
        }

        if (!GST_IS_PROXY_PAD (proxypad))
          goto retry;
        parent = gst_pad_get_parent (proxypad);
        if (!parent)
          goto retry;
        gst_object_unref (parent);
        if (GST_PAD_CAST (parent) != ghost)
          goto retry;
      }

      if (gst_pad_get_direction (pad) == GST_PAD_SRC) {
        peersrcpad = pad;
        peersinkpad = peer;
      } else {
        peersrcpad = peer;
        peersinkpad = pad;
      }

      if (GST_IS_PROXY_PAD (peersrcpad)) {
        GstObject *parent = gst_pad_get_parent (peersrcpad);

        if (GST_PAD_CAST (parent) == self->priv->sinkpad)
          peersrcpad = NULL;

        if (parent)
          gst_object_unref (parent);
      }

      if (GST_IS_PROXY_PAD (peersinkpad)) {
        GstObject *parent = gst_pad_get_parent (peersinkpad);

        if (GST_PAD_CAST (parent) == self->priv->srcpad)
          peersinkpad = NULL;

        if (parent)
          gst_object_unref (parent);
      }

      if (peersinkpad && peersrcpad) {
        gst_pad_unlink (peersrcpad, peersinkpad);
      } else {
        if (!peersinkpad)
          gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad), NULL);
        if (!peersrcpad)
          gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad), NULL);
      }

      srcpad = get_single_pad (data->element, GST_PAD_SRC);
      sinkpad = get_single_pad (data->element, GST_PAD_SINK);

      if (srcpad == NULL || sinkpad == NULL) {
        GST_WARNING_OBJECT (self, "Can not get element src or sink pad");
        goto error;
      }

      if (!gst_bin_add (GST_BIN (self), data->element)) {
        GST_WARNING_OBJECT (self, "Can not add element to bin");
        goto error;
      }

      if (peersrcpad) {
        if (GST_PAD_LINK_FAILED (gst_pad_link (peersrcpad, sinkpad))) {
          GST_WARNING_OBJECT (self, "Can not link sibling's %s:%s pad"
              " to element's %s:%s pad", GST_DEBUG_PAD_NAME (peersrcpad),
              GST_DEBUG_PAD_NAME (sinkpad));
          goto error;
        }
      } else {
        if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad),
                sinkpad)) {
          GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s",
              GST_DEBUG_PAD_NAME (sinkpad),
              GST_DEBUG_PAD_NAME (self->priv->sinkpad));
          goto error;
        }
      }

      if (peersinkpad) {
        if (GST_PAD_LINK_FAILED (gst_pad_link (srcpad, peersinkpad))) {
          GST_WARNING_OBJECT (self, "Can not link element's %s:%s pad"
              " to sibling's %s:%s pad", GST_DEBUG_PAD_NAME (srcpad),
              GST_DEBUG_PAD_NAME (peersinkpad));
          goto error;
        }
      } else {
        if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad),
                srcpad)) {
          GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s",
              GST_DEBUG_PAD_NAME (srcpad),
              GST_DEBUG_PAD_NAME (self->priv->srcpad));
          goto error;
        }
      }

      gst_object_unref (srcpad);
      gst_object_unref (sinkpad);

      if (!gst_element_sync_state_with_parent (data->element)) {
        GST_WARNING_OBJECT (self, "Can not sync element's state with parent");
        goto error;
      }
    } else {
      GstElement *parent = NULL;
      GstPad *other_pad;
      GstCaps *caps = NULL, *peercaps = NULL;
      gboolean can_intersect;
      gboolean success;

      parent = gst_pad_get_parent_element (peer);
      if (parent != NULL)
        gst_object_unref (parent);

      if (parent != data->element)
        goto retry;

      if (gst_pad_get_direction (peer) == GST_PAD_SRC)
        other_pad = get_single_pad (data->element, GST_PAD_SINK);
      else
        other_pad = get_single_pad (data->element, GST_PAD_SRC);

      if (!other_pad) {
        GST_WARNING_OBJECT (self, "Can not get element's other pad");
        goto error;
      }

      other_peer = gst_pad_get_peer (other_pad);
      gst_object_unref (other_pad);

      if (!other_peer) {
        GST_WARNING_OBJECT (self, "Can not get element's other peer");
        goto error;
      }

      /* Get the negotiated caps for the source pad peer,
       * because renegotiation while the pipeline is playing doesn't work
       * that fast.
       */
      if (gst_pad_get_direction (pad) == GST_PAD_SRC)
        caps = gst_pad_get_current_caps (pad);
      else
        peercaps = gst_pad_get_current_caps (other_peer);
      if (!caps)
        caps = gst_pad_query_caps (pad, NULL);
      if (!peercaps)
        peercaps = gst_pad_query_caps (other_peer, NULL);
      can_intersect = gst_caps_can_intersect (caps, peercaps);
      gst_caps_unref (caps);
      gst_caps_unref (peercaps);

      if (!can_intersect) {
        GST_WARNING_OBJECT (self, "Pads are incompatible without the element");
        goto error;
      }

      if (gst_pad_get_direction (other_peer) == GST_PAD_SRC &&
          gst_pad_is_active (other_peer)) {
        gulong probe_id;

        probe_id = gst_pad_add_probe (other_peer,
            GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
            wait_and_drop_eos_cb, NULL, NULL);
        gst_pad_send_event (peer, gst_event_new_eos ());
        gst_pad_remove_probe (other_peer, probe_id);
      }

      gst_element_set_locked_state (data->element, TRUE);
      gst_element_set_state (data->element, GST_STATE_NULL);
      if (!gst_bin_remove (GST_BIN (self), data->element)) {
        GST_WARNING_OBJECT (self, "Element removal rejected");
        goto error;
      }
      gst_element_set_locked_state (data->element, FALSE);

      if (gst_pad_get_direction (pad) == GST_PAD_SRC)
        success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (pad, other_peer,
                GST_PAD_LINK_CHECK_HIERARCHY |
                GST_PAD_LINK_CHECK_TEMPLATE_CAPS));
      else
        success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (other_peer, pad,
                GST_PAD_LINK_CHECK_HIERARCHY |
                GST_PAD_LINK_CHECK_TEMPLATE_CAPS));
      gst_object_unref (other_peer);
      other_peer = NULL;

      if (!success) {
        GST_ERROR_OBJECT (self, "Could not re-link after the element's"
            " removal");
        goto error;
      }
    }


    gst_insert_bin_change_data_complete (self, data, TRUE);
    gst_object_unref (peer);

    GST_OBJECT_LOCK (self);
    continue;
  done:
    if (other_peer != NULL)
      gst_object_unref (other_peer);

    if (peer != NULL)
      gst_object_unref (peer);
    break;
  retry:
    GST_OBJECT_LOCK (self);
    g_queue_push_head (&self->priv->change_queue, data);
    goto done;
  error:
    /* Handle error */
    gst_insert_bin_change_data_complete (self, data, FALSE);
    GST_OBJECT_LOCK (self);
    goto done;
  }

next:
  gst_insert_bin_block_pad_unlock (self);
}
Example #23
0
/**
 * FIXME: remove GOTO
 */
void MediaImpl::gstPadAddedCallback(GstElement *src, GstPad *newPad, MediaImpl::GstPadHandlerData* data)
{
    g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (newPad), GST_ELEMENT_NAME (src));
    GstPad *sinkPad = NULL;

    // Check the new pad's type.
    GstCaps *newPadCaps = gst_pad_query_caps (newPad, NULL);
    GstStructure *newPadStruct = gst_caps_get_structure (newPadCaps, 0);
    const gchar *newPadType   = gst_structure_get_name (newPadStruct);
    gchar *newPadStructStr = gst_structure_to_string(newPadStruct);
    g_print("Structure is %s\n", newPadStructStr);
    g_free(newPadStructStr);
    if (g_str_has_prefix (newPadType, "video/x-raw"))
    {
        sinkPad = gst_element_get_static_pad (data->videoToConnect, "sink");
        gst_structure_get_int(newPadStruct, "width",  &data->width);
        gst_structure_get_int(newPadStruct, "height", &data->height);
    }
    else if (g_str_has_prefix (newPadType, "audio/x-raw"))
    {
        sinkPad = gst_element_get_static_pad (data->audioToConnect, "sink");
    }
    else {
        g_print ("  It has type '%s' which is not raw audio/video. Ignoring.\n", newPadType);
        goto exit;
    }

    // If our converter is already linked, we have nothing to do here.
    if (gst_pad_is_linked (sinkPad))
    {
        // Best prefixes.
        if (g_str_has_prefix (newPadType, "audio/x-raw-float") ||
                g_str_has_prefix (newPadType, "video/x-raw-int") )
        {
            g_print ("  Found a better pad.\n");
            GstPad* oldPad = gst_pad_get_peer(sinkPad);
            gst_pad_unlink(oldPad, sinkPad);
            g_object_unref(oldPad);
        }
        else
        {
            g_print ("  We are already linked. Ignoring.\n");
            goto exit;
        }
    }

    // Attempt the link
    if (GST_PAD_LINK_FAILED (gst_pad_link (newPad, sinkPad)))
    {
        g_print ("  Type is '%s' but link failed.\n", newPadType);
        goto exit;
    } else {
        data->videoIsConnected = true;
        g_print ("  Link succeeded (type '%s').\n", newPadType);
    }

exit:
    // Unreference the new pad's caps, if we got them.
    if (newPadCaps != NULL)
    {
        gst_caps_unref (newPadCaps);
    }

    // Unreference the sink pad.
    if (sinkPad != NULL)
    {
        gst_object_unref (sinkPad);
    }
}
static GstElement *
gst_auto_convert_add_element (GstAutoConvert * autoconvert,
    GstElementFactory * factory)
{
  GstElement *element = NULL;
  GstPad *internal_sinkpad = NULL;
  GstPad *internal_srcpad = NULL;
  GstPad *sinkpad = NULL;
  GstPad *srcpad = NULL;
  GstPadLinkReturn padlinkret;

  GST_DEBUG_OBJECT (autoconvert, "Adding element %s to the autoconvert bin",
      gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));

  element = gst_element_factory_create (factory, NULL);
  if (!element)
    return NULL;

  if (!gst_bin_add (GST_BIN (autoconvert), element)) {
    GST_ERROR_OBJECT (autoconvert, "Could not add element %s to the bin",
        GST_OBJECT_NAME (element));
    gst_object_unref (element);
    return NULL;
  }

  srcpad = get_pad_by_direction (element, GST_PAD_SRC);
  if (!srcpad) {
    GST_ERROR_OBJECT (autoconvert, "Could not find source in %s",
        GST_OBJECT_NAME (element));
    goto error;
  }

  sinkpad = get_pad_by_direction (element, GST_PAD_SINK);
  if (!sinkpad) {
    GST_ERROR_OBJECT (autoconvert, "Could not find sink in %s",
        GST_OBJECT_NAME (element));
    goto error;
  }

  internal_sinkpad =
      gst_pad_new_from_static_template (&sink_internal_template,
      "sink_internal");
  internal_srcpad =
      gst_pad_new_from_static_template (&src_internal_template, "src_internal");

  if (!internal_sinkpad || !internal_srcpad) {
    GST_ERROR_OBJECT (autoconvert, "Could not create internal pads");
    if (internal_srcpad)
      gst_object_unref (internal_srcpad);
    if (internal_sinkpad)
      gst_object_unref (internal_sinkpad);
    goto error;
  }

  g_object_weak_ref (G_OBJECT (element), (GWeakNotify) gst_object_unref,
      internal_sinkpad);
  g_object_weak_ref (G_OBJECT (element), (GWeakNotify) gst_object_unref,
      internal_srcpad);

  gst_pad_set_active (internal_sinkpad, TRUE);
  gst_pad_set_active (internal_srcpad, TRUE);

  g_object_set_qdata (G_OBJECT (internal_srcpad), parent_quark, autoconvert);
  g_object_set_qdata (G_OBJECT (internal_sinkpad), parent_quark, autoconvert);

  gst_pad_set_chain_function (internal_sinkpad,
      GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_chain));
  gst_pad_set_chain_list_function (internal_sinkpad,
      GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_chain_list));
  gst_pad_set_event_function (internal_sinkpad,
      GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_event));
  gst_pad_set_query_function (internal_sinkpad,
      GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_query));

  gst_pad_set_event_function (internal_srcpad,
      GST_DEBUG_FUNCPTR (gst_auto_convert_internal_src_event));
  gst_pad_set_query_function (internal_srcpad,
      GST_DEBUG_FUNCPTR (gst_auto_convert_internal_src_query));

  padlinkret = gst_pad_link_full (internal_srcpad, sinkpad,
      GST_PAD_LINK_CHECK_NOTHING);
  if (GST_PAD_LINK_FAILED (padlinkret)) {
    GST_WARNING_OBJECT (autoconvert, "Could not links pad %s:%s to %s:%s"
        " for reason %d",
        GST_DEBUG_PAD_NAME (internal_srcpad),
        GST_DEBUG_PAD_NAME (sinkpad), padlinkret);
    goto error;
  }

  padlinkret = gst_pad_link_full (srcpad, internal_sinkpad,
      GST_PAD_LINK_CHECK_NOTHING);
  if (GST_PAD_LINK_FAILED (padlinkret)) {
    GST_WARNING_OBJECT (autoconvert, "Could not links pad %s:%s to %s:%s"
        " for reason %d",
        GST_DEBUG_PAD_NAME (internal_srcpad),
        GST_DEBUG_PAD_NAME (sinkpad), padlinkret);
    goto error;
  }

  g_object_set_qdata (G_OBJECT (element),
      internal_srcpad_quark, internal_srcpad);
  g_object_set_qdata (G_OBJECT (element),
      internal_sinkpad_quark, internal_sinkpad);

  /* Iffy */
  gst_element_sync_state_with_parent (element);

  /* Increment the reference count we will return to the caller */
  gst_object_ref (element);

  /* unref sink and src pad */
  gst_object_unref (srcpad);
  gst_object_unref (sinkpad);
  return element;

error:
  gst_element_set_locked_state (element, TRUE);
  gst_element_set_state (element, GST_STATE_NULL);
  gst_bin_remove (GST_BIN (autoconvert), element);

  if (srcpad)
    gst_object_unref (srcpad);
  if (sinkpad)
    gst_object_unref (sinkpad);

  return NULL;
}
Example #25
0
static void
gst_tcp_mix_src_request_link_pad (GstTCPMixSrc * src, GstTCPMixSrcPad * pad)
{
  GstTCPMixSrcPad *p;
  GstPad *pp;
  GList *item;
  gboolean linked = FALSE;
  GstBin *parent;
  GstElement *target;
  GstPadLinkReturn linkRet;

  if (gst_pad_is_linked (GST_PAD (pad))) {
#if 1
    pp = GST_PAD_PEER (pad);
    GST_WARNING_OBJECT (src, "Pad %s.%s already linked to %s.%s",
        GST_ELEMENT_NAME (src), GST_PAD_NAME (pad),
        GST_ELEMENT_NAME (GST_PAD_PARENT (pp)), GST_PAD_NAME (pp));
#endif
    return;
  }

  GST_LOG_OBJECT (src, "Linking pad '%s.%s'",
      GST_ELEMENT_NAME (src), GST_PAD_NAME (pad));

  INFO ("link");

  /**
   *  Don't do GST_OBJECT_LOCK() here, it causes DEADLOCK.
   */
  /* GST_OBJECT_LOCK (src); */

  if (!src->autosink)
    goto find_sink;

  parent = GST_BIN (GST_ELEMENT_PARENT (src));
  target = gst_bin_get_by_name (parent, src->autosink);

  INFO ("link");

  if (!target)
    goto find_sink;

  pp = gst_element_get_request_pad (target, "sink_%u");

  GST_DEBUG_OBJECT (src, "Link %s.%s-%s.%s",
      GST_ELEMENT_NAME (src), GST_PAD_NAME (pad),
      GST_ELEMENT_NAME (GST_PAD_PARENT (pp)), GST_PAD_NAME (pp));

  INFO ("link");

  linkRet = gst_pad_link (GST_PAD (pad), GST_PAD (pp));
  if (GST_PAD_LINK_FAILED (linkRet)) {
    GST_ERROR_OBJECT (src, "can't link");
  }

  return;

find_sink:
#if 1
  for (item = GST_ELEMENT_PADS (src); item; item = g_list_next (item)) {
    p = GST_TCP_MIX_SRC_PAD (item->data);
    if (GST_PAD_IS_SRC (p)) {
      GST_OBJECT_LOCK (p);
      if ((pp = GST_PAD_PEER (p))) {
        GstElement *ele = GST_ELEMENT (GST_PAD_PARENT (pp));

        // FIXME: pad name calculation
        pp = gst_element_get_request_pad (ele, "sink_%u");

        GST_DEBUG_OBJECT (src, "Link %s.%s-%s.%s",
            GST_ELEMENT_NAME (src), GST_PAD_NAME (pad),
            GST_ELEMENT_NAME (GST_PAD_PARENT (pp)), GST_PAD_NAME (pp));

        linkRet = gst_pad_link (GST_PAD (pad), GST_PAD (pp));
        if (GST_PAD_LINK_FAILED (linkRet)) {
          GST_ERROR_OBJECT (src, "can't link");
        } else {
          linked = TRUE;
        }
      }
      GST_OBJECT_UNLOCK (p);

      if (linked)
        break;
    }
  }
#endif

  /* GST_OBJECT_UNLOCK (src); */
  return;
}
static gboolean
setup_recoder_pipeline (GstSmartEncoder * smart_encoder)
{
  GstPad *tmppad;
  GstCaps *caps;

  /* Fast path */
  if (G_UNLIKELY (smart_encoder->encoder))
    return TRUE;

  GST_DEBUG ("Creating internal decoder and encoder");

  /* Create decoder/encoder */
  caps = gst_pad_get_current_caps (smart_encoder->sinkpad);
  smart_encoder->decoder = get_decoder (caps);
  if (G_UNLIKELY (smart_encoder->decoder == NULL))
    goto no_decoder;
  gst_caps_unref (caps);
  gst_element_set_bus (smart_encoder->decoder, GST_ELEMENT_BUS (smart_encoder));

  caps = gst_pad_get_current_caps (smart_encoder->sinkpad);
  smart_encoder->encoder = get_encoder (caps);
  if (G_UNLIKELY (smart_encoder->encoder == NULL))
    goto no_encoder;
  gst_caps_unref (caps);
  gst_element_set_bus (smart_encoder->encoder, GST_ELEMENT_BUS (smart_encoder));

  GST_DEBUG ("Creating internal pads");

  /* Create internal pads */

  /* Source pad which we'll use to feed data to decoders */
  smart_encoder->internal_srcpad = gst_pad_new ("internal_src", GST_PAD_SRC);
  g_object_set_qdata ((GObject *) smart_encoder->internal_srcpad,
      INTERNAL_ELEMENT, smart_encoder);
  gst_pad_set_active (smart_encoder->internal_srcpad, TRUE);

  /* Sink pad which will get the buffers from the encoder.
   * Note: We don't need an event function since we'll be discarding all
   * of them. */
  smart_encoder->internal_sinkpad = gst_pad_new ("internal_sink", GST_PAD_SINK);
  g_object_set_qdata ((GObject *) smart_encoder->internal_sinkpad,
      INTERNAL_ELEMENT, smart_encoder);
  gst_pad_set_chain_function (smart_encoder->internal_sinkpad, internal_chain);
  gst_pad_set_active (smart_encoder->internal_sinkpad, TRUE);

  GST_DEBUG ("Linking pads to elements");

  /* Link everything */
  tmppad = gst_element_get_static_pad (smart_encoder->encoder, "src");
  if (GST_PAD_LINK_FAILED (gst_pad_link (tmppad,
              smart_encoder->internal_sinkpad)))
    goto sinkpad_link_fail;
  gst_object_unref (tmppad);

  if (!gst_element_link (smart_encoder->decoder, smart_encoder->encoder))
    goto encoder_decoder_link_fail;

  tmppad = gst_element_get_static_pad (smart_encoder->decoder, "sink");
  if (GST_PAD_LINK_FAILED (gst_pad_link (smart_encoder->internal_srcpad,
              tmppad)))
    goto srcpad_link_fail;
  gst_object_unref (tmppad);

  GST_DEBUG ("Done creating internal elements/pads");

  return TRUE;

no_decoder:
  {
    GST_WARNING ("Couldn't find a decoder for %" GST_PTR_FORMAT, caps);
    gst_caps_unref (caps);
    return FALSE;
  }

no_encoder:
  {
    GST_WARNING ("Couldn't find an encoder for %" GST_PTR_FORMAT, caps);
    gst_caps_unref (caps);
    return FALSE;
  }

srcpad_link_fail:
  {
    gst_object_unref (tmppad);
    GST_WARNING ("Couldn't link internal srcpad to decoder");
    return FALSE;
  }

sinkpad_link_fail:
  {
    gst_object_unref (tmppad);
    GST_WARNING ("Couldn't link encoder to internal sinkpad");
    return FALSE;
  }

encoder_decoder_link_fail:
  {
    GST_WARNING ("Couldn't link decoder to encoder");
    return FALSE;
  }
}
Example #27
0
static void
fs_rtp_sub_stream_constructed (GObject *object)
{
  FsRtpSubStream *self = FS_RTP_SUB_STREAM (object);
  GstPad *valve_sink_pad = NULL;
  GstPadLinkReturn linkret;
  gchar *tmp;

  GST_DEBUG ("New substream in session %u for ssrc %x and pt %u",
      self->priv->session->id, self->ssrc, self->pt);

  if (!self->priv->conference) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_INVALID_ARGUMENTS, "A Substream needs a conference object");
    return;
  }

  self->priv->rtpbin_unlinked_sig = g_signal_connect_object (
      self->priv->rtpbin_pad, "unlinked", G_CALLBACK (rtpbin_pad_unlinked),
      self, 0);

  tmp = g_strdup_printf ("output_recv_valve_%d_%d_%d", self->priv->session->id,
      self->ssrc, self->pt);
  self->priv->output_valve = gst_element_factory_make ("valve", tmp);
  g_free (tmp);

  if (!self->priv->output_valve) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not create a valve element for"
      " session substream with ssrc: %u and pt:%d", self->ssrc,
      self->pt);
    return;
  }

  if (!gst_bin_add (GST_BIN (self->priv->conference), self->priv->output_valve))
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not add the valve element for session"
      " substream with ssrc: %u and pt:%d to the conference bin",
      self->ssrc, self->pt);
    return;
  }

  /* We set the valve to dropping, the stream will unblock it when its linked */
  g_object_set (self->priv->output_valve, "drop", TRUE, NULL);

  if (gst_element_set_state (self->priv->output_valve, GST_STATE_PLAYING) ==
    GST_STATE_CHANGE_FAILURE) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not set the valve element for session"
      " substream with ssrc: %u and pt:%d to the playing state",
      self->ssrc, self->pt);
    return;
  }

  tmp = g_strdup_printf ("recv_capsfilter_%d_%d_%d", self->priv->session->id,
      self->ssrc, self->pt);
  self->priv->capsfilter = gst_element_factory_make ("capsfilter", tmp);
  g_free (tmp);

  if (!self->priv->capsfilter) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not create a capsfilter element for"
      " session substream with ssrc: %u and pt:%d", self->ssrc,
      self->pt);
    return;
  }

  if (!gst_bin_add (GST_BIN (self->priv->conference), self->priv->capsfilter)) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not add the capsfilter element for session"
      " substream with ssrc: %u and pt:%d to the conference bin",
      self->ssrc, self->pt);
    return;
  }

  if (gst_element_set_state (self->priv->capsfilter, GST_STATE_PLAYING) ==
    GST_STATE_CHANGE_FAILURE) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not set the capsfilter element for session"
      " substream with ssrc: %u and pt:%d to the playing state",
      self->ssrc, self->pt);
    return;
  }

  tmp = g_strdup_printf ("input_recv_valve_%d_%d_%d", self->priv->session->id,
      self->ssrc, self->pt);
  self->priv->input_valve = gst_element_factory_make ("valve", tmp);
  g_free (tmp);

  if (!self->priv->input_valve) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not create a valve element for"
      " session substream with ssrc: %u and pt:%d", self->ssrc,
      self->pt);
    return;
  }

  if (!gst_bin_add (GST_BIN (self->priv->conference), self->priv->input_valve))
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not add the valve element for session"
      " substream with ssrc: %u and pt:%d to the conference bin",
      self->ssrc, self->pt);
    return;
  }

  if (gst_element_set_state (self->priv->input_valve, GST_STATE_PLAYING) ==
    GST_STATE_CHANGE_FAILURE) {
    self->priv->construction_error = g_error_new (FS_ERROR,
      FS_ERROR_CONSTRUCTION, "Could not set the valve element for session"
      " substream with ssrc: %u and pt:%d to the playing state",
      self->ssrc, self->pt);
    return;
  }

  if (!gst_element_link (self->priv->input_valve, self->priv->capsfilter))
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
        FS_ERROR_CONSTRUCTION, "Could not link the input valve"
        " and the capsfilter");
    return;
  }

  valve_sink_pad = gst_element_get_static_pad (self->priv->input_valve,
      "sink");
  if (!valve_sink_pad)
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
        FS_ERROR_CONSTRUCTION,
        "Could not get the valve's sink pad");
    return;
  }

  linkret = gst_pad_link (self->priv->rtpbin_pad, valve_sink_pad);

  gst_object_unref (valve_sink_pad);

  if (GST_PAD_LINK_FAILED (linkret))
  {
    self->priv->construction_error = g_error_new (FS_ERROR,
        FS_ERROR_CONSTRUCTION,
        "Could not link the rtpbin to the codec bin (%d)", linkret);
    return;
  }

  if (self->no_rtcp_timeout > 0)
    if (!fs_rtp_sub_stream_start_no_rtcp_timeout_thread (self,
            &self->priv->construction_error))
      return;

  GST_CALL_PARENT (G_OBJECT_CLASS, constructed, (object));
}
Example #28
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);
  }

  /* 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;
}
Example #29
0
/* This function will be called by the pad-added signal */
void MediaPlayer::cb_pad_added (GstElement *src, GstPad *new_pad, MediaPlayer * self )
{
    GstPad *sink_pad = 0;
    GstPadLinkReturn ret;
    GstCaps *new_pad_caps = NULL;
    GstStructure *new_pad_struct = NULL;
    const gchar *new_pad_type = NULL;

    Logger::debug( "GstMediaPlayer: received new pad '%s' from '%s'", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src) );

    /* Check the new pad's type */
    new_pad_caps = gst_pad_query_caps (new_pad, NULL);
    new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
    new_pad_type = gst_structure_get_name (new_pad_struct);

    if ( g_str_has_prefix (new_pad_type, "video/x-raw") )
    {
        if ( (self->m_loadOptions & MediaPlayer::LoadVideoStream) == 0 )
        {
            Logger::debug( "GstMediaPlayer:  Stream has video type, but video is not enabled, ignoring." );
            goto exit;
        }

        // Link the decoder pad with the color converter
        sink_pad = gst_element_get_static_pad ( self->m_gst_video_colorconv, "sink");

        // If our converter is already linked, we have nothing to do here
        if ( gst_pad_is_linked (sink_pad) )
        {
            Logger::debug( "GstMediaPlayer:  We are already linked. Ignoring.");
            goto exit;
        }

        // Attempt the link
        ret = gst_pad_link( new_pad, sink_pad );

        if ( GST_PAD_LINK_FAILED (ret) )
        {
            self->reportError( "link failed" );
        }
        else
        {
            Logger::debug( "GstMediaPlayer:   Video link succeeded (type '%s').", new_pad_type );
        }
    }
    else if ( g_str_has_prefix (new_pad_type, "audio/x-raw") )
    {
        if ( (self->m_loadOptions & MediaPlayer::LoadAudioStream) == 0 )
        {
            Logger::debug( "GstMediaPlayer:  Stream has audio type, but audio is not enabled, ignoring." );
            goto exit;
        }

        // Connect the pads
        sink_pad = gst_element_get_static_pad (self->m_gst_audioconverter, "sink");

        // Attempt the link
        ret = gst_pad_link (new_pad, sink_pad);

        if (GST_PAD_LINK_FAILED (ret))
        {
            Logger::debug( "GstMediaPlayer:  Audio link failed (type '%s').", new_pad_type );
        }
        else
        {
            Logger::debug( "GstMediaPlayer:  Audio link succeeded (type '%s').", new_pad_type );
        }
    }
    else
        Logger::debug( "GstMediaPlayer:  It has type '%s' which is not handled here, ignoring", new_pad_type );

exit:
    // Unreference the new pad's caps, if we got them
    if (new_pad_caps != NULL)
        gst_caps_unref (new_pad_caps);

    // Unreference the sink pad
    if ( sink_pad )
        gst_object_unref (sink_pad);
}
Example #30
0
static void
_connected (
    FsMsnConnection *connection,
    guint fd,
    gpointer user_data)
{
  FsMsnStream *self = FS_MSN_STREAM (user_data);
  GError *error = NULL;
  GstPad *pad;
  GstElement *fdelem;
  int checkfd;
  FsMsnConference *conference = fs_msn_stream_get_conference (self, NULL);
  GstElement *codecbin = NULL;
  GstElement *recv_valve = NULL;
  GstElement *send_valve = NULL;
  gboolean drop;

  if (!conference)
    goto error;

  GST_DEBUG ("******** CONNECTED %d**********", fd);

  gst_element_post_message (GST_ELEMENT (conference),
      gst_message_new_element (GST_OBJECT (conference),
          gst_structure_new ("farstream-component-state-changed",
              "stream", FS_TYPE_STREAM, self,
              "component", G_TYPE_UINT, 1,
              "state", FS_TYPE_STREAM_STATE, FS_STREAM_STATE_READY,
              NULL)));

  if (self->priv->conference->max_direction == FS_DIRECTION_RECV)
    codecbin = gst_parse_bin_from_description (
        "fdsrc name=fdsrc do-timestamp=true ! mimdec ! valve name=recv_valve", TRUE, &error);
  else
    codecbin = gst_parse_bin_from_description (
        "videoconvert ! videoscale ! mimenc name=enc !"
        " fdsink name=fdsink sync=false async=false",
        TRUE, &error);

  if (!codecbin)
  {
    g_prefix_error (&error, "Error creating codecbin: ");
    fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION,
        error->message);
    g_clear_error (&error);
    goto error;
  }

  /* So we don't require an unlreased gst-plugins-bad mimenc */
  if (self->priv->conference->max_direction == FS_DIRECTION_SEND)
  {
    GstElement *mimenc = gst_bin_get_by_name (GST_BIN (codecbin), "enc");
    if (g_object_class_find_property (
            G_OBJECT_GET_CLASS (mimenc), "paused-mode"))
      g_object_set (mimenc, "paused-mode", TRUE, NULL);
    gst_object_unref (mimenc);
  }

  if (self->priv->conference->max_direction == FS_DIRECTION_RECV)
  {
    fdelem = gst_bin_get_by_name (GST_BIN (codecbin), "fdsrc");
    gst_base_src_set_format (GST_BASE_SRC (fdelem), GST_FORMAT_TIME);
  }
  else
  {
    fdelem = gst_bin_get_by_name (GST_BIN (codecbin), "fdsink");
  }

  if (!fdelem)
  {
    fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION,
        "Could not get fd element");
    goto error;
  }

  g_object_set (fdelem, "fd", fd, NULL);
  g_object_get (fdelem, "fd", &checkfd, NULL);
  gst_object_unref (fdelem);

  if (fd != checkfd)
  {
    fs_stream_emit_error (FS_STREAM (self), FS_ERROR_INTERNAL,
        "Could not set file descriptor");
    goto error;
  }


  if (self->priv->conference->max_direction == FS_DIRECTION_RECV)
    pad = gst_element_get_static_pad (codecbin, "src");
  else
    pad = gst_element_get_static_pad (codecbin, "sink");

  if (!pad)
  {
    fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION,
        "Could not get codecbin pad");
    goto error;
  }

  if (!gst_bin_add (GST_BIN (conference), codecbin))
  {
    gst_object_unref (pad);
    fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION,
        "Could not add codecbin to the conference");
    goto error;
  }

  GST_OBJECT_LOCK (conference);
  self->priv->fd = fd;
  self->priv->codecbin = gst_object_ref (codecbin);
  GST_OBJECT_UNLOCK (conference);

  if (self->priv->conference->max_direction == FS_DIRECTION_RECV)
  {
    FsCodec *mimic_codec;
    GstPad *src_pad;

    src_pad = gst_ghost_pad_new ("src_1_1_1", pad);
    gst_object_unref (pad);

    GST_OBJECT_LOCK (conference);
    self->priv->src_pad =  gst_object_ref (src_pad);
    GST_OBJECT_UNLOCK (conference);

    gst_pad_set_active (src_pad, TRUE);
    if (!gst_element_add_pad (GST_ELEMENT (conference), src_pad))
    {
      fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION,
          "Could not add src_1_1_1 pad");
      gst_object_unref (src_pad);
      goto error;
    }

    recv_valve = gst_bin_get_by_name (GST_BIN (codecbin), "recv_valve");

    if (!recv_valve)
    {
       fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION,
           "Could not get recv_valve");
       gst_object_unref (src_pad);
       goto error;
    }

    GST_OBJECT_LOCK (conference);
    self->priv->recv_valve = gst_object_ref (recv_valve);
    drop = !(self->priv->direction & FS_DIRECTION_RECV);
    GST_OBJECT_UNLOCK (conference);

    g_object_set (recv_valve, "drop", drop, NULL);


    mimic_codec = fs_codec_new (0, "mimic",
        FS_MEDIA_TYPE_VIDEO, 0);
    fs_stream_emit_src_pad_added (FS_STREAM (self), src_pad, mimic_codec);
    fs_codec_destroy (mimic_codec);
    gst_object_unref (src_pad);

  }
  else
  {
    GstPad *valvepad;

    GST_OBJECT_LOCK (conference);
    if (self->priv->session->valve)
      send_valve = gst_object_ref (self->priv->session->valve);
    GST_OBJECT_UNLOCK (conference);

    if (!send_valve)
    {
      fs_stream_emit_error (FS_STREAM (self), FS_ERROR_DISPOSED,
          "Session was disposed");
      goto error;
    }

    valvepad = gst_element_get_static_pad (send_valve, "src");

    if (!valvepad)
    {
      gst_object_unref (pad);
      fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION,
          "Could not get valve sink pad");
      goto error;
    }

    if (GST_PAD_LINK_FAILED (gst_pad_link (valvepad, pad)))
    {
      gst_object_unref (valvepad);
      gst_object_unref (pad);
      fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION,
          "Could not link valve to codec bin");
      goto error;
    }
    gst_object_unref (valvepad);
    gst_object_unref (pad);
  }

  if (!gst_element_sync_state_with_parent (codecbin))
  {
    fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION,
        "Could not start codec bin");
    goto error;
  }

  if (self->priv->conference->max_direction == FS_DIRECTION_SEND)
  {
    GST_OBJECT_LOCK (conference);
    fs_msn_stream_set_tos_locked (self, self->priv->tos);
    drop = !(self->priv->direction & FS_DIRECTION_SEND);
    GST_OBJECT_UNLOCK (conference);
    g_object_set (send_valve, "drop", drop, NULL);
  }

 error:

  if (send_valve)
    gst_object_unref (send_valve);
  if (recv_valve)
    gst_object_unref (recv_valve);
  if (codecbin)
    gst_object_unref (codecbin);
  if (conference)
    gst_object_unref (conference);
}