/* * Copyright 2011 The LibYuv Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "libyuv/row.h" #include <stdio.h>#include <string.h> // For memcpy and memset. #include "libyuv/basic_types.h" #ifdef __cplusplusnamespace libyuv {extern "C" {#endif // llvm x86 is poor at ternary operator, so use branchless min/max. #define USE_BRANCHLESS 1#if USE_BRANCHLESSstatic __inline int32_t clamp0(int32_t v) { return ((-(v) >> 31) & (v));} static __inline int32_t clamp255(int32_t v) { return (((255 - (v)) >> 31) | (v)) & 255;} static __inline int32_t clamp1023(int32_t v) { return (((1023 - (v)) >> 31) | (v)) & 1023;} static __inline uint32_t Abs(int32_t v) { int m = v >> 31; return (v + m) ^ m;}#else // USE_BRANCHLESSstatic __inline int32_t clamp0(int32_t v) { return (v < 0) ? 0 : v;} static __inline int32_t clamp255(int32_t v) { return (v > 255) ? 255 : v;} static __inline int32_t clamp1023(int32_t v) { return (v > 1023) ? 1023 : v;} static __inline uint32_t Abs(int32_t v) { return (v < 0) ? -v : v;}#endif // USE_BRANCHLESSstatic __inline uint32_t Clamp(int32_t val) { int v = clamp0(val); return (uint32_t)(clamp255(v));} static __inline uint32_t Clamp10(int32_t val) { int v = clamp0(val); return (uint32_t)(clamp1023(v));} // Little Endian#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) || \ (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)#define WRITEWORD(p, v) *(uint32_t*)(p) = v#elsestatic inline void WRITEWORD(uint8_t* p, uint32_t v) { p[0] = (uint8_t)(v & 255); p[1] = (uint8_t)((v >> 8) & 255); p[2] = (uint8_t)((v >> 16) & 255); p[3] = (uint8_t)((v >> 24) & 255);}#endif void RGB24ToARGBRow_C(const uint8_t* src_rgb24, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_rgb24[0]; uint8_t g = src_rgb24[1]; uint8_t r = src_rgb24[2]; dst_argb[0] = b; dst_argb[1] = g; dst_argb[2] = r; dst_argb[3] = 255u; dst_argb += 4; src_rgb24 += 3; }} void RAWToARGBRow_C(const uint8_t* src_raw, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t r = src_raw[0]; uint8_t g = src_raw[1]; uint8_t b = src_raw[2]; dst_argb[0] = b; dst_argb[1] = g; dst_argb[2] = r; dst_argb[3] = 255u; dst_argb += 4; src_raw += 3; }} void RAWToRGB24Row_C(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) { int x; for (x = 0; x < width; ++x) { uint8_t r = src_raw[0]; uint8_t g = src_raw[1]; uint8_t b = src_raw[2]; dst_rgb24[0] = b; dst_rgb24[1] = g; dst_rgb24[2] = r; dst_rgb24 += 3; src_raw += 3; }} void RGB565ToARGBRow_C(const uint8_t* src_rgb565, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_rgb565[0] & 0x1f; uint8_t g = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); uint8_t r = src_rgb565[1] >> 3; dst_argb[0] = (b << 3) | (b >> 2); dst_argb[1] = (g << 2) | (g >> 4); dst_argb[2] = (r << 3) | (r >> 2); dst_argb[3] = 255u; dst_argb += 4; src_rgb565 += 2; }} void ARGB1555ToARGBRow_C(const uint8_t* src_argb1555, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_argb1555[0] & 0x1f; uint8_t g = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); uint8_t r = (src_argb1555[1] & 0x7c) >> 2; uint8_t a = src_argb1555[1] >> 7; dst_argb[0] = (b << 3) | (b >> 2); dst_argb[1] = (g << 3) | (g >> 2); dst_argb[2] = (r << 3) | (r >> 2); dst_argb[3] = -a; dst_argb += 4; src_argb1555 += 2; }} void ARGB4444ToARGBRow_C(const uint8_t* src_argb4444, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_argb4444[0] & 0x0f; uint8_t g = src_argb4444[0] >> 4; uint8_t r = src_argb4444[1] & 0x0f; uint8_t a = src_argb4444[1] >> 4; dst_argb[0] = (b << 4) | b; dst_argb[1] = (g << 4) | g; dst_argb[2] = (r << 4) | r; dst_argb[3] = (a << 4) | a; dst_argb += 4; src_argb4444 += 2; }} void AR30ToARGBRow_C(const uint8_t* src_ar30, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint32_t ar30 = *(const uint32_t*)src_ar30; uint32_t b = (ar30 >> 2) & 0xff; uint32_t g = (ar30 >> 12) & 0xff; uint32_t r = (ar30 >> 22) & 0xff; uint32_t a = (ar30 >> 30) * 0x55; // Replicate 2 bits to 8 bits. *(uint32_t*)(dst_argb) = b | (g << 8) | (r << 16) | (a << 24); dst_argb += 4; src_ar30 += 4; }} void AR30ToABGRRow_C(const uint8_t* src_ar30, uint8_t* dst_abgr, int width) { int x; for (x = 0; x < width; ++x) { uint32_t ar30 = *(const uint32_t*)src_ar30; uint32_t b = (ar30 >> 2) & 0xff; uint32_t g = (ar30 >> 12) & 0xff; uint32_t r = (ar30 >> 22) & 0xff; uint32_t a = (ar30 >> 30) * 0x55; // Replicate 2 bits to 8 bits. *(uint32_t*)(dst_abgr) = r | (g << 8) | (b << 16) | (a << 24); dst_abgr += 4; src_ar30 += 4; }} void AR30ToAB30Row_C(const uint8_t* src_ar30, uint8_t* dst_ab30, int width) { int x; for (x = 0; x < width; ++x) { uint32_t ar30 = *(const uint32_t*)src_ar30; uint32_t b = ar30 & 0x3ff; uint32_t ga = ar30 & 0xc00ffc00; uint32_t r = (ar30 >> 20) & 0x3ff; *(uint32_t*)(dst_ab30) = r | ga | (b << 20); dst_ab30 += 4; src_ar30 += 4; }} void ARGBToRGB24Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_argb[0]; uint8_t g = src_argb[1]; uint8_t r = src_argb[2]; dst_rgb[0] = b; dst_rgb[1] = g; dst_rgb[2] = r; dst_rgb += 3; src_argb += 4; }} void ARGBToRAWRow_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_argb[0]; uint8_t g = src_argb[1]; uint8_t r = src_argb[2]; dst_rgb[0] = r; dst_rgb[1] = g; dst_rgb[2] = b; dst_rgb += 3; src_argb += 4; }} void ARGBToRGB565Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width - 1; x += 2) { uint8_t b0 = src_argb[0] >> 3; uint8_t g0 = src_argb[1] >> 2; uint8_t r0 = src_argb[2] >> 3; uint8_t b1 = src_argb[4] >> 3; uint8_t g1 = src_argb[5] >> 2; uint8_t r1 = src_argb[6] >> 3; WRITEWORD(dst_rgb, b0 | (g0 << 5) | (r0 << 11) | (b1 << 16) | (g1 << 21) | (r1 << 27)); dst_rgb += 4; src_argb += 8; } if (width & 1) { uint8_t b0 = src_argb[0] >> 3; uint8_t g0 = src_argb[1] >> 2; uint8_t r0 = src_argb[2] >> 3; *(uint16_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 11); }} // dither4 is a row of 4 values from 4x4 dither matrix.// The 4x4 matrix contains values to increase RGB. When converting to// fewer bits (565) this provides an ordered dither.// The order in the 4x4 matrix in first byte is upper left.// The 4 values are passed as an int, then referenced as an array, so// endian will not affect order of the original matrix. But the dither4// will containing the first pixel in the lower byte for little endian// or the upper byte for big endian.void ARGBToRGB565DitherRow_C(const uint8_t* src_argb, uint8_t* dst_rgb, const uint32_t dither4, int width) { int x; for (x = 0; x < width - 1; x += 2) { int dither0 = ((const unsigned char*)(&dither4))[x & 3]; int dither1 = ((const unsigned char*)(&dither4))[(x + 1) & 3]; uint8_t b0 = clamp255(src_argb[0] + dither0) >> 3; uint8_t g0 = clamp255(src_argb[1] + dither0) >> 2; uint8_t r0 = clamp255(src_argb[2] + dither0) >> 3; uint8_t b1 = clamp255(src_argb[4] + dither1) >> 3; uint8_t g1 = clamp255(src_argb[5] + dither1) >> 2; uint8_t r1 = clamp255(src_argb[6] + dither1) >> 3; WRITEWORD(dst_rgb, b0 | (g0 << 5) | (r0 << 11) | (b1 << 16) | (g1 << 21) | (r1 << 27)); dst_rgb += 4; src_argb += 8; } if (width & 1) { int dither0 = ((const unsigned char*)(&dither4))[(width - 1) & 3]; uint8_t b0 = clamp255(src_argb[0] + dither0) >> 3; uint8_t g0 = clamp255(src_argb[1] + dither0) >> 2; uint8_t r0 = clamp255(src_argb[2] + dither0) >> 3; *(uint16_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 11); }} void ARGBToARGB1555Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width - 1; x += 2) { uint8_t b0 = src_argb[0] >> 3; uint8_t g0 = src_argb[1] >> 3; uint8_t r0 = src_argb[2] >> 3; uint8_t a0 = src_argb[3] >> 7; uint8_t b1 = src_argb[4] >> 3; uint8_t g1 = src_argb[5] >> 3; uint8_t r1 = src_argb[6] >> 3; uint8_t a1 = src_argb[7] >> 7; *(uint32_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 10) | (a0 << 15) | (b1 << 16) | (g1 << 21) | (r1 << 26) | (a1 << 31); dst_rgb += 4; src_argb += 8; } if (width & 1) { uint8_t b0 = src_argb[0] >> 3; uint8_t g0 = src_argb[1] >> 3; uint8_t r0 = src_argb[2] >> 3; uint8_t a0 = src_argb[3] >> 7; *(uint16_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 10) | (a0 << 15); }} void ARGBToARGB4444Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width - 1; x += 2) { uint8_t b0 = src_argb[0] >> 4; uint8_t g0 = src_argb[1] >> 4; uint8_t r0 = src_argb[2] >> 4; uint8_t a0 = src_argb[3] >> 4; uint8_t b1 = src_argb[4] >> 4; uint8_t g1 = src_argb[5] >> 4; uint8_t r1 = src_argb[6] >> 4; uint8_t a1 = src_argb[7] >> 4; *(uint32_t*)(dst_rgb) = b0 | (g0 << 4) | (r0 << 8) | (a0 << 12) | (b1 << 16) | (g1 << 20) | (r1 << 24) | (a1 << 28); dst_rgb += 4; src_argb += 8; } if (width & 1) { uint8_t b0 = src_argb[0] >> 4; uint8_t g0 = src_argb[1] >> 4; uint8_t r0 = src_argb[2] >> 4; uint8_t a0 = src_argb[3] >> 4; *(uint16_t*)(dst_rgb) = b0 | (g0 << 4) | (r0 << 8) | (a0 << 12); }} void ABGRToAR30Row_C(const uint8_t* src_abgr, uint8_t* dst_ar30, int width) { int x; for (x = 0; x < width; ++x) { uint32_t b0 = (src_abgr[0] >> 6) | ((uint32_t)(src_abgr[0]) << 2); uint32_t g0 = (src_abgr[1] >> 6) | ((uint32_t)(src_abgr[1]) << 2); uint32_t r0 = (src_abgr[2] >> 6) | ((uint32_t)(src_abgr[2]) << 2); uint32_t a0 = (src_abgr[3] >> 6); *(uint32_t*)(dst_ar30) = r0 | (g0 << 10) | (b0 << 20) | (a0 << 30); dst_ar30 += 4; src_abgr += 4; }} void ARGBToAR30Row_C(const uint8_t* src_argb, uint8_t* dst_ar30, int width) { int x; for (x = 0; x < width; ++x) { uint32_t b0 = (src_argb[0] >> 6) | ((uint32_t)(src_argb[0]) << 2); uint32_t g0 = (src_argb[1] >> 6) | ((uint32_t)(src_argb[1]) << 2); uint32_t r0 = (src_argb[2] >> 6) | ((uint32_t)(src_argb[2]) << 2); uint32_t a0 = (src_argb[3] >> 6); *(uint32_t*)(dst_ar30) = b0 | (g0 << 10) | (r0 << 20) | (a0 << 30); dst_ar30 += 4; src_argb += 4; }} static __inline int RGBToY(uint8_t r, uint8_t g, uint8_t b) { return (66 * r + 129 * g + 25 * b + 0x1080) >> 8;} static __inline int RGBToU(uint8_t r, uint8_t g, uint8_t b) { return (112 * b - 74 * g - 38 * r + 0x8080) >> 8;}static __inline int RGBToV(uint8_t r, uint8_t g, uint8_t b) { return (112 * r - 94 * g - 18 * b + 0x8080) >> 8;} // ARGBToY_C and ARGBToUV_C#define MAKEROWY(NAME, R, G, B, BPP) \ void NAME##ToYRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width) { \ int x; \ for (x = 0; x < width; ++x) { \ dst_y[0] = RGBToY(src_argb0[R], src_argb0[G], src_argb0[B]); \ src_argb0 += BPP; \ dst_y += 1; \ } \ } \ void NAME##ToUVRow_C(const uint8_t* src_rgb0, int src_stride_rgb, \ uint8_t* dst_u, uint8_t* dst_v, int width) { \ const uint8_t* src_rgb1 = src_rgb0 + src_stride_rgb; \ int x; \ for (x = 0; x < width - 1; x += 2) { \ uint8_t ab = (src_rgb0[B] + src_rgb0[B + BPP] + src_rgb1[B] + \ src_rgb1[B + BPP]) >> \ 2; \ uint8_t ag = (src_rgb0[G] + src_rgb0[G + BPP] + src_rgb1[G] + \ src_rgb1[G + BPP]) >> \ 2; \ uint8_t ar = (src_rgb0[R] + src_rgb0[R + BPP] + src_rgb1[R] + \ src_rgb1[R + BPP]) >> \ 2; \ dst_u[0] = RGBToU(ar, ag, ab); \ dst_v[0] = RGBToV(ar, ag, ab); \ src_rgb0 += BPP * 2; \ src_rgb1 += BPP * 2; \ dst_u += 1; \ dst_v += 1; \ } \ if (width & 1) { \ uint8_t ab = (src_rgb0[B] + src_rgb1[B]) >> 1; \ uint8_t ag = (src_rgb0[G] + src_rgb1[G]) >> 1; \ uint8_t ar = (src_rgb0[R] + src_rgb1[R]) >> 1; \ dst_u[0] = RGBToU(ar, ag, ab); \ dst_v[0] = RGBToV(ar, ag, ab); \ } \ } MAKEROWY(ARGB, 2, 1, 0, 4)MAKEROWY(BGRA, 1, 2, 3, 4)MAKEROWY(ABGR, 0, 1, 2, 4)MAKEROWY(RGBA, 3, 2, 1, 4)MAKEROWY(RGB24, 2, 1, 0, 3)MAKEROWY(RAW, 0, 1, 2, 3)#undef MAKEROWY // JPeg uses a variation on BT.601-1 full range// y = 0.29900 * r + 0.58700 * g + 0.11400 * b// u = -0.16874 * r - 0.33126 * g + 0.50000 * b + center// v = 0.50000 * r - 0.41869 * g - 0.08131 * b + center// BT.601 Mpeg range uses:// b 0.1016 * 255 = 25.908 = 25// g 0.5078 * 255 = 129.489 = 129// r 0.2578 * 255 = 65.739 = 66// JPeg 8 bit Y (not used):// b 0.11400 * 256 = 29.184 = 29// g 0.58700 * 256 = 150.272 = 150// r 0.29900 * 256 = 76.544 = 77// JPeg 7 bit Y:// b 0.11400 * 128 = 14.592 = 15// g 0.58700 * 128 = 75.136 = 75// r 0.29900 * 128 = 38.272 = 38// JPeg 8 bit U:// b 0.50000 * 255 = 127.5 = 127// g -0.33126 * 255 = -84.4713 = -84// r -0.16874 * 255 = -43.0287 = -43// JPeg 8 bit V:// b -0.08131 * 255 = -20.73405 = -20// g -0.41869 * 255 = -106.76595 = -107// r 0.50000 * 255 = 127.5 = 127 static __inline int RGBToYJ(uint8_t r, uint8_t g, uint8_t b) { return (38 * r + 75 * g + 15 * b + 64) >> 7;} static __inline int RGBToUJ(uint8_t r, uint8_t g, uint8_t b) { return (127 * b - 84 * g - 43 * r + 0x8080) >> 8;}static __inline int RGBToVJ(uint8_t r, uint8_t g, uint8_t b) { return (127 * r - 107 * g - 20 * b + 0x8080) >> 8;} #define AVGB(a, b) (((a) + (b) + 1) >> 1) // ARGBToYJ_C and ARGBToUVJ_C#define MAKEROWYJ(NAME, R, G, B, BPP) \ void NAME##ToYJRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width) { \ int x; \ for (x = 0; x < width; ++x) { \ dst_y[0] = RGBToYJ(src_argb0[R], src_argb0[G], src_argb0[B]); \ src_argb0 += BPP; \ dst_y += 1; \ } \ } \ void NAME##ToUVJRow_C(const uint8_t* src_rgb0, int src_stride_rgb, \ uint8_t* dst_u, uint8_t* dst_v, int width) { \ const uint8_t* src_rgb1 = src_rgb0 + src_stride_rgb; \ int x; \ for (x = 0; x < width - 1; x += 2) { \ uint8_t ab = AVGB(AVGB(src_rgb0[B], src_rgb1[B]), \ AVGB(src_rgb0[B + BPP], src_rgb1[B + BPP])); \ uint8_t ag = AVGB(AVGB(src_rgb0[G], src_rgb1[G]), \ AVGB(src_rgb0[G + BPP], src_rgb1[G + BPP])); \ uint8_t ar = AVGB(AVGB(src_rgb0[R], src_rgb1[R]), \Lines 1–500 of 3237. Load more
/* * Copyright 2011 The LibYuv Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "libyuv/row.h" #include <stdio.h> #include <string.h> // For memcpy and memset. #include "libyuv/basic_types.h" #ifdef __cplusplus namespace libyuv { extern "C" { #endif // llvm x86 is poor at ternary operator, so use branchless min/max. #define USE_BRANCHLESS 1 #if USE_BRANCHLESS static __inline int32_t clamp0(int32_t v) { return ((-(v) >> 31) & (v)); } static __inline int32_t clamp255(int32_t v) { return (((255 - (v)) >> 31) | (v)) & 255; } static __inline int32_t clamp1023(int32_t v) { return (((1023 - (v)) >> 31) | (v)) & 1023; } static __inline uint32_t Abs(int32_t v) { int m = v >> 31; return (v + m) ^ m; } #else // USE_BRANCHLESS static __inline int32_t clamp0(int32_t v) { return (v < 0) ? 0 : v; } static __inline int32_t clamp255(int32_t v) { return (v > 255) ? 255 : v; } static __inline int32_t clamp1023(int32_t v) { return (v > 1023) ? 1023 : v; } static __inline uint32_t Abs(int32_t v) { return (v < 0) ? -v : v; } #endif // USE_BRANCHLESS static __inline uint32_t Clamp(int32_t val) { int v = clamp0(val); return (uint32_t)(clamp255(v)); } static __inline uint32_t Clamp10(int32_t val) { int v = clamp0(val); return (uint32_t)(clamp1023(v)); } // Little Endian #if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) || \ (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) #define WRITEWORD(p, v) *(uint32_t*)(p) = v #else static inline void WRITEWORD(uint8_t* p, uint32_t v) { p[0] = (uint8_t)(v & 255); p[1] = (uint8_t)((v >> 8) & 255); p[2] = (uint8_t)((v >> 16) & 255); p[3] = (uint8_t)((v >> 24) & 255); } #endif void RGB24ToARGBRow_C(const uint8_t* src_rgb24, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_rgb24[0]; uint8_t g = src_rgb24[1]; uint8_t r = src_rgb24[2]; dst_argb[0] = b; dst_argb[1] = g; dst_argb[2] = r; dst_argb[3] = 255u; dst_argb += 4; src_rgb24 += 3; } } void RAWToARGBRow_C(const uint8_t* src_raw, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t r = src_raw[0]; uint8_t g = src_raw[1]; uint8_t b = src_raw[2]; dst_argb[0] = b; dst_argb[1] = g; dst_argb[2] = r; dst_argb[3] = 255u; dst_argb += 4; src_raw += 3; } } void RAWToRGB24Row_C(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) { int x; for (x = 0; x < width; ++x) { uint8_t r = src_raw[0]; uint8_t g = src_raw[1]; uint8_t b = src_raw[2]; dst_rgb24[0] = b; dst_rgb24[1] = g; dst_rgb24[2] = r; dst_rgb24 += 3; src_raw += 3; } } void RGB565ToARGBRow_C(const uint8_t* src_rgb565, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_rgb565[0] & 0x1f; uint8_t g = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); uint8_t r = src_rgb565[1] >> 3; dst_argb[0] = (b << 3) | (b >> 2); dst_argb[1] = (g << 2) | (g >> 4); dst_argb[2] = (r << 3) | (r >> 2); dst_argb[3] = 255u; dst_argb += 4; src_rgb565 += 2; } } void ARGB1555ToARGBRow_C(const uint8_t* src_argb1555, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_argb1555[0] & 0x1f; uint8_t g = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); uint8_t r = (src_argb1555[1] & 0x7c) >> 2; uint8_t a = src_argb1555[1] >> 7; dst_argb[0] = (b << 3) | (b >> 2); dst_argb[1] = (g << 3) | (g >> 2); dst_argb[2] = (r << 3) | (r >> 2); dst_argb[3] = -a; dst_argb += 4; src_argb1555 += 2; } } void ARGB4444ToARGBRow_C(const uint8_t* src_argb4444, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_argb4444[0] & 0x0f; uint8_t g = src_argb4444[0] >> 4; uint8_t r = src_argb4444[1] & 0x0f; uint8_t a = src_argb4444[1] >> 4; dst_argb[0] = (b << 4) | b; dst_argb[1] = (g << 4) | g; dst_argb[2] = (r << 4) | r; dst_argb[3] = (a << 4) | a; dst_argb += 4; src_argb4444 += 2; } } void AR30ToARGBRow_C(const uint8_t* src_ar30, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { uint32_t ar30 = *(const uint32_t*)src_ar30; uint32_t b = (ar30 >> 2) & 0xff; uint32_t g = (ar30 >> 12) & 0xff; uint32_t r = (ar30 >> 22) & 0xff; uint32_t a = (ar30 >> 30) * 0x55; // Replicate 2 bits to 8 bits. *(uint32_t*)(dst_argb) = b | (g << 8) | (r << 16) | (a << 24); dst_argb += 4; src_ar30 += 4; } } void AR30ToABGRRow_C(const uint8_t* src_ar30, uint8_t* dst_abgr, int width) { int x; for (x = 0; x < width; ++x) { uint32_t ar30 = *(const uint32_t*)src_ar30; uint32_t b = (ar30 >> 2) & 0xff; uint32_t g = (ar30 >> 12) & 0xff; uint32_t r = (ar30 >> 22) & 0xff; uint32_t a = (ar30 >> 30) * 0x55; // Replicate 2 bits to 8 bits. *(uint32_t*)(dst_abgr) = r | (g << 8) | (b << 16) | (a << 24); dst_abgr += 4; src_ar30 += 4; } } void AR30ToAB30Row_C(const uint8_t* src_ar30, uint8_t* dst_ab30, int width) { int x; for (x = 0; x < width; ++x) { uint32_t ar30 = *(const uint32_t*)src_ar30; uint32_t b = ar30 & 0x3ff; uint32_t ga = ar30 & 0xc00ffc00; uint32_t r = (ar30 >> 20) & 0x3ff; *(uint32_t*)(dst_ab30) = r | ga | (b << 20); dst_ab30 += 4; src_ar30 += 4; } } void ARGBToRGB24Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_argb[0]; uint8_t g = src_argb[1]; uint8_t r = src_argb[2]; dst_rgb[0] = b; dst_rgb[1] = g; dst_rgb[2] = r; dst_rgb += 3; src_argb += 4; } } void ARGBToRAWRow_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width; ++x) { uint8_t b = src_argb[0]; uint8_t g = src_argb[1]; uint8_t r = src_argb[2]; dst_rgb[0] = r; dst_rgb[1] = g; dst_rgb[2] = b; dst_rgb += 3; src_argb += 4; } } void ARGBToRGB565Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width - 1; x += 2) { uint8_t b0 = src_argb[0] >> 3; uint8_t g0 = src_argb[1] >> 2; uint8_t r0 = src_argb[2] >> 3; uint8_t b1 = src_argb[4] >> 3; uint8_t g1 = src_argb[5] >> 2; uint8_t r1 = src_argb[6] >> 3; WRITEWORD(dst_rgb, b0 | (g0 << 5) | (r0 << 11) | (b1 << 16) | (g1 << 21) | (r1 << 27)); dst_rgb += 4; src_argb += 8; } if (width & 1) { uint8_t b0 = src_argb[0] >> 3; uint8_t g0 = src_argb[1] >> 2; uint8_t r0 = src_argb[2] >> 3; *(uint16_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 11); } } // dither4 is a row of 4 values from 4x4 dither matrix. // The 4x4 matrix contains values to increase RGB. When converting to // fewer bits (565) this provides an ordered dither. // The order in the 4x4 matrix in first byte is upper left. // The 4 values are passed as an int, then referenced as an array, so // endian will not affect order of the original matrix. But the dither4 // will containing the first pixel in the lower byte for little endian // or the upper byte for big endian. void ARGBToRGB565DitherRow_C(const uint8_t* src_argb, uint8_t* dst_rgb, const uint32_t dither4, int width) { int x; for (x = 0; x < width - 1; x += 2) { int dither0 = ((const unsigned char*)(&dither4))[x & 3]; int dither1 = ((const unsigned char*)(&dither4))[(x + 1) & 3]; uint8_t b0 = clamp255(src_argb[0] + dither0) >> 3; uint8_t g0 = clamp255(src_argb[1] + dither0) >> 2; uint8_t r0 = clamp255(src_argb[2] + dither0) >> 3; uint8_t b1 = clamp255(src_argb[4] + dither1) >> 3; uint8_t g1 = clamp255(src_argb[5] + dither1) >> 2; uint8_t r1 = clamp255(src_argb[6] + dither1) >> 3; WRITEWORD(dst_rgb, b0 | (g0 << 5) | (r0 << 11) | (b1 << 16) | (g1 << 21) | (r1 << 27)); dst_rgb += 4; src_argb += 8; } if (width & 1) { int dither0 = ((const unsigned char*)(&dither4))[(width - 1) & 3]; uint8_t b0 = clamp255(src_argb[0] + dither0) >> 3; uint8_t g0 = clamp255(src_argb[1] + dither0) >> 2; uint8_t r0 = clamp255(src_argb[2] + dither0) >> 3; *(uint16_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 11); } } void ARGBToARGB1555Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width - 1; x += 2) { uint8_t b0 = src_argb[0] >> 3; uint8_t g0 = src_argb[1] >> 3; uint8_t r0 = src_argb[2] >> 3; uint8_t a0 = src_argb[3] >> 7; uint8_t b1 = src_argb[4] >> 3; uint8_t g1 = src_argb[5] >> 3; uint8_t r1 = src_argb[6] >> 3; uint8_t a1 = src_argb[7] >> 7; *(uint32_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 10) | (a0 << 15) | (b1 << 16) | (g1 << 21) | (r1 << 26) | (a1 << 31); dst_rgb += 4; src_argb += 8; } if (width & 1) { uint8_t b0 = src_argb[0] >> 3; uint8_t g0 = src_argb[1] >> 3; uint8_t r0 = src_argb[2] >> 3; uint8_t a0 = src_argb[3] >> 7; *(uint16_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 10) | (a0 << 15); } } void ARGBToARGB4444Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width - 1; x += 2) { uint8_t b0 = src_argb[0] >> 4; uint8_t g0 = src_argb[1] >> 4; uint8_t r0 = src_argb[2] >> 4; uint8_t a0 = src_argb[3] >> 4; uint8_t b1 = src_argb[4] >> 4; uint8_t g1 = src_argb[5] >> 4; uint8_t r1 = src_argb[6] >> 4; uint8_t a1 = src_argb[7] >> 4; *(uint32_t*)(dst_rgb) = b0 | (g0 << 4) | (r0 << 8) | (a0 << 12) | (b1 << 16) | (g1 << 20) | (r1 << 24) | (a1 << 28); dst_rgb += 4; src_argb += 8; } if (width & 1) { uint8_t b0 = src_argb[0] >> 4; uint8_t g0 = src_argb[1] >> 4; uint8_t r0 = src_argb[2] >> 4; uint8_t a0 = src_argb[3] >> 4; *(uint16_t*)(dst_rgb) = b0 | (g0 << 4) | (r0 << 8) | (a0 << 12); } } void ABGRToAR30Row_C(const uint8_t* src_abgr, uint8_t* dst_ar30, int width) { int x; for (x = 0; x < width; ++x) { uint32_t b0 = (src_abgr[0] >> 6) | ((uint32_t)(src_abgr[0]) << 2); uint32_t g0 = (src_abgr[1] >> 6) | ((uint32_t)(src_abgr[1]) << 2); uint32_t r0 = (src_abgr[2] >> 6) | ((uint32_t)(src_abgr[2]) << 2); uint32_t a0 = (src_abgr[3] >> 6); *(uint32_t*)(dst_ar30) = r0 | (g0 << 10) | (b0 << 20) | (a0 << 30); dst_ar30 += 4; src_abgr += 4; } } void ARGBToAR30Row_C(const uint8_t* src_argb, uint8_t* dst_ar30, int width) { int x; for (x = 0; x < width; ++x) { uint32_t b0 = (src_argb[0] >> 6) | ((uint32_t)(src_argb[0]) << 2); uint32_t g0 = (src_argb[1] >> 6) | ((uint32_t)(src_argb[1]) << 2); uint32_t r0 = (src_argb[2] >> 6) | ((uint32_t)(src_argb[2]) << 2); uint32_t a0 = (src_argb[3] >> 6); *(uint32_t*)(dst_ar30) = b0 | (g0 << 10) | (r0 << 20) | (a0 << 30); dst_ar30 += 4; src_argb += 4; } } static __inline int RGBToY(uint8_t r, uint8_t g, uint8_t b) { return (66 * r + 129 * g + 25 * b + 0x1080) >> 8; } static __inline int RGBToU(uint8_t r, uint8_t g, uint8_t b) { return (112 * b - 74 * g - 38 * r + 0x8080) >> 8; } static __inline int RGBToV(uint8_t r, uint8_t g, uint8_t b) { return (112 * r - 94 * g - 18 * b + 0x8080) >> 8; } // ARGBToY_C and ARGBToUV_C #define MAKEROWY(NAME, R, G, B, BPP) \ void NAME##ToYRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width) { \ int x; \ for (x = 0; x < width; ++x) { \ dst_y[0] = RGBToY(src_argb0[R], src_argb0[G], src_argb0[B]); \ src_argb0 += BPP; \ dst_y += 1; \ } \ } \ void NAME##ToUVRow_C(const uint8_t* src_rgb0, int src_stride_rgb, \ uint8_t* dst_u, uint8_t* dst_v, int width) { \ const uint8_t* src_rgb1 = src_rgb0 + src_stride_rgb; \ int x; \ for (x = 0; x < width - 1; x += 2) { \ uint8_t ab = (src_rgb0[B] + src_rgb0[B + BPP] + src_rgb1[B] + \ src_rgb1[B + BPP]) >> \ 2; \ uint8_t ag = (src_rgb0[G] + src_rgb0[G + BPP] + src_rgb1[G] + \ src_rgb1[G + BPP]) >> \ 2; \ uint8_t ar = (src_rgb0[R] + src_rgb0[R + BPP] + src_rgb1[R] + \ src_rgb1[R + BPP]) >> \ 2; \ dst_u[0] = RGBToU(ar, ag, ab); \ dst_v[0] = RGBToV(ar, ag, ab); \ src_rgb0 += BPP * 2; \ src_rgb1 += BPP * 2; \ dst_u += 1; \ dst_v += 1; \ } \ if (width & 1) { \ uint8_t ab = (src_rgb0[B] + src_rgb1[B]) >> 1; \ uint8_t ag = (src_rgb0[G] + src_rgb1[G]) >> 1; \ uint8_t ar = (src_rgb0[R] + src_rgb1[R]) >> 1; \ dst_u[0] = RGBToU(ar, ag, ab); \ dst_v[0] = RGBToV(ar, ag, ab); \ } \ } MAKEROWY(ARGB, 2, 1, 0, 4) MAKEROWY(BGRA, 1, 2, 3, 4) MAKEROWY(ABGR, 0, 1, 2, 4) MAKEROWY(RGBA, 3, 2, 1, 4) MAKEROWY(RGB24, 2, 1, 0, 3) MAKEROWY(RAW, 0, 1, 2, 3) #undef MAKEROWY // JPeg uses a variation on BT.601-1 full range // y = 0.29900 * r + 0.58700 * g + 0.11400 * b // u = -0.16874 * r - 0.33126 * g + 0.50000 * b + center // v = 0.50000 * r - 0.41869 * g - 0.08131 * b + center // BT.601 Mpeg range uses: // b 0.1016 * 255 = 25.908 = 25 // g 0.5078 * 255 = 129.489 = 129 // r 0.2578 * 255 = 65.739 = 66 // JPeg 8 bit Y (not used): // b 0.11400 * 256 = 29.184 = 29 // g 0.58700 * 256 = 150.272 = 150 // r 0.29900 * 256 = 76.544 = 77 // JPeg 7 bit Y: // b 0.11400 * 128 = 14.592 = 15 // g 0.58700 * 128 = 75.136 = 75 // r 0.29900 * 128 = 38.272 = 38 // JPeg 8 bit U: // b 0.50000 * 255 = 127.5 = 127 // g -0.33126 * 255 = -84.4713 = -84 // r -0.16874 * 255 = -43.0287 = -43 // JPeg 8 bit V: // b -0.08131 * 255 = -20.73405 = -20 // g -0.41869 * 255 = -106.76595 = -107 // r 0.50000 * 255 = 127.5 = 127 static __inline int RGBToYJ(uint8_t r, uint8_t g, uint8_t b) { return (38 * r + 75 * g + 15 * b + 64) >> 7; } static __inline int RGBToUJ(uint8_t r, uint8_t g, uint8_t b) { return (127 * b - 84 * g - 43 * r + 0x8080) >> 8; } static __inline int RGBToVJ(uint8_t r, uint8_t g, uint8_t b) { return (127 * r - 107 * g - 20 * b + 0x8080) >> 8; } #define AVGB(a, b) (((a) + (b) + 1) >> 1) // ARGBToYJ_C and ARGBToUVJ_C #define MAKEROWYJ(NAME, R, G, B, BPP) \ void NAME##ToYJRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width) { \ int x; \ for (x = 0; x < width; ++x) { \ dst_y[0] = RGBToYJ(src_argb0[R], src_argb0[G], src_argb0[B]); \ src_argb0 += BPP; \ dst_y += 1; \ } \ } \ void NAME##ToUVJRow_C(const uint8_t* src_rgb0, int src_stride_rgb, \ uint8_t* dst_u, uint8_t* dst_v, int width) { \ const uint8_t* src_rgb1 = src_rgb0 + src_stride_rgb; \ int x; \ for (x = 0; x < width - 1; x += 2) { \ uint8_t ab = AVGB(AVGB(src_rgb0[B], src_rgb1[B]), \ AVGB(src_rgb0[B + BPP], src_rgb1[B + BPP])); \ uint8_t ag = AVGB(AVGB(src_rgb0[G], src_rgb1[G]), \ AVGB(src_rgb0[G + BPP], src_rgb1[G + BPP])); \ uint8_t ar = AVGB(AVGB(src_rgb0[R], src_rgb1[R]), \