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