static gboolean gst_play_sink_convert_bin_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstPlaySinkConvertBin *self = GST_PLAY_SINK_CONVERT_BIN (parent); gboolean ret; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); ret = gst_play_sink_convert_bin_sink_setcaps (self, caps); break; } default: break; } ret = gst_pad_event_default (pad, parent, gst_event_ref (event)); gst_event_unref (event); return ret; }
static gboolean gst_play_sink_video_convert_add_conversion_elements (GstPlaySinkVideoConvert * self) { GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self); GstElement *el, *prev = NULL; el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, COLORSPACE, "conv"); if (el) prev = el; el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, "videoscale", "scale"); if (el) { /* Add black borders if necessary to keep the DAR */ g_object_set (el, "add-borders", TRUE, NULL); if (prev) { if (!gst_element_link_pads_full (prev, "src", el, "sink", GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) goto link_failed; } prev = el; } return TRUE; link_failed: return FALSE; }
static void gst_play_sink_video_convert_init (GstPlaySinkVideoConvert * self) { GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self); cbin->audio = FALSE; gst_play_sink_video_convert_add_conversion_elements (self); gst_play_sink_convert_bin_cache_converter_caps (cbin); }
static gboolean gst_play_sink_audio_convert_add_conversion_elements (GstPlaySinkAudioConvert * self) { GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self); GstElement *el, *prev = NULL; g_assert (cbin->conversion_elements == NULL); GST_DEBUG_OBJECT (self, "Building audio conversion with use-converters %d, use-volume %d", self->use_converters, self->use_volume); if (self->use_converters) { el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, "audioconvert", "conv"); if (el) { prev = el; } el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, "audioresample", "resample"); if (el) { if (prev) { if (!gst_element_link_pads_full (prev, "src", el, "sink", GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) goto link_failed; } prev = el; } } if (self->use_volume && self->volume) { el = self->volume; gst_play_sink_convert_bin_add_conversion_element (cbin, el); if (prev) { if (!gst_element_link_pads_full (prev, "src", el, "sink", GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) goto link_failed; } prev = el; } return TRUE; link_failed: return FALSE; }
static gboolean gst_play_sink_convert_bin_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstPlaySinkConvertBin *self = GST_PLAY_SINK_CONVERT_BIN (parent); gboolean ret; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); ret = gst_play_sink_convert_bin_sink_setcaps (self, caps); break; } default: break; } ret = gst_pad_event_default (pad, parent, gst_event_ref (event)); if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { GstSegment seg; GST_PLAY_SINK_CONVERT_BIN_LOCK (self); gst_event_copy_segment (event, &seg); GST_DEBUG_OBJECT (self, "Segment before %" GST_SEGMENT_FORMAT, &self->segment); self->segment = seg; GST_DEBUG_OBJECT (self, "Segment after %" GST_SEGMENT_FORMAT, &self->segment); GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) { GST_PLAY_SINK_CONVERT_BIN_LOCK (self); GST_DEBUG_OBJECT (self, "Resetting segment"); gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED); GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); } gst_event_unref (event); return ret; }
static void gst_play_sink_audio_convert_init (GstPlaySinkAudioConvert * self) { GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self); cbin->audio = TRUE; /* FIXME: Only create this on demand but for now we need * it to always exist because of playsink's volume proxying * logic. */ self->volume = gst_element_factory_make ("volume", "volume"); if (self->volume) gst_object_ref_sink (self->volume); gst_play_sink_audio_convert_add_conversion_elements (self); gst_play_sink_convert_bin_cache_converter_caps (cbin); }
static GstCaps * gst_play_sink_convert_bin_getcaps (GstPad * pad, GstCaps * filter) { GstPlaySinkConvertBin *self = GST_PLAY_SINK_CONVERT_BIN (gst_pad_get_parent (pad)); GstCaps *ret; GstPad *otherpad, *peer; GST_PLAY_SINK_CONVERT_BIN_LOCK (self); if (pad == self->srcpad) { otherpad = self->sinkpad; } else if (pad == self->sinkpad) { otherpad = self->srcpad; } else { GST_ERROR_OBJECT (pad, "Not one of our pads"); otherpad = NULL; } if (otherpad) { peer = gst_pad_get_peer (otherpad); if (peer) { GstCaps *peer_caps = gst_pad_query_caps (peer, filter); gst_object_unref (peer); if (self->converter_caps && is_raw_caps (peer_caps, self->audio)) { ret = gst_caps_merge (peer_caps, gst_caps_ref (self->converter_caps)); } else { ret = peer_caps; } } else { ret = gst_caps_ref (self->converter_caps); } } else { ret = gst_caps_new_any (); } GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); gst_object_unref (self); GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret); return ret; }
static void gst_play_sink_audio_convert_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstPlaySinkAudioConvert *self = GST_PLAY_SINK_AUDIO_CONVERT_CAST (object); gboolean v, changed = FALSE; GST_PLAY_SINK_CONVERT_BIN_LOCK (self); switch (prop_id) { case PROP_USE_CONVERTERS: v = g_value_get_boolean (value); if (v != self->use_converters) { self->use_converters = v; changed = TRUE; } break; case PROP_USE_VOLUME: v = g_value_get_boolean (value); if (v != self->use_volume) { self->use_volume = v; changed = TRUE; } break; default: break; } if (changed) { GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self); GST_DEBUG_OBJECT (self, "Rebuilding converter bin"); gst_play_sink_convert_bin_remove_elements (cbin); gst_play_sink_audio_convert_add_conversion_elements (self); gst_play_sink_convert_bin_add_identity (cbin); gst_play_sink_convert_bin_cache_converter_caps (cbin); } GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); }
static GstCaps * gst_play_sink_convert_bin_getcaps (GstPad * pad, GstCaps * filter) { GstPlaySinkConvertBin *self = GST_PLAY_SINK_CONVERT_BIN (gst_pad_get_parent (pad)); GstCaps *ret; GstPad *otherpad, *peer; GST_PLAY_SINK_CONVERT_BIN_LOCK (self); if (pad == self->srcpad) { otherpad = self->sinkpad; } else if (pad == self->sinkpad) { otherpad = self->srcpad; } else { GST_ERROR_OBJECT (pad, "Not one of our pads"); otherpad = NULL; } if (otherpad) { peer = gst_pad_get_peer (otherpad); if (peer) { GstCaps *peer_caps; GstCaps *downstream_filter = NULL; /* Add all the caps that we can convert to to the filter caps, * otherwise downstream might just return EMPTY caps because * it doesn't handle the filter caps but we could still convert * to these caps */ if (filter) { guint i, n; downstream_filter = gst_caps_new_empty (); /* Intersect raw video caps in the filter caps with the converter * caps. This makes sure that we don't accept raw video that we * can't handle, e.g. because of caps features */ n = gst_caps_get_size (filter); for (i = 0; i < n; i++) { GstStructure *s; GstCaps *tmp, *tmp2; s = gst_structure_copy (gst_caps_get_structure (filter, i)); if (gst_structure_has_name (s, self->audio ? "audio/x-raw" : "video/x-raw")) { tmp = gst_caps_new_full (s, NULL); tmp2 = gst_caps_intersect (tmp, self->converter_caps); gst_caps_append (downstream_filter, tmp2); gst_caps_unref (tmp); } else { gst_caps_append_structure (downstream_filter, s); } } downstream_filter = gst_caps_merge (downstream_filter, gst_caps_ref (self->converter_caps)); } peer_caps = gst_pad_query_caps (peer, downstream_filter); if (downstream_filter) gst_caps_unref (downstream_filter); gst_object_unref (peer); if (self->converter_caps && is_raw_caps (peer_caps, self->audio)) { GstCaps *converter_caps = gst_caps_ref (self->converter_caps); GstCapsFeatures *cf; GstStructure *s; guint i, n; ret = gst_caps_make_writable (peer_caps); /* Filter out ANY capsfeatures from the converter caps. We can't * convert to ANY capsfeatures, they are only there so that we * can passthrough whatever downstream can support... but we * definitely don't want to return them here */ n = gst_caps_get_size (converter_caps); for (i = 0; i < n; i++) { s = gst_caps_get_structure (converter_caps, i); cf = gst_caps_get_features (converter_caps, i); if (cf && gst_caps_features_is_any (cf)) continue; ret = gst_caps_merge_structure_full (ret, gst_structure_copy (s), (cf ? gst_caps_features_copy (cf) : NULL)); } gst_caps_unref (converter_caps); } else { ret = peer_caps; } } else { ret = gst_caps_ref (self->converter_caps); } GST_PLAY_SINK_CONVERT_BIN_FILTER_CAPS (filter, ret); } else { ret = filter ? gst_caps_ref (filter) : gst_caps_new_any (); } GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); gst_object_unref (self); GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret); return ret; }
static GstCaps * gst_play_sink_convert_bin_getcaps (GstPad * pad, GstCaps * filter) { GstPlaySinkConvertBin *self = GST_PLAY_SINK_CONVERT_BIN (gst_pad_get_parent (pad)); GstCaps *ret; GstPad *otherpad, *peer; GST_PLAY_SINK_CONVERT_BIN_LOCK (self); if (pad == self->srcpad) { otherpad = self->sinkpad; } else if (pad == self->sinkpad) { otherpad = self->srcpad; } else { GST_ERROR_OBJECT (pad, "Not one of our pads"); otherpad = NULL; } if (otherpad) { peer = gst_pad_get_peer (otherpad); if (peer) { GstCaps *peer_caps; GstCaps *downstream_filter = NULL; /* Add all the caps that we can convert to to the filter caps, * otherwise downstream might just return EMPTY caps because * it doesn't handle the filter caps but we could still convert * to these caps */ if (filter) { downstream_filter = gst_caps_copy (filter); downstream_filter = gst_caps_merge (downstream_filter, gst_caps_ref (self->converter_caps)); } peer_caps = gst_pad_query_caps (peer, downstream_filter); if (downstream_filter) gst_caps_unref (downstream_filter); gst_object_unref (peer); if (self->converter_caps && is_raw_caps (peer_caps, self->audio)) { ret = gst_caps_merge (peer_caps, gst_caps_ref (self->converter_caps)); } else { ret = peer_caps; } } else { ret = gst_caps_ref (self->converter_caps); } } else { ret = gst_caps_new_any (); } GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); gst_object_unref (self); if (filter) { GstCaps *intersection = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (ret); ret = intersection; } GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret); return ret; }