mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-28 04:31:06 +00:00
videoscale: Add support for adding black borders to keep the DAR if necessary
Fixes bug #617506.
This commit is contained in:
parent
619e5b6e44
commit
52e711b11d
7 changed files with 804 additions and 198 deletions
|
@ -7,7 +7,8 @@ libgstvideoscale_la_SOURCES = \
|
|||
gstvideoscale.c \
|
||||
vs_image.c \
|
||||
vs_scanline.c \
|
||||
vs_4tap.c
|
||||
vs_4tap.c \
|
||||
vs_fill_borders.c
|
||||
|
||||
nodist_libgstvideoscale_la_SOURCES = $(ORC_NODIST_SOURCES)
|
||||
|
||||
|
@ -22,6 +23,6 @@ noinst_HEADERS = \
|
|||
gstvideoscale.h \
|
||||
vs_image.h \
|
||||
vs_scanline.h \
|
||||
vs_4tap.h
|
||||
|
||||
vs_4tap.h \
|
||||
vs_fill_borders.h
|
||||
|
||||
|
|
|
@ -48,6 +48,26 @@
|
|||
* Last reviewed on 2006-03-02 (0.10.4)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Formulas for PAR, DAR, width and height relations:
|
||||
*
|
||||
* dar_n w par_n
|
||||
* ----- = - * -----
|
||||
* dar_d h par_d
|
||||
*
|
||||
* par_n h dar_n
|
||||
* ----- = - * -----
|
||||
* par_d w dar_d
|
||||
*
|
||||
* dar_n par_d
|
||||
* w = h * ----- * -----
|
||||
* dar_d par_n
|
||||
*
|
||||
* dar_d par_n
|
||||
* h = w * ----- * -----
|
||||
* dar_n par_d
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
@ -61,17 +81,19 @@
|
|||
#include "gstvideoscale.h"
|
||||
#include "vs_image.h"
|
||||
#include "vs_4tap.h"
|
||||
|
||||
#include "vs_fill_borders.h"
|
||||
|
||||
/* debug variable definition */
|
||||
GST_DEBUG_CATEGORY (video_scale_debug);
|
||||
|
||||
#define DEFAULT_PROP_METHOD GST_VIDEO_SCALE_BILINEAR
|
||||
#define DEFAULT_PROP_METHOD GST_VIDEO_SCALE_BILINEAR
|
||||
#define DEFAULT_PROP_ADD_BORDERS FALSE
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_METHOD
|
||||
PROP_METHOD,
|
||||
PROP_ADD_BORDERS
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
|
@ -220,6 +242,12 @@ gst_video_scale_class_init (GstVideoScaleClass * klass)
|
|||
GST_TYPE_VIDEO_SCALE_METHOD, DEFAULT_PROP_METHOD,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_ADD_BORDERS,
|
||||
g_param_spec_boolean ("borders", "Add Borders",
|
||||
"Add black borders if necessary to keep the display aspect ratio",
|
||||
DEFAULT_PROP_ADD_BORDERS,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
trans_class->transform_caps =
|
||||
GST_DEBUG_FUNCPTR (gst_video_scale_transform_caps);
|
||||
trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_scale_set_caps);
|
||||
|
@ -235,6 +263,7 @@ gst_video_scale_init (GstVideoScale * videoscale, GstVideoScaleClass * klass)
|
|||
{
|
||||
videoscale->tmp_buf = NULL;
|
||||
videoscale->method = DEFAULT_PROP_METHOD;
|
||||
videoscale->add_borders = DEFAULT_PROP_ADD_BORDERS;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -258,6 +287,12 @@ gst_video_scale_set_property (GObject * object, guint prop_id,
|
|||
vscale->method = g_value_get_enum (value);
|
||||
GST_OBJECT_UNLOCK (vscale);
|
||||
break;
|
||||
case PROP_ADD_BORDERS:
|
||||
GST_OBJECT_LOCK (vscale);
|
||||
vscale->add_borders = g_value_get_boolean (value);
|
||||
GST_OBJECT_UNLOCK (vscale);
|
||||
gst_base_transform_reconfigure (GST_BASE_TRANSFORM_CAST (vscale));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -276,6 +311,11 @@ gst_video_scale_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
g_value_set_enum (value, vscale->method);
|
||||
GST_OBJECT_UNLOCK (vscale);
|
||||
break;
|
||||
case PROP_ADD_BORDERS:
|
||||
GST_OBJECT_LOCK (vscale);
|
||||
g_value_set_boolean (value, vscale->add_borders);
|
||||
GST_OBJECT_UNLOCK (vscale);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -313,17 +353,6 @@ gst_video_scale_transform_caps (GstBaseTransform * trans,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_video_scale_setup_vs_image (VSImage * image, GstVideoFormat format,
|
||||
gint component, gint width, gint height)
|
||||
{
|
||||
image->width =
|
||||
gst_video_format_get_component_width (format, component, width);
|
||||
image->height =
|
||||
gst_video_format_get_component_height (format, component, height);
|
||||
image->stride = gst_video_format_get_row_stride (format, component, width);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_video_scale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
|
||||
{
|
||||
|
@ -341,21 +370,11 @@ gst_video_scale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
|
|||
if (!ret)
|
||||
goto done;
|
||||
|
||||
|
||||
videoscale->src_size = gst_video_format_get_size (videoscale->format,
|
||||
videoscale->from_width, videoscale->from_height);
|
||||
videoscale->dest_size = gst_video_format_get_size (videoscale->format,
|
||||
videoscale->to_width, videoscale->to_height);
|
||||
|
||||
gst_video_scale_setup_vs_image (&videoscale->src, videoscale->format, 0,
|
||||
videoscale->from_width, videoscale->from_height);
|
||||
gst_video_scale_setup_vs_image (&videoscale->dest, videoscale->format, 0,
|
||||
videoscale->to_width, videoscale->to_height);
|
||||
|
||||
if (videoscale->tmp_buf)
|
||||
g_free (videoscale->tmp_buf);
|
||||
videoscale->tmp_buf = g_malloc (videoscale->dest.stride * 4);
|
||||
|
||||
if (!gst_video_parse_caps_pixel_aspect_ratio (in, &from_par_n, &from_par_d))
|
||||
from_par_n = from_par_d = 1;
|
||||
if (!gst_video_parse_caps_pixel_aspect_ratio (out, &to_par_n, &to_par_d))
|
||||
|
@ -367,24 +386,53 @@ gst_video_scale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out)
|
|||
from_dar_n = from_dar_d = -1;
|
||||
}
|
||||
|
||||
if (!gst_util_fraction_multiply (videoscale->to_width, videoscale->to_height,
|
||||
to_par_n, to_par_d, &to_dar_n, &to_dar_d)) {
|
||||
if (!gst_util_fraction_multiply (videoscale->to_width,
|
||||
videoscale->to_height, to_par_n, to_par_d, &to_dar_n, &to_dar_d)) {
|
||||
to_dar_n = to_dar_d = -1;
|
||||
}
|
||||
|
||||
if (to_dar_n != from_dar_n || to_dar_d != from_dar_d)
|
||||
GST_WARNING_OBJECT (videoscale, "Can't keep DAR!");
|
||||
videoscale->borders_w = videoscale->borders_h = 0;
|
||||
if (to_dar_n != from_dar_n || to_dar_d != from_dar_d) {
|
||||
if (videoscale->add_borders) {
|
||||
gint n, d, to_h, to_w;
|
||||
|
||||
if (from_dar_n != -1 && from_dar_d != -1
|
||||
&& gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_n,
|
||||
to_par_d, &n, &d)) {
|
||||
to_h = gst_util_uint64_scale_int (videoscale->to_width, d, n);
|
||||
if (to_h <= videoscale->to_height) {
|
||||
videoscale->borders_h = videoscale->to_height - to_h;
|
||||
videoscale->borders_w = 0;
|
||||
} else {
|
||||
to_w = gst_util_uint64_scale_int (videoscale->to_height, n, d);
|
||||
g_assert (to_w <= videoscale->to_width);
|
||||
videoscale->borders_h = 0;
|
||||
videoscale->borders_w = videoscale->to_width - to_w;
|
||||
}
|
||||
} else {
|
||||
GST_WARNING_OBJECT (videoscale, "Can't calculate borders");
|
||||
}
|
||||
} else {
|
||||
GST_WARNING_OBJECT (videoscale, "Can't keep DAR!");
|
||||
}
|
||||
}
|
||||
|
||||
if (videoscale->tmp_buf)
|
||||
g_free (videoscale->tmp_buf);
|
||||
videoscale->tmp_buf =
|
||||
g_malloc (gst_video_format_get_row_stride (videoscale->format, 0,
|
||||
videoscale->to_width) * 4);
|
||||
|
||||
gst_base_transform_set_passthrough (trans,
|
||||
(videoscale->from_width == videoscale->to_width
|
||||
&& videoscale->from_height == videoscale->to_height));
|
||||
|
||||
GST_DEBUG_OBJECT (videoscale, "from=%dx%d (par=%d/%d dar=%d/%d), size %d "
|
||||
"-> to=%dx%d (par=%d/%d dar=%d/%d), size %d",
|
||||
"-> to=%dx%d (par=%d/%d dar=%d/%d borders=%d:%d), size %d",
|
||||
videoscale->from_width, videoscale->from_height, from_par_n, from_par_d,
|
||||
from_dar_n, from_dar_d, videoscale->src_size, videoscale->to_width,
|
||||
videoscale->to_height, to_par_n, to_par_d, to_dar_n, to_dar_d,
|
||||
videoscale->dest_size);
|
||||
videoscale->borders_w, videoscale->borders_h, videoscale->dest_size);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
|
@ -814,33 +862,113 @@ done:
|
|||
g_value_unset (&tpar);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_video_scale_prepare_image (gint format, GstBuffer * buf,
|
||||
VSImage * img, VSImage * img_u, VSImage * img_v)
|
||||
static void
|
||||
gst_video_scale_setup_vs_image (VSImage * image, GstVideoFormat format,
|
||||
gint component, gint width, gint height, gint b_w, gint b_h, uint8_t * data)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
image->real_width =
|
||||
gst_video_format_get_component_width (format, component, width);
|
||||
image->real_height =
|
||||
gst_video_format_get_component_height (format, component, height);
|
||||
image->width =
|
||||
gst_video_format_get_component_width (format, component, MAX (1,
|
||||
width - b_w));
|
||||
image->height =
|
||||
gst_video_format_get_component_height (format, component, MAX (1,
|
||||
height - b_h));
|
||||
image->stride = gst_video_format_get_row_stride (format, component, width);
|
||||
|
||||
image->border_top = (image->real_height - image->height) / 2;
|
||||
image->border_bottom = image->real_height - image->height - image->border_top;
|
||||
|
||||
if (format == GST_VIDEO_FORMAT_YUY2 || format == GST_VIDEO_FORMAT_YVYU
|
||||
|| format == GST_VIDEO_FORMAT_UYVY) {
|
||||
g_assert (component == 0);
|
||||
|
||||
image->border_left = (image->real_width - image->width) / 2;
|
||||
|
||||
if (image->border_left % 2 == 1)
|
||||
image->border_left--;
|
||||
image->border_right = image->real_width - image->width - image->border_left;
|
||||
} else {
|
||||
image->border_left = (image->real_width - image->width) / 2;
|
||||
image->border_right = image->real_width - image->width - image->border_left;
|
||||
}
|
||||
|
||||
if (format == GST_VIDEO_FORMAT_I420
|
||||
|| format == GST_VIDEO_FORMAT_YV12
|
||||
|| format == GST_VIDEO_FORMAT_Y444
|
||||
|| format == GST_VIDEO_FORMAT_Y42B || format == GST_VIDEO_FORMAT_Y41B) {
|
||||
image->real_pixels = data + gst_video_format_get_component_offset (format,
|
||||
component, width, height);
|
||||
} else {
|
||||
g_assert (component == 0);
|
||||
image->real_pixels = data;
|
||||
}
|
||||
|
||||
image->pixels =
|
||||
image->real_pixels + image->border_top * image->stride +
|
||||
image->border_left * gst_video_format_get_pixel_stride (format,
|
||||
component);
|
||||
}
|
||||
|
||||
static const guint8 *
|
||||
_get_black_for_format (GstVideoFormat format)
|
||||
{
|
||||
static const guint8 black[][4] = {
|
||||
{255, 0, 0, 0}, /* 0 = ARGB, ABGR, xRGB, xBGR */
|
||||
{0, 0, 0, 255}, /* 1 = RGBA, BGRA, RGBx, BGRx */
|
||||
{255, 16, 128, 128}, /* 2 = AYUV */
|
||||
{0, 0, 0, 0}, /* 3 = RGB and BGR */
|
||||
{16, 128, 128, 0}, /* 4 = v301 */
|
||||
{16, 128, 16, 128}, /* 5 = YUY2, YUYV */
|
||||
{128, 16, 128, 16}, /* 6 = UYVY */
|
||||
{16, 0, 0, 0}, /* 7 = Y */
|
||||
{0, 0, 0, 0} /* 8 = RGB565, RGB666 */
|
||||
};
|
||||
|
||||
switch (format) {
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
case GST_VIDEO_FORMAT_xRGB:
|
||||
case GST_VIDEO_FORMAT_xBGR:
|
||||
return black[0];
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
case GST_VIDEO_FORMAT_BGRx:
|
||||
return black[1];
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
return black[2];
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
case GST_VIDEO_FORMAT_BGR:
|
||||
return black[3];
|
||||
case GST_VIDEO_FORMAT_v308:
|
||||
return black[4];
|
||||
case GST_VIDEO_FORMAT_YUY2:
|
||||
case GST_VIDEO_FORMAT_YVYU:
|
||||
return black[5];
|
||||
case GST_VIDEO_FORMAT_UYVY:
|
||||
return black[6];
|
||||
case GST_VIDEO_FORMAT_Y800:
|
||||
case GST_VIDEO_FORMAT_GRAY8:
|
||||
return black[7];
|
||||
case GST_VIDEO_FORMAT_GRAY16_LE:
|
||||
case GST_VIDEO_FORMAT_GRAY16_BE:
|
||||
case GST_VIDEO_FORMAT_Y16:
|
||||
return NULL; /* Handled by the caller */
|
||||
case GST_VIDEO_FORMAT_I420:
|
||||
case GST_VIDEO_FORMAT_YV12:
|
||||
case GST_VIDEO_FORMAT_Y444:
|
||||
case GST_VIDEO_FORMAT_Y42B:
|
||||
case GST_VIDEO_FORMAT_Y41B:
|
||||
gst_video_scale_setup_vs_image (img_u, format, 1, img->width,
|
||||
img->height);
|
||||
gst_video_scale_setup_vs_image (img_v, format, 2, img->width,
|
||||
img->height);
|
||||
img_u->pixels =
|
||||
GST_BUFFER_DATA (buf) + gst_video_format_get_component_offset (format,
|
||||
1, img->width, img->height);
|
||||
img_v->pixels =
|
||||
GST_BUFFER_DATA (buf) + gst_video_format_get_component_offset (format,
|
||||
2, img->width, img->height);
|
||||
break;
|
||||
return black[4]; /* Y, U, V, 0 */
|
||||
case GST_VIDEO_FORMAT_RGB16:
|
||||
case GST_VIDEO_FORMAT_RGB15:
|
||||
return black[8];
|
||||
default:
|
||||
break;
|
||||
return NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -849,195 +977,230 @@ gst_video_scale_transform (GstBaseTransform * trans, GstBuffer * in,
|
|||
{
|
||||
GstVideoScale *videoscale = GST_VIDEO_SCALE (trans);
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
VSImage dest = videoscale->dest;
|
||||
VSImage src = videoscale->src;
|
||||
VSImage dest = { NULL, };
|
||||
VSImage src = { NULL, };
|
||||
VSImage dest_u = { NULL, };
|
||||
VSImage dest_v = { NULL, };
|
||||
VSImage src_u = { NULL, };
|
||||
VSImage src_v = { NULL, };
|
||||
gint method;
|
||||
const guint8 *black = _get_black_for_format (videoscale->format);
|
||||
gboolean add_borders;
|
||||
|
||||
GST_OBJECT_LOCK (videoscale);
|
||||
method = videoscale->method;
|
||||
add_borders = videoscale->add_borders;
|
||||
GST_OBJECT_UNLOCK (videoscale);
|
||||
|
||||
src.pixels = GST_BUFFER_DATA (in);
|
||||
dest.pixels = GST_BUFFER_DATA (out);
|
||||
gst_video_scale_setup_vs_image (&src, videoscale->format, 0,
|
||||
videoscale->from_width, videoscale->from_height, 0, 0,
|
||||
GST_BUFFER_DATA (in));
|
||||
gst_video_scale_setup_vs_image (&dest, videoscale->format, 0,
|
||||
videoscale->to_width, videoscale->to_height, videoscale->borders_w,
|
||||
videoscale->borders_h, GST_BUFFER_DATA (out));
|
||||
|
||||
if (src.height < 4 && method == GST_VIDEO_SCALE_4TAP)
|
||||
method = GST_VIDEO_SCALE_BILINEAR;
|
||||
if (videoscale->format == GST_VIDEO_FORMAT_I420
|
||||
|| videoscale->format == GST_VIDEO_FORMAT_YV12
|
||||
|| videoscale->format == GST_VIDEO_FORMAT_Y444
|
||||
|| videoscale->format == GST_VIDEO_FORMAT_Y42B
|
||||
|| videoscale->format == GST_VIDEO_FORMAT_Y41B) {
|
||||
gst_video_scale_setup_vs_image (&src_u, videoscale->format, 1,
|
||||
videoscale->from_width, videoscale->from_height, 0, 0,
|
||||
GST_BUFFER_DATA (in));
|
||||
gst_video_scale_setup_vs_image (&src_v, videoscale->format, 2,
|
||||
videoscale->from_width, videoscale->from_height, 0, 0,
|
||||
GST_BUFFER_DATA (in));
|
||||
gst_video_scale_setup_vs_image (&dest_u, videoscale->format, 1,
|
||||
videoscale->to_width, videoscale->to_height, videoscale->borders_w,
|
||||
videoscale->borders_h, GST_BUFFER_DATA (out));
|
||||
gst_video_scale_setup_vs_image (&dest_v, videoscale->format, 2,
|
||||
videoscale->to_width, videoscale->to_height, videoscale->borders_w,
|
||||
videoscale->borders_h, GST_BUFFER_DATA (out));
|
||||
}
|
||||
|
||||
gst_video_scale_prepare_image (videoscale->format, in, &videoscale->src,
|
||||
&src_u, &src_v);
|
||||
gst_video_scale_prepare_image (videoscale->format, out, &videoscale->dest,
|
||||
&dest_u, &dest_v);
|
||||
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
GST_LOG_OBJECT (videoscale, "doing nearest scaling");
|
||||
switch (videoscale->format) {
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
case GST_VIDEO_FORMAT_xRGB:
|
||||
case GST_VIDEO_FORMAT_BGRx:
|
||||
case GST_VIDEO_FORMAT_xBGR:
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
switch (videoscale->format) {
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
case GST_VIDEO_FORMAT_xRGB:
|
||||
case GST_VIDEO_FORMAT_BGRx:
|
||||
case GST_VIDEO_FORMAT_xBGR:
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
if (add_borders)
|
||||
vs_fill_borders_RGBA (&dest, black);
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
vs_image_scale_nearest_RGBA (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
case GST_VIDEO_FORMAT_BGR:
|
||||
case GST_VIDEO_FORMAT_v308:
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
vs_image_scale_linear_RGBA (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
vs_image_scale_4tap_RGBA (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
default:
|
||||
goto unknown_mode;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
case GST_VIDEO_FORMAT_BGR:
|
||||
case GST_VIDEO_FORMAT_v308:
|
||||
if (add_borders)
|
||||
vs_fill_borders_RGB (&dest, black);
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
vs_image_scale_nearest_RGB (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_YUY2:
|
||||
case GST_VIDEO_FORMAT_YVYU:
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
vs_image_scale_linear_RGB (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
vs_image_scale_4tap_RGB (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
default:
|
||||
goto unknown_mode;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_YUY2:
|
||||
case GST_VIDEO_FORMAT_YVYU:
|
||||
if (add_borders)
|
||||
vs_fill_borders_YUYV (&dest, black);
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
vs_image_scale_nearest_YUYV (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_UYVY:
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
vs_image_scale_linear_YUYV (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
vs_image_scale_4tap_YUYV (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
default:
|
||||
goto unknown_mode;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_UYVY:
|
||||
if (add_borders)
|
||||
vs_fill_borders_UYVY (&dest, black);
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
vs_image_scale_nearest_UYVY (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_Y800:
|
||||
case GST_VIDEO_FORMAT_GRAY8:
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
vs_image_scale_linear_UYVY (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
vs_image_scale_4tap_UYVY (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
default:
|
||||
goto unknown_mode;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_Y800:
|
||||
case GST_VIDEO_FORMAT_GRAY8:
|
||||
if (add_borders)
|
||||
vs_fill_borders_Y (&dest, black);
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_GRAY16_LE:
|
||||
case GST_VIDEO_FORMAT_GRAY16_BE:
|
||||
case GST_VIDEO_FORMAT_Y16:
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
vs_image_scale_4tap_Y (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
default:
|
||||
goto unknown_mode;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_GRAY16_LE:
|
||||
case GST_VIDEO_FORMAT_GRAY16_BE:
|
||||
case GST_VIDEO_FORMAT_Y16:
|
||||
if (add_borders)
|
||||
vs_fill_borders_Y16 (&dest, 0);
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
vs_image_scale_nearest_Y16 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_I420:
|
||||
case GST_VIDEO_FORMAT_YV12:
|
||||
case GST_VIDEO_FORMAT_Y444:
|
||||
case GST_VIDEO_FORMAT_Y42B:
|
||||
case GST_VIDEO_FORMAT_Y41B:
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
vs_image_scale_linear_Y16 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
vs_image_scale_4tap_Y16 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
default:
|
||||
goto unknown_mode;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_I420:
|
||||
case GST_VIDEO_FORMAT_YV12:
|
||||
case GST_VIDEO_FORMAT_Y444:
|
||||
case GST_VIDEO_FORMAT_Y42B:
|
||||
case GST_VIDEO_FORMAT_Y41B:
|
||||
if (add_borders) {
|
||||
vs_fill_borders_Y (&dest, black);
|
||||
vs_fill_borders_Y (&dest_u, black + 1);
|
||||
vs_fill_borders_Y (&dest_v, black + 2);
|
||||
}
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf);
|
||||
vs_image_scale_nearest_Y (&dest_u, &src_u, videoscale->tmp_buf);
|
||||
vs_image_scale_nearest_Y (&dest_v, &src_v, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB16:
|
||||
vs_image_scale_nearest_RGB565 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB15:
|
||||
vs_image_scale_nearest_RGB555 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
default:
|
||||
goto unsupported;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
GST_LOG_OBJECT (videoscale, "doing bilinear scaling");
|
||||
switch (videoscale->format) {
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
case GST_VIDEO_FORMAT_xRGB:
|
||||
case GST_VIDEO_FORMAT_BGRx:
|
||||
case GST_VIDEO_FORMAT_xBGR:
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
vs_image_scale_linear_RGBA (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
case GST_VIDEO_FORMAT_BGR:
|
||||
case GST_VIDEO_FORMAT_v308:
|
||||
vs_image_scale_linear_RGB (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_YUY2:
|
||||
case GST_VIDEO_FORMAT_YVYU:
|
||||
vs_image_scale_linear_YUYV (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_UYVY:
|
||||
vs_image_scale_linear_UYVY (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_Y800:
|
||||
case GST_VIDEO_FORMAT_GRAY8:
|
||||
vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_GRAY16_LE:
|
||||
case GST_VIDEO_FORMAT_GRAY16_BE:
|
||||
case GST_VIDEO_FORMAT_Y16:
|
||||
vs_image_scale_linear_Y16 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_I420:
|
||||
case GST_VIDEO_FORMAT_YV12:
|
||||
case GST_VIDEO_FORMAT_Y444:
|
||||
case GST_VIDEO_FORMAT_Y42B:
|
||||
case GST_VIDEO_FORMAT_Y41B:
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf);
|
||||
vs_image_scale_linear_Y (&dest_u, &src_u, videoscale->tmp_buf);
|
||||
vs_image_scale_linear_Y (&dest_v, &src_v, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB16:
|
||||
vs_image_scale_linear_RGB565 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB15:
|
||||
vs_image_scale_linear_RGB555 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
default:
|
||||
goto unsupported;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
GST_LOG_OBJECT (videoscale, "doing 4tap scaling");
|
||||
|
||||
switch (videoscale->format) {
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
case GST_VIDEO_FORMAT_xRGB:
|
||||
case GST_VIDEO_FORMAT_BGRx:
|
||||
case GST_VIDEO_FORMAT_xBGR:
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
vs_image_scale_4tap_RGBA (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
case GST_VIDEO_FORMAT_BGR:
|
||||
case GST_VIDEO_FORMAT_v308:
|
||||
vs_image_scale_4tap_RGB (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_YUY2:
|
||||
case GST_VIDEO_FORMAT_YVYU:
|
||||
vs_image_scale_4tap_YUYV (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_UYVY:
|
||||
vs_image_scale_4tap_UYVY (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_Y800:
|
||||
case GST_VIDEO_FORMAT_GRAY8:
|
||||
vs_image_scale_4tap_Y (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_GRAY16_LE:
|
||||
case GST_VIDEO_FORMAT_GRAY16_BE:
|
||||
case GST_VIDEO_FORMAT_Y16:
|
||||
vs_image_scale_4tap_Y16 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_I420:
|
||||
case GST_VIDEO_FORMAT_YV12:
|
||||
case GST_VIDEO_FORMAT_Y444:
|
||||
case GST_VIDEO_FORMAT_Y42B:
|
||||
case GST_VIDEO_FORMAT_Y41B:
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
vs_image_scale_4tap_Y (&dest, &src, videoscale->tmp_buf);
|
||||
vs_image_scale_4tap_Y (&dest_u, &src_u, videoscale->tmp_buf);
|
||||
vs_image_scale_4tap_Y (&dest_v, &src_v, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB16:
|
||||
default:
|
||||
goto unknown_mode;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB16:
|
||||
if (add_borders)
|
||||
vs_fill_borders_RGB565 (&dest, black);
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
vs_image_scale_nearest_RGB565 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
vs_image_scale_linear_RGB565 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
vs_image_scale_4tap_RGB565 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB15:
|
||||
default:
|
||||
goto unknown_mode;
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_RGB15:
|
||||
if (add_borders)
|
||||
vs_fill_borders_RGB555 (&dest, black);
|
||||
switch (method) {
|
||||
case GST_VIDEO_SCALE_NEAREST:
|
||||
vs_image_scale_nearest_RGB555 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_BILINEAR:
|
||||
vs_image_scale_linear_RGB555 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
case GST_VIDEO_SCALE_4TAP:
|
||||
vs_image_scale_4tap_RGB555 (&dest, &src, videoscale->tmp_buf);
|
||||
break;
|
||||
default:
|
||||
goto unsupported;
|
||||
goto unknown_mode;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto unknown_mode;
|
||||
goto unsupported;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (videoscale, "pushing buffer of %d bytes",
|
||||
|
|
|
@ -68,6 +68,7 @@ struct _GstVideoScale {
|
|||
GstVideoFilter element;
|
||||
|
||||
GstVideoScaleMethod method;
|
||||
gboolean add_borders;
|
||||
|
||||
/* negotiated stuff */
|
||||
GstVideoFormat format;
|
||||
|
@ -78,9 +79,9 @@ struct _GstVideoScale {
|
|||
guint src_size;
|
||||
guint dest_size;
|
||||
|
||||
VSImage src;
|
||||
VSImage dest;
|
||||
|
||||
gint borders_h;
|
||||
gint borders_w;
|
||||
|
||||
/*< private >*/
|
||||
guint8 *tmp_buf;
|
||||
};
|
||||
|
|
|
@ -30,3 +30,15 @@ addl t1, t1, t2
|
|||
shrul t1, t1, 16
|
||||
convlw d1, t1
|
||||
|
||||
.function orc_splat_u16
|
||||
.dest 2 d1
|
||||
.param 2 p1
|
||||
|
||||
copyw d1, p1
|
||||
|
||||
.function orc_splat_u32
|
||||
.dest 4 d1
|
||||
.param 4 p1
|
||||
|
||||
copyl d1, p1
|
||||
|
||||
|
|
381
gst/videoscale/vs_fill_borders.c
Normal file
381
gst/videoscale/vs_fill_borders.c
Normal file
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* Image Scaling Functions
|
||||
* Copyright (c) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vs_fill_borders.h"
|
||||
#include "gstvideoscaleorc.h"
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
#define READ_UINT32(ptr) GST_READ_UINT32_LE(ptr)
|
||||
#define READ_UINT16(ptr) GST_READ_UINT16_LE(ptr)
|
||||
#else
|
||||
#define READ_UINT32(ptr) GST_READ_UINT32_BE(ptr)
|
||||
#define READ_UINT16(ptr) GST_READ_UINT16_BE(ptr)
|
||||
#endif
|
||||
|
||||
void
|
||||
vs_fill_borders_RGBA (const VSImage * dest, const uint8_t * val)
|
||||
{
|
||||
int i;
|
||||
int top = dest->border_top, bottom = dest->border_bottom;
|
||||
int left = dest->border_left, right = dest->border_right;
|
||||
int width = dest->width;
|
||||
int height = dest->height;
|
||||
int real_width = dest->real_width;
|
||||
int stride = dest->stride;
|
||||
int tmp, tmp2;
|
||||
uint8_t *data;
|
||||
uint32_t v = READ_UINT32 (val);
|
||||
|
||||
data = dest->real_pixels;
|
||||
for (i = 0; i < top; i++) {
|
||||
orc_splat_u32 ((uint32_t *) data, v, real_width);
|
||||
data += stride;
|
||||
}
|
||||
|
||||
if (left || right) {
|
||||
tmp = height;
|
||||
tmp2 = (left + width) * 4;
|
||||
for (i = 0; i < tmp; i++) {
|
||||
orc_splat_u32 ((uint32_t *) data, v, left);
|
||||
orc_splat_u32 ((uint32_t *) (data + tmp2), v, right);
|
||||
data += stride;
|
||||
}
|
||||
} else {
|
||||
data += stride * height;
|
||||
}
|
||||
|
||||
for (i = 0; i < bottom; i++) {
|
||||
orc_splat_u32 ((uint32_t *) data, v, real_width);
|
||||
data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_memset_u24 (uint8_t * data, uint8_t val1, uint8_t val2, uint8_t val3,
|
||||
unsigned int n)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
data[0] = val1;
|
||||
data[1] = val2;
|
||||
data[2] = val3;
|
||||
data += 3;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vs_fill_borders_RGB (const VSImage * dest, const uint8_t * val)
|
||||
{
|
||||
int i;
|
||||
int top = dest->border_top, bottom = dest->border_bottom;
|
||||
int left = dest->border_left, right = dest->border_right;
|
||||
int width = dest->width;
|
||||
int height = dest->height;
|
||||
int real_width = dest->real_width;
|
||||
int stride = dest->stride;
|
||||
int tmp, tmp2;
|
||||
uint8_t *data;
|
||||
|
||||
data = dest->real_pixels;
|
||||
for (i = 0; i < top; i++) {
|
||||
_memset_u24 (data, val[0], val[1], val[2], real_width);
|
||||
data += stride;
|
||||
}
|
||||
|
||||
if (left || right) {
|
||||
tmp = height;
|
||||
tmp2 = (left + width) * 3;
|
||||
for (i = 0; i < tmp; i++) {
|
||||
_memset_u24 (data, val[0], val[1], val[2], left);
|
||||
_memset_u24 (data + tmp2, val[0], val[1], val[2], right);
|
||||
data += stride;
|
||||
}
|
||||
} else {
|
||||
data += stride * height;
|
||||
}
|
||||
|
||||
for (i = 0; i < bottom; i++) {
|
||||
_memset_u24 (data, val[0], val[1], val[2], real_width);
|
||||
data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vs_fill_borders_YUYV (const VSImage * dest, const uint8_t * val)
|
||||
{
|
||||
int i, j;
|
||||
int top = dest->border_top, bottom = dest->border_bottom;
|
||||
int left = dest->border_left, right = dest->border_right;
|
||||
int width = dest->width;
|
||||
int height = dest->height;
|
||||
int real_width = dest->real_width;
|
||||
int stride = dest->stride;
|
||||
int tmp, tmp2;
|
||||
uint8_t *data;
|
||||
|
||||
data = dest->real_pixels;
|
||||
for (i = 0; i < top; i++) {
|
||||
for (j = 0; j < real_width; j++) {
|
||||
data[2 * j] = val[0];
|
||||
data[2 * j + 1] = (j % 2 == 0) ? val[1] : val[3];
|
||||
}
|
||||
data += stride;
|
||||
}
|
||||
|
||||
if (left || right) {
|
||||
tmp = height;
|
||||
tmp2 = (left + width) * 2;
|
||||
for (i = 0; i < tmp; i++) {
|
||||
for (j = 0; j < left; j++) {
|
||||
data[2 * j] = val[0];
|
||||
data[2 * j + 1] = (j % 2 == 0) ? val[1] : val[3];
|
||||
}
|
||||
for (j = 0; j < right; j++) {
|
||||
data[tmp2 + 2 * j] = val[0];
|
||||
data[tmp2 + 2 * j + 1] = (j % 2 == 0) ? val[1] : val[3];
|
||||
}
|
||||
data += stride;
|
||||
}
|
||||
} else {
|
||||
data += stride * height;
|
||||
}
|
||||
|
||||
for (i = 0; i < bottom; i++) {
|
||||
for (j = 0; j < real_width; j++) {
|
||||
data[2 * j] = val[0];
|
||||
data[2 * j + 1] = (j % 2 == 0) ? val[1] : val[3];
|
||||
}
|
||||
data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vs_fill_borders_UYVY (const VSImage * dest, const uint8_t * val)
|
||||
{
|
||||
int i, j;
|
||||
int top = dest->border_top, bottom = dest->border_bottom;
|
||||
int left = dest->border_left, right = dest->border_right;
|
||||
int width = dest->width;
|
||||
int height = dest->height;
|
||||
int real_width = dest->real_width;
|
||||
int stride = dest->stride;
|
||||
int tmp, tmp2;
|
||||
uint8_t *data;
|
||||
|
||||
data = dest->real_pixels;
|
||||
for (i = 0; i < top; i++) {
|
||||
for (j = 0; j < real_width; j++) {
|
||||
data[2 * j] = (j % 2 == 0) ? val[0] : val[2];
|
||||
data[2 * j + 1] = val[1];
|
||||
}
|
||||
data += stride;
|
||||
}
|
||||
|
||||
if (left || right) {
|
||||
tmp = height;
|
||||
tmp2 = (left + width) * 2;
|
||||
for (i = 0; i < tmp; i++) {
|
||||
for (j = 0; j < left; j++) {
|
||||
data[2 * j] = (j % 2 == 0) ? val[0] : val[2];
|
||||
data[2 * j + 1] = val[1];
|
||||
}
|
||||
for (j = 0; j < right; j++) {
|
||||
data[tmp2 + 2 * j] = (j % 2 == 0) ? val[0] : val[2];
|
||||
data[tmp2 + 2 * j + 1] = val[1];
|
||||
}
|
||||
data += stride;
|
||||
}
|
||||
} else {
|
||||
data += stride * height;
|
||||
}
|
||||
|
||||
for (i = 0; i < bottom; i++) {
|
||||
for (j = 0; j < real_width; j++) {
|
||||
data[2 * j] = (j % 2 == 0) ? val[0] : val[2];
|
||||
data[2 * j + 1] = val[1];
|
||||
}
|
||||
data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vs_fill_borders_Y (const VSImage * dest, const uint8_t * val)
|
||||
{
|
||||
int i;
|
||||
int top = dest->border_top, bottom = dest->border_bottom;
|
||||
int left = dest->border_left, right = dest->border_right;
|
||||
int width = dest->width;
|
||||
int height = dest->height;
|
||||
int real_width = dest->real_width;
|
||||
int stride = dest->stride;
|
||||
int tmp, tmp2;
|
||||
uint8_t *data;
|
||||
|
||||
data = dest->real_pixels;
|
||||
for (i = 0; i < top; i++) {
|
||||
memset (data, *val, real_width);
|
||||
data += stride;
|
||||
}
|
||||
|
||||
if (left || right) {
|
||||
tmp = height;
|
||||
tmp2 = left + width;
|
||||
for (i = 0; i < tmp; i++) {
|
||||
memset (data, *val, left);
|
||||
memset (data + tmp2, *val, right);
|
||||
data += stride;
|
||||
}
|
||||
} else {
|
||||
data += stride * height;
|
||||
}
|
||||
|
||||
for (i = 0; i < bottom; i++) {
|
||||
memset (data, *val, real_width);
|
||||
data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vs_fill_borders_Y16 (const VSImage * dest, const uint16_t val)
|
||||
{
|
||||
int i;
|
||||
int top = dest->border_top, bottom = dest->border_bottom;
|
||||
int left = dest->border_left, right = dest->border_right;
|
||||
int width = dest->width;
|
||||
int height = dest->height;
|
||||
int real_width = dest->real_width;
|
||||
int stride = dest->stride;
|
||||
int tmp, tmp2;
|
||||
uint8_t *data;
|
||||
|
||||
data = dest->real_pixels;
|
||||
for (i = 0; i < top; i++) {
|
||||
orc_splat_u16 ((uint16_t *) data, val, real_width);
|
||||
data += stride;
|
||||
}
|
||||
|
||||
if (left || right) {
|
||||
tmp = height;
|
||||
tmp2 = (left + width) * 2;
|
||||
for (i = 0; i < tmp; i++) {
|
||||
orc_splat_u16 ((uint16_t *) data, val, left);
|
||||
orc_splat_u16 ((uint16_t *) (data + tmp2), val, right);
|
||||
data += stride;
|
||||
}
|
||||
} else {
|
||||
data += stride * height;
|
||||
}
|
||||
|
||||
for (i = 0; i < bottom; i++) {
|
||||
orc_splat_u16 ((uint16_t *) data, val, real_width);
|
||||
data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vs_fill_borders_RGB565 (const VSImage * dest, const uint8_t * val)
|
||||
{
|
||||
int i;
|
||||
int top = dest->border_top, bottom = dest->border_bottom;
|
||||
int left = dest->border_left, right = dest->border_right;
|
||||
int width = dest->width;
|
||||
int height = dest->height;
|
||||
int real_width = dest->real_width;
|
||||
int stride = dest->stride;
|
||||
int tmp, tmp2;
|
||||
uint8_t *data;
|
||||
uint16_t v = READ_UINT16 (val);
|
||||
|
||||
data = dest->real_pixels;
|
||||
for (i = 0; i < top; i++) {
|
||||
orc_splat_u16 ((uint16_t *) data, v, real_width);
|
||||
data += stride;
|
||||
}
|
||||
|
||||
if (left || right) {
|
||||
tmp = height;
|
||||
tmp2 = (left + width) * 2;
|
||||
for (i = 0; i < tmp; i++) {
|
||||
orc_splat_u16 ((uint16_t *) data, v, left);
|
||||
orc_splat_u16 ((uint16_t *) (data + tmp2), v, right);
|
||||
data += stride;
|
||||
}
|
||||
} else {
|
||||
data += stride * height;
|
||||
}
|
||||
|
||||
for (i = 0; i < bottom; i++) {
|
||||
orc_splat_u16 ((uint16_t *) data, v, real_width);
|
||||
data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vs_fill_borders_RGB555 (const VSImage * dest, const uint8_t * val)
|
||||
{
|
||||
int i;
|
||||
int top = dest->border_top, bottom = dest->border_bottom;
|
||||
int left = dest->border_left, right = dest->border_right;
|
||||
int width = dest->width;
|
||||
int height = dest->height;
|
||||
int real_width = dest->real_width;
|
||||
int stride = dest->stride;
|
||||
int tmp, tmp2;
|
||||
uint8_t *data;
|
||||
uint16_t v = READ_UINT16 (val);
|
||||
|
||||
data = dest->real_pixels;
|
||||
for (i = 0; i < top; i++) {
|
||||
orc_splat_u16 ((uint16_t *) data, v, real_width);
|
||||
data += stride;
|
||||
}
|
||||
|
||||
if (left || right) {
|
||||
tmp = height;
|
||||
tmp2 = (left + width) * 2;
|
||||
for (i = 0; i < tmp; i++) {
|
||||
orc_splat_u16 ((uint16_t *) data, v, left);
|
||||
orc_splat_u16 ((uint16_t *) (data + tmp2), v, right);
|
||||
data += stride;
|
||||
}
|
||||
} else {
|
||||
data += stride * height;
|
||||
}
|
||||
|
||||
for (i = 0; i < bottom; i++) {
|
||||
orc_splat_u16 ((uint16_t *) data, v, real_width);
|
||||
data += stride;
|
||||
}
|
||||
}
|
43
gst/videoscale/vs_fill_borders.h
Normal file
43
gst/videoscale/vs_fill_borders.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Image Scaling Functions
|
||||
* Copyright (c) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __VS_FILL_BORDERS_H__
|
||||
#define __VS_FILL_BORDERS_H__
|
||||
|
||||
#include <_stdint.h>
|
||||
#include "vs_image.h"
|
||||
|
||||
void vs_fill_borders_RGBA (const VSImage *dest, const uint8_t *val);
|
||||
void vs_fill_borders_RGB (const VSImage *dest, const uint8_t *val);
|
||||
void vs_fill_borders_YUYV (const VSImage *dest, const uint8_t *val);
|
||||
void vs_fill_borders_UYVY (const VSImage *dest, const uint8_t *val);
|
||||
void vs_fill_borders_Y (const VSImage *dest, const uint8_t *val);
|
||||
void vs_fill_borders_Y16 (const VSImage *dest, const uint16_t val);
|
||||
void vs_fill_borders_RGB565 (const VSImage *dest, const uint8_t *val);
|
||||
void vs_fill_borders_RGB555 (const VSImage *dest, const uint8_t *val);
|
||||
|
||||
#endif /* __VS_FILL_BORDERS_H__ */
|
|
@ -33,6 +33,11 @@
|
|||
typedef struct _VSImage VSImage;
|
||||
|
||||
struct _VSImage {
|
||||
uint8_t *real_pixels;
|
||||
int real_width;
|
||||
int real_height;
|
||||
int border_left, border_right;
|
||||
int border_top, border_bottom;
|
||||
uint8_t *pixels;
|
||||
int width;
|
||||
int height;
|
||||
|
|
Loading…
Reference in a new issue