* The videobox plugin has many uses such as doing a mosaic of pictures,
* letterboxing video, cutting out pieces of video, picture in picture, etc..
*/
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
gdouble border_alpha;
GstVideoBoxFill fill_type;
+
+ gboolean autocrop;
};
struct _GstVideoBoxClass
PROP_BOTTOM,
PROP_FILL_TYPE,
PROP_ALPHA,
- PROP_BORDER_ALPHA
+ PROP_BORDER_ALPHA,
+ PROP_AUTOCROP
/* FILL ME */
};
+/*
+
+Setting autocrop to true changes the behavior of the plugin so that
+caps determine crop properties rather than the other way around: given
+input and output dimensions, the crop values are selected so that the
+smaller frame is effectively centered in the larger frame. This
+involves either cropping or padding.
+
+If you use autocrop there is little point in setting the other
+properties manually because they will be overriden if the caps change,
+but nothing stops you from doing so.
+
+Sample pipeline:
+gst-launch videotestsrc ! videobox autocrop=true ! \
+"video/x-raw-yuv, width=600, height=400" ! ffmpegcolorspace ! ximagesink
+
+*/
+
+
static GstStaticPadTemplate gst_video_box_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
static void gst_video_box_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
+static gboolean video_box_recalc_transform (GstVideoBox * video_box);
static GstCaps *gst_video_box_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * from);
static gboolean gst_video_box_set_caps (GstBaseTransform * trans,
g_param_spec_double ("border_alpha", "Border Alpha",
"Alpha value of the border", 0.0, 1.0, DEFAULT_BORDER_ALPHA,
G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOCROP,
+ g_param_spec_boolean ("autocrop", "Auto crop",
+ "Auto crop", FALSE, G_PARAM_READWRITE));
trans_class->transform = GST_DEBUG_FUNCPTR (gst_video_box_transform);
trans_class->transform_caps =
video_box->fill_type = DEFAULT_FILL_TYPE;
video_box->alpha = DEFAULT_ALPHA;
video_box->border_alpha = DEFAULT_BORDER_ALPHA;
+ video_box->autocrop = FALSE;
}
static void
case PROP_BORDER_ALPHA:
video_box->border_alpha = g_value_get_double (value);
break;
+ case PROP_AUTOCROP:
+ video_box->autocrop = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
- GST_DEBUG_OBJECT (video_box, "Calling reconfigure");
- gst_base_transform_reconfigure (GST_BASE_TRANSFORM (video_box));
+ video_box_recalc_transform (video_box);
+ /*
+ GST_DEBUG_OBJECT (video_box, "Calling reconfigure");
+ gst_base_transform_reconfigure (GST_BASE_TRANSFORM (video_box));
+ */
+ GST_BASE_TRANSFORM_UNLOCK (GST_BASE_TRANSFORM_CAST (video_box));
+}
+
+static void
+gst_video_box_autocrop (GstVideoBox * video_box)
+{
+ gint crop_w = (video_box->in_width - video_box->out_width) / 2;
+ gint crop_h = (video_box->in_height - video_box->out_height) / 2;
+
+ GST_BASE_TRANSFORM_LOCK (GST_BASE_TRANSFORM_CAST (video_box));
+
+ video_box->box_left = crop_w;
+ if (video_box->box_left < 0) {
+ video_box->border_left = -video_box->box_left;
+ video_box->crop_left = 0;
+ } else {
+ video_box->border_left = 0;
+ video_box->crop_left = video_box->box_left;
+ }
+
+ video_box->box_right = crop_w;
+ if (video_box->box_right < 0) {
+ video_box->border_right = -video_box->box_right;
+ video_box->crop_right = 0;
+ } else {
+ video_box->border_right = 0;
+ video_box->crop_right = video_box->box_right;
+ }
+
+ video_box->box_top = crop_h;
+ if (video_box->box_top < 0) {
+ video_box->border_top = -video_box->box_top;
+ video_box->crop_top = 0;
+ } else {
+ video_box->border_top = 0;
+ video_box->crop_top = video_box->box_top;
+ }
+
+ video_box->box_bottom = crop_h;
+ if (video_box->box_bottom < 0) {
+ video_box->border_bottom = -video_box->box_bottom;
+ video_box->crop_bottom = 0;
+ } else {
+ video_box->border_bottom = 0;
+ video_box->crop_bottom = video_box->box_bottom;
+ }
+
GST_BASE_TRANSFORM_UNLOCK (GST_BASE_TRANSFORM_CAST (video_box));
}
case PROP_BORDER_ALPHA:
g_value_set_double (value, video_box->border_alpha);
break;
+ case PROP_AUTOCROP:
+ g_value_set_boolean (value, video_box->autocrop);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
/* get rid of format */
gst_structure_remove_field (structure, "format");
- /* calculate width and height */
- if (gst_structure_get_int (structure, "width", &width)) {
- if (direction == GST_PAD_SINK) {
- width -= video_box->box_left;
- width -= video_box->box_right;
- } else {
- width += video_box->box_left;
- width += video_box->box_right;
- }
- if (width <= 0)
- width = 1;
-
- GST_DEBUG_OBJECT (trans, "New caps width: %d", width);
- gst_structure_set (structure, "width", G_TYPE_INT, width, NULL);
+ /* otherwise caps nego will fail: */
+ if (video_box->autocrop) {
+ gst_structure_remove_field (structure, "width");
+ gst_structure_remove_field (structure, "height");
}
- if (gst_structure_get_int (structure, "height", &height)) {
- if (direction == GST_PAD_SINK) {
- height -= video_box->box_top;
- height -= video_box->box_bottom;
- } else {
- height += video_box->box_top;
- height += video_box->box_bottom;
+ if (!video_box->autocrop) {
+
+ /* calculate width and height */
+ if (gst_structure_get_int (structure, "width", &width)) {
+ if (direction == GST_PAD_SINK) {
+ width -= video_box->box_left;
+ width -= video_box->box_right;
+ } else {
+ width += video_box->box_left;
+ width += video_box->box_right;
+ }
+ if (width <= 0)
+ width = 1;
+
+ GST_DEBUG_OBJECT (trans, "New caps width: %d", width);
+ gst_structure_set (structure, "width", G_TYPE_INT, width, NULL);
}
- if (height <= 0)
- height = 1;
+ if (gst_structure_get_int (structure, "height", &height)) {
+ if (direction == GST_PAD_SINK) {
+ height -= video_box->box_top;
+ height -= video_box->box_bottom;
+ } else {
+ height += video_box->box_top;
+ height += video_box->box_bottom;
+ }
- GST_DEBUG_OBJECT (trans, "New caps height: %d", height);
- gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
+ if (height <= 0)
+ height = 1;
+
+ GST_DEBUG_OBJECT (trans, "New caps height: %d", height);
+ gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
+ }
}
/* filter against set allowed caps on the pad */
return ret;
}
+static gboolean
+video_box_recalc_transform (GstVideoBox * video_box)
+{
+ gboolean res = TRUE;
+
+ /* if we have the same format in and out and we don't need to perform any
+ * cropping at all, we can just operate in passthorugh mode */
+ if (video_box->in_fourcc == video_box->out_fourcc &&
+ video_box->box_left == 0 && video_box->box_right == 0 &&
+ video_box->box_top == 0 && video_box->box_bottom == 0) {
+
+ GST_LOG_OBJECT (video_box, "we are using passthrough");
+ gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), TRUE);
+ } else {
+ GST_LOG_OBJECT (video_box, "we are not using passthrough");
+ gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), FALSE);
+ }
+ return res;
+}
+
static gboolean
gst_video_box_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
{
GST_DEBUG_OBJECT (trans, "Output w: %d h: %d", video_box->out_width,
video_box->out_height);
- /* if we have the same format in and out and we don't need to perform and
- * cropping at all, we can just operate in passthorugh mode */
- if (video_box->in_fourcc == video_box->out_fourcc &&
- video_box->box_left == 0 && video_box->box_right == 0 &&
- video_box->box_top == 0 && video_box->box_bottom == 0) {
+ if (video_box->autocrop)
+ gst_video_box_autocrop (video_box);
- GST_LOG_OBJECT (video_box, "we are using passthrough");
- gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), TRUE);
- } else {
- GST_LOG_OBJECT (video_box, "we are not using passthrough");
- gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), FALSE);
- }
+ /* recalc the transformation strategy */
+ ret = video_box_recalc_transform (video_box);
return ret;
{
guint8 *srcY, *srcU, *srcV;
gint crop_width, crop_width2, crop_height;
- gint out_width;
+ gint out_width, out_height;
gint src_stridey, src_strideu, src_stridev;
gint br, bl, bt, bb;
gint colorY, colorU, colorV;
bb = video_box->border_bottom;
out_width = video_box->out_width;
+ out_height = video_box->out_height;
src_stridey = GST_VIDEO_I420_Y_ROWSTRIDE (video_box->in_width);
src_strideu = GST_VIDEO_I420_U_ROWSTRIDE (video_box->in_width);