#include <gst/base/gstbasetransform.h>
#include <gst/video/video.h>
+#include <liboil/liboil.h>
#include <string.h>
+GST_DEBUG_CATEGORY (videobox_debug);
+#define GST_CAT_DEFAULT videobox_debug
+
#define GST_TYPE_VIDEO_BOX \
(gst_video_box_get_type())
#define GST_VIDEO_BOX(obj) \
GValue * value, GParamSpec * pspec);
static GstCaps *gst_video_box_transform_caps (GstBaseTransform * trans,
- GstPad * pad, GstCaps * from);
+ GstPadDirection direction, GstCaps * from);
static gboolean gst_video_box_set_caps (GstBaseTransform * trans,
GstCaps * in, GstCaps * out);
-static guint gst_video_box_get_size (GstBaseTransform * trans);
+static gboolean gst_video_box_get_unit_size (GstBaseTransform * trans,
+ GstCaps * caps, guint * size);
static GstFlowReturn gst_video_box_transform (GstBaseTransform * trans,
GstBuffer * in, GstBuffer * out);
{
static GType video_box_fill_type = 0;
static GEnumValue video_box_fill[] = {
- {VIDEO_BOX_FILL_BLACK, "0", "Black"},
- {VIDEO_BOX_FILL_GREEN, "1", "Colorkey green"},
- {VIDEO_BOX_FILL_BLUE, "2", "Colorkey blue"},
+ {VIDEO_BOX_FILL_BLACK, "Black", "black"},
+ {VIDEO_BOX_FILL_GREEN, "Colorkey green", "green"},
+ {VIDEO_BOX_FILL_BLUE, "Colorkey blue", "blue"},
{0, NULL, NULL},
};
trans_class->transform_caps = gst_video_box_transform_caps;
trans_class->set_caps = gst_video_box_set_caps;
- trans_class->get_size = gst_video_box_get_size;
+ trans_class->get_unit_size = gst_video_box_get_unit_size;
trans_class->transform = gst_video_box_transform;
+
+ GST_DEBUG_CATEGORY_INIT (videobox_debug, "videobox", 0,
+ "Resizes a video by adding borders or cropping");
}
static void
-gst_video_box_init (GstVideoBox * video_box)
+gst_video_box_init (GstVideoBox * video_box, GstVideoBoxClass * g_class)
{
video_box->box_right = DEFAULT_RIGHT;
video_box->box_left = DEFAULT_LEFT;
break;
}
}
+
static void
gst_video_box_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
}
static GstCaps *
-gst_video_box_transform_caps (GstBaseTransform * trans, GstPad * pad,
- GstCaps * from)
+gst_video_box_transform_caps (GstBaseTransform * trans,
+ GstPadDirection direction, GstCaps * from)
{
GstVideoBox *video_box;
GstCaps *to;
GstStructure *structure;
- gint direction, i, tmp;
+ GValue list_value = { 0 }, value = {
+ 0};
+ gint dir, i, tmp;
video_box = GST_VIDEO_BOX (trans);
+
+ g_value_init (&list_value, GST_TYPE_LIST);
+ g_value_init (&value, GST_TYPE_FOURCC);
+ gst_value_set_fourcc (&value, GST_MAKE_FOURCC ('I', '4', '2', '0'));
+ gst_value_list_append_value (&list_value, &value);
+ g_value_unset (&value);
+
to = gst_caps_copy (from);
- direction = (pad == trans->sinkpad) ? -1 : 1;
+ dir = (direction == GST_PAD_SINK) ? -1 : 1;
- /* FIXME, include AYUV */
for (i = 0; i < gst_caps_get_size (to); i++) {
structure = gst_caps_get_structure (to, i);
+ if (direction == GST_PAD_SINK) { /* I420 to { I420, AYUV } */
+ g_value_init (&value, GST_TYPE_FOURCC);
+ gst_value_set_fourcc (&value, GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'));
+ gst_value_list_append_value (&list_value, &value);
+ g_value_unset (&value);
+ gst_structure_set_value (structure, "format", &list_value);
+ } else if (direction == GST_PAD_SRC) {
+ gst_structure_set_value (structure, "format", &list_value);
+ }
if (gst_structure_get_int (structure, "width", &tmp))
gst_structure_set (structure, "width", G_TYPE_INT,
- tmp + direction * (video_box->box_left + video_box->box_right), NULL);
+ tmp + dir * (video_box->box_left + video_box->box_right), NULL);
if (gst_structure_get_int (structure, "height", &tmp))
gst_structure_set (structure, "height", G_TYPE_INT,
- tmp + direction * (video_box->box_top + video_box->box_bottom), NULL);
+ tmp + dir * (video_box->box_top + video_box->box_bottom), NULL);
}
+ g_value_unset (&list_value);
+
+ GST_DEBUG_OBJECT (video_box, "direction %d, transformed %" GST_PTR_FORMAT
+ " to %" GST_PTR_FORMAT, direction, from, to);
+
return to;
}
ret &= gst_structure_get_int (structure, "height", &video_box->out_height);
ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
- video_box->use_alpha = fourcc == GST_STR_FOURCC ("AYUV");
+ if (fourcc == GST_STR_FOURCC ("AYUV")) {
+ video_box->use_alpha = TRUE;
+ } else {
+ if (video_box->box_left == 0 && video_box->box_right == 0 &&
+ video_box->box_top == 0 && video_box->box_bottom == 0) {
+ gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box), TRUE);
+ GST_LOG ("we are using passthrough");
+ } else {
+ gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (video_box),
+ FALSE);
+ GST_LOG ("we are not using passthrough");
+ }
+ }
return ret;
}
-#define ROUND_UP_2(x) (((x)+1)&~1)
-#define ROUND_UP_4(x) (((x)+3)&~3)
-#define ROUND_UP_8(x) (((x)+7)&~7)
-
/* see gst-plugins/gst/games/gstvideoimage.c, paint_setup_I420() */
-#define GST_VIDEO_I420_Y_ROWSTRIDE(width) (ROUND_UP_4(width))
-#define GST_VIDEO_I420_U_ROWSTRIDE(width) (ROUND_UP_8(width)/2)
-#define GST_VIDEO_I420_V_ROWSTRIDE(width) ((ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
+#define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
+#define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
+#define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
#define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
-#define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*ROUND_UP_2(h)))
-#define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*ROUND_UP_2(h)/2))
+#define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
+#define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
-#define GST_VIDEO_I420_SIZE(w,h) (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*ROUND_UP_2(h)/2))
+#define GST_VIDEO_I420_SIZE(w,h) (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
-static guint
-gst_video_box_get_size (GstBaseTransform * trans)
+static gboolean
+gst_video_box_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
+ guint * size)
{
- guint size;
GstVideoBox *video_box;
+ GstStructure *structure = NULL;
+ guint32 fourcc;
+ gint width, height;
+ g_return_val_if_fail (size, FALSE);
video_box = GST_VIDEO_BOX (trans);
- if (video_box->use_alpha) {
- size = video_box->out_height * video_box->out_height * 4;
- } else {
- size = GST_VIDEO_I420_SIZE (video_box->out_width, video_box->out_height);
+ structure = gst_caps_get_structure (caps, 0);
+ gst_structure_get_fourcc (structure, "format", &fourcc);
+ gst_structure_get_int (structure, "width", &width);
+ gst_structure_get_int (structure, "height", &height);
+
+ switch (fourcc) {
+ case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'):
+ *size = width * height * 4;
+ break;
+ case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+ *size = GST_VIDEO_I420_SIZE (width, height);
+ break;
+ default:
+ return FALSE;
+ break;
}
- return size;
+
+ return TRUE;
}
static int yuv_colors_Y[] = { 16, 150, 29 };
/* top border */
for (j = 0; j < bt; j++) {
- memset (dest, fill_color, dest_width);
+ oil_splat_u8_ns (dest, &fill_color, dest_width);
dest += dest_stride;
}
/* copy and add left and right border */
for (j = 0; j < src_crop_height; j++) {
- memset (dest, fill_color, bl);
- memcpy (dest + bl, src, src_crop_width);
- memset (dest + bl + src_crop_width, fill_color, br);
+ oil_splat_u8_ns (dest, &fill_color, bl);
+ oil_memcpy (dest + bl, src, src_crop_width);
+ oil_splat_u8_ns (dest + bl + src_crop_width, &fill_color, br);
dest += dest_stride;
src += src_stride;
}
/* bottom border */
for (j = 0; j < bb; j++) {
- memset (dest, fill_color, dest_width);
+ oil_splat_u8_ns (dest, &fill_color, dest_width);
dest += dest_stride;
}
}
/* Note the source image is always I420, we
* are converting to AYUV on the fly here */
-
static void
gst_video_box_ayuv (GstVideoBox * video_box, guint8 * src, guint8 * dest)
{
guint8 *srcY, *srcU, *srcV;
gint crop_width, crop_width2, crop_height;
gint out_width, out_height;
- gint src_stride, src_stride2;
+ gint src_stridey, src_strideu, src_stridev;
gint br, bl, bt, bb;
gint colorY, colorU, colorV;
gint i, j;
out_width = video_box->out_width;
out_height = video_box->out_height;
- src_stride = GST_VIDEO_I420_Y_ROWSTRIDE (video_box->in_width);
- src_stride2 = src_stride / 2;
+ src_stridey = GST_VIDEO_I420_Y_ROWSTRIDE (video_box->in_width);
+ src_strideu = GST_VIDEO_I420_U_ROWSTRIDE (video_box->in_width);
+ src_stridev = GST_VIDEO_I420_V_ROWSTRIDE (video_box->in_width);
crop_width =
video_box->in_width - (video_box->crop_left + video_box->crop_right);
srcY =
src + GST_VIDEO_I420_Y_OFFSET (video_box->in_width, video_box->in_height);
- srcY += src_stride * video_box->crop_top + video_box->crop_left;
+ srcY += src_stridey * video_box->crop_top + video_box->crop_left;
srcU =
src + GST_VIDEO_I420_U_OFFSET (video_box->in_width, video_box->in_height);
- srcU += src_stride2 * (video_box->crop_top / 2) + (video_box->crop_left / 2);
+ srcU += src_strideu * (video_box->crop_top / 2) + (video_box->crop_left / 2);
srcV =
src + GST_VIDEO_I420_V_OFFSET (video_box->in_width, video_box->in_height);
- srcV += src_stride2 * (video_box->crop_top / 2) + (video_box->crop_left / 2);
+ srcV += src_stridev * (video_box->crop_top / 2) + (video_box->crop_left / 2);
colorY = yuv_colors_Y[video_box->fill_type];
colorU = yuv_colors_U[video_box->fill_type];
colorV);
/* top border */
- for (i = 0; i < bt; i++) {
- for (j = 0; j < out_width; j++) {
- *destp++ = ayuv;
- }
+ if (bt) {
+ size_t nb_pixels = bt * out_width;
+
+ oil_splat_u32_ns (destp, &ayuv, nb_pixels);
+ destp += nb_pixels;
}
for (i = 0; i < crop_height; i++) {
/* left border */
- for (j = 0; j < bl; j++) {
- *destp++ = ayuv;
+ if (bl) {
+ oil_splat_u32_ns (destp, &ayuv, bl);
+ destp += bl;
}
dest = (guint8 *) destp;
/* center */
+ /* We can splat the alpha channel for the whole line */
+ oil_splat_u8 (dest, 4, &i_alpha, crop_width);
for (j = 0; j < crop_width2; j++) {
- *dest++ = i_alpha;
+ dest++;
*dest++ = *srcY++;
*dest++ = *srcU;
*dest++ = *srcV;
- *dest++ = i_alpha;
+ dest++;
*dest++ = *srcY++;
*dest++ = *srcU++;
*dest++ = *srcV++;
srcU -= crop_width2;
srcV -= crop_width2;
} else {
- srcU += src_stride2 - crop_width2;
- srcV += src_stride2 - crop_width2;
+ srcU += src_strideu - crop_width2;
+ srcV += src_stridev - crop_width2;
}
- srcY += src_stride - crop_width;
+ srcY += src_stridey - crop_width;
destp = (guint32 *) dest;
/* right border */
- for (j = 0; j < br; j++) {
- *destp++ = ayuv;
+ if (br) {
+ oil_splat_u32_ns (destp, &ayuv, br);
+ destp += br;
}
}
/* bottom border */
- for (i = 0; i < bb; i++) {
- for (j = 0; j < out_width; j++) {
- *destp++ = ayuv;
- }
+ if (bb) {
+ size_t nb_pixels = bb * out_width;
+
+ oil_splat_u32_ns (destp, &ayuv, nb_pixels);
+ destp += nb_pixels;
}
}
GST_VERSION_MINOR,
"videobox",
"resizes a video by adding borders or cropping",
- plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)