android13/hardware/rockchip/camera/common/imageProcess/ImageScalerCore.cpp

251 lines
10 KiB
C++

/*
* Copyright (C) 2012-2017 Intel Corporation
* Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "ImageScalerCore"
#include "LogHelper.h"
#include "ImageScalerCore.h"
#include <libyuv.h>
#include <linux/videodev2.h>
#define RESOLUTION_VGA_WIDTH 640
#define RESOLUTION_VGA_HEIGHT 480
#define RESOLUTION_QVGA_WIDTH 320
#define RESOLUTION_QVGA_HEIGHT 240
#define RESOLUTION_QCIF_WIDTH 176
#define RESOLUTION_QCIF_HEIGHT 144
#define MIN(a,b) ((a)<(b)?(a):(b))
NAMESPACE_DECLARATION {
void ImageScalerCore::downScaleImage(std::shared_ptr<CommonBuffer> srcBuf,
std::shared_ptr<CommonBuffer> dstBuf)
{
downScaleImage(srcBuf->data(), dstBuf->data(),
dstBuf->width(), dstBuf->height(), dstBuf->stride(),
srcBuf->width(), srcBuf->height(), srcBuf->stride(),
srcBuf->v4l2Fmt());
}
void ImageScalerCore::downScaleImage(void *src, void *dest,
int dest_w, int dest_h, int dest_stride,
int src_w, int src_h, int src_stride,
int format, int src_skip_lines_top, // number of lines that are skipped from src image start pointer
int src_skip_lines_bottom) // number of lines that are skipped after reading src_h (should be set always to reach full image height)
{
unsigned char *m_dest = (unsigned char *)dest;
const unsigned char * m_src = (const unsigned char *)src;
switch (format) {
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV12: {
// downscale & crop
ImageScalerCore::downScaleAndCropNv12Image(m_dest, m_src,
dest_w, dest_h, dest_stride,
src_w, src_h, src_stride,
src_skip_lines_top, src_skip_lines_bottom);
break;
}
case V4L2_PIX_FMT_YUYV: {
ImageScalerCore::downScaleYUY2Image(m_dest, m_src,
dest_w, dest_h, dest_stride,
src_w, src_h, src_stride);
break;
}
default: {
LOGE("no downscale support for format = %d", format);
break;
}
}
}
void ImageScalerCore::downScaleYUY2Image(unsigned char *dest, const unsigned char *src,
const int dest_w, const int dest_h, const int dest_stride,
const int src_w, const int src_h, const int src_stride)
{
if (dest==nullptr || dest_w <=0 || dest_h <=0 || src==nullptr || src_w <=0 || src_h <= 0 )
return;
if (dest_w%2 != 0) // if the dest_w is not an even number, exit
return;
const int scale_w = (src_w<<8) / dest_w; // scale factors
const int scale_h = (src_h<<8) / dest_h;
int dx, dy;
int macro_pixel_width = dest_w >> 1;
int src_i, src_j; // the left up coordinates of src that correspond to (j,i) in dest
unsigned int val_1, val_2; // for bi-linear-interpolation
int i,j,k;
for(i=0; i < dest_h; ++i) {
src_i = i * scale_h;
dy = src_i & 0xff;
src_i >>= 8;
for(j=0; j < macro_pixel_width; ++j) {
src_j = j * scale_w;
dx = src_j & 0xff;
src_j = src_j >> 8;
for(k = 0; k < 4; ++k) {
// bi-linear-interpolation
if(dx == 0 && dy == 0) {
dest[i * 2 * dest_stride + 4 * j + k] = src[src_i * 2 * src_stride + src_j * 4 + k];
} else if(dx == 0 && dy != 0){
val_1 = (unsigned int)src[src_i * 2 * src_stride + src_j * 4 + k];
val_2 = (unsigned int)src[(src_i + 1) * 2 * src_stride + src_j * 4 + k];
val_1 = (val_1 * (256 - dy) + val_2 * dy) >> 8;
dest[i * 2 * dest_stride + 4 * j + k] = ((val_1 <= 255) ? val_1: 255);
} else if(dx != 0 && dy == 0) {
val_1 = ((unsigned int)src[src_i * 2 * src_stride + src_j * 4 + k] * (256 - dx)
+ (unsigned int)src[src_i * 2 * src_stride + (src_j +1) * 4 + k] * dx) >> 8;
dest[i * 2 * dest_stride + 4 * j + k] = ((val_1 <= 255) ? val_1: 255);
} else {
val_1 = ((unsigned int)src[src_i * 2 * src_stride + src_j * 4 + k] * (256 - dx)
+ (unsigned int)src[src_i * 2 * src_stride + (src_j +1) * 4 + k] * dx) >> 8;
val_2 = ((unsigned int)src[(src_i + 1) * 2 * src_stride + src_j * 4 + k] * (256 - dx)
+ (unsigned int)src[(src_i + 1) * 2 * src_stride + (src_j+1) * 4 + k] * dx) >> 8;
val_1 = (val_1 * (256 - dy) + val_2 * dy) >> 8;
dest[i * 2 * dest_stride + 4 * j + k] = ((val_1 <= 255) ? val_1: 255);
}
}
}
}
}
void ImageScalerCore::downScaleAndCropNv12Image(unsigned char *dest, const unsigned char *src,
const int dest_w, const int dest_h, const int dest_stride,
const int src_w, const int src_h, const int src_stride,
const int src_skip_lines_top, // number of lines that are skipped from src image start pointer
const int src_skip_lines_bottom) // number of lines that are skipped after reading src_h (should be set always to reach full image height)
{
LOGI("@%s: dest_w: %d, dest_h: %d, dest_stride: %d, src_w: %d, src_h: %d, src_stride: %d, skip_top: %d, skip_bottom: %d, dest: %p, src: %p",
__FUNCTION__, dest_w, dest_h, dest_stride, src_w, src_h, src_stride, src_skip_lines_top, src_skip_lines_bottom, dest, src);
int total_height = src_skip_lines_top + src_h + src_skip_lines_bottom;
int width = src_w, height = src_h;
int left = 0, top = src_skip_lines_top;
int proper_source_width = (int)((float)dest_w / dest_h * src_h);
// Aligned to 4
proper_source_width = (proper_source_width + 3) & ~3;
int proper_source_height = (int)((float)dest_h / dest_w * src_w);
if (src_w != dest_w || src_h != dest_h) {
// Crop width/height if needed
if (proper_source_width < src_w) {
width = proper_source_width;
left = (src_w - width) / 2;
left = (left + 1) & ~1; // Aligned for uv
} else if (proper_source_height < src_h) {
height = proper_source_height;
top += (src_h - height) / 2;
}
}
int offset = top * src_stride + left;
uint8_t *src_y = (uint8_t *)src + offset;
uint8_t *src_uv = (uint8_t *)src + total_height * src_stride + offset/2;
libyuv::ScalePlane(src_y, src_stride, width, height,
dest, dest_stride, dest_w, dest_h,
libyuv::kFilterNone);
dest += dest_stride * dest_h;
libyuv::ScalePlane_16((uint16_t *)src_uv, src_stride/2,
width/2, height/2,
(uint16_t *)dest, dest_stride/2,
dest_w/2, dest_h/2,
libyuv::kFilterNone);
}
void ImageScalerCore::cropComposeCopy(void *src, void *dst, unsigned int size)
{
STDCOPY((int8_t *) dst, (int8_t *) src, size);
}
// Bilinear scaling, chrominance with nearest neighbor
void ImageScalerCore::cropComposeUpscaleNV12_bl(
void *src, unsigned int srcH, unsigned int srcStride,
unsigned int srcCropLeft, unsigned int srcCropTop,
unsigned int srcCropW, unsigned int srcCropH,
void *dst, unsigned int dstH, unsigned int dstStride,
unsigned int dstCropLeft, unsigned int dstCropTop,
unsigned int dstCropW, unsigned int dstCropH)
{
static const int BILINEAR = 1;
static const unsigned int FP_1 = 1 << MFP; // Fixed point 1.0
static const unsigned int FRACT = (1 << MFP) - 1; // Fractional part mask
unsigned int dx, dy, sx, sy;
unsigned char *s = (unsigned char *)src;
unsigned char *d = (unsigned char *)dst;
unsigned int sx0, sy0, dx0, dy0, dx1, dy1;
unsigned int sxd = ((srcCropW<<MFP) + (dstCropW>>1)) / dstCropW;
unsigned int syd = ((srcCropH<<MFP) + (dstCropH>>1)) / dstCropH;
if (!src || !dst) {
LOGE("buffer pointer is nullptr");
return;
}
// Upscale luminance
sx0 = srcCropLeft << MFP;
sy0 = srcCropTop << MFP;
dx0 = dstCropLeft;
dy0 = dstCropTop;
dx1 = dstCropLeft + dstCropW;
dy1 = dstCropTop + dstCropH;
for (dy = dy0, sy = sy0; dy < dy1; dy++, sy += syd) {
for (dx = dx0, sx = sx0; dx < dx1; dx++, sx += sxd) {
unsigned int sxi = sx >> MFP;
unsigned int syi = sy >> MFP;
unsigned int s0 = s[srcStride*syi+sxi];
if (BILINEAR) {
unsigned int fx = sx & FRACT; // Fractional part
unsigned int fy = sy & FRACT;
unsigned int fx1 = FP_1 - fx; // 1 - fractional part
unsigned int fy1 = FP_1 - fy;
unsigned int s1 = s[srcStride*syi+sxi+1];
unsigned int s2 = s[srcStride*(syi+1)+sxi];
unsigned int s3 = s[srcStride*(syi+1)+sxi+1];
unsigned int s4 = (s0 * fx1 + s1 * fx) >> MFP;
unsigned int s5 = (s2 * fx1 + s3 * fx) >> MFP;
s0 = (s4 * fy1 + s5 * fy) >> MFP;
}
d[dstStride*dy+dx] = s0;
}
}
// Upscale chrominance
s = (unsigned char *)src + srcStride*srcH;
d = (unsigned char *)dst + dstStride*dstH;
sx0 = srcCropLeft << (MFP - 1);
sy0 = srcCropTop << (MFP - 1);
dx0 = dstCropLeft >> 1;
dy0 = dstCropTop >> 1;
dx1 = (dstCropLeft + dstCropW) >> 1;
dy1 = (dstCropTop + dstCropH) >> 1;
for (dy = dy0, sy = sy0; dy < dy1; dy++, sy += syd) {
for (dx = dx0, sx = sx0; dx < dx1; dx++, sx += sxd) {
unsigned int sxi = sx >> MFP;
unsigned int syi = sy >> MFP;
d[dstStride*dy+dx*2+0] = s[srcStride*syi+sxi*2+0];
d[dstStride*dy+dx*2+1] = s[srcStride*syi+sxi*2+1];
}
}
}
} NAMESPACE_DECLARATION_END