#include "config.h"
#endif
+#include <math.h>
#include "gstframepositioner.h"
#include "ges-frame-composition-meta.h"
#include "ges-types.h"
gdouble alpha;
GstSegment segment;
+
+ GParamSpec *width_pspec;
+ GParamSpec *height_pspec;
+ GParamSpec *xpos_pspec;
+ GParamSpec *ypos_pspec;
};
struct _GESSmartMixerPadClass
G_DEFINE_TYPE (GESSmartMixerPad, ges_smart_mixer_pad, GST_TYPE_GHOST_PAD);
+static void
+ges_smart_mixer_notify_wrapped_pad (GESSmartMixerPad * self,
+ GstPad * real_mixer_pad)
+{
+ GObjectClass *klass = G_OBJECT_GET_CLASS (real_mixer_pad);
+
+ self->width_pspec = g_object_class_find_property (klass, "width");
+ self->height_pspec = g_object_class_find_property (klass, "height");
+ self->xpos_pspec = g_object_class_find_property (klass, "xpos");
+ self->ypos_pspec = g_object_class_find_property (klass, "ypos");
+}
+
static void
ges_smart_mixer_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
g_object_set (mixer_pad, "alpha", meta->alpha * transalpha, NULL);
}
- g_object_set (mixer_pad, "xpos", meta->posx, "ypos", meta->posy, NULL);
+ if (G_PARAM_SPEC_VALUE_TYPE (ghost->xpos_pspec) == G_TYPE_INT) {
+ g_object_set (mixer_pad, "xpos", (gint) round (meta->posx), "ypos",
+ (gint) round (meta->posy), NULL);
+ } else if (G_PARAM_SPEC_VALUE_TYPE (ghost->xpos_pspec) == G_TYPE_FLOAT) {
+ g_object_set (mixer_pad, "xpos", (gfloat) meta->posx, "ypos",
+ (gfloat) meta->posy, NULL);
+ } else {
+ g_object_set (mixer_pad, "xpos", meta->posx, "ypos", meta->posy, NULL);
+ }
- if (meta->width >= 0)
- g_object_set (mixer_pad, "width", meta->width, NULL);
+ if (meta->width >= 0) {
+ if (G_PARAM_SPEC_VALUE_TYPE (ghost->width_pspec) == G_TYPE_INT) {
+ g_object_set (mixer_pad, "width", (gint) round (meta->width), NULL);
+ } else if (G_PARAM_SPEC_VALUE_TYPE (ghost->width_pspec) == G_TYPE_FLOAT) {
+ g_object_set (mixer_pad, "width", (gfloat) meta->width, NULL);
+ } else {
+ g_object_set (mixer_pad, "width", meta->width, NULL);
+ }
+ }
- if (meta->height >= 0)
- g_object_set (mixer_pad, "height", meta->height, NULL);
+ if (meta->height >= 0) {
+ if (G_PARAM_SPEC_VALUE_TYPE (ghost->height_pspec) == G_TYPE_INT) {
+ g_object_set (mixer_pad, "height", (gint) round (meta->height), NULL);
+ } else if (G_PARAM_SPEC_VALUE_TYPE (ghost->height_pspec) == G_TYPE_FLOAT) {
+ g_object_set (mixer_pad, "height", (gfloat) meta->height, NULL);
+ } else {
+ g_object_set (mixer_pad, "height", meta->height, NULL);
+ }
+ }
if (self->ABI.abi.has_operator)
g_object_set (mixer_pad, "operator", meta->operator, NULL);
"direction", GST_PAD_DIRECTION (infos->mixer_pad), NULL);
infos->ghostpad = ghost;
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghost), infos->mixer_pad);
+ ges_smart_mixer_notify_wrapped_pad (GES_SMART_MIXER_PAD (ghost),
+ infos->real_mixer_pad);
gst_pad_set_active (ghost, TRUE);
if (!gst_element_add_pad (GST_ELEMENT (self), ghost))
goto could_not_add;
{
PROP_0,
PROP_ALPHA,
+
PROP_POSX,
+ PROP_FPOSX,
+
PROP_POSY,
- PROP_ZORDER,
+ PROP_FPOSY,
+
PROP_WIDTH,
+ PROP_FWIDTH,
+
PROP_HEIGHT,
+ PROP_FHEIGHT,
+
+ PROP_ZORDER,
PROP_OPERATOR,
PROP_LAST,
};
gint i;
GParamSpec *positioning_props[] = {
properties[PROP_WIDTH],
+ properties[PROP_FWIDTH],
+
properties[PROP_HEIGHT],
+ properties[PROP_FHEIGHT],
+
properties[PROP_POSX],
+ properties[PROP_FPOSX],
+
properties[PROP_POSY],
+ properties[PROP_FPOSY],
};
if (self->user_positioned)
gint old_track_height)
{
gint i;
+ /* *INDENT-OFF* */
RepositionPropertyData props_data[] = {
+ {&pos->width, old_track_width, pos->track_width, properties[PROP_FWIDTH]},
{&pos->width, old_track_width, pos->track_width, properties[PROP_WIDTH]},
- {&pos->height, old_track_height, pos->track_height,
- properties[PROP_HEIGHT]},
+
+ {&pos->height, old_track_height, pos->track_height, properties[PROP_FHEIGHT]},
+ {&pos->height, old_track_height, pos->track_height, properties[PROP_HEIGHT]},
+
+ {&pos->posx, old_track_width, pos->track_width, properties[PROP_FPOSX]},
{&pos->posx, old_track_width, pos->track_width, properties[PROP_POSX]},
+
+ {&pos->posy, old_track_height, pos->track_height, properties[PROP_FPOSY]},
{&pos->posy, old_track_height, pos->track_height, properties[PROP_POSY]},
};
+ /* *INDENT-ON* */
+
for (i = 0; i < G_N_ELEMENTS (props_data); i++) {
GList *values, *tmp;
GstControlBinding *binding =
gst_object_get_control_binding (GST_OBJECT (pos), d.pspec->name);
- *(d.value) =
- *(d.value) * (gdouble) d.track_value / (gdouble) d.old_track_value;
+ if (G_PARAM_SPEC_VALUE_TYPE (d.pspec) == G_TYPE_FLOAT) {
+ *(d.value) =
+ *(d.value) * (gdouble) d.track_value / (gdouble) d.old_track_value;
+ }
if (!binding)
continue;
* The desired x position for the stream.
*/
properties[PROP_POSX] =
- g_param_spec_int ("posx", "posx", "x position of the stream", MIN_PIXELS,
- MAX_PIXELS, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE);
+ g_param_spec_int ("posx", "posx", "x position of the stream",
+ MIN_PIXELS, MAX_PIXELS, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
+ /**
+ * gstframepositioner:fposx:
+ *
+ * The desired x position for the stream.
+ */
+ properties[PROP_FPOSX] =
+ g_param_spec_float ("fposx", "fposx", "x position of the stream in float",
+ MIN_PIXELS, MAX_PIXELS, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
/**
* gstframepositioner:posy:
* The desired y position for the stream.
*/
properties[PROP_POSY] =
- g_param_spec_int ("posy", "posy", "y position of the stream", MIN_PIXELS,
- MAX_PIXELS, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE);
+ g_param_spec_int ("posy", "posy", "y position of the stream",
+ MIN_PIXELS, MAX_PIXELS, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
+
+
+ /**
+ * gstframepositioner:fposy:
+ *
+ * The desired y position for the stream.
+ */
+ properties[PROP_FPOSY] =
+ g_param_spec_float ("fposy", "fposy", "y position of the stream in float",
+ MIN_PIXELS, MAX_PIXELS, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
/**
* gstframepositioner:zorder:
* Set to 0 if size is not mandatory, will be set to width of the current track.
*/
properties[PROP_WIDTH] =
- g_param_spec_int ("width", "width", "width of the source", 0, MAX_PIXELS,
- 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE);
+ g_param_spec_int ("width", "width", "width of the source", 0,
+ MAX_PIXELS, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
+
+ /**
+ * gesframepositioner:fwidth:
+ *
+ * The desired width for that source.
+ * Set to 0 if size is not mandatory, will be set to width of the current track.
+ */
+ properties[PROP_FWIDTH] =
+ g_param_spec_float ("fwidth", "fwidth", "width of the source in float", 0,
+ MAX_PIXELS, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
/**
* gesframepositioner:height:
*/
properties[PROP_HEIGHT] =
g_param_spec_int ("height", "height", "height of the source", 0,
- MAX_PIXELS, 0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE);
+ MAX_PIXELS, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
+
+ /**
+ * gesframepositioner:fheight:
+ *
+ * The desired height for that source.
+ * Set to 0 if size is not mandatory, will be set to height of the current track.
+ */
+ properties[PROP_FHEIGHT] =
+ g_param_spec_float ("fheight", "fheight", "height of the source in float",
+ 0, MAX_PIXELS, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_LAX_VALIDATION);
/**
* gesframepositioner:operator:
framepositioner->posx = g_value_get_int (value);
framepositioner->user_positioned = TRUE;
break;
+ case PROP_FPOSX:
+ framepositioner->posx = g_value_get_float (value);
+ framepositioner->user_positioned = TRUE;
+ break;
case PROP_POSY:
framepositioner->posy = g_value_get_int (value);
framepositioner->user_positioned = TRUE;
break;
+ case PROP_FPOSY:
+ framepositioner->posy = g_value_get_float (value);
+ framepositioner->user_positioned = TRUE;
+ break;
case PROP_ZORDER:
framepositioner->zorder = g_value_get_uint (value);
break;
gst_frame_positioner_update_properties (framepositioner, track_mixing,
0, 0);
break;
+ case PROP_FWIDTH:
+ framepositioner->user_positioned = TRUE;
+ framepositioner->width = g_value_get_float (value);
+ gst_frame_positioner_update_properties (framepositioner, track_mixing,
+ 0, 0);
+ break;
case PROP_HEIGHT:
framepositioner->user_positioned = TRUE;
framepositioner->height = g_value_get_int (value);
gst_frame_positioner_update_properties (framepositioner, track_mixing,
0, 0);
break;
+ case PROP_FHEIGHT:
+ framepositioner->user_positioned = TRUE;
+ framepositioner->height = g_value_get_float (value);
+ gst_frame_positioner_update_properties (framepositioner, track_mixing,
+ 0, 0);
+ break;
case PROP_OPERATOR:
framepositioner->operator = g_value_get_enum (value);
gst_frame_positioner_update_properties (framepositioner, track_mixing,
GValue * value, GParamSpec * pspec)
{
GstFramePositioner *pos = GST_FRAME_POSITIONNER (object);
- gint real_width, real_height;
+ gdouble real_width, real_height;
switch (property_id) {
case PROP_ALPHA:
case PROP_POSX:
g_value_set_int (value, round (pos->posx));
break;
+ case PROP_FPOSX:
+ g_value_set_float (value, pos->posx);
+ break;
case PROP_POSY:
g_value_set_int (value, round (pos->posy));
break;
+ case PROP_FPOSY:
+ g_value_set_float (value, pos->posy);
+ break;
case PROP_ZORDER:
g_value_set_uint (value, pos->zorder);
break;
if (pos->scale_in_compositor) {
g_value_set_int (value, round (pos->width));
} else {
- real_width =
- pos->width > 0 ? round (pos->width) : round (pos->track_width);
- g_value_set_int (value, real_width);
+ real_width = pos->width > 0 ? pos->width : pos->track_width;
+ g_value_set_int (value, round (real_width));
+ }
+ break;
+ case PROP_FWIDTH:
+ if (pos->scale_in_compositor) {
+ g_value_set_float (value, pos->width);
+ } else {
+ real_width = pos->width > 0 ? pos->width : pos->track_width;
+ g_value_set_float (value, real_width);
}
break;
case PROP_HEIGHT:
if (pos->scale_in_compositor) {
g_value_set_int (value, round (pos->height));
} else {
- real_height =
- pos->height > 0 ? round (pos->height) : round (pos->track_height);
- g_value_set_int (value, real_height);
+ real_height = pos->height > 0 ? pos->height : pos->track_height;
+ g_value_set_int (value, round (real_height));
+ }
+ break;
+ case PROP_FHEIGHT:
+ if (pos->scale_in_compositor) {
+ g_value_set_float (value, pos->height);
+ } else {
+ real_height = pos->height > 0 ? pos->height : pos->track_height;
+ g_value_set_float (value, real_height);
}
break;
case PROP_OPERATOR:
GST_OBJECT_LOCK (framepositioner);
meta->alpha = framepositioner->alpha;
- meta->posx = round (framepositioner->posx);
- meta->posy = round (framepositioner->posy);
- meta->width = round (framepositioner->width);
- meta->height = round (framepositioner->height);
+ meta->posx = framepositioner->posx;
+ meta->posy = framepositioner->posy;
+ meta->width = framepositioner->width;
+ meta->height = framepositioner->height;
meta->zorder = framepositioner->zorder;
meta->operator = framepositioner->operator;
GST_OBJECT_UNLOCK (framepositioner);
return GST_FLOW_OK;
}
+
+gboolean
+gst_frame_positioner_check_can_add_binding (GstFramePositioner * self,
+ const gchar * property_name)
+{
+ gint i = 0;
+ const gchar *checked_prop = NULL;
+ const gchar *props[][2] = {
+ {"posx", "fposx"},
+ {"posy", "fposy"},
+ {"width", "fwidth"},
+ {"height", "fheight"},
+ };
+
+
+ for (i = 0; i < G_N_ELEMENTS (props); i++) {
+ if (!g_strcmp0 (property_name, props[i][0])) {
+ checked_prop = props[i][1];
+ break;
+ } else if (!g_strcmp0 (property_name, props[i][1])) {
+ checked_prop = props[i][0];
+ break;
+ }
+ }
+
+ if (!checked_prop)
+ return TRUE;
+
+ GstControlBinding *b =
+ gst_object_get_control_binding (GST_OBJECT (self), checked_prop);
+ if (b) {
+ gst_object_unref (b);
+ GST_WARNING_OBJECT (self,
+ "Can't add control binding for %s as %s already has one", property_name,
+ checked_prop);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}