mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-02 20:42:30 +00:00
videoscale: Add nearest/linear scaling for NV12
This commit is contained in:
parent
e4f01106d0
commit
beacccc396
5 changed files with 251 additions and 4 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue