static void gst_frei0r_mixer_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstFrei0rMixer *self = GST_FREI0R_MIXER (object); GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (object); GST_OBJECT_LOCK (self); if (!gst_frei0r_set_property (self->f0r_instance, klass->ftable, klass->properties, klass->n_properties, self->property_cache, prop_id, value)) G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); GST_OBJECT_UNLOCK (self); }
static void gst_frei0r_mixer_finalize (GObject * object) { GstFrei0rMixer *self = GST_FREI0R_MIXER (object); GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (object); if (self->property_cache) gst_frei0r_property_cache_free (klass->properties, self->property_cache, klass->n_properties); self->property_cache = NULL; if (self->collect) gst_object_unref (self->collect); self->collect = NULL; G_OBJECT_CLASS (g_type_class_peek_parent (klass))->finalize (object); }
static GstStateChangeReturn gst_frei0r_mixer_change_state (GstElement * element, GstStateChange transition) { GstFrei0rMixer *self = GST_FREI0R_MIXER (element); GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self); GstStateChangeReturn ret; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: gst_collect_pads_start (self->collect); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } /* Stop before calling the parent's state change function as * GstCollectPads might take locks and we would deadlock in that * case */ if (transition == GST_STATE_CHANGE_PAUSED_TO_READY) gst_collect_pads_stop (self->collect); ret = GST_ELEMENT_CLASS (g_type_class_peek_parent (klass))->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: gst_frei0r_mixer_reset (self); break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; }
static void gst_frei0r_mixer_reset (GstFrei0rMixer * self) { GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self); GstEvent **p_ev; if (self->f0r_instance) { klass->ftable->destruct (self->f0r_instance); self->f0r_instance = NULL; } if (self->property_cache) gst_frei0r_property_cache_free (klass->properties, self->property_cache, klass->n_properties); self->property_cache = NULL; gst_caps_replace (&self->caps, NULL); p_ev = &self->segment_event; gst_event_replace (p_ev, NULL); gst_video_info_init (&self->info); }
static void gst_frei0r_mixer_reset (GstFrei0rMixer * self) { GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self); GstEvent **p_ev; if (self->f0r_instance) { klass->ftable->destruct (self->f0r_instance); self->f0r_instance = NULL; } if (self->property_cache) gst_frei0r_property_cache_free (klass->properties, self->property_cache, klass->n_properties); self->property_cache = NULL; gst_caps_replace (&self->caps, NULL); p_ev = &self->newseg_event; gst_event_replace (p_ev, NULL); self->fmt = GST_VIDEO_FORMAT_UNKNOWN; self->width = self->height = 0; }
static GstFlowReturn gst_frei0r_mixer_collected (GstCollectPads * pads, GstFrei0rMixer * self) { GstBuffer *inbuf0 = NULL, *inbuf1 = NULL, *inbuf2 = NULL; GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; GSList *l; GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self); GstClockTime timestamp; gdouble time; GstSegment *segment = NULL; GstAllocationParams alloc_params = { 0, 31, 0, 0 }; GstMapInfo outmap, inmap0, inmap1, inmap2; if (G_UNLIKELY (self->info.width <= 0 || self->info.height <= 0)) return GST_FLOW_NOT_NEGOTIATED; if (G_UNLIKELY (!self->f0r_instance)) { self->f0r_instance = gst_frei0r_instance_construct (klass->ftable, klass->properties, klass->n_properties, self->property_cache, self->info.width, self->info.height); if (G_UNLIKELY (!self->f0r_instance)) return GST_FLOW_ERROR; } if (self->segment_event) { gst_pad_push_event (self->src, self->segment_event); self->segment_event = NULL; } /* FIXME Request an allocator and/or pool */ outbuf = gst_buffer_new_allocate (NULL, self->info.size, &alloc_params); for (l = pads->data; l; l = l->next) { GstCollectData *cdata = l->data; if (cdata->pad == self->sink0) { inbuf0 = gst_collect_pads_pop (pads, cdata); segment = &cdata->segment; } else if (cdata->pad == self->sink1) { inbuf1 = gst_collect_pads_pop (pads, cdata); } else if (cdata->pad == self->sink2) { inbuf2 = gst_collect_pads_pop (pads, cdata); } } if (!inbuf0 || !inbuf1 || (!inbuf2 && self->sink2)) goto eos; gst_buffer_map (outbuf, &outmap, GST_MAP_READWRITE); gst_buffer_map (inbuf0, &inmap0, GST_MAP_READ); gst_buffer_map (inbuf1, &inmap1, GST_MAP_READ); if (inbuf2) gst_buffer_map (inbuf2, &inmap2, GST_MAP_READ); g_assert (segment != NULL); timestamp = GST_BUFFER_PTS (inbuf0); timestamp = gst_segment_to_stream_time (segment, GST_FORMAT_TIME, timestamp); GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_CLOCK_TIME_IS_VALID (timestamp)) gst_object_sync_values (GST_OBJECT (self), timestamp); gst_buffer_copy_into (outbuf, inbuf0, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1); time = ((gdouble) GST_BUFFER_PTS (outbuf)) / GST_SECOND; GST_OBJECT_LOCK (self); klass->ftable->update2 (self->f0r_instance, time, (const guint32 *) inmap0.data, (const guint32 *) inmap1.data, (inbuf2) ? (const guint32 *) inmap2.data : NULL, (guint32 *) outmap.data); GST_OBJECT_UNLOCK (self); gst_buffer_unmap (outbuf, &outmap); gst_buffer_unref (inbuf0); gst_buffer_unmap (inbuf0, &inmap0); gst_buffer_unref (inbuf1); gst_buffer_unmap (inbuf1, &inmap1); if (inbuf2) { gst_buffer_unmap (inbuf2, &inmap2); gst_buffer_unref (inbuf2); } ret = gst_pad_push (self->src, outbuf); return ret; eos: { GST_DEBUG_OBJECT (self, "no data available, must be EOS"); gst_buffer_unref (outbuf); if (inbuf0) gst_buffer_unref (inbuf0); if (inbuf1) gst_buffer_unref (inbuf1); if (inbuf2) gst_buffer_unref (inbuf2); gst_pad_push_event (self->src, gst_event_new_eos ()); return GST_FLOW_EOS; } }
static GstFlowReturn gst_frei0r_mixer_collected (GstCollectPads * pads, GstFrei0rMixer * self) { GstBuffer *inbuf0 = NULL, *inbuf1 = NULL, *inbuf2 = NULL; GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; GSList *l; GstFrei0rMixerClass *klass = GST_FREI0R_MIXER_GET_CLASS (self); GstClockTime timestamp; gdouble time; GstSegment *segment = NULL; if (G_UNLIKELY (self->width <= 0 || self->height <= 0)) return GST_FLOW_NOT_NEGOTIATED; if (G_UNLIKELY (!self->f0r_instance)) { self->f0r_instance = gst_frei0r_instance_construct (klass->ftable, klass->properties, klass->n_properties, self->property_cache, self->width, self->height); if (G_UNLIKELY (!self->f0r_instance)) return GST_FLOW_ERROR; } if (self->newseg_event) { gst_pad_push_event (self->src, self->newseg_event); self->newseg_event = NULL; } if ((ret = gst_pad_alloc_buffer_and_set_caps (self->src, GST_BUFFER_OFFSET_NONE, gst_video_format_get_size (self->fmt, self->width, self->height), GST_PAD_CAPS (self->src), &outbuf)) != GST_FLOW_OK) return ret; for (l = pads->data; l; l = l->next) { GstCollectData *cdata = l->data; if (cdata->pad == self->sink0) { inbuf0 = gst_collect_pads_pop (pads, cdata); segment = &cdata->segment; } else if (cdata->pad == self->sink1) { inbuf1 = gst_collect_pads_pop (pads, cdata); } else if (cdata->pad == self->sink2) { inbuf2 = gst_collect_pads_pop (pads, cdata); } } if (!inbuf0 || !inbuf1 || (!inbuf2 && self->sink2)) goto eos; g_assert (segment != NULL); timestamp = GST_BUFFER_TIMESTAMP (inbuf0); timestamp = gst_segment_to_stream_time (segment, GST_FORMAT_TIME, timestamp); GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_CLOCK_TIME_IS_VALID (timestamp)) gst_object_sync_values (G_OBJECT (self), timestamp); gst_buffer_copy_metadata (outbuf, inbuf0, GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS); time = ((gdouble) GST_BUFFER_TIMESTAMP (outbuf)) / GST_SECOND; GST_OBJECT_LOCK (self); klass->ftable->update2 (self->f0r_instance, time, (const guint32 *) GST_BUFFER_DATA (inbuf0), (const guint32 *) GST_BUFFER_DATA (inbuf1), (inbuf2) ? (const guint32 *) GST_BUFFER_DATA (inbuf2) : NULL, (guint32 *) GST_BUFFER_DATA (outbuf)); GST_OBJECT_UNLOCK (self); gst_buffer_unref (inbuf0); gst_buffer_unref (inbuf1); if (inbuf2) gst_buffer_unref (inbuf2); ret = gst_pad_push (self->src, outbuf); return ret; eos: { GST_DEBUG_OBJECT (self, "no data available, must be EOS"); gst_buffer_unref (outbuf); if (inbuf0) gst_buffer_unref (inbuf0); if (inbuf1) gst_buffer_unref (inbuf1); if (inbuf2) gst_buffer_unref (inbuf2); gst_pad_push_event (self->src, gst_event_new_eos ()); return GST_FLOW_UNEXPECTED; } }