static gboolean gst_deinterleave_src_query (GstPad * pad, GstQuery * query) { GstDeinterleave *self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); gboolean res; res = gst_pad_query_default (pad, query); if (res && GST_QUERY_TYPE (query) == GST_QUERY_DURATION) { GstFormat format; gint64 dur; gst_query_parse_duration (query, &format, &dur); /* Need to divide by the number of channels in byte format * to get the correct value. All other formats should be fine */ if (format == GST_FORMAT_BYTES && dur != -1) gst_query_set_duration (query, format, dur / self->channels); } else if (res && GST_QUERY_TYPE (query) == GST_QUERY_POSITION) { GstFormat format; gint64 pos; gst_query_parse_position (query, &format, &pos); /* Need to divide by the number of channels in byte format * to get the correct value. All other formats should be fine */ if (format == GST_FORMAT_BYTES && pos != -1) gst_query_set_position (query, format, pos / self->channels); } gst_object_unref (self); return res; }
static gboolean gst_deinterleave_sink_activate_push (GstPad * pad, gboolean active) { GstDeinterleave *self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); /* Reset everything when the pad is deactivated */ if (!active) { gst_deinterleave_remove_pads (self); if (self->pos) { g_free (self->pos); self->pos = NULL; } self->channels = 0; self->width = 0; self->func = NULL; if (self->pending_events) { g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref, NULL); g_list_free (self->pending_events); self->pending_events = NULL; } } gst_object_unref (self); return TRUE; }
static void gst_deinterleave_finalize (GObject * obj) { GstDeinterleave *self = GST_DEINTERLEAVE (obj); if (self->pending_events) { g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref, NULL); g_list_free (self->pending_events); self->pending_events = NULL; } G_OBJECT_CLASS (parent_class)->finalize (obj); }
static GstStateChangeReturn gst_deinterleave_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; GstDeinterleave *self = GST_DEINTERLEAVE (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: gst_deinterleave_remove_pads (self); self->func = NULL; if (self->pending_events) { g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref, NULL); g_list_free (self->pending_events); self->pending_events = NULL; } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: gst_deinterleave_remove_pads (self); self->func = NULL; if (self->pending_events) { g_list_foreach (self->pending_events, (GFunc) gst_mini_object_unref, NULL); g_list_free (self->pending_events); self->pending_events = NULL; } break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; }
static void gst_deinterleave_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstDeinterleave *self = GST_DEINTERLEAVE (object); switch (prop_id) { case PROP_KEEP_POSITIONS: g_value_set_boolean (value, self->keep_positions); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_deinterleave_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstDeinterleave *self = GST_DEINTERLEAVE (parent); gboolean res; res = gst_pad_query_default (pad, parent, query); if (res && GST_QUERY_TYPE (query) == GST_QUERY_DURATION) { GstFormat format; gint64 dur; gst_query_parse_duration (query, &format, &dur); /* Need to divide by the number of channels in byte format * to get the correct value. All other formats should be fine */ if (format == GST_FORMAT_BYTES && dur != -1) gst_query_set_duration (query, format, dur / GST_AUDIO_INFO_CHANNELS (&self->audio_info)); } else if (res && GST_QUERY_TYPE (query) == GST_QUERY_POSITION) { GstFormat format; gint64 pos; gst_query_parse_position (query, &format, &pos); /* Need to divide by the number of channels in byte format * to get the correct value. All other formats should be fine */ if (format == GST_FORMAT_BYTES && pos != -1) gst_query_set_position (query, format, pos / GST_AUDIO_INFO_CHANNELS (&self->audio_info)); } else if (res && GST_QUERY_TYPE (query) == GST_QUERY_CAPS) { GstCaps *filter, *caps; gst_query_parse_caps (query, &filter); caps = gst_deinterleave_sink_getcaps (pad, parent, filter); gst_query_set_caps_result (query, caps); gst_caps_unref (caps); } return res; }
static GstFlowReturn gst_deinterleave_chain (GstPad * pad, GstBuffer * buffer) { GstDeinterleave *self = GST_DEINTERLEAVE (GST_PAD_PARENT (pad)); GstFlowReturn ret; g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED); ret = gst_deinterleave_process (self, buffer); if (ret != GST_FLOW_OK) GST_DEBUG_OBJECT (self, "flow return: %s", gst_flow_get_name (ret)); return ret; }
static gboolean gst_deinterleave_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstDeinterleave *self = GST_DEINTERLEAVE (parent); gboolean ret; GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (pad)); /* Send FLUSH_STOP, FLUSH_START and EOS immediately, no matter if * we have src pads already or not. Queue all other events and * push them after we have src pads */ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: case GST_EVENT_FLUSH_START: case GST_EVENT_EOS: ret = gst_pad_event_default (pad, parent, event); break; case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); ret = gst_deinterleave_sink_setcaps (self, caps); gst_event_unref (event); break; } default: if (!self->srcpads && !GST_EVENT_IS_STICKY (event)) { /* Sticky events are copied when creating a new pad */ GST_OBJECT_LOCK (self); self->pending_events = g_list_append (self->pending_events, event); GST_OBJECT_UNLOCK (self); ret = TRUE; } else { ret = gst_pad_event_default (pad, parent, event); } break; } return ret; }
static GstFlowReturn gst_deinterleave_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstDeinterleave *self = GST_DEINTERLEAVE (parent); GstFlowReturn ret; g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (GST_AUDIO_INFO_WIDTH (&self->audio_info) > 0, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (GST_AUDIO_INFO_CHANNELS (&self->audio_info) > 0, GST_FLOW_NOT_NEGOTIATED); ret = gst_deinterleave_process (self, buffer); if (ret != GST_FLOW_OK) GST_DEBUG_OBJECT (self, "flow return: %s", gst_flow_get_name (ret)); return ret; }
static gboolean gst_deinterleave_sink_event (GstPad * pad, GstEvent * event) { GstDeinterleave *self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); gboolean ret; GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (pad)); /* Send FLUSH_STOP, FLUSH_START and EOS immediately, no matter if * we have src pads already or not. Queue all other events and * push them after we have src pads */ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: case GST_EVENT_FLUSH_START: case GST_EVENT_EOS: ret = gst_pad_event_default (pad, event); break; default: if (self->srcpads) { ret = gst_pad_event_default (pad, event); } else { GST_OBJECT_LOCK (self); self->pending_events = g_list_append (self->pending_events, event); GST_OBJECT_UNLOCK (self); ret = TRUE; } break; } gst_object_unref (self); return ret; }
static GstCaps * gst_deinterleave_sink_getcaps (GstPad * pad) { GstDeinterleave *self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); GstCaps *ret; GList *l; GST_OBJECT_LOCK (self); /* Intersect all of our pad template caps with the peer caps of the pad * to get all formats that are possible up- and downstream. * * For the pad for which the caps are requested we don't remove the channel * informations as they must be in the returned caps and incompatibilities * will be detected here already */ ret = gst_caps_new_any (); for (l = GST_ELEMENT (self)->pads; l != NULL; l = l->next) { GstPad *ourpad = GST_PAD (l->data); GstCaps *peercaps = NULL, *ourcaps; ourcaps = gst_caps_copy (gst_pad_get_pad_template_caps (ourpad)); if (pad == ourpad) { if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) __set_channels (ourcaps, self->channels); else __set_channels (ourcaps, 1); } else { __remove_channels (ourcaps); /* Only ask for peer caps for other pads than pad * as otherwise gst_pad_peer_get_caps() might call * back into this function and deadlock */ peercaps = gst_pad_peer_get_caps (ourpad); } /* If the peer exists and has caps add them to the intersection, * otherwise assume that the peer accepts everything */ if (peercaps) { GstCaps *intersection; GstCaps *oldret = ret; __remove_channels (peercaps); intersection = gst_caps_intersect (peercaps, ourcaps); ret = gst_caps_intersect (ret, intersection); gst_caps_unref (intersection); gst_caps_unref (peercaps); gst_caps_unref (oldret); } else { GstCaps *oldret = ret; ret = gst_caps_intersect (ret, ourcaps); gst_caps_unref (oldret); } gst_caps_unref (ourcaps); } GST_OBJECT_UNLOCK (self); gst_object_unref (self); GST_DEBUG_OBJECT (pad, "Intersected caps to %" GST_PTR_FORMAT, ret); return ret; }
static gboolean gst_deinterleave_sink_setcaps (GstPad * pad, GstCaps * caps) { GstDeinterleave *self; GstCaps *srccaps; GstStructure *s; self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps); if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) { gint new_channels, i; GstAudioChannelPosition *pos; gboolean same_layout = TRUE; s = gst_caps_get_structure (caps, 0); /* We allow caps changes as long as the number of channels doesn't change * and the channel positions stay the same. _getcaps() should've cared * for this already but better be safe. */ if (!gst_structure_get_int (s, "channels", &new_channels) || new_channels != self->channels || !gst_deinterleave_set_process_function (self, caps)) goto cannot_change_caps; /* Now check the channel positions. If we had no channel positions * and get them or the other way around things have changed. * If we had channel positions and get different ones things have * changed too of course */ pos = gst_audio_get_channel_positions (s); if ((pos && !self->pos) || (!pos && self->pos)) goto cannot_change_caps; if (pos) { for (i = 0; i < self->channels; i++) { if (self->pos[i] != pos[i]) { same_layout = FALSE; break; } } g_free (pos); if (!same_layout) goto cannot_change_caps; } } else { s = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (s, "channels", &self->channels)) goto no_channels; if (!gst_deinterleave_set_process_function (self, caps)) goto unsupported_caps; self->pos = gst_audio_get_channel_positions (s); } gst_caps_replace (&self->sinkcaps, caps); /* Get srcpad caps */ srccaps = gst_caps_copy (caps); s = gst_caps_get_structure (srccaps, 0); gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL); gst_structure_remove_field (s, "channel-positions"); /* If we already have pads, update the caps otherwise * add new pads */ if (self->srcpads) { gst_deinterleave_set_pads_caps (self, srccaps); } else { gst_deinterleave_add_new_pads (self, srccaps); } gst_caps_unref (srccaps); gst_object_unref (self); return TRUE; cannot_change_caps: { GST_ERROR_OBJECT (self, "can't set new caps: %" GST_PTR_FORMAT, caps); gst_object_unref (self); return FALSE; } unsupported_caps: { GST_ERROR_OBJECT (self, "caps not supported: %" GST_PTR_FORMAT, caps); gst_object_unref (self); return FALSE; } no_channels: { GST_ERROR_OBJECT (self, "invalid caps"); gst_object_unref (self); return FALSE; } }