static void kms_recorder_endpoint_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (object); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); switch (property_id) { case PROP_DVR: self->priv->use_dvr = g_value_get_boolean (value); break; case PROP_PROFILE:{ if (self->priv->profile == KMS_RECORDING_PROFILE_NONE) { self->priv->profile = g_value_get_enum (value); if (self->priv->profile != KMS_RECORDING_PROFILE_NONE) { kms_recorder_endpoint_new_media_muxer (self); } } else { GST_ERROR_OBJECT (self, "Profile can only be configured once"); } break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); }
static gboolean kms_dummy_sink_release_requested_sink_pad (KmsElement * obj, GstPad * pad) { KmsDummySink *self = KMS_DUMMY_SINK (obj); KmsDummySinkElement *dummy; gchar *padname; padname = gst_pad_get_name (pad); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); dummy = g_hash_table_lookup (self->priv->sinks, padname); if (dummy == NULL) { KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); return FALSE; } kms_element_remove_sink_by_type_full (obj, dummy->type, dummy->description); g_hash_table_remove (self->priv->sinks, padname); g_free (padname); return TRUE; }
static void kms_element_release_pad (GstElement * element, GstPad * pad) { GstElement *agnosticbin; GstPad *target; if (g_str_has_prefix (GST_OBJECT_NAME (pad), "audio_src")) { agnosticbin = KMS_ELEMENT (element)->priv->audio_agnosticbin; } else if (g_str_has_prefix (GST_OBJECT_NAME (pad), "video_src")) { agnosticbin = KMS_ELEMENT (element)->priv->video_agnosticbin; } else { return; } // TODO: Remove pad if is a sinkpad target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); if (target != NULL && agnosticbin != NULL) gst_element_release_request_pad (agnosticbin, target); if (GST_STATE (element) >= GST_STATE_PAUSED || GST_STATE_PENDING (element) >= GST_STATE_PAUSED) gst_pad_set_active (pad, FALSE); gst_element_remove_pad (element, pad); }
static void kms_recorder_endpoint_dispose (GObject * object) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (object); GST_DEBUG_OBJECT (self, "dispose"); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); if (self->priv->mux != NULL) { if (kms_base_media_muxer_get_state (self->priv->mux) != GST_STATE_NULL) { GST_ELEMENT_WARNING (self, RESOURCE, BUSY, ("Recorder may have buffers to save"), ("Disposing recorder when it isn't stopped.")); } kms_base_media_muxer_set_state (self->priv->mux, GST_STATE_NULL); if (self->priv->stopping) { GST_WARNING_OBJECT (self, "Forcing pending stop operation to finish"); kms_recorder_endpoint_state_changed (self, KMS_URI_ENDPOINT_STATE_STOP); self->priv->stopping = FALSE; } } KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); g_mutex_clear (&self->priv->base_time_lock); /* clean up as possible. may be called multiple times */ G_OBJECT_CLASS (kms_recorder_endpoint_parent_class)->dispose (object); }
static void unlink_sinkpad_cb (GstPad * pad, GstPad * peer, gpointer user_data) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (user_data); gchar *id = NULL; KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); id = gst_pad_get_name (pad); if (self->priv->stopping) { GST_DEBUG_OBJECT (self, "Stop operation is pending"); self->priv->pending_pads = g_slist_prepend (self->priv->pending_pads, g_strdup (id)); goto end; } if (kms_base_media_muxer_remove_src (self->priv->mux, id)) { g_hash_table_remove (self->priv->srcs, id); } end: KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); g_free (id); }
static void kms_recorder_endpoint_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (object); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); switch (property_id) { case PROP_DVR: g_value_set_boolean (value, self->priv->use_dvr); break; case PROP_PROFILE:{ KmsRecordingProfile profile; g_object_get (G_OBJECT (self->priv->controller), "profile", &profile, NULL); g_value_set_enum (value, profile); break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); }
static void kms_dummy_sink_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { KmsDummySink *self = KMS_DUMMY_SINK (object); gboolean val; KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); switch (property_id) { case PROP_DATA: val = g_value_get_boolean (value); if (val && !self->priv->data) { kms_dummy_sink_add_sinkpad (self, KMS_ELEMENT_PAD_TYPE_DATA); } else if (!val && self->priv->data) { kms_element_remove_sink_by_type (KMS_ELEMENT (self), KMS_ELEMENT_PAD_TYPE_DATA); } else { GST_DEBUG_OBJECT (self, "Operation without effect"); } self->priv->data = val; break; case PROP_AUDIO: val = g_value_get_boolean (value); if (val && !self->priv->audio) { kms_dummy_sink_add_sinkpad (self, KMS_ELEMENT_PAD_TYPE_AUDIO); } else if (!val && self->priv->audio) { kms_element_remove_sink_by_type (KMS_ELEMENT (self), KMS_ELEMENT_PAD_TYPE_AUDIO); } else { GST_DEBUG_OBJECT (self, "Operation without effect"); } self->priv->audio = val; break; case PROP_VIDEO: val = g_value_get_boolean (value); if (val && !self->priv->video) { kms_dummy_sink_add_sinkpad (self, KMS_ELEMENT_PAD_TYPE_VIDEO); } else if (!val && self->priv->video) { kms_element_remove_sink_by_type (KMS_ELEMENT (self), KMS_ELEMENT_PAD_TYPE_VIDEO); } else { GST_DEBUG_OBJECT (self, "Operation without effect"); } self->priv->video = val; break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); }
static void kms_recorder_endpoint_state_changed (KmsRecorderEndpoint * self, KmsUriEndpointState state) { KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); if (!self->priv->stopping || state == KMS_URI_ENDPOINT_STATE_STOP) { KMS_URI_ENDPOINT_GET_CLASS (self)->change_state (KMS_URI_ENDPOINT (self), state); } KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); }
static void kms_recorder_endpoint_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (object); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); switch (property_id) { case PROP_DVR: self->priv->use_dvr = g_value_get_boolean (value); break; case PROP_PROFILE:{ if (self->priv->profile == KMS_RECORDING_PROFILE_NONE) { self->priv->profile = g_value_get_enum (value); if (self->priv->profile != KMS_RECORDING_PROFILE_NONE) { GstElement *sink; GstBus *bus; sink = kms_recorder_endpoint_create_sink (self); self->priv->mux = kms_muxing_pipeline_new (KMS_MUXING_PIPELINE_PROFILE, self->priv->profile, KMS_MUXING_PIPELINE_SINK, sink, NULL); g_object_unref (sink); bus = kms_muxing_pipeline_get_bus (self->priv->mux); gst_bus_set_sync_handler (bus, bus_sync_signal_handler, self, NULL); g_object_unref (bus); if (kms_recording_profile_supports_type (self->priv->profile, KMS_ELEMENT_PAD_TYPE_AUDIO)) { kms_recorder_endpoint_add_appsink (self, KMS_ELEMENT_PAD_TYPE_AUDIO); } if (kms_recording_profile_supports_type (self->priv->profile, KMS_ELEMENT_PAD_TYPE_VIDEO)) { kms_recorder_endpoint_add_appsink (self, KMS_ELEMENT_PAD_TYPE_VIDEO); } } } else { GST_ERROR_OBJECT (self, "Profile can only be configured once"); } break; } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); }
static void kms_recorder_end_point_close_valves (KmsRecorderEndPoint * self) { GstElement *valve; valve = kms_element_get_audio_valve (KMS_ELEMENT (self)); if (valve != NULL) kms_utils_set_valve_drop (valve, TRUE); valve = kms_element_get_video_valve (KMS_ELEMENT (self)); if (valve != NULL) kms_utils_set_valve_drop (valve, TRUE); }
static GstPad * kms_hub_port_request_new_pad (GstElement * element, GstPadTemplate * templ, const gchar * name, const GstCaps * caps) { GstElement *output = NULL; if (templ == gst_element_class_get_pad_template (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)), HUB_AUDIO_SINK_PAD)) { if (g_strcmp0 (name, HUB_AUDIO_SINK_PAD) != 0) { GST_ERROR_OBJECT (element, "Invalid pad name %s for template %" GST_PTR_FORMAT, name, templ); return NULL; } output = kms_element_get_audio_agnosticbin (KMS_ELEMENT (element)); } else if (templ == gst_element_class_get_pad_template (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)), HUB_VIDEO_SINK_PAD)) { if (g_strcmp0 (name, HUB_VIDEO_SINK_PAD) != 0) { GST_ERROR_OBJECT (element, "Invalid pad name %s for template %" GST_PTR_FORMAT, name, templ); return NULL; } output = kms_element_get_video_agnosticbin (KMS_ELEMENT (element)); } else if (templ == gst_element_class_get_pad_template (GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)), HUB_DATA_SINK_PAD)) { if (g_strcmp0 (name, HUB_DATA_SINK_PAD) != 0) { GST_ERROR_OBJECT (element, "Invalid pad name %s for template %" GST_PTR_FORMAT, name, templ); return NULL; } output = kms_element_get_data_tee (KMS_ELEMENT (element)); } if (output == NULL) { GST_WARNING_OBJECT (element, "No agnosticbin got for template %" GST_PTR_FORMAT, templ); return NULL; } else { return kms_hub_port_generate_sink_pad (element, templ, name, caps, output); } }
static void kms_show_data_init (KmsShowData *self) { self->priv = KMS_SHOW_DATA_GET_PRIVATE (self); self->priv->text_overlay = gst_element_factory_make ("textoverlay", NULL); g_object_set (self->priv->text_overlay, "font-desc", "Sans 26", NULL); gst_bin_add (GST_BIN (self), self->priv->text_overlay); kms_show_data_connect_video (self, kms_element_get_video_agnosticbin (KMS_ELEMENT (self))); kms_show_data_connect_audio (self, kms_element_get_audio_agnosticbin (KMS_ELEMENT (self))); kms_show_data_connect_data (self, kms_element_get_data_tee (KMS_ELEMENT (self))); gst_element_sync_state_with_parent (self->priv->text_overlay); }
static void kms_hub_port_init (KmsHubPort * self) { KmsElement *kmselement; GstPadTemplate *templ; self->priv = KMS_HUB_PORT_GET_PRIVATE (self); kmselement = KMS_ELEMENT (self); templ = gst_static_pad_template_get (&hub_video_src_factory); kms_hub_port_start_media_type (kmselement, KMS_ELEMENT_PAD_TYPE_VIDEO, templ, HUB_VIDEO_SRC_PAD); g_object_unref (templ); templ = gst_static_pad_template_get (&hub_audio_src_factory); kms_hub_port_start_media_type (kmselement, KMS_ELEMENT_PAD_TYPE_AUDIO, templ, HUB_AUDIO_SRC_PAD); g_object_unref (templ); templ = gst_static_pad_template_get (&hub_data_src_factory); kms_hub_port_start_media_type (kmselement, KMS_ELEMENT_PAD_TYPE_DATA, templ, HUB_DATA_SRC_PAD); g_object_unref (templ); }
static void kms_hub_port_internal_src_pad_linked (GstPad * pad, GstPad * peer, gpointer data) { GstPad *target, *new_pad; GstElement *capsfilter; KmsElement *self; KmsElementPadType type; capsfilter = g_object_get_qdata (G_OBJECT (pad), key_elem_data_quark ()); g_return_if_fail (capsfilter); self = KMS_ELEMENT (gst_object_get_parent (GST_OBJECT (capsfilter))); g_return_if_fail (self); target = gst_element_get_static_pad (capsfilter, "sink"); if (!target) { GST_WARNING_OBJECT (pad, "No sink in capsfilter"); goto end; } type = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (pad), key_type_data_quark ())); new_pad = kms_element_connect_sink_target (self, target, type); g_object_unref (target); g_object_set_qdata_full (G_OBJECT (pad), key_pad_data_quark (), g_object_ref (new_pad), g_object_unref); end: g_object_unref (self); }
static void kms_recorder_endpoint_send_eos_to_appsrcs (KmsRecorderEndpoint * self) { if (g_hash_table_size (self->priv->srcs) == 0) { KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); kms_base_media_muxer_set_state (self->priv->mux, GST_STATE_NULL); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); return; } KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); kms_base_media_muxer_set_state (self->priv->mux, GST_STATE_PLAYING); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); g_hash_table_foreach (self->priv->srcs, (GHFunc) send_eos_cb, NULL); }
static void kms_element_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) { KmsElement *self = KMS_ELEMENT (object); switch (property_id) { case PROP_ACCEPT_EOS: KMS_ELEMENT_LOCK (self); g_value_set_boolean (value, self->priv->accept_eos); KMS_ELEMENT_UNLOCK (self); break; case PROP_AUDIO_CAPS: g_value_take_boxed (value, kms_element_endpoint_get_caps (self, self->priv->audio_caps)); break; case PROP_VIDEO_CAPS: g_value_take_boxed (value, kms_element_endpoint_get_caps (self, self->priv->video_caps)); break; case PROP_TARGET_BITRATE: KMS_ELEMENT_LOCK (self); g_value_set_int (value, self->priv->target_bitrate); KMS_ELEMENT_UNLOCK (self); break; case PROP_MEDIA_STATS: KMS_ELEMENT_LOCK (self); g_value_set_boolean (value, self->priv->stats_enabled); KMS_ELEMENT_UNLOCK (self); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static void kms_recorder_endpoint_state_changed (KmsRecorderEndpoint * self, KmsUriEndpointState state) { KMS_URI_ENDPOINT_GET_CLASS (self)->change_state (KMS_URI_ENDPOINT (self), state); KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); g_mutex_lock (&self->priv->state_manager.mutex); self->priv->state_manager.changing = FALSE; if (self->priv->state_manager.locked > 0) g_cond_broadcast (&self->priv->state_manager.cond); g_mutex_unlock (&self->priv->state_manager.mutex); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); }
static GstPadProbeReturn accept_eos_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data) { GstEvent *event = gst_pad_probe_info_get_event (info); GstEventType type = GST_EVENT_TYPE (event); if (type == GST_EVENT_EOS || type == GST_EVENT_FLUSH_START || type == GST_EVENT_FLUSH_STOP) { KmsElement *self; gboolean accept; self = KMS_ELEMENT (data); KMS_ELEMENT_LOCK (self); accept = self->priv->accept_eos; KMS_ELEMENT_UNLOCK (self); if (!accept) { GST_DEBUG_OBJECT (pad, "Event %s dropped", gst_event_type_get_name (type)); } return (accept) ? GST_PAD_PROBE_OK : GST_PAD_PROBE_DROP; } return GST_PAD_PROBE_OK; }
static void remove_sink_func (const gchar * key, KmsSinkPadData * data, KmsRecorderEndpoint * self) { kms_element_remove_sink_by_type_full (KMS_ELEMENT (self), data->type, data->description); }
static void kms_http_post_endpoint_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) { KmsHttpPostEndpoint *self = KMS_HTTP_POST_ENDPOINT (object); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); switch (property_id) { case PROP_USE_ENCODED_MEDIA: g_value_set_boolean (value, self->priv->use_encoded_media); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); }
static void kms_recorder_end_point_open_valves (KmsRecorderEndPoint * self) { GstElement *valve; valve = kms_element_get_audio_valve (KMS_ELEMENT (self)); if (valve != NULL) { kms_utils_set_valve_drop (valve, FALSE); kms_recorder_end_point_send_force_key_unit_event (valve); } valve = kms_element_get_video_valve (KMS_ELEMENT (self)); if (valve != NULL) { kms_utils_set_valve_drop (valve, FALSE); kms_recorder_end_point_send_force_key_unit_event (valve); } }
static gboolean set_to_null_state_on_EOS (gpointer data) { KmsRecorderEndpoint *recorder = KMS_RECORDER_ENDPOINT (data); GST_DEBUG ("Received EOS in pipeline, setting NULL state"); KMS_ELEMENT_LOCK (KMS_ELEMENT (recorder)); kms_muxing_pipeline_set_state (recorder->priv->mux, GST_STATE_NULL); kms_recorder_endpoint_state_changed (recorder, KMS_URI_ENDPOINT_STATE_STOP); KMS_ELEMENT_UNLOCK (KMS_ELEMENT (recorder)); return G_SOURCE_REMOVE; }
static void kms_recorder_endpoint_remove_pads (KmsRecorderEndpoint * self) { KmsElement *elem = KMS_ELEMENT (self); kms_element_remove_sink_by_type (elem, KMS_ELEMENT_PAD_TYPE_AUDIO); kms_element_remove_sink_by_type (elem, KMS_ELEMENT_PAD_TYPE_VIDEO); }
static void kms_show_data_connect_audio (KmsShowData * self, GstElement * agnosticbin) { GstPad *target = gst_element_get_static_pad (agnosticbin, "sink"); kms_element_connect_sink_target (KMS_ELEMENT (self), target, KMS_ELEMENT_PAD_TYPE_AUDIO); g_object_unref (target); }
static void kms_filter_element_connect_passthrough (KmsFilterElement * self, KmsElementPadType type, GstElement * element) { GstPad *target = gst_element_get_static_pad (element, "sink"); kms_element_connect_sink_target (KMS_ELEMENT (self), target, type); g_object_unref (target); }
static void kms_recorder_endpoint_send_eos_to_appsrcs (KmsRecorderEndpoint * self) { KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); if (g_hash_table_size (self->priv->srcs) == 0) { kms_base_media_muxer_set_state (self->priv->mux, GST_STATE_NULL); kms_recorder_endpoint_state_changed (self, KMS_URI_ENDPOINT_STATE_STOP); goto end; } kms_base_media_muxer_set_state (self->priv->mux, GST_STATE_PLAYING); g_hash_table_foreach (self->priv->srcs, (GHFunc) send_eos_cb, NULL); end: KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); }
static void kms_recorder_endpoint_change_state (KmsRecorderEndpoint * self) { KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); g_mutex_lock (&self->priv->state_manager.mutex); while (self->priv->state_manager.changing) { GST_WARNING ("Change of state is taking place"); self->priv->state_manager.locked++; g_cond_wait (&self->priv->state_manager.cond, &self->priv->state_manager.mutex); self->priv->state_manager.locked--; } self->priv->state_manager.changing = TRUE; g_mutex_unlock (&self->priv->state_manager.mutex); KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); }
static void kms_element_release_pad (GstElement * element, GstPad * pad) { GstElement *agnosticbin; GstPad *target; GstPad *peer; if (g_str_has_prefix (GST_OBJECT_NAME (pad), "audio_src")) { agnosticbin = KMS_ELEMENT (element)->priv->audio_agnosticbin; } else if (g_str_has_prefix (GST_OBJECT_NAME (pad), "video_src")) { agnosticbin = KMS_ELEMENT (element)->priv->video_agnosticbin; } else { return; } // TODO: Remove pad if is a sinkpad target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); if (target != NULL) { if (agnosticbin != NULL) { gst_element_release_request_pad (agnosticbin, target); } g_object_unref (target); } peer = gst_pad_get_peer (pad); gst_pad_push_event (pad, gst_event_new_flush_start ()); if (GST_STATE (element) >= GST_STATE_PAUSED || GST_STATE_PENDING (element) >= GST_STATE_PAUSED) { gst_pad_set_active (pad, FALSE); } if (peer) { gst_pad_send_event (peer, gst_event_new_flush_stop (FALSE)); g_object_unref (peer); } gst_element_remove_pad (element, pad); }
static gboolean kms_recorder_endpoint_release_requested_sink_pad (KmsElement * obj, GstPad * pad) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (obj); gchar *padname = NULL; KmsSinkPadData *data; gboolean ret = FALSE; KMS_ELEMENT_LOCK (KMS_ELEMENT (self)); ret = self->priv->profile == KMS_RECORDING_PROFILE_KSR; if (!ret) { goto end; } padname = gst_pad_get_name (pad); data = g_hash_table_lookup (self->priv->sink_pad_data, padname); if (data == NULL) { GST_ERROR_OBJECT (self, "Can not release requested pad %s", padname); goto end; } if (!data->requested) { GST_ERROR_OBJECT (self, "Can not release not requested pad %" GST_PTR_FORMAT, pad); goto end; } kms_element_remove_sink_by_type_full (KMS_ELEMENT (self), data->type, data->description); g_hash_table_remove (self->priv->sink_pad_data, padname); end: KMS_ELEMENT_UNLOCK (KMS_ELEMENT (self)); g_free (padname); return ret; }
static gboolean kms_element_pad_query (GstPad * pad, GstObject * parent, GstQuery * query) { KmsElementClass *klass; KmsElement *element; element = KMS_ELEMENT (parent); klass = KMS_ELEMENT_GET_CLASS (element); return klass->sink_query (element, pad, query); }