static void kms_recorder_endpoint_started (KmsUriEndpoint * obj) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (obj); kms_recorder_endpoint_change_state (self); /* Set internal pipeline to playing */ gst_element_set_state (self->priv->pipeline, GST_STATE_PLAYING); KMS_ELEMENT_LOCK (self); if (GST_CLOCK_TIME_IS_VALID (self->priv->paused_start)) { self->priv->paused_time += gst_clock_get_time (GST_ELEMENT (self->priv->pipeline)->clock) - self->priv->paused_start; self->priv->paused_start = GST_CLOCK_TIME_NONE; } KMS_ELEMENT_UNLOCK (self); /* Open valves */ kms_recorder_endpoint_open_valves (self); kms_recorder_endpoint_state_changed (self, KMS_URI_ENDPOINT_STATE_START); }
static void kms_recorder_endpoint_started (KmsUriEndpoint * obj) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (obj); kms_recorder_endpoint_create_parent_directories (self); kms_recorder_endpoint_change_state (self); /* Set internal pipeline to playing */ kms_base_media_muxer_set_state (self->priv->mux, GST_STATE_PLAYING); BASE_TIME_LOCK (self); if (GST_CLOCK_TIME_IS_VALID (self->priv->paused_start)) { self->priv->paused_time += gst_clock_get_time (kms_base_media_muxer_get_clock (self->priv->mux)) - self->priv->paused_start; self->priv->paused_start = GST_CLOCK_TIME_NONE; } BASE_TIME_UNLOCK (self); kms_recorder_generate_pads (self); kms_recorder_endpoint_state_changed (self, KMS_URI_ENDPOINT_STATE_START); }
static void kms_recorder_endpoint_dispose (GObject * object) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (object); GST_DEBUG_OBJECT (self, "dispose"); g_clear_object (&self->priv->loop); g_clear_object (&self->priv->controller); if (self->priv->pipeline != NULL) { if (GST_STATE (self->priv->pipeline) != GST_STATE_NULL) { GST_ELEMENT_WARNING (self, RESOURCE, BUSY, ("Recorder may have buffers to save"), ("Disposing recorder when it isn't stopped.")); } gst_element_set_state (self->priv->pipeline, GST_STATE_NULL); g_object_unref (self->priv->pipeline); self->priv->pipeline = NULL; } /* clean up as possible. may be called multiple times */ G_OBJECT_CLASS (kms_recorder_endpoint_parent_class)->dispose (object); }
static void kms_recorder_endpoint_paused (KmsUriEndpoint * obj) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (obj); GstClock *clk; kms_recorder_endpoint_change_state (self, KMS_URI_ENDPOINT_STATE_PAUSE); kms_recorder_endpoint_remove_pads (self); KMS_ELEMENT_UNLOCK (self); /* Set internal pipeline to GST_STATE_PAUSED */ kms_base_media_muxer_set_state (self->priv->mux, GST_STATE_PAUSED); KMS_ELEMENT_LOCK (self); clk = kms_base_media_muxer_get_clock (self->priv->mux); if (clk) { self->priv->paused_start = gst_clock_get_time (clk); } kms_recorder_endpoint_state_changed (self, KMS_URI_ENDPOINT_STATE_PAUSE); }
static void kms_recorder_endpoint_audio_valve_added (KmsElement * self, GstElement * valve) { // TODO: This caps should be set using the profile data kms_recorder_endpoint_valve_added (KMS_RECORDER_ENDPOINT (self), valve, AUDIO_APPSINK, AUDIO_APPSRC, "audio_%u"); }
static void sink_required_cb (KmsConfController * controller, gpointer recorder) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (recorder); gulong *probe_id; GstElement *sink; GstPad *sinkpad; sink = kms_recorder_endpoint_get_sink (self); if (sink == NULL) { sink = gst_element_factory_make ("fakesink", NULL); GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, ("No available sink"), (NULL)); return; } g_object_set (self->priv->controller, "sink", sink, NULL); sinkpad = gst_element_get_static_pad (sink, "sink"); if (sinkpad == NULL) { GST_WARNING ("No sink pad available for element %" GST_PTR_FORMAT, sink); return; } probe_id = g_slice_new0 (gulong); *probe_id = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, stop_notification_cb, self, NULL); g_object_set_data_full (G_OBJECT (sinkpad), KEY_RECORDER_PAD_PROBE_ID, probe_id, destroy_ulong); g_object_unref (sinkpad); }
static void kms_recorder_endpoint_on_eos_message (gpointer data) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (data); kms_recorder_endpoint_on_eos (self->priv->mux, 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) { 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 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_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 kms_recorder_endpoint_latency_cb (GstPad * pad, KmsMediaType type, GstClockTimeDiff t, KmsList * mdata, gpointer user_data) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (user_data); KmsListIter iter; gpointer key, value; gchar *name; name = gst_element_get_name (self); kms_list_iter_init (&iter, mdata); while (kms_list_iter_next (&iter, &key, &value)) { gchar *id = (gchar *) key; StreamE2EAvgStat *stat; if (!g_str_has_prefix (id, name)) { /* This element did not add this mark to the metada */ continue; } stat = (StreamE2EAvgStat *) value; stat->avg = KMS_STATS_CALCULATE_LATENCY_AVG (t, stat->avg); } }
static GstCaps * kms_recorder_endpoint_allowed_caps (KmsElement * kmselement, KmsElementPadType type) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (kmselement); GstPad *target_pad; GstCaps *caps; switch (type) { case KMS_ELEMENT_PAD_TYPE_VIDEO: target_pad = self->priv->video_target; break; case KMS_ELEMENT_PAD_TYPE_AUDIO: target_pad = self->priv->audio_target; break; default: return NULL; } if (target_pad == NULL) { return NULL; } caps = gst_pad_get_allowed_caps (target_pad); return caps; }
static GstBusSyncReply bus_sync_signal_handler (GstBus * bus, GstMessage * msg, gpointer data) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (data); if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { ErrorData *data; GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (self), GST_DEBUG_GRAPH_SHOW_ALL, GST_ELEMENT_NAME (self)); kms_base_media_muxer_dot_file (self->priv->mux); GST_ERROR_OBJECT (self, "Message %" GST_PTR_FORMAT, msg); data = create_error_data (self, msg); GST_ERROR_OBJECT (self, "Error: %" GST_PTR_FORMAT, msg); gst_task_pool_push (self->priv->pool, kms_recorder_endpoint_post_error, data, NULL); } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) { gst_task_pool_push (self->priv->pool, kms_recorder_endpoint_on_eos_message, self, NULL); } return GST_BUS_PASS; }
static void kms_recorder_endpoint_dispose (GObject * object) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (object); GST_DEBUG_OBJECT (self, "dispose"); g_clear_object (&self->priv->loop); if (self->priv->mux != NULL) { if (kms_muxing_pipeline_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_muxing_pipeline_set_state (self->priv->mux, GST_STATE_NULL); g_clear_object (&self->priv->mux); } 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 GstStructure * kms_recorder_endpoint_stats (KmsElement * obj, gchar * selector) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (obj); GstStructure *stats, *e_stats, *l_stats; /* chain up */ stats = KMS_ELEMENT_CLASS (kms_recorder_endpoint_parent_class)->stats (obj, selector); if (!self->priv->stats.enabled) { return stats; } e_stats = kms_stats_get_element_stats (stats); if (e_stats == NULL) { return stats; } l_stats = kms_element_get_e2e_latency_stats (self, selector); /* Add end to end latency */ gst_structure_set (e_stats, "e2e-latencies", GST_TYPE_STRUCTURE, l_stats, NULL); gst_structure_free (l_stats); GST_DEBUG_OBJECT (self, "Stats: %" GST_PTR_FORMAT, stats); return stats; }
static void kms_recorder_endpoint_stopped (KmsUriEndpoint * obj) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (obj); kms_recorder_endpoint_change_state (self); if (kms_base_media_muxer_get_state (self->priv->mux) >= GST_STATE_PAUSED) { kms_recorder_endpoint_send_eos_to_appsrcs (self); self->priv->stopping = TRUE; } kms_recorder_endpoint_remove_pads (self); // Reset base time data BASE_TIME_LOCK (self); g_object_set_data_full (G_OBJECT (self), BASE_TIME_DATA, NULL, NULL); self->priv->paused_time = G_GUINT64_CONSTANT (0); self->priv->paused_start = GST_CLOCK_TIME_NONE; BASE_TIME_UNLOCK (self); if (kms_base_media_muxer_get_state (self->priv->mux) < GST_STATE_PAUSED && !self->priv->stopping) { kms_base_media_muxer_set_state (self->priv->mux, GST_STATE_NULL); kms_recorder_endpoint_state_changed (self, KMS_URI_ENDPOINT_STATE_STOP); } }
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_recorder_endpoint_video_valve_added (KmsElement * self, GstElement * valve) { KmsRecorderEndpoint *recorder = KMS_RECORDER_ENDPOINT (self); // TODO: This caps should be set using the profile data kms_recorder_endpoint_valve_added (recorder, valve, VIDEO_APPSINK, VIDEO_APPSRC, "video_%u"); }
static gboolean kms_recorder_endpoint_query_accept_caps (KmsElement * element, GstPad * pad, GstQuery * query) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (element); GstCaps *caps, *accept; GstElement *appsrc; gboolean ret = TRUE; switch (kms_element_get_pad_type (element, pad)) { case KMS_ELEMENT_PAD_TYPE_VIDEO: g_object_get (self->priv->mux, KMS_MUXING_PIPELINE_VIDEO_APPSRC, &appsrc, NULL); caps = kms_recorder_endpoint_get_caps_from_profile (self, KMS_ELEMENT_PAD_TYPE_VIDEO); break; case KMS_ELEMENT_PAD_TYPE_AUDIO: g_object_get (self->priv->mux, KMS_MUXING_PIPELINE_AUDIO_APPSRC, &appsrc, NULL); caps = kms_recorder_endpoint_get_caps_from_profile (self, KMS_ELEMENT_PAD_TYPE_AUDIO); break; default: GST_ERROR_OBJECT (pad, "unknown pad"); return FALSE; } if (caps == NULL) { GST_ERROR_OBJECT (self, "Can not accept caps without profile"); gst_query_set_accept_caps_result (query, FALSE); g_object_unref (appsrc); return TRUE; } gst_query_parse_accept_caps (query, &accept); ret = gst_caps_can_intersect (accept, caps); if (ret) { GstPad *srcpad; srcpad = gst_element_get_static_pad (appsrc, "src"); ret = gst_pad_peer_query_accept_caps (srcpad, accept); gst_object_unref (srcpad); } else { GST_ERROR_OBJECT (self, "Incompatbile caps %" GST_PTR_FORMAT, caps); } gst_caps_unref (caps); g_object_unref (appsrc); gst_query_set_accept_caps_result (query, ret); return TRUE; }
static void kms_recorder_endpoint_finalize (GObject * object) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (object); GST_DEBUG_OBJECT (self, "finalize"); kms_recorder_endpoint_release_pending_requests (self); G_OBJECT_CLASS (kms_recorder_endpoint_parent_class)->finalize (object); }
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 gboolean kms_recorder_endpoint_post_error (gpointer data) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (data); gchar *message = (gchar *) g_object_steal_data (G_OBJECT (self), "message"); GST_ELEMENT_ERROR (self, STREAM, FAILED, ("%s", message), (NULL)); g_free (message); return G_SOURCE_REMOVE; }
static GstBusSyncReply bus_sync_signal_handler (GstBus * bus, GstMessage * msg, gpointer data) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (data); if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { ErrorData *data; GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (self), GST_DEBUG_GRAPH_SHOW_ALL, GST_ELEMENT_NAME (self)); kms_base_media_muxer_dot_file (self->priv->mux); GST_ERROR_OBJECT (self, "Message %" GST_PTR_FORMAT, msg); data = create_error_data (self, msg); GST_ERROR_OBJECT (self, "Error: %" GST_PTR_FORMAT, msg); gst_task_pool_push (self->priv->pool, kms_recorder_endpoint_post_error, data, NULL); } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) { gst_task_pool_push (self->priv->pool, kms_recorder_endpoint_on_eos_message, self, NULL); } else if ((GST_MESSAGE_TYPE (msg) == GST_MESSAGE_STATE_CHANGED) && (GST_OBJECT_CAST (KMS_BASE_MEDIA_MUXER_GET_PIPELINE (self-> priv->mux)) == GST_MESSAGE_SRC (msg))) { GstState new_state, pending; gst_message_parse_state_changed (msg, NULL, &new_state, &pending); if (pending == GST_STATE_VOID_PENDING || (pending == GST_STATE_NULL && new_state == GST_STATE_READY)) { GST_DEBUG_OBJECT (self, "Pipeline changed state to %d", new_state); switch (new_state) { case GST_STATE_PLAYING: kms_recorder_endpoint_state_changed (self, KMS_URI_ENDPOINT_STATE_START); break; case GST_STATE_READY: kms_recorder_endpoint_state_changed (self, KMS_URI_ENDPOINT_STATE_STOP); break; default: GST_DEBUG_OBJECT (self, "Not raising event"); break; } } } return GST_BUS_PASS; }
static GstPadProbeReturn stop_notification_cb (GstPad * srcpad, GstPadProbeInfo * info, gpointer user_data) { KmsRecorderEndpoint *recorder = KMS_RECORDER_ENDPOINT (user_data); if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_DATA (info)) != GST_EVENT_EOS) return GST_PAD_PROBE_OK; kms_loop_idle_add_full (recorder->priv->loop, G_PRIORITY_HIGH_IDLE, set_to_null_state_on_EOS, g_object_ref (recorder), g_object_unref); return GST_PAD_PROBE_OK; }
static void kms_recorder_endpoint_collect_media_stats (KmsElement * obj, gboolean enable) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (obj); KMS_ELEMENT_LOCK (self); self->priv->stats.enabled = enable; kms_recorder_endpoint_update_media_stats (self); KMS_ELEMENT_UNLOCK (self); KMS_ELEMENT_CLASS (kms_recorder_endpoint_parent_class)->collect_media_stats (obj, enable); }
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 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 GstBusSyncReply bus_sync_signal_handler (GstBus * bus, GstMessage * msg, gpointer data) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (data); if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { GError *err = NULL; gst_message_parse_error (msg, &err, NULL); GST_ERROR_OBJECT (self, "Message %" GST_PTR_FORMAT, msg); g_object_set_data_full (G_OBJECT (self), "message", g_strdup (err->message), (GDestroyNotify) g_free); kms_loop_idle_add_full (self->priv->loop, G_PRIORITY_HIGH_IDLE, kms_recorder_endpoint_post_error, g_object_ref (self), g_object_unref); g_error_free (err); } return GST_BUS_PASS; }
static void kms_recorder_endpoint_finalize (GObject * object) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (object); GST_DEBUG_OBJECT (self, "releasing resources..."); kms_recorder_endpoint_release_pending_requests (self); g_slist_free_full (self->priv->sink_probes, (GDestroyNotify) kms_stats_probe_destroy); g_hash_table_unref (self->priv->srcs); g_hash_table_unref (self->priv->sink_pad_data); g_slist_free_full (self->priv->pending_pads, g_free); g_hash_table_unref (self->priv->stats.avg_e2e); GST_DEBUG_OBJECT (self, "finalized"); G_OBJECT_CLASS (kms_recorder_endpoint_parent_class)->finalize (object); }
static void kms_recorder_endpoint_stopped (KmsUriEndpoint * obj) { KmsRecorderEndpoint *self = KMS_RECORDER_ENDPOINT (obj); GstElement *audio_src, *video_src; kms_recorder_endpoint_change_state (self); /* Close valves */ kms_recorder_endpoint_close_valves (self); // Reset base time data audio_src = gst_bin_get_by_name (GST_BIN (self->priv->pipeline), AUDIO_APPSRC); video_src = gst_bin_get_by_name (GST_BIN (self->priv->pipeline), VIDEO_APPSRC); KMS_ELEMENT_LOCK (self); if (audio_src != NULL) { g_object_set_data_full (G_OBJECT (audio_src), BASE_TIME_DATA, NULL, NULL); g_object_unref (audio_src); } if (video_src != NULL) { g_object_set_data_full (G_OBJECT (video_src), BASE_TIME_DATA, NULL, NULL); g_object_unref (video_src); } self->priv->paused_time = G_GUINT64_CONSTANT (0); self->priv->paused_start = GST_CLOCK_TIME_NONE; KMS_ELEMENT_UNLOCK (self); if (GST_STATE (self->priv->pipeline) >= GST_STATE_PAUSED) { kms_recorder_endpoint_send_eos_to_appsrcs (self); } else { gst_element_set_state (self->priv->pipeline, GST_STATE_NULL); kms_recorder_endpoint_state_changed (self, KMS_URI_ENDPOINT_STATE_STOP); } }