From beacccc3969b82ea9c9a8808c7d353010c082d0b Mon Sep 17 00:00:00 2001 From: David Schleef Date: Mon, 30 Jan 2012 08:21:54 -0800 Subject: [PATCH] videoscale: Add nearest/linear scaling for NV12 --- gst/videoscale/gstvideoscale.c | 31 +++++++++- gst/videoscale/vs_image.c | 132 ++++++++++++++++++++++++++++++++++++++++- gst/videoscale/vs_image.h | 5 ++ gst/videoscale/vs_scanline.c | 82 +++++++++++++++++++++++++ gst/videoscale/vs_scanline.h | 5 ++ 5 files changed, 251 insertions(+), 4 deletions(-) diff --git a/gst/videoscale/gstvideoscale.c b/gst/videoscale/gstvideoscale.c index 6df4ba6..9f072a3 100644 --- a/gst/videoscale/gstvideoscale.c +++ b/gst/videoscale/gstvideoscale.c @@ -1,6 +1,6 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) 2005 David Schleef + * Copyright (C) 2005-2012 David Schleef * * 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); diff --git a/gst/videoscale/vs_image.c b/gst/videoscale/vs_image.c index c28b0d8..09ccf25 100644 --- a/gst/videoscale/vs_image.c +++ b/gst/videoscale/vs_image.c @@ -1,6 +1,6 @@ /* * Image Scaling Functions - * Copyright (c) 2005 David A. Schleef + * Copyright (c) 2005-2012 David A. Schleef * 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 diff --git a/gst/videoscale/vs_image.h b/gst/videoscale/vs_image.h index 7b34991..d3cc31d 100644 --- a/gst/videoscale/vs_image.h +++ b/gst/videoscale/vs_image.h @@ -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, diff --git a/gst/videoscale/vs_scanline.c b/gst/videoscale/vs_scanline.c index 822a6b6..c9459c2 100644 --- a/gst/videoscale/vs_scanline.c +++ b/gst/videoscale/vs_scanline.c @@ -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 */ diff --git a/gst/videoscale/vs_scanline.h b/gst/videoscale/vs_scanline.h index 387fc95..92d8f6f 100644 --- a/gst/videoscale/vs_scanline.h +++ b/gst/videoscale/vs_scanline.h @@ -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); -- 2.7.4