videoscale: Add nearest/linear scaling for NV12

This commit is contained in:
David Schleef 2012-01-30 08:21:54 -08:00
parent e4f01106d0
commit beacccc396
5 changed files with 251 additions and 4 deletions

View file

@ -1,6 +1,6 @@
/* 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
@ -140,7 +140,8 @@ static GstStaticCaps gst_video_scale_format_caps[] = {
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())
@ -1024,7 +1025,8 @@ gst_video_scale_setup_vs_image (VSImage * image, GstVideoFormat format,
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 {
@ -1090,6 +1092,7 @@ _get_black_for_format (GstVideoFormat format)
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:
@ -1153,6 +1156,14 @@ gst_video_scale_transform (GstBaseTransform * trans, GstBuffer * in,
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:
@ -1340,6 +1351,20 @@ gst_video_scale_transform (GstBaseTransform * trans, GstBuffer * in,
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);

View file

@ -1,6 +1,6 @@
/*
* 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
@ -522,6 +522,136 @@ vs_image_scale_linear_UYVY (const VSImage * dest, const VSImage * src,
}
}
/* 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

View file

@ -71,6 +71,11 @@ void vs_image_scale_nearest_UYVY (const VSImage *dest, const VSImage *src,
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,

View file

@ -519,6 +519,88 @@ vs_scanline_merge_linear_UYVY (uint8_t * dest, uint8_t * src1,
}
/* 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 */

View file

@ -55,6 +55,11 @@ void vs_scanline_resample_nearest_UYVY (uint8_t *dest, uint8_t *src, int src_wid
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);