/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) 2005 David Schleef <ds@schleef.org>
+ * Copyright (C) 2005-2012 David Schleef <ds@schleef.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y8 ")),
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("GREY")),
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AY64")),
- GST_STATIC_CAPS (GST_VIDEO_CAPS_ARGB_64)
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_ARGB_64),
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("NV12"))
};
#define GST_TYPE_VIDEO_SCALE_METHOD (gst_video_scale_method_get_type())
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) {
+ || format == GST_VIDEO_FORMAT_Y42B || format == GST_VIDEO_FORMAT_Y41B
+ || format == GST_VIDEO_FORMAT_NV12) {
image->real_pixels = data + gst_video_format_get_component_offset (format,
component, width, height);
} else {
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_Y41B:
+ case GST_VIDEO_FORMAT_NV12:
return black[4]; /* Y, U, V, 0 */
case GST_VIDEO_FORMAT_RGB16:
case GST_VIDEO_FORMAT_RGB15:
videoscale->to_width, videoscale->to_height, videoscale->borders_w,
videoscale->borders_h, GST_BUFFER_DATA (out));
}
+ if (videoscale->format == GST_VIDEO_FORMAT_NV12) {
+ 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 (&dest_u, videoscale->format, 1,
+ videoscale->to_width, videoscale->to_height, videoscale->borders_w,
+ videoscale->borders_h, GST_BUFFER_DATA (out));
+ }
switch (videoscale->format) {
case GST_VIDEO_FORMAT_RGBx:
goto unknown_mode;
}
break;
+ case GST_VIDEO_FORMAT_NV12:
+ switch (method) {
+ case GST_VIDEO_SCALE_NEAREST:
+ vs_image_scale_nearest_Y (&dest, &src, videoscale->tmp_buf);
+ vs_image_scale_nearest_NV12 (&dest_u, &src_u, videoscale->tmp_buf);
+ break;
+ case GST_VIDEO_SCALE_BILINEAR:
+ vs_image_scale_linear_Y (&dest, &src, videoscale->tmp_buf);
+ vs_image_scale_linear_NV12 (&dest_u, &src_u, videoscale->tmp_buf);
+ break;
+ default:
+ goto unknown_mode;
+ }
+ break;
case GST_VIDEO_FORMAT_RGB16:
if (add_borders)
vs_fill_borders_RGB565 (&dest, black);
/*
* Image Scaling Functions
- * Copyright (c) 2005 David A. Schleef <ds@schleef.org>
+ * Copyright (c) 2005-2012 David A. Schleef <ds@schleef.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
}
}
+/* NV12 */
+
+void
+vs_image_scale_nearest_NV12 (const VSImage * dest, const VSImage * src,
+ uint8_t * tmpbuf)
+{
+ int acc;
+ int y_increment;
+ int x_increment;
+ int i;
+ int j;
+ int xacc;
+
+ if (dest->height == 1)
+ y_increment = 0;
+ else
+ y_increment = ((src->height - 1) << 16) / (dest->height - 1);
+
+ if (dest->width == 1)
+ x_increment = 0;
+ else
+ x_increment = ((src->width - 1) << 16) / (dest->width - 1);
+
+ acc = 0;
+ for (i = 0; i < dest->height; i++) {
+ j = acc >> 16;
+
+ xacc = 0;
+ vs_scanline_resample_nearest_NV12 (dest->pixels + i * dest->stride,
+ src->pixels + j * src->stride, src->width, dest->width, &xacc,
+ x_increment);
+
+ acc += y_increment;
+ }
+}
+
+void
+vs_image_scale_linear_NV12 (const VSImage * dest, const VSImage * src,
+ uint8_t * tmpbuf)
+{
+ int acc;
+ int y_increment;
+ int x_increment;
+ uint8_t *tmp1;
+ uint8_t *tmp2;
+ int y1;
+ int y2;
+ int i;
+ int j;
+ int x;
+ int dest_size;
+ int xacc;
+
+ if (dest->height == 1)
+ y_increment = 0;
+ else
+ y_increment = ((src->height - 1) << 16) / (dest->height - 1) - 1;
+
+ if (dest->width == 1)
+ x_increment = 0;
+ else
+ x_increment = ((src->width - 1) << 16) / (dest->width - 1) - 1;
+
+ dest_size = ROUND_UP_4 (dest->width * 2);
+
+ tmp1 = tmpbuf;
+ tmp2 = tmpbuf + dest_size;
+
+ acc = 0;
+ xacc = 0;
+ y2 = -1;
+ vs_scanline_resample_linear_NV12 (tmp1, src->pixels, src->width, dest->width,
+ &xacc, x_increment);
+ y1 = 0;
+ for (i = 0; i < dest->height; i++) {
+ j = acc >> 16;
+ x = acc & 0xffff;
+
+ if (x == 0) {
+ if (j == y1) {
+ memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
+ } else if (j == y2) {
+ memcpy (dest->pixels + i * dest->stride, tmp2, dest_size);
+ } else {
+ xacc = 0;
+ vs_scanline_resample_linear_NV12 (tmp1, src->pixels + j * src->stride,
+ src->width, dest->width, &xacc, x_increment);
+ y1 = j;
+ memcpy (dest->pixels + i * dest->stride, tmp1, dest_size);
+ }
+ } else {
+ if (j == y1) {
+ if (j + 1 != y2) {
+ xacc = 0;
+ vs_scanline_resample_linear_NV12 (tmp2,
+ src->pixels + (j + 1) * src->stride, src->width, dest->width,
+ &xacc, x_increment);
+ y2 = j + 1;
+ }
+ vs_scanline_merge_linear_NV12 (dest->pixels + i * dest->stride,
+ tmp1, tmp2, dest->width, x);
+ } else if (j == y2) {
+ if (j + 1 != y1) {
+ xacc = 0;
+ vs_scanline_resample_linear_NV12 (tmp1,
+ src->pixels + (j + 1) * src->stride, src->width, dest->width,
+ &xacc, x_increment);
+ y1 = j + 1;
+ }
+ vs_scanline_merge_linear_NV12 (dest->pixels + i * dest->stride,
+ tmp2, tmp1, dest->width, x);
+ } else {
+ xacc = 0;
+ vs_scanline_resample_linear_NV12 (tmp1, src->pixels + j * src->stride,
+ src->width, dest->width, &xacc, x_increment);
+ y1 = j;
+ xacc = 0;
+ vs_scanline_resample_linear_NV12 (tmp2,
+ src->pixels + (j + 1) * src->stride, src->width, dest->width,
+ &xacc, x_increment);
+ y2 = (j + 1);
+ vs_scanline_merge_linear_NV12 (dest->pixels + i * dest->stride,
+ tmp1, tmp2, dest->width, x);
+ }
+ }
+
+ acc += y_increment;
+ }
+}
+
/* greyscale */
void
void vs_image_scale_linear_UYVY (const VSImage *dest, const VSImage *src,
uint8_t *tmpbuf);
+void vs_image_scale_nearest_NV12 (const VSImage *dest, const VSImage *src,
+ uint8_t *tmpbuf);
+void vs_image_scale_linear_NV12 (const VSImage *dest, const VSImage *src,
+ uint8_t *tmpbuf);
+
void vs_image_scale_nearest_Y (const VSImage *dest, const VSImage *src,
uint8_t *tmpbuf);
void vs_image_scale_linear_Y (const VSImage *dest, const VSImage *src,
}
+/* NV12 */
+
+/* n is the number of bi-pixels */
+
+void
+vs_scanline_downsample_NV12 (uint8_t * dest, uint8_t * src, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ dest[i * 2 + 0] = (src[i * 4 + 0] + src[i * 4 + 2]) / 2;
+ dest[i * 2 + 1] = (src[i * 4 + 1] + src[i * 4 + 3]) / 2;
+ }
+}
+
+void
+vs_scanline_resample_nearest_NV12 (uint8_t * dest, uint8_t * src, int src_width,
+ int n, int *accumulator, int increment)
+{
+ int acc = *accumulator;
+ int i;
+ int j;
+ int x;
+
+ for (i = 0; i < n; i++) {
+ j = acc >> 16;
+ x = acc & 0xffff;
+
+ dest[i * 2 + 0] = (x < 32768
+ || j + 1 >= src_width) ? src[j * 2 + 0] : src[j * 2 + 2];
+ dest[i * 2 + 1] = (x < 32768
+ || j + 1 >= src_width) ? src[j * 2 + 1] : src[j * 2 + 3];
+
+ acc += increment;
+ }
+
+ *accumulator = acc;
+}
+
+void
+vs_scanline_resample_linear_NV12 (uint8_t * dest, uint8_t * src, int src_width,
+ int n, int *accumulator, int increment)
+{
+ int acc = *accumulator;
+ int i;
+ int j;
+ int x;
+
+ for (i = 0; i < n; i++) {
+ j = acc >> 16;
+ x = acc & 0xffff;
+
+ if (j + 1 < src_width) {
+ dest[i * 2 + 0] =
+ (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16;
+ dest[i * 2 + 1] =
+ (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16;
+ } else {
+ dest[i * 4 + 0] = src[j * 2 + 0];
+ dest[i * 4 + 1] = src[j * 2 + 1];
+ }
+
+ acc += increment;
+ }
+
+ *accumulator = acc;
+}
+
+void
+vs_scanline_merge_linear_NV12 (uint8_t * dest, uint8_t * src1,
+ uint8_t * src2, int n, int x)
+{
+ uint32_t value = x >> 8;
+
+ if (value == 0) {
+ memcpy (dest, src1, n * 2);
+ } else {
+ orc_merge_linear_u8 (dest, src1, src2, value, n * 2);
+ }
+}
+
+
/* RGB565 */
/* note that src and dest are uint16_t, and thus endian dependent */
void vs_scanline_resample_linear_UYVY (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);
void vs_scanline_merge_linear_UYVY (uint8_t *dest, uint8_t *src1, uint8_t *src2, int n, int x);
+void vs_scanline_downsample_NV12 (uint8_t *dest, uint8_t *src, int n);
+void vs_scanline_resample_nearest_NV12 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);
+void vs_scanline_resample_linear_NV12 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);
+void vs_scanline_merge_linear_NV12 (uint8_t *dest, uint8_t *src1, uint8_t *src2, int n, int x);
+
void vs_scanline_downsample_RGB565 (uint8_t *dest, uint8_t *src, int n);
void vs_scanline_resample_nearest_RGB565 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);
void vs_scanline_resample_linear_RGB565 (uint8_t *dest, uint8_t *src, int src_width, int n, int *accumulator, int increment);