mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
video-transition: Port to the new 'operator' API in compositor
Now subclassing a ghostpad with an alpha property so that we can multiply the alpha of the frame positioning meta and the alpha of that pad, setting it on the compositor pad. https://bugzilla.gnome.org/show_bug.cgi?id=797169
This commit is contained in:
parent
b64dd33661
commit
3c7f488fc2
3 changed files with 111 additions and 6 deletions
|
@ -22,6 +22,76 @@
|
||||||
#include "ges-internal.h"
|
#include "ges-internal.h"
|
||||||
#include "ges-smart-video-mixer.h"
|
#include "ges-smart-video-mixer.h"
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (GESSmartMixerPad, ges_smart_mixer_pad, GES,
|
||||||
|
SMART_MIXER_PAD, GstGhostPad);
|
||||||
|
struct _GESSmartMixerPad
|
||||||
|
{
|
||||||
|
GstGhostPad parent;
|
||||||
|
|
||||||
|
gdouble alpha;
|
||||||
|
GstSegment segment;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_PAD_0,
|
||||||
|
PROP_PAD_ALPHA,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
ges_smart_mixer_pad_get_property (GObject * object, guint prop_id,
|
||||||
|
GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GESSmartMixerPad *pad = GES_SMART_MIXER_PAD (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_PAD_ALPHA:
|
||||||
|
g_value_set_double (value, pad->alpha);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ges_smart_mixer_pad_set_property (GObject * object, guint prop_id,
|
||||||
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GESSmartMixerPad *pad = GES_SMART_MIXER_PAD (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_PAD_ALPHA:
|
||||||
|
pad->alpha = g_value_get_double (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (GESSmartMixerPad, ges_smart_mixer_pad, GST_TYPE_GHOST_PAD);
|
||||||
|
|
||||||
|
static void
|
||||||
|
ges_smart_mixer_pad_init (GESSmartMixerPad * self)
|
||||||
|
{
|
||||||
|
gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ges_smart_mixer_pad_class_init (GESSmartMixerPadClass * klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||||
|
|
||||||
|
gobject_class->get_property = ges_smart_mixer_pad_get_property;
|
||||||
|
gobject_class->set_property = ges_smart_mixer_pad_set_property;
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_PAD_ALPHA,
|
||||||
|
g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
|
||||||
|
1.0,
|
||||||
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
}
|
||||||
|
|
||||||
G_DEFINE_TYPE (GESSmartMixer, ges_smart_mixer, GST_TYPE_BIN);
|
G_DEFINE_TYPE (GESSmartMixer, ges_smart_mixer, GST_TYPE_BIN);
|
||||||
|
|
||||||
#define GET_LOCK(obj) (&((GESSmartMixer*)(obj))->lock)
|
#define GET_LOCK(obj) (&((GESSmartMixer*)(obj))->lock)
|
||||||
|
@ -88,9 +158,10 @@ ges_smart_mixer_get_mixer_pad (GESSmartMixer * self, GstPad ** mixerpad)
|
||||||
added in the video sources' bin */
|
added in the video sources' bin */
|
||||||
static GstPadProbeReturn
|
static GstPadProbeReturn
|
||||||
parse_metadata (GstPad * mixer_pad, GstPadProbeInfo * info,
|
parse_metadata (GstPad * mixer_pad, GstPadProbeInfo * info,
|
||||||
GESSmartMixer * self)
|
GESSmartMixerPad * ghost)
|
||||||
{
|
{
|
||||||
GstFramePositionerMeta *meta;
|
GstFramePositionerMeta *meta;
|
||||||
|
GESSmartMixer *self = GES_SMART_MIXER (GST_OBJECT_PARENT (ghost));
|
||||||
|
|
||||||
meta =
|
meta =
|
||||||
(GstFramePositionerMeta *) gst_buffer_get_meta ((GstBuffer *) info->data,
|
(GstFramePositionerMeta *) gst_buffer_get_meta ((GstBuffer *) info->data,
|
||||||
|
@ -104,6 +175,34 @@ parse_metadata (GstPad * mixer_pad, GstPadProbeInfo * info,
|
||||||
if (!self->disable_zorder_alpha) {
|
if (!self->disable_zorder_alpha) {
|
||||||
g_object_set (mixer_pad, "alpha", meta->alpha,
|
g_object_set (mixer_pad, "alpha", meta->alpha,
|
||||||
"zorder", meta->zorder, NULL);
|
"zorder", meta->zorder, NULL);
|
||||||
|
} else {
|
||||||
|
gint64 stream_time;
|
||||||
|
gdouble transalpha;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (ghost);
|
||||||
|
if (ghost->segment.format == GST_FORMAT_UNDEFINED) {
|
||||||
|
const GstSegment *seg;
|
||||||
|
GstEvent *segev;
|
||||||
|
|
||||||
|
GST_OBJECT_UNLOCK (ghost);
|
||||||
|
segev = gst_pad_get_sticky_event (GST_PAD (ghost), GST_EVENT_SEGMENT, 0);
|
||||||
|
gst_event_parse_segment (segev, &seg);
|
||||||
|
gst_event_unref (segev);
|
||||||
|
GST_OBJECT_LOCK (ghost);
|
||||||
|
|
||||||
|
ghost->segment = *seg;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_time = gst_segment_to_stream_time (&ghost->segment, GST_FORMAT_TIME,
|
||||||
|
GST_BUFFER_PTS (info->data));
|
||||||
|
GST_OBJECT_UNLOCK (ghost);
|
||||||
|
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (stream_time))
|
||||||
|
gst_object_sync_values (GST_OBJECT (ghost), stream_time);
|
||||||
|
|
||||||
|
g_object_get (ghost, "alpha", &transalpha, NULL);
|
||||||
|
g_object_set (mixer_pad, "alpha", meta->alpha * transalpha, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_set (mixer_pad, "xpos", meta->posx, "ypos",
|
g_object_set (mixer_pad, "xpos", meta->posx, "ypos",
|
||||||
|
@ -150,7 +249,10 @@ _request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||||
gst_element_add_pad (GST_ELEMENT (infos->bin), tmpghost);
|
gst_element_add_pad (GST_ELEMENT (infos->bin), tmpghost);
|
||||||
|
|
||||||
gst_bin_add (GST_BIN (self), infos->bin);
|
gst_bin_add (GST_BIN (self), infos->bin);
|
||||||
ghost = gst_ghost_pad_new (NULL, tmpghost);
|
ghost = g_object_new (ges_smart_mixer_pad_get_type (), "name", name,
|
||||||
|
"direction", GST_PAD_DIRECTION (tmpghost), NULL);
|
||||||
|
gst_ghost_pad_construct (GST_GHOST_PAD (ghost));
|
||||||
|
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghost), tmpghost);
|
||||||
gst_pad_set_active (ghost, TRUE);
|
gst_pad_set_active (ghost, TRUE);
|
||||||
if (!gst_element_add_pad (GST_ELEMENT (self), ghost))
|
if (!gst_element_add_pad (GST_ELEMENT (self), ghost))
|
||||||
goto could_not_add;
|
goto could_not_add;
|
||||||
|
@ -164,7 +266,7 @@ _request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||||
|
|
||||||
infos->probe_id =
|
infos->probe_id =
|
||||||
gst_pad_add_probe (infos->mixer_pad, GST_PAD_PROBE_TYPE_BUFFER,
|
gst_pad_add_probe (infos->mixer_pad, GST_PAD_PROBE_TYPE_BUFFER,
|
||||||
(GstPadProbeCallback) parse_metadata, self, NULL);
|
(GstPadProbeCallback) parse_metadata, ghost, NULL);
|
||||||
|
|
||||||
LOCK (self);
|
LOCK (self);
|
||||||
g_hash_table_insert (self->pads_infos, ghost, infos);
|
g_hash_table_insert (self->pads_infos, ghost, infos);
|
||||||
|
|
|
@ -350,6 +350,7 @@ ges_video_transition_create_element (GESTrackElement * object)
|
||||||
|
|
||||||
mixer = ges_smart_mixer_new (NULL);
|
mixer = ges_smart_mixer_new (NULL);
|
||||||
GES_SMART_MIXER (mixer)->disable_zorder_alpha = TRUE;
|
GES_SMART_MIXER (mixer)->disable_zorder_alpha = TRUE;
|
||||||
|
g_object_set (GES_SMART_MIXER (mixer)->mixer, "background", 3, NULL); /* transparent */
|
||||||
gst_bin_add (GST_BIN (topbin), mixer);
|
gst_bin_add (GST_BIN (topbin), mixer);
|
||||||
|
|
||||||
priv->mixer_sinka =
|
priv->mixer_sinka =
|
||||||
|
@ -361,7 +362,9 @@ ges_video_transition_create_element (GESTrackElement * object)
|
||||||
mixer, GES_VIDEO_STANDARD_TRANSITION_TYPE_BAR_WIPE_LR, &priv->smpte,
|
mixer, GES_VIDEO_STANDARD_TRANSITION_TYPE_BAR_WIPE_LR, &priv->smpte,
|
||||||
priv, &priv->mixer_ghostb);
|
priv, &priv->mixer_ghostb);
|
||||||
g_object_set (priv->mixer_sinka, "zorder", 0, NULL);
|
g_object_set (priv->mixer_sinka, "zorder", 0, NULL);
|
||||||
|
gst_util_set_object_arg (G_OBJECT (priv->mixer_sinka), "operator", "source");
|
||||||
g_object_set (priv->mixer_sinkb, "zorder", 1, NULL);
|
g_object_set (priv->mixer_sinkb, "zorder", 1, NULL);
|
||||||
|
gst_util_set_object_arg (G_OBJECT (priv->mixer_sinkb), "operator", "add");
|
||||||
|
|
||||||
fast_element_link (mixer, priv->positioner);
|
fast_element_link (mixer, priv->positioner);
|
||||||
fast_element_link (priv->positioner, oconv);
|
fast_element_link (priv->positioner, oconv);
|
||||||
|
@ -385,9 +388,9 @@ ges_video_transition_create_element (GESTrackElement * object)
|
||||||
/* set up interpolation */
|
/* set up interpolation */
|
||||||
|
|
||||||
priv->fade_out_control_source =
|
priv->fade_out_control_source =
|
||||||
set_interpolation (GST_OBJECT (priv->mixer_sinka), priv, "alpha");
|
set_interpolation (GST_OBJECT (priv->mixer_ghosta), priv, "alpha");
|
||||||
priv->fade_in_control_source =
|
priv->fade_in_control_source =
|
||||||
set_interpolation (GST_OBJECT (priv->mixer_sinkb), priv, "alpha");
|
set_interpolation (GST_OBJECT (priv->mixer_ghostb), priv, "alpha");
|
||||||
priv->smpte_control_source =
|
priv->smpte_control_source =
|
||||||
set_interpolation (GST_OBJECT (priv->smpte), priv, "position");
|
set_interpolation (GST_OBJECT (priv->smpte), priv, "position");
|
||||||
priv->mixer = gst_object_ref (mixer);
|
priv->mixer = gst_object_ref (mixer);
|
||||||
|
|
|
@ -506,7 +506,7 @@ gst_frame_positioner_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstFramePositionerMeta *meta;
|
GstFramePositionerMeta *meta;
|
||||||
GstFramePositioner *framepositioner = GST_FRAME_POSITIONNER (trans);
|
GstFramePositioner *framepositioner = GST_FRAME_POSITIONNER (trans);
|
||||||
GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buf);
|
GstClockTime timestamp = GST_BUFFER_PTS (buf);
|
||||||
|
|
||||||
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
|
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
|
||||||
gst_object_sync_values (GST_OBJECT (trans), timestamp);
|
gst_object_sync_values (GST_OBJECT (trans), timestamp);
|
||||||
|
|
Loading…
Reference in a new issue