blob: 8e600ba937de9b62eab5a7c54eec635f1ee54bd5 [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 "ColorConverter"
#include <sys/types.h>
#include <linux/videodev2.h>
#include "iutils/CameraLog.h"
#include "iutils/Utils.h"
#include "iutils/Errors.h"
#include "ImageConverter.h"
namespace icamera {
namespace ImageConverter {
void YUV420ToRGB565(int width, int height, void *src, void *dst)
{
int line, col, linewidth;
int y, u, v, yy, vr, ug, vg, ub;
int r, g, b;
const unsigned char *py, *pu, *pv;
unsigned short *rgbs = (unsigned short *) dst;
linewidth = width >> 1;
py = (unsigned char *) src;
pu = py + (width * height);
pv = pu + (width * height) / 4;
y = *py++;
yy = y << 8;
u = *pu - 128;
ug = 88 * u;
ub = 454 * u;
v = *pv - 128;
vg = 183 * v;
vr = 359 * v;
for (line = 0; line < height; line++) {
for (col = 0; col < width; col++) {
r = (yy + vr) >> 8;
g = (yy - ug - vg) >> 8;
b = (yy + ub ) >> 8;
if (r < 0) r = 0;
if (r > 255) r = 255;
if (g < 0) g = 0;
if (g > 255) g = 255;
if (b < 0) b = 0;
if (b > 255) b = 255;
*rgbs++ = (((unsigned short)r>>3)<<11) | (((unsigned short)g>>2)<<5)
| (((unsigned short)b>>3)<<0);
y = *py++;
yy = y << 8;
if (col & 1) {
pu++;
pv++;
u = *pu - 128;
ug = 88 * u;
ub = 454 * u;
v = *pv - 128;
vg = 183 * v;
vr = 359 * v;
}
}
if ((line & 1) == 0) {
pu -= linewidth;
pv -= linewidth;
}
}
}
void trimConvertNV12ToRGB565(int width, int height, int srcStride, void *src, void *dst)
{
unsigned char *yuvs = (unsigned char *) src;
unsigned char *rgbs = (unsigned char *) dst;
//the end of the luminance data
int lumEnd = srcStride * height;
int i = 0, j = 0;
for( i=0; i < height; i++) {
//points to the next luminance value pair
int lumPtr = i * srcStride;
//points to the next chromiance value pair
int chrPtr = i / 2 * srcStride + lumEnd;
for ( j=0; j < width; j+=2 ) {
//read the luminance and chromiance values
int Y1 = yuvs[lumPtr++] & 0xff;
int Y2 = yuvs[lumPtr++] & 0xff;
int Cb = (yuvs[chrPtr++] & 0xff) - 128;
int Cr = (yuvs[chrPtr++] & 0xff) - 128;
int R, G, B;
//generate first RGB components
B = Y1 + ((454 * Cb) >> 8);
if(B < 0) B = 0; else if(B > 255) B = 255;
G = Y1 - ((88 * Cb + 183 * Cr) >> 8);
if(G < 0) G = 0; else if(G > 255) G = 255;
R = Y1 + ((359 * Cr) >> 8);
if(R < 0) R = 0; else if(R > 255) R = 255;
//NOTE: this assume little-endian encoding
*rgbs++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3));
*rgbs++ = (unsigned char) ((R & 0xf8) | (G >> 5));
//generate second RGB components
B = Y2 + ((454 * Cb) >> 8);
if(B < 0) B = 0; else if(B > 255) B = 255;
G = Y2 - ((88 * Cb + 183 * Cr) >> 8);
if(G < 0) G = 0; else if(G > 255) G = 255;
R = Y2 + ((359 * Cr) >> 8);
if(R < 0) R = 0; else if(R > 255) R = 255;
//NOTE: this assume little-endian encoding
*rgbs++ = (unsigned char) (((G & 0x3c) << 3) | (B >> 3));
*rgbs++ = (unsigned char) ((R & 0xf8) | (G >> 5));
}
}
}
// covert YV12 (Y plane, V plane, U plane) to NV21 (Y plane, interlaced VU bytes)
void convertYV12ToNV21(int width, int height, int srcStride, int dstStride, void *src, void *dst)
{
const int cStride = srcStride>>1;
const int vuStride = dstStride;
const int hhalf = height>>1;
const int whalf = width>>1;
// copy the entire Y plane
unsigned char *srcPtr = (unsigned char *)src;
unsigned char *dstPtr = (unsigned char *)dst;
if (srcStride == dstStride) {
MEMCPY_S(dstPtr, dstStride*height, srcPtr, dstStride*height);
} else {
for (int i = 0; i < height; i++) {
MEMCPY_S(dstPtr, width, srcPtr, width);
srcPtr += srcStride;
dstPtr += dstStride;
}
}
// interlace the VU data
unsigned char *srcPtrV = (unsigned char *)src + height*srcStride;
unsigned char *srcPtrU = srcPtrV + cStride*hhalf;
dstPtr = (unsigned char *)dst + dstStride*height;
for (int i = 0; i < hhalf; ++i) {
unsigned char *pDstVU = dstPtr;
unsigned char *pSrcV = srcPtrV;
unsigned char *pSrcU = srcPtrU;
for (int j = 0; j < whalf; ++j) {
*pDstVU ++ = *pSrcV ++;
*pDstVU ++ = *pSrcU ++;
}
dstPtr += vuStride;
srcPtrV += cStride;
srcPtrU += cStride;
}
}
// copy YV12 to YV12 (Y plane, V plan, U plan) in case of different stride length
void copyYV12ToYV12(int width, int height, int srcStride, int dstStride, void *src, void *dst)
{
// copy the entire Y plane
if (srcStride == dstStride) {
MEMCPY_S(dst, dstStride * height, src, dstStride * height);
} else {
unsigned char *srcPtrY = (unsigned char *)src;
unsigned char *dstPtrY = (unsigned char *)dst;
for (int i = 0; i < height; i ++) {
MEMCPY_S(dstPtrY, width, srcPtrY, width);
srcPtrY += srcStride;
dstPtrY += dstStride;
}
}
// copy VU plane
const int scStride = srcStride >> 1;
const int dcStride = ALIGN_16(dstStride >> 1); // Android CTS required: U/V plane needs 16 bytes aligned!
if (dcStride == scStride) {
unsigned char *srcPtrVU = (unsigned char *)src + height * srcStride;
unsigned char *dstPtrVU = (unsigned char *)dst + height * dstStride;
MEMCPY_S(dstPtrVU, height * dcStride, srcPtrVU, height * dcStride);
} else {
const int wHalf = width >> 1;
const int hHalf = height >> 1;
unsigned char *srcPtrV = (unsigned char *)src + height * srcStride;
unsigned char *srcPtrU = srcPtrV + scStride * hHalf;
unsigned char *dstPtrV = (unsigned char *)dst + height * dstStride;
unsigned char *dstPtrU = dstPtrV + dcStride * hHalf;
for (int i = 0; i < hHalf; i ++) {
MEMCPY_S(dstPtrU, wHalf, srcPtrU, wHalf);
MEMCPY_S(dstPtrV, wHalf, srcPtrV, wHalf);
dstPtrU += dcStride, srcPtrU += scStride;
dstPtrV += dcStride, srcPtrV += scStride;
}
}
}
// covert NV12 (Y plane, interlaced UV bytes) to
// NV21 (Y plane, interlaced VU bytes) and trim stride width to real width
void trimConvertNV12ToNV21(int width, int height, int srcStride, void *src, void *dst)
{
const int ysize = width * height;
unsigned const char *pSrc = (unsigned char *)src;
unsigned char *pDst = (unsigned char *)dst;
// Copy Y component
if (srcStride == width) {
MEMCPY_S(pDst, ysize, pSrc, ysize);
} else if (srcStride > width) {
int j = height;
while(j--) {
MEMCPY_S(pDst, width, pSrc, width);
pSrc += srcStride;
pDst += width;
}
} else {
ALOGE("bad stride value");
return;
}
// Convert UV to VU
pSrc = (unsigned char *)src + srcStride * height;
pDst = (unsigned char *)dst + width * height;
for (int j = 0; j < height / 2; j++) {
if (width >= 16) {
const uint32_t *ptr0 = (const uint32_t *)(pSrc);
uint32_t *ptr1 = (uint32_t *)(pDst);
int bNotLastLine = ((j+1) == (height/2)) ? 0 : 1;
int width_16 = (width + 15 * bNotLastLine) & ~0xf;
if ((((uint64_t)(pSrc)) & 0xf) == 0 && (((uint64_t)(pDst)) & 0xf) == 0) { // 16 bytes aligned for both src and dest
__asm__ volatile(\
"movl %0, %%eax \n\t"
"movl %1, %%edx \n\t"
"movl %2, %%ecx \n\t"
"1: \n\t"
"movdqa (%%eax), %%xmm1 \n\t"
"movdqa %%xmm1, %%xmm0 \n\t"
"psllw $8, %%xmm1 \n\t"
"psrlw $8, %%xmm0 \n\t"
"por %%xmm0, %%xmm1 \n\t"
"movdqa %%xmm1, (%%edx) \n\t"
"add $16, %%eax \n\t"
"add $16, %%edx \n\t"
"sub $16, %%ecx \n\t"
"jnz 1b \n\t"
: "+m"(ptr0), "+m"(ptr1), "+m"(width_16)
:
: "eax", "ecx", "edx", "xmm0", "xmm1"
);
}
else { // either src or dest is not 16-bytes aligned
__asm__ volatile(\
"movl %0, %%eax \n\t"
"movl %1, %%edx \n\t"
"movl %2, %%ecx \n\t"
"1: \n\t"
"lddqu (%%eax), %%xmm1 \n\t"
"movdqa %%xmm1, %%xmm0 \n\t"
"psllw $8, %%xmm1 \n\t"
"psrlw $8, %%xmm0 \n\t"
"por %%xmm0, %%xmm1 \n\t"
"movdqu %%xmm1, (%%edx) \n\t"
"add $16, %%eax \n\t"
"add $16, %%edx \n\t"
"sub $16, %%ecx \n\t"
"jnz 1b \n\t"
: "+m"(ptr0), "+m"(ptr1), "+m"(width_16)
:
: "eax", "ecx", "edx", "xmm0", "xmm1"
);
}
// process remaining data of less than 16 bytes of last row
for (int i = width_16; i < width; i += 2) {
pDst[i] = pSrc[i + 1];
pDst[i + 1] = pSrc[i];
}
}
else if ((((uint64_t)(pSrc)) & 0x3) == 0 && (((uint64_t)(pDst)) & 0x3) == 0){ // 4 bytes aligned for both src and dest
const uint32_t *ptr0 = (const uint32_t *)(pSrc);
uint32_t *ptr1 = (uint32_t *)(pDst);
int width_4 = width & ~3;
for (int i = 0; i < width_4; i += 4) {
uint32_t data0 = *ptr0++;
uint32_t data1 = (data0 >> 8) & 0x00ff00ff;
uint32_t data2 = (data0 << 8) & 0xff00ff00;
*ptr1++ = data1 | data2;
}
// process remaining data of less than 4 bytes at end of each row
for (int i = width_4; i < width; i += 2) {
pDst[i] = pSrc[i + 1];
pDst[i + 1] = pSrc[i];
}
}
else {
unsigned const char *ptr0 = pSrc;
unsigned char *ptr1 = pDst;
for (int i = 0; i < width; i += 2) {
*ptr1++ = ptr0[1];
*ptr1++ = ptr0[0];
ptr0 += 2;
}
}
pDst += width;
pSrc += srcStride;
}
}
// convert NV12 (Y plane, interlaced UV bytes) to YV12 (Y plane, V plane, U plane)
// without Y and C 16 bytes aligned
void convertNV12ToYV12(int width, int height, int srcStride, void *src, void *dst)
{
int yStride = width;
size_t ySize = yStride * height;
int cStride = yStride/2;
size_t cSize = cStride * height/2;
unsigned char *srcPtr = (unsigned char *) src;
unsigned char *dstPtr = (unsigned char *) dst;
unsigned char *dstPtrV = (unsigned char *) dst + ySize;
unsigned char *dstPtrU = (unsigned char *) dst + ySize + cSize;
// copy the entire Y plane
if (srcStride == yStride) {
MEMCPY_S(dstPtr, ySize, srcPtr, ySize);
srcPtr += ySize;
} else if (srcStride > width) {
for (int i = 0; i < height; i++) {
MEMCPY_S(dstPtr, width, srcPtr, width);
srcPtr += srcStride;
dstPtr += yStride;
}
} else {
ALOGE("bad src stride value");
return;
}
// deinterlace the UV data
int halfHeight = height / 2;
int halfWidth = width / 2;
for ( int i = 0; i < halfHeight; ++i) {
for ( int j = 0; j < halfWidth; ++j) {
dstPtrV[j] = srcPtr[j * 2 + 1];
dstPtrU[j] = srcPtr[j * 2];
}
srcPtr += srcStride;
dstPtrV += cStride;
dstPtrU += cStride;
}
}
// convert NV12 (Y plane, interlaced UV bytes) to YV12 (Y plane, V plane, U plane)
// with Y and C 16 bytes aligned
void align16ConvertNV12ToYV12(int width, int height, int srcStride, void *src, void *dst)
{
int yStride = ALIGN_16(width);
size_t ySize = yStride * height;
int cStride = ALIGN_16(yStride/2);
size_t cSize = cStride * height/2;
unsigned char *srcPtr = (unsigned char *) src;
unsigned char *dstPtr = (unsigned char *) dst;
unsigned char *dstPtrV = (unsigned char *) dst + ySize;
unsigned char *dstPtrU = (unsigned char *) dst + ySize + cSize;
// copy the entire Y plane
if (srcStride == yStride) {
MEMCPY_S(dstPtr, ySize, srcPtr, ySize);
srcPtr += ySize;
} else if (srcStride > width) {
for (int i = 0; i < height; i++) {
MEMCPY_S(dstPtr, width, srcPtr, width);
srcPtr += srcStride;
dstPtr += yStride;
}
} else {
ALOGE("bad src stride value");
return;
}
// deinterlace the UV data
for ( int i = 0; i < height / 2; ++i) {
for ( int j = 0; j < width / 2; ++j) {
dstPtrV[j] = srcPtr[j * 2 + 1];
dstPtrU[j] = srcPtr[j * 2];
}
srcPtr += srcStride;
dstPtrV += cStride;
dstPtrU += cStride;
}
}
// P411's Y, U, V are seperated. But the YUY2's Y, U and V are interleaved.
void YUY2ToP411(int width, int height, int stride, void *src, void *dst)
{
int ySize = width * height;
int cSize = width * height / 4;
int wHalf = width >> 1;
unsigned char *srcPtr = (unsigned char *) src;
unsigned char *dstPtr = (unsigned char *) dst;
unsigned char *dstPtrU = (unsigned char *) dst + ySize;
unsigned char *dstPtrV = (unsigned char *) dst + ySize + cSize;
for (int i = 0; i < height; i++) {
//The first line of the source
//Copy first Y Plane first
for (int j=0; j < width; j++) {
dstPtr[j] = srcPtr[j*2];
}
if (i & 1) {
//Copy the V plane
for (int k = 0; k < wHalf; k++) {
dstPtrV[k] = srcPtr[k * 4 + 3];
}
dstPtrV = dstPtrV + wHalf;
} else {
//Copy the U plane
for (int k = 0; k< wHalf; k++) {
dstPtrU[k] = srcPtr[k * 4 + 1];
}
dstPtrU = dstPtrU + wHalf;
}
srcPtr = srcPtr + stride * 2;
dstPtr = dstPtr + width;
}
}
// P411's Y, U, V are separated. But the NV12's U and V are interleaved.
void NV12ToP411Separate(int width, int height, int stride,
void *srcY, void *srcUV, void *dst)
{
int i, j, p, q;
unsigned char *psrcY = (unsigned char *) srcY;
unsigned char *pdstY = (unsigned char *) dst;
unsigned char *pdstU, *pdstV;
unsigned char *psrcUV;
// copy Y data
for (i = 0; i < height; i++) {
MEMCPY_S(pdstY, width, psrcY, width);
pdstY += width;
psrcY += stride;
}
// copy U data and V data
psrcUV = (unsigned char *)srcUV;
pdstU = (unsigned char *)dst + width * height;
pdstV = pdstU + width * height / 4;
p = q = 0;
for (i = 0; i < height / 2; i++) {
for (j = 0; j < width; j++) {
if (j % 2 == 0) {
pdstU[p] = (psrcUV[i * stride + j] & 0xFF);
p++;
} else {
pdstV[q] = (psrcUV[i * stride + j] & 0xFF);
q++;
}
}
}
}
// P411's Y, U, V are seperated. But the NV12's U and V are interleaved.
void NV12ToP411(int width, int height, int stride, void *src, void *dst)
{
NV12ToP411Separate(width, height, stride,
src, (void *)((unsigned char *)src + width * height), dst);
}
// P411's Y, U, V are separated. But the NV21's U and V are interleaved.
void NV21ToP411Separate(int width, int height, int stride,
void *srcY, void *srcUV, void *dst)
{
int i, j, p, q;
unsigned char *psrcY = (unsigned char *) srcY;
unsigned char *pdstY = (unsigned char *) dst;
unsigned char *pdstU, *pdstV;
unsigned char *psrcUV;
// copy Y data
for (i = 0; i < height; i++) {
MEMCPY_S(pdstY, width, psrcY, width);
pdstY += width;
psrcY += stride;
}
// copy U data and V data
psrcUV = (unsigned char *)srcUV;
pdstU = (unsigned char *)dst + width * height;
pdstV = pdstU + width * height / 4;
p = q = 0;
for (i = 0; i < height / 2; i++) {
for (j = 0; j < width; j++) {
if ((j & 1) == 0) {
pdstV[p] = (psrcUV[i * stride + j] & 0xFF);
p++;
} else {
pdstU[q] = (psrcUV[i * stride + j] & 0xFF);
q++;
}
}
}
}
// P411's Y, U, V are seperated. But the NV21's U and V are interleaved.
void NV21ToP411(int width, int height, int stride, void *src, void *dst)
{
NV21ToP411Separate(width, height, stride,
src, (void *)((unsigned char *)src + width * height), dst);
}
// IMC3 Y, U, V are separated,the stride for U/V is the same as Y.
// about IMC3 detail, please refer to http://www.fourcc.org/yuv.php
// But the NV12's U and V are interleaved.
void NV12ToIMC3(int width, int height, int stride, void *srcY, void *srcUV, void *dst)
{
int i, j, p, q;
unsigned char *pdstU, *pdstV;
unsigned char *psrcUV;
// copy Y data even with stride
MEMCPY_S(dst, stride * height, srcY, stride * height);
// copy U data and V data
psrcUV = (unsigned char *)srcUV;
pdstU = (unsigned char *)dst + stride * height;
pdstV = pdstU + stride * height / 2;
p = q = 0;
for (i = 0; i < height / 2; i++) {
for (j = 0; j < width; j++) {
if (j % 2 == 0) {
pdstU[p]= (psrcUV[i * stride + j] & 0xFF) ;
p++;
} else {
pdstV[q]= (psrcUV[i * stride + j] & 0xFF);
q++;
}
}
p += stride - width/2;
q += stride - width/2;
}
}
// IMC1 Y, V,U are separated,the stride for U/V is the same as Y.
// IMC's V is before U
// But the NV12's U and V are interleaved.
void NV12ToIMC1(int width, int height, int stride, void *srcY, void *srcUV, void *dst)
{
int i, j, p, q;
unsigned char *pdstU, *pdstV;
unsigned char *psrcUV;
// copy Y data even with stride
MEMCPY_S(dst, stride * height, srcY, stride * height);
// copy U data and V data
psrcUV = (unsigned char *)srcUV;
pdstV = (unsigned char *)dst + stride * height;
pdstU = pdstV + stride * height / 2;
p = q = 0;
for (i = 0; i < height / 2; i++) {
for (j = 0; j < width; j++) {
if (j % 2 == 0) {
pdstU[p]= (psrcUV[i * stride + j] & 0xFF) ;
p++;
} else {
pdstV[q]= (psrcUV[i * stride + j] & 0xFF);
q++;
}
}
p += stride - width/2;
q += stride - width/2;
}
}
// Re-pad YUV420 format image, the format can be YV12, YU12 or YUV420 planar.
// If buffer size: (height*dstStride*1.5) > (height*srcStride*1.5), src and dst
// buffer start addresses are same, the re-padding can be done inplace.
void repadYUV420(int width, int height, int srcStride, int dstStride, void *src, void *dst)
{
unsigned char *dptr;
unsigned char *sptr;
void * (*myCopy)(void *dst, const void *src, size_t n);
const int whalf = width >> 1;
const int hhalf = height >> 1;
const int scStride = srcStride >> 1;
const int dcStride = dstStride >> 1;
const int sySize = height * srcStride;
const int dySize = height * dstStride;
const int scSize = hhalf * scStride;
const int dcSize = hhalf * dcStride;
// directly copy, if (srcStride == dstStride)
if (srcStride == dstStride) {
MEMCPY_S(dst, dySize + 2*dcSize, src, dySize + 2*dcSize);
return;
}
// copy V(YV12 case) or U(YU12 case) plane line by line
sptr = (unsigned char *)src + sySize + 2*scSize - scStride;
dptr = (unsigned char *)dst + dySize + 2*dcSize - dcStride;
// try to avoid overlapped memcpy()
myCopy = (abs(sptr -dptr) > dstStride) ? memcpy : memmove;
for (int i = 0; i < hhalf; i ++) {
myCopy(dptr, sptr, whalf);
sptr -= scStride;
dptr -= dcStride;
}
// copy V(YV12 case) or U(YU12 case) U/V plane line by line
sptr = (unsigned char *)src + sySize + scSize - scStride;
dptr = (unsigned char *)dst + dySize + dcSize - dcStride;
for (int i = 0; i < hhalf; i ++) {
myCopy(dptr, sptr, whalf);
sptr -= scStride;
dptr -= dcStride;
}
// copy Y plane line by line
sptr = (unsigned char *)src + sySize - srcStride;
dptr = (unsigned char *)dst + dySize - dstStride;
for (int i = 0; i < height; i ++) {
myCopy(dptr, sptr, width);
sptr -= srcStride;
dptr -= dstStride;
}
}
// covert YUYV(YUY2, YUV422 format) to YV12 (Y plane, V plane, U plane)
void convertYUYVToYV12(int width, int height, int srcStride, int dstStride, void *src, void *dst)
{
int ySize = width * height;
int cSize = ALIGN_16(dstStride/2) * height / 2;
int wHalf = width >> 1;
unsigned char *srcPtr = (unsigned char *) src;
unsigned char *dstPtr = (unsigned char *) dst;
unsigned char *dstPtrV = (unsigned char *) dst + ySize;
unsigned char *dstPtrU = (unsigned char *) dst + ySize + cSize;
for (int i = 0; i < height; i++) {
//The first line of the source
//Copy first Y Plane first
for (int j=0; j < width; j++) {
dstPtr[j] = srcPtr[j*2];
}
if (i & 1) {
//Copy the V plane
for (int k = 0; k< wHalf; k++) {
dstPtrV[k] = srcPtr[k * 4 + 3];
}
dstPtrV = dstPtrV + ALIGN_16(dstStride>>1);
} else {
//Copy the U plane
for (int k = 0; k< wHalf; k++) {
dstPtrU[k] = srcPtr[k * 4 + 1];
}
dstPtrU = dstPtrU + ALIGN_16(dstStride>>1);
}
srcPtr = srcPtr + srcStride * 2;
dstPtr = dstPtr + width;
}
}
// covert YUYV(YUY2, YUV422 format) to NV21 (Y plane, interlaced VU bytes)
void convertYUYVToNV21(int width, int height, int srcStride, void *src, void *dst)
{
int ySize = width * height;
int u_counter=1, v_counter=0;
unsigned char *srcPtr = (unsigned char *) src;
unsigned char *dstPtr = (unsigned char *) dst;
unsigned char *dstPtrUV = (unsigned char *) dst + ySize;
for (int i=0; i < height; i++) {
//The first line of the source
//Copy first Y Plane first
for (int j=0; j < width * 2; j++) {
if (j % 2 == 0)
dstPtr[j/2] = srcPtr[j];
if (i%2) {
if (( j % 4 ) == 3) {
dstPtrUV[v_counter] = srcPtr[j]; //V plane
v_counter += 2;
}
if (( j % 4 ) == 1) {
dstPtrUV[u_counter] = srcPtr[j]; //U plane
u_counter += 2;
}
}
}
srcPtr = srcPtr + srcStride * 2;
dstPtr = dstPtr + width;
}
}
void convertNV12ToYUYV(int srcWidth, int srcHeight, int srcStride, int dstStride, const void *src, void *dst)
{
int y_counter = 0, u_counter = 1, v_counter = 3, uv_counter = 0;
unsigned char *srcYPtr = (unsigned char *) src;
unsigned char *srcUVPtr = (unsigned char *)src + srcWidth * srcHeight;
unsigned char *dstPtr = (unsigned char *) dst;
for (int i = 0; i < srcHeight; i++) {
for (int k = 0; k < srcWidth; k++) {
dstPtr[y_counter] = srcYPtr[k];
y_counter += 2;
dstPtr[u_counter] = srcUVPtr[uv_counter];
u_counter += 4;
dstPtr[v_counter] = srcUVPtr[uv_counter + 1];
v_counter += 4;
uv_counter += 2;
}
if ((i % 2) == 0) {
srcUVPtr = srcUVPtr + srcStride;
}
dstPtr = dstPtr + 2 * dstStride;
srcYPtr = srcYPtr + srcStride;
u_counter = 1;
v_counter = 3;
y_counter = 0;
uv_counter = 0;
}
}
void convertBuftoYV12(int format, int width, int height, int srcStride,
int dstStride, void *src, void *dst, bool align16)
{
switch (format) {
case V4L2_PIX_FMT_NV12:
align16 ? align16ConvertNV12ToYV12(width, height, srcStride, src, dst)
: convertNV12ToYV12(width, height, srcStride, src, dst);
break;
case V4L2_PIX_FMT_YVU420:
copyYV12ToYV12(width, height, srcStride, dstStride, src, dst);
break;
case V4L2_PIX_FMT_YUYV:
convertYUYVToYV12(width, height, srcStride, dstStride, src, dst);
break;
default:
ALOGE("%s: unsupported format %d", __func__, format);
break;
}
}
void convertBuftoNV21(int format, int width, int height, int srcStride,
int dstStride, void *src, void *dst)
{
switch (format) {
case V4L2_PIX_FMT_NV12:
trimConvertNV12ToNV21(width, height, srcStride, src, dst);
break;
case V4L2_PIX_FMT_YVU420:
convertYV12ToNV21(width, height, srcStride, dstStride, src, dst);
break;
case V4L2_PIX_FMT_YUYV:
convertYUYVToNV21(width, height, srcStride, src, dst);
break;
default:
ALOGE("%s: unsupported format %d", __func__, format);
break;
}
}
void convertBuftoYUYV(int format, int width, int height, int srcStride,
int dstStride, void *src, void *dst)
{
switch (format) {
case V4L2_PIX_FMT_NV12:
convertNV12ToYUYV(width, height, srcStride, dstStride, src, dst);
break;
default:
LOGE("%s: unsupported format %d", __func__, format);
break;
}
}
} // namespace ImageConverter
} // namespace icamera