blob: a6e63c6beffdf440f7917d1107cdd89aa694caca [file] [log] [blame]
/*
* Copyright (C) 2016-2020 Intel Corporation.
*
* 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 "SwImageConverter"
#include "Errors.h"
#include "Utils.h"
#include "CameraLog.h"
#include "SwImageConverter.h"
namespace icamera {
void SwImageConverter::RGB2YUV(unsigned short R, unsigned short G, unsigned short B,
unsigned char *Y, unsigned char *U, unsigned char *V)
{
int Rp, Gp, Bp;
int oY, oU, oV;
Rp = R; Gp = G; Bp = B;
oY = (257 * Rp + 504 * Gp + 98 * Bp) / 4000 + 16;
oU = (-148 * Rp - 291 * Gp + 439 * Bp) / 4000 + 128;
oV = (439 * Rp - 368 * Gp - 71 * Bp) / 4000 + 128;
if (oY > 255) oY = 255;
if (oY < 0) oY = 0;
if (oU > 255) oU = 255;
if (oU < 0) oU = 0;
if (oV > 255) oV = 255;
if (oV < 0) oV = 0;
*Y = (unsigned char)oY;
*U = (unsigned char)oU;
*V = (unsigned char)oV;
}
void SwImageConverter::YUV2RGB(unsigned char Y, unsigned char U, unsigned char V,
unsigned short *R, unsigned short *G, unsigned short *B)
{
int Yp, Up, Vp, Ypp;
int oR, oG, oB;
Yp = Y - 16;
Up = (U - 128);
Vp = (V - 128);
Ypp = 9535 * Yp;
oB = (Ypp + 16531 * Up) >> 11;
oG = (Ypp - 6660 * Vp - 3203 * Up) >> 11;
oR = (Ypp + 13074 * Vp) >> 11;
if (oR > 1023) oR = 1023;
if (oR < 0) oR = 0;
if (oG > 1023) oG = 1023;
if (oG < 0) oG = 0;
if (oB > 1023) oB = 1023;
if (oB < 0) oB = 0;
*R = (unsigned short)oR;
*G = (unsigned short)oG;
*B = (unsigned short)oB;
}
void SwImageConverter::convertBayerBlock(unsigned int x, unsigned int y,
unsigned int width, unsigned int height,
unsigned short bayer_data[4], unsigned char *out_buf,
unsigned int src_fmt, unsigned int dst_fmt)
{
unsigned char *Ybase;
unsigned char *UVbase;
unsigned char Y, U, V;
unsigned short R, Gr, Gb, B;
switch (src_fmt) {
case V4L2_PIX_FMT_SRGGB8: R = bayer_data[0] << 2; Gr = bayer_data[1] << 2; Gb = bayer_data[2] << 2; B = bayer_data[3] << 2; break;
case V4L2_PIX_FMT_SGRBG8: Gr = bayer_data[0] << 2; R = bayer_data[1] << 2; B = bayer_data[2] << 2; Gb = bayer_data[3] << 2; break;
case V4L2_PIX_FMT_SGBRG8: Gb = bayer_data[0] << 2; B = bayer_data[1] << 2; R = bayer_data[2] << 2; Gr = bayer_data[3] << 2; break;
case V4L2_PIX_FMT_SBGGR8: B = bayer_data[0] << 2; Gb = bayer_data[1] << 2; Gr = bayer_data[2] << 2; R = bayer_data[3] << 2; break;
case V4L2_PIX_FMT_SRGGB10: R = bayer_data[0]; Gr = bayer_data[1]; Gb = bayer_data[2]; B = bayer_data[3]; break;
case V4L2_PIX_FMT_SGRBG10: Gr = bayer_data[0]; R = bayer_data[1]; B = bayer_data[2]; Gb = bayer_data[3]; break;
case V4L2_PIX_FMT_SGBRG10: Gb = bayer_data[0]; B = bayer_data[1]; R = bayer_data[2]; Gr = bayer_data[3]; break;
case V4L2_PIX_FMT_SBGGR10: B = bayer_data[0]; Gb = bayer_data[1]; Gr = bayer_data[2]; R = bayer_data[3]; break;
case V4L2_PIX_FMT_SRGGB12: R = bayer_data[0] >> 2; Gr = bayer_data[1] >> 2; Gb = bayer_data[2] >> 2; B = bayer_data[3] >> 2; break;
case V4L2_PIX_FMT_SGRBG12: Gr = bayer_data[0] >> 2; R = bayer_data[1] >> 2; B = bayer_data[2] >> 2; Gb = bayer_data[3] >> 2; break;
case V4L2_PIX_FMT_SGBRG12: Gb = bayer_data[0] >> 2; B = bayer_data[1] >> 2; R = bayer_data[2] >> 2; Gr = bayer_data[3] >> 2; break;
case V4L2_PIX_FMT_SBGGR12: B = bayer_data[0] >> 2; Gb = bayer_data[1] >> 2; Gr = bayer_data[2] >> 2; R = bayer_data[3] >> 2; break;
default: return;
}
int dstStride = CameraUtils::getStride(dst_fmt, width);
switch(dst_fmt) {
case V4L2_PIX_FMT_SRGGB8:
out_buf[y * dstStride + x] = (R >> 2);
out_buf[y * dstStride + x + 1] = (Gr >> 2);
out_buf[(y + 1) * dstStride + x] = (Gb >> 2);
out_buf[(y + 1) * dstStride + x + 1] = (B >> 2);
break;
case V4L2_PIX_FMT_SGRBG8:
out_buf[y * dstStride + x] = (Gr >> 2);
out_buf[y * dstStride + x + 1] = (R >> 2);
out_buf[(y + 1) * dstStride + x] = (B >> 2);
out_buf[(y + 1) * dstStride + x + 1] = (Gb >> 2);
break;
case V4L2_PIX_FMT_SGBRG8:
out_buf[y * dstStride + x] = (Gb >> 2);
out_buf[y * dstStride + x + 1] = (B >> 2);
out_buf[(y + 1) * dstStride + x] = (R >> 2);
out_buf[(y + 1) * dstStride + x + 1] = (Gr >> 2);
break;
case V4L2_PIX_FMT_SBGGR8:
out_buf[y * dstStride + x] = (B >> 2);
out_buf[y * dstStride + x + 1] = (Gb >> 2);
out_buf[(y + 1) * dstStride + x] = (Gr >> 2);
out_buf[(y + 1) * dstStride + x + 1] = (R >> 2);
break;
case V4L2_PIX_FMT_SRGGB10:
*((unsigned short *) out_buf + y * dstStride + x) = R;
*((unsigned short *) out_buf + y * dstStride + x + 1) = Gr;
*((unsigned short *) out_buf + (y + 1) * dstStride + x) = Gb;
*((unsigned short *) out_buf + (y + 1) * dstStride + x + 1) = B;
break;
case V4L2_PIX_FMT_SGRBG10:
*((unsigned short *) out_buf + y * dstStride + x) = Gr;
*((unsigned short *) out_buf + y * dstStride + x + 1) = R;
*((unsigned short *) out_buf + (y + 1) * dstStride + x) = B;
*((unsigned short *) out_buf + (y + 1) * dstStride + x + 1) = Gb;
break;
case V4L2_PIX_FMT_SGBRG10:
*((unsigned short *) out_buf + y * dstStride + x) = Gb;
*((unsigned short *) out_buf + y * dstStride + x + 1) = B;
*((unsigned short *) out_buf + (y + 1) * dstStride + x) = R;
*((unsigned short *) out_buf + (y + 1) * dstStride + x + 1) = Gr;
break;
case V4L2_PIX_FMT_SBGGR10:
*((unsigned short *) out_buf + y * dstStride + x) = B;
*((unsigned short *) out_buf + y * dstStride + x + 1) = Gb;
*((unsigned short *) out_buf + (y + 1) * dstStride + x) = Gr;
*((unsigned short *) out_buf + (y + 1) * dstStride + x + 1) = R;
break;
case V4L2_PIX_FMT_NV12:
Ybase = out_buf;
UVbase = Ybase + dstStride * height;
RGB2YUV(R, (Gr + Gb) / 2, B, &Y, &U, &V);
Ybase[y * dstStride + x] = Ybase[y * dstStride + x + 1] =
Ybase[(y + 1) * dstStride + x] = Ybase[(y + 1) * dstStride + x + 1] = Y;
UVbase[y / 2 * dstStride + x / 2 * 2] = U;
UVbase[y / 2 * dstStride + x / 2 * 2 + 1] = V;
break;
case V4L2_PIX_FMT_UYVY:
RGB2YUV(R, (Gr + Gb) / 2, B, &Y, &U, &V);
out_buf[y * dstStride + x * 2] = U;
out_buf[y * dstStride + x * 2 + 1] = Y;
out_buf[y * dstStride + x * 2 + 2] = V;
out_buf[y * dstStride + x * 2 + 3] = Y;
out_buf[(y + 1) * dstStride + x * 2] = U;
out_buf[(y + 1) * dstStride + x * 2 + 1] = Y;
out_buf[(y + 1) * dstStride + x * 2 + 2] = V;
out_buf[(y + 1) * dstStride + x * 2 + 3] = Y;
break;
case V4L2_PIX_FMT_YUYV:
RGB2YUV(R, (Gr + Gb) / 2, B, &Y, &U, &V);
out_buf[y * dstStride + x * 2] = Y;
out_buf[y * dstStride + x * 2 + 1] = U;
out_buf[y * dstStride + x * 2 + 2] = Y;
out_buf[y * dstStride + x * 2 + 3] = V;
out_buf[(y + 1) * dstStride + x * 2] = Y;
out_buf[(y + 1) * dstStride + x * 2 + 1] = U;
out_buf[(y + 1) * dstStride + x * 2 + 2] = Y;
out_buf[(y + 1) * dstStride + x * 2 + 3] = V;
break;
case V4L2_PIX_FMT_YUV420:
{
RGB2YUV(R, (Gr + Gb) / 2, B, &Y, &U, &V);
Ybase = out_buf;
uint8_t* UBase = out_buf + dstStride * height;
uint8_t* VBase = out_buf + dstStride * (height + height / 4);
Ybase[y * dstStride + x] = Y;
Ybase[y * dstStride + x + 1] = Y;
Ybase[(y + 1) * dstStride + x] = Y;
Ybase[(y + 1) * dstStride + x + 1] = Y;
if (y % 4 == 0) {
UBase[y / 4 * dstStride + x / 2] = U;
VBase[y / 4 * dstStride + x / 2] = V;
} else {
UBase[y / 4 * dstStride + width / 2 + x / 2] = U;
VBase[y / 4 * dstStride + width / 2 + x / 2] = V;
}
break;
}
default:
break;
}
}
void SwImageConverter::convertYuvBlock(unsigned int x, unsigned int y,
unsigned int width, unsigned int height,
unsigned char *in_buf, unsigned char *out_buf,
unsigned int src_fmt, unsigned int dst_fmt)
{
unsigned char *YBase;
unsigned char *UVBase;
unsigned char Y[4];
unsigned char U[4];
unsigned char V[4];
unsigned short R, G, B;
int srcStride = CameraUtils::getStride(src_fmt, width);
switch(src_fmt) {
case V4L2_PIX_FMT_NV12:
YBase = in_buf;
UVBase = in_buf + srcStride * height;
Y[0] = YBase[y * srcStride + x];
Y[1] = YBase[y * srcStride + x + 1];
Y[2] = YBase[(y + 1) * srcStride + x];
Y[3] = YBase[(y + 1) * srcStride + x + 1];
U[0] = U[1] = U[2] = U[3] = UVBase[y / 2 * srcStride + x / 2 * 2];
V[0] = V[1] = V[2] = V[3] = UVBase[y / 2 * srcStride + x / 2 * 2 + 1];
break;
case V4L2_PIX_FMT_UYVY:
Y[0] = in_buf[y * srcStride + x * 2 + 1];
Y[1] = in_buf[y * srcStride + x * 2 + 3];
Y[2] = in_buf[(y + 1) * srcStride + x * 2 + 1];
Y[3] = in_buf[(y + 1) * srcStride + x * 2 + 3];
U[0] = U[1] = in_buf[y * srcStride + x * 2];
U[2] = U[3] = in_buf[(y + 1) * srcStride + x * 2];
V[0] = V[1] = in_buf[y * srcStride + x * 2 + 2];
V[2] = V[3] = in_buf[(y + 1) * srcStride + x * 2 + 2];
break;
case V4L2_PIX_FMT_YUYV:
Y[0] = in_buf[y * srcStride + x * 2];
Y[1] = in_buf[y * srcStride + x * 2 + 2];
Y[2] = in_buf[(y + 1) * srcStride + x * 2];
Y[3] = in_buf[(y + 1) * srcStride + x * 2 + 2];
U[0] = U[1] = in_buf[y * srcStride + x * 2 + 1];
U[2] = U[3] = in_buf[(y + 1) * srcStride + x * 2 + 1];
V[0] = V[1] = in_buf[y * srcStride + x * 2 + 3];
V[2] = V[3] = in_buf[(y + 1) * srcStride + x * 2 + 3];
break;
default:
return;
}
int dstStride = CameraUtils::getStride(dst_fmt, width);
switch(dst_fmt) {
case V4L2_PIX_FMT_NV12:
YBase = out_buf;
UVBase = out_buf + dstStride * height;
YBase[y * dstStride + x] = Y[0];
YBase[y * dstStride + x + 1] = Y[1];
YBase[(y + 1) * dstStride + x] = Y[2];
YBase[(y + 1) * dstStride + x + 1] = Y[3];
UVBase[y / 2 * dstStride + x / 2 * 2] = U[0];
UVBase[y / 2 * dstStride + x / 2 * 2 + 1] = V[0];
break;
case V4L2_PIX_FMT_UYVY:
out_buf[y * dstStride + x * 2 + 1] = Y[0];
out_buf[y * dstStride + x * 2 + 3] = Y[1];
out_buf[(y + 1) * dstStride + x * 2 + 1] = Y[2];
out_buf[(y + 1) * dstStride + x * 2 + 3] = Y[3];
out_buf[y * dstStride + x * 2] = U[0];
out_buf[(y + 1) * dstStride + x * 2] = U[2];
out_buf[y * dstStride + x * 2 + 2] = V[0];
out_buf[(y + 1) * dstStride + x * 2 + 2] = V[2];
break;
case V4L2_PIX_FMT_YUYV:
out_buf[y * dstStride + x * 2] = Y[0];
out_buf[y * dstStride + x * 2 + 2] = Y[1];
out_buf[(y + 1) * dstStride + x * 2] = Y[2];
out_buf[(y + 1) * dstStride + x * 2 + 2] = Y[3];
out_buf[y * dstStride + x * 2 + 1] = U[0];
out_buf[(y + 1) * dstStride + x * 2 + 1] = U[2];
out_buf[y * dstStride + x * 2 + 3] = V[0];
out_buf[(y + 1) * dstStride + x * 2 + 3] = V[2];
break;
case V4L2_PIX_FMT_YUV420:
{
YBase = out_buf;
uint8_t* UBase = out_buf + dstStride * height;
uint8_t* VBase = out_buf + dstStride * (height + height / 4);
YBase[y * dstStride + x] = Y[0];
YBase[y * dstStride + x + 1] = Y[1];
YBase[(y + 1) * dstStride + x] = Y[2];
YBase[(y + 1) * dstStride + x + 1] = Y[3];
if (y % 4 == 0) {
UBase[y / 4 * dstStride + x / 2] = (U[0] + U[2]) / 2;
VBase[y / 4 * dstStride + x / 2] = (V[0] + V[2]) / 2;
} else {
UBase[y / 4 * dstStride + width / 2 + x / 2] = (U[0] + U[2]) / 2;
VBase[y / 4 * dstStride + width / 2 + x / 2] = (V[0] + V[2]) / 2;
}
break;
}
case V4L2_PIX_FMT_SRGGB8:
YUV2RGB(Y[0], U[0], V[0], &R, &G, &B);
out_buf[y * dstStride + x] = (R >> 2);
out_buf[y * dstStride + x + 1] = (G >> 2);
out_buf[(y + 1) * dstStride + x] = (G >> 2);
out_buf[(y + 1) * dstStride + x + 1] = (B >> 2);
break;
case V4L2_PIX_FMT_SGRBG8:
YUV2RGB(Y[0], U[0], V[0], &R, &G, &B);
out_buf[y * dstStride + x] = (G >> 2);
out_buf[y * dstStride + x + 1] = (R >> 2);
out_buf[(y + 1) * dstStride + x] = (B >> 2);
out_buf[(y + 1) * dstStride + x + 1] = (G >> 2);
break;
case V4L2_PIX_FMT_SGBRG8:
YUV2RGB(Y[0], U[0], V[0], &R, &G, &B);
out_buf[y * dstStride + x] = (G >> 2);
out_buf[y * dstStride + x + 1] = (B >> 2);
out_buf[(y + 1) * dstStride + x] = (R >> 2);
out_buf[(y + 1) * dstStride + x + 1] = (G >> 2);
break;
case V4L2_PIX_FMT_SBGGR8:
YUV2RGB(Y[0], U[0], V[0], &R, &G, &B);
out_buf[y * dstStride + x] = (B >> 2);
out_buf[y * dstStride + x + 1] = (G >> 2);
out_buf[(y + 1) * dstStride + x] = (G >> 2);
out_buf[(y + 1) * dstStride + x + 1] = (R >> 2);
break;
case V4L2_PIX_FMT_SRGGB10:
YUV2RGB(Y[0], U[0], V[0], &R, &G, &B);
*((unsigned short *) out_buf + y * dstStride + x) = R;
*((unsigned short *) out_buf + y * dstStride + x + 1) = G;
*((unsigned short *) out_buf + (y + 1) * dstStride + x) = G;
*((unsigned short *) out_buf + (y + 1) * dstStride + x + 1) = B;
break;
case V4L2_PIX_FMT_SGRBG10:
YUV2RGB(Y[0], U[0], V[0], &R, &G, &B);
*((unsigned short *) out_buf + y * dstStride + x) = G;
*((unsigned short *) out_buf + y * dstStride + x + 1) = R;
*((unsigned short *) out_buf + (y + 1) * dstStride + x) = B;
*((unsigned short *) out_buf + (y + 1) * dstStride + x + 1) = G;
break;
case V4L2_PIX_FMT_SGBRG10:
YUV2RGB(Y[0], U[0], V[0], &R, &G, &B);
*((unsigned short *) out_buf + y * dstStride + x) = G;
*((unsigned short *) out_buf + y * dstStride + x + 1) = B;
*((unsigned short *) out_buf + (y + 1) * dstStride + x) = R;
*((unsigned short *) out_buf + (y + 1) * dstStride + x + 1) = G;
break;
case V4L2_PIX_FMT_SBGGR10:
YUV2RGB(Y[0], U[0], V[0], &R, &G, &B);
*((unsigned short *) out_buf + y * dstStride + x) = B;
*((unsigned short *) out_buf + y * dstStride + x + 1) = G;
*((unsigned short *) out_buf + (y + 1) * dstStride + x) = G;
*((unsigned short *) out_buf + (y + 1) * dstStride + x + 1) = R;
break;
default:
return;
}
}
int SwImageConverter::convertFormat(unsigned int width, unsigned int height,
unsigned char *inBuf, unsigned int inLength, unsigned int srcFmt,
unsigned char *outBuf, unsigned int outLength, unsigned int dstFmt)
{
CheckError((inBuf == nullptr || outBuf == nullptr), BAD_VALUE, "Invalid input(%p) or output buffer(%p)", inBuf, outBuf);
unsigned int x, y;
unsigned short bayer_data[4];
LOG2("%s srcFmt %s => dstFmt %s %dx%d", __func__,
CameraUtils::format2string(srcFmt).c_str(),
CameraUtils::format2string(dstFmt).c_str(), width, height);
if (dstFmt == srcFmt) {
// No need do format convertion.
LOG2("No conversion needed");
MEMCPY_S(outBuf, outLength, inBuf, inLength);
return 0;
}
// for not vector raw
int srcStride = CameraUtils::getStride(srcFmt, width);
for(y = 0; y < height; y += 2) {
for(x = 0; x < width; x += 2) {
if(CameraUtils::isRaw(srcFmt)) {
if(CameraUtils::getBpp(srcFmt) == 8) {
bayer_data[0] = inBuf[y * srcStride + x];
bayer_data[1] = inBuf[y * srcStride + x + 1];
bayer_data[2] = inBuf[(y + 1) * srcStride + x];
bayer_data[3] = inBuf[(y + 1) * srcStride + x + 1];
} else {
int offset = srcStride / (CameraUtils::getBpp(srcFmt) / 8);
bayer_data[0] = *((unsigned short *) inBuf + y * offset + x);
bayer_data[1] = *((unsigned short *) inBuf + y * offset + x + 1);
bayer_data[2] = *((unsigned short *) inBuf + (y + 1) * offset + x);
bayer_data[3] =
*((unsigned short *) inBuf + (y + 1) * offset + x + 1);
}
convertBayerBlock(x, y, width, height, bayer_data, outBuf, srcFmt, dstFmt);
} else {
convertYuvBlock(x, y, width, height, inBuf, outBuf, srcFmt, dstFmt);
}
}
}
return 0;
}
} //namespace icamera