static GstBin * kms_agnostic_bin2_create_dec_bin (KmsAgnosticBin2 * self, const GstCaps * raw_caps) { KmsDecTreeBin *dec_bin; GstElement *output_tee, *input_element; GstCaps *caps = self->priv->input_bin_src_caps; if (caps == NULL || raw_caps == NULL) { return NULL; } dec_bin = kms_dec_tree_bin_new (caps, raw_caps); if (dec_bin == NULL) { return NULL; } gst_bin_add (GST_BIN (self), GST_ELEMENT (dec_bin)); gst_element_sync_state_with_parent (GST_ELEMENT (dec_bin)); output_tee = kms_tree_bin_get_output_tee (KMS_TREE_BIN (self->priv->input_bin)); input_element = kms_tree_bin_get_input_element (KMS_TREE_BIN (dec_bin)); link_element_to_tee (output_tee, input_element); return GST_BIN (dec_bin); }
static GstBin * kms_agnostic_bin2_create_bin_for_caps (KmsAgnosticBin2 * self, GstCaps * caps) { GstBin *dec_bin; KmsEncTreeBin *enc_bin; GstElement *input_element, *output_tee; dec_bin = kms_agnostic_bin2_get_or_create_dec_bin (self, caps); if (dec_bin == NULL) { return NULL; } if (is_raw_caps (caps)) { return dec_bin; } enc_bin = kms_enc_tree_bin_new (caps, self->priv->default_bitrate); if (enc_bin == NULL) { return NULL; } gst_bin_add (GST_BIN (self), GST_ELEMENT (enc_bin)); gst_element_sync_state_with_parent (GST_ELEMENT (enc_bin)); output_tee = kms_tree_bin_get_output_tee (KMS_TREE_BIN (dec_bin)); input_element = kms_tree_bin_get_input_element (KMS_TREE_BIN (enc_bin)); link_element_to_tee (output_tee, input_element); kms_agnostic_bin2_insert_bin (self, GST_BIN (enc_bin)); return GST_BIN (enc_bin); }
static GstBin * kms_agnostic_bin2_find_bin_for_caps (KmsAgnosticBin2 * self, GstCaps * caps) { GList *bins, *l; GstBin *bin = NULL; if (gst_caps_is_any (caps) || gst_caps_is_empty (caps)) { return self->priv->input_bin; } if (check_bin (KMS_TREE_BIN (self->priv->input_bin), caps)) { bin = self->priv->input_bin; } bins = g_hash_table_get_values (self->priv->bins); for (l = bins; l != NULL && bin == NULL; l = l->next) { KmsTreeBin *tree_bin = KMS_TREE_BIN (l->data); if (check_bin (tree_bin, caps)) { bin = GST_BIN_CAST (tree_bin); } } g_list_free (bins); return bin; }
static GstBin * kms_agnostic_bin2_create_rtp_pay_bin (KmsAgnosticBin2 * self, GstCaps * caps) { KmsRtpPayTreeBin *bin; GstBin *enc_bin; GstElement *output_tee, *input_element; GstCaps *input_caps; GstPad *sink; bin = kms_rtp_pay_tree_bin_new (caps); if (bin == NULL) { return NULL; } gst_bin_add (GST_BIN (self), GST_ELEMENT (bin)); gst_element_sync_state_with_parent (GST_ELEMENT (bin)); input_element = kms_tree_bin_get_input_element (KMS_TREE_BIN (bin)); sink = gst_element_get_static_pad (input_element, "sink"); input_caps = gst_pad_query_caps (sink, NULL); g_object_unref (sink); enc_bin = kms_agnostic_bin2_find_or_create_bin_for_caps (self, input_caps); kms_agnostic_bin2_insert_bin (self, GST_BIN (bin)); gst_caps_unref (input_caps); output_tee = kms_tree_bin_get_output_tee (KMS_TREE_BIN (enc_bin)); gst_element_link (output_tee, input_element); return GST_BIN (bin); }
/** * Link a pad internally * * @self: The #KmsAgnosticBin2 owner of the pad * @pad: (transfer full): The pad to be linked * @peer: (transfer full): The peer pad */ static void kms_agnostic_bin2_link_pad (KmsAgnosticBin2 * self, GstPad * pad, GstPad * peer) { GstCaps *caps; GstBin *bin; GST_INFO_OBJECT (self, "Linking: %" GST_PTR_FORMAT, pad); caps = gst_pad_query_caps (peer, NULL); if (caps == NULL) { goto end; } GST_DEBUG ("Query caps are: %" GST_PTR_FORMAT, caps); bin = kms_agnostic_bin2_find_bin_for_caps (self, caps); if (bin == NULL) { bin = kms_agnostic_bin2_create_bin_for_caps (self, caps); GST_DEBUG_OBJECT (self, "Created bin: %" GST_PTR_FORMAT, bin); } if (bin != NULL) { GstElement *tee = kms_tree_bin_get_output_tee (KMS_TREE_BIN (bin)); kms_utils_drop_until_keyframe (pad, TRUE); kms_agnostic_bin2_link_to_tee (self, pad, tee, caps); } gst_caps_unref (caps); end: g_object_unref (peer); }
static gboolean kms_rtp_pay_tree_bin_configure (KmsRtpPayTreeBin * self, const GstCaps * caps) { KmsTreeBin *tree_bin = KMS_TREE_BIN (self); GstElement *pay, *output_tee; GstPad *pad; pay = create_payloader_for_caps (caps); if (pay == NULL) { GST_WARNING_OBJECT (self, "Cannot find payloader for caps %" GST_PTR_FORMAT, caps); return FALSE; } GST_DEBUG_OBJECT (self, "Payloader found: %" GST_PTR_FORMAT, pay); pad = gst_element_get_static_pad (pay, "sink"); kms_utils_drop_until_keyframe (pad, TRUE); gst_object_unref (pad); gst_bin_add (GST_BIN (self), pay); gst_element_sync_state_with_parent (pay); kms_tree_bin_set_input_element (tree_bin, pay); output_tee = kms_tree_bin_get_output_tee (tree_bin); gst_element_link (pay, output_tee); return TRUE; }
static GstBin * kms_agnostic_bin2_create_bin_for_caps (KmsAgnosticBin2 * self, GstCaps * caps) { GstBin *dec_bin; KmsEncTreeBin *enc_bin; GstElement *input_element, *output_tee; if (kms_utils_caps_are_rtp (caps)) { return kms_agnostic_bin2_create_rtp_pay_bin (self, caps); } dec_bin = kms_agnostic_bin2_get_or_create_dec_bin (self, caps); if (dec_bin == NULL) { return NULL; } if (kms_utils_caps_are_raw (caps)) { return dec_bin; } enc_bin = kms_enc_tree_bin_new (caps, TARGET_BITRATE_DEFAULT, self->priv->min_bitrate, self->priv->max_bitrate, self->priv->codec_config); if (enc_bin == NULL) { return NULL; } gst_bin_add (GST_BIN (self), GST_ELEMENT (enc_bin)); gst_element_sync_state_with_parent (GST_ELEMENT (enc_bin)); output_tee = kms_tree_bin_get_output_tee (KMS_TREE_BIN (dec_bin)); input_element = kms_tree_bin_get_input_element (KMS_TREE_BIN (enc_bin)); gst_element_link (output_tee, input_element); kms_agnostic_bin2_insert_bin (self, GST_BIN (enc_bin)); return GST_BIN (enc_bin); }
static void kms_agnostic_bin2_configure_input (KmsAgnosticBin2 * self, const GstCaps * caps) { KmsParseTreeBin *parse_bin; GstElement *parser; GstPad *parser_src; GstElement *input_element; KMS_AGNOSTIC_BIN2_LOCK (self); if (self->priv->input_bin != NULL) { kms_tree_bin_unlink_input_element_from_tee (KMS_TREE_BIN (self-> priv->input_bin)); } parse_bin = kms_parse_tree_bin_new (caps); self->priv->input_bin = GST_BIN (parse_bin); parser = kms_parse_tree_bin_get_parser (KMS_PARSE_TREE_BIN (parse_bin)); parser_src = gst_element_get_static_pad (parser, "src"); gst_pad_add_probe (parser_src, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, input_bin_src_caps_probe, g_object_ref (parse_bin), g_object_unref); g_object_unref (parser_src); gst_bin_add (GST_BIN (self), GST_ELEMENT (parse_bin)); gst_element_sync_state_with_parent (GST_ELEMENT (parse_bin)); input_element = kms_tree_bin_get_input_element (KMS_TREE_BIN (parse_bin)); link_element_to_tee (self->priv->input_tee, input_element); self->priv->started = FALSE; GST_DEBUG ("Removing old treebins"); g_hash_table_foreach (self->priv->bins, remove_bin, self); g_hash_table_remove_all (self->priv->bins); KMS_AGNOSTIC_BIN2_UNLOCK (self); }
static gboolean tee_query_function (GstPad * pad, GstObject * parent, GstQuery * query) { if (GST_QUERY_TYPE (query) == GST_QUERY_ACCEPT_CAPS) { GstCaps *caps; KmsTreeBin *self = KMS_TREE_BIN (GST_OBJECT_PARENT (parent)); gst_query_parse_accept_caps (query, &caps); kms_tree_bin_set_input_caps (self, caps); } return gst_pad_query_default (pad, parent, query); }
static void kms_parse_tree_bin_configure (KmsParseTreeBin * self, const GstCaps * caps) { KmsTreeBin *tree_bin = KMS_TREE_BIN (self); GstElement *output_tee; self->priv->parser = create_parser_for_caps (caps); gst_bin_add (GST_BIN (self), self->priv->parser); gst_element_sync_state_with_parent (self->priv->parser); kms_tree_bin_set_input_element (tree_bin, self->priv->parser); output_tee = kms_tree_bin_get_output_tee (tree_bin); gst_element_link_many (self->priv->parser, output_tee, NULL); }
static gboolean tee_event_function (GstPad * pad, GstObject * parent, GstEvent * event) { if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) { GstCaps *caps; KmsTreeBin *self = KMS_TREE_BIN (GST_OBJECT_PARENT (parent)); gst_event_parse_caps (event, &caps); kms_tree_bin_set_input_caps (self, caps); } gst_event_unref (event); /* Return TRUE so that next handler chained can manage this stuff too */ return TRUE; }
static GstBin * kms_agnostic_bin2_find_bin_for_caps (KmsAgnosticBin2 * self, GstCaps * caps) { GList *bins, *l; GstBin *bin = NULL; if (gst_caps_is_any (caps)) { return self->priv->input_bin; } bins = g_hash_table_get_values (self->priv->bins); for (l = bins; l != NULL && bin == NULL; l = l->next) { GstElement *output_tee = kms_tree_bin_get_output_tee (KMS_TREE_BIN (l->data)); GstPad *tee_sink = gst_element_get_static_pad (output_tee, "sink"); GstCaps *current_caps = gst_pad_get_current_caps (tee_sink); if (current_caps == NULL) { current_caps = gst_pad_get_allowed_caps (tee_sink); GST_TRACE_OBJECT (l->data, "Allowed caps are: %" GST_PTR_FORMAT, current_caps); } else { GST_TRACE_OBJECT (l->data, "Current caps are: %" GST_PTR_FORMAT, current_caps); } if (current_caps != NULL) { if (gst_caps_can_intersect (caps, current_caps)) bin = l->data; gst_caps_unref (current_caps); } g_object_unref (tee_sink); } g_list_free (bins); return bin; }
static gboolean kms_enc_tree_bin_configure (KmsEncTreeBin * self, const GstCaps * caps, gint target_bitrate) { KmsTreeBin *tree_bin = KMS_TREE_BIN (self); GstElement *rate, *convert, *mediator, *output_tee, *capsfilter = NULL; self->priv->current_bitrate = target_bitrate; kms_enc_tree_bin_create_encoder_for_caps (self, caps, target_bitrate); if (self->priv->enc == NULL) { GST_WARNING_OBJECT (self, "Invalid encoder for caps: %" GST_PTR_FORMAT, caps); return FALSE; } GST_DEBUG_OBJECT (self, "Encoder found: %" GST_PTR_FORMAT, self->priv->enc); self->priv->enc_sink = gst_element_get_static_pad (self->priv->enc, "sink"); self->priv->remb_manager = kms_utils_remb_event_manager_create (self->priv->enc_sink); kms_utils_remb_event_manager_set_callback (self->priv->remb_manager, bitrate_callback, self, NULL); gst_pad_add_probe (self->priv->enc_sink, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, tag_event_probe, self, NULL); rate = kms_utils_create_rate_for_caps (caps); convert = kms_utils_create_convert_for_caps (caps); mediator = kms_utils_create_mediator_element (caps); gst_bin_add_many (GST_BIN (self), rate, convert, mediator, self->priv->enc, NULL); gst_element_sync_state_with_parent (self->priv->enc); gst_element_sync_state_with_parent (mediator); gst_element_sync_state_with_parent (convert); gst_element_sync_state_with_parent (rate); // FIXME: This is a hack to avoid an error on x264enc that does not work // properly with some raw formats, this should be fixed in gstreamer // but until this is done this hack makes it work if (self->priv->enc_type == X264) { GstCaps *filter_caps = gst_caps_from_string ("video/x-raw,format=I420"); GstPad *sink; capsfilter = gst_element_factory_make ("capsfilter", NULL); sink = gst_element_get_static_pad (capsfilter, "sink"); gst_pad_add_probe (sink, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, check_caps_probe, NULL, NULL); g_object_unref (sink); g_object_set (capsfilter, "caps", filter_caps, NULL); gst_caps_unref (filter_caps); gst_bin_add (GST_BIN (self), capsfilter); gst_element_sync_state_with_parent (capsfilter); } kms_tree_bin_set_input_element (tree_bin, rate); output_tee = kms_tree_bin_get_output_tee (tree_bin); if (self->priv->enc_type == X264) { gst_element_link_many (rate, convert, mediator, capsfilter, self->priv->enc, output_tee, NULL); } else { gst_element_link_many (rate, convert, mediator, self->priv->enc, output_tee, NULL); } return TRUE; }