/* * 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" #include"libyuv/convert_argb.h"// For kYuvI601Constants
// The following ifdef from row_win makes the C code match the row_win code, // which is 7 bit fixed point. #if !defined(LIBYUV_DISABLE_X86) && defined(_MSC_VER) && \
(defined(_M_IX86) || (defined(_M_X64) && !defined(__clang__))) #define LIBYUV_RGB7 1 #endif
// 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 = ((constunsignedchar*)(&dither4))[x & 3]; int dither1 = ((constunsignedchar*)(&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 = ((constunsignedchar*)(&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);
}
}
// 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 7 bit Y (deprecated) // b 0.11400 * 128 = 14.592 = 15 // g 0.58700 * 128 = 75.136 = 75 // r 0.29900 * 128 = 38.272 = 38 // JPeg 8 bit Y: // b 0.11400 * 256 = 29.184 = 29 // g 0.58700 * 256 = 150.272 = 150 // r 0.29900 * 256 = 76.544 = 77 // 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
#ifdef LIBYUV_RGB7 // Old 7 bit math for compatibility on unsupported platforms. static __inlineint RGBToYJ(uint8_t r, uint8_t g, uint8_t b) { return (38 * r + 75 * g + 15 * b + 64) >> 7;
} #else // 8 bit static __inlineint RGBToYJ(uint8_t r, uint8_t g, uint8_t b) { return (77 * r + 150 * g + 29 * b + 128) >> 8;
} #endif
#ifdefined(LIBYUV_ARGBTOUV_PAVGB) static __inlineint RGBToUJ(uint8_t r, uint8_t g, uint8_t b) { return (127 * b - 84 * g - 43 * r + 0x8080) >> 8;
} static __inlineint RGBToVJ(uint8_t r, uint8_t g, uint8_t b) { return (127 * r - 107 * g - 20 * b + 0x8080) >> 8;
} #else static __inlineint RGB2xToUJ(uint16_t r, uint16_t g, uint16_t b) { return ((127 / 2) * b - (84 / 2) * g - (43 / 2) * r + 0x8080) >> 8;
} static __inlineint RGB2xToVJ(uint16_t r, uint16_t g, uint16_t b) { return ((127 / 2) * r - (107 / 2) * g - (20 / 2) * b + 0x8080) >> 8;
} #endif
#ifdefined(LIBYUV_ARGBTOUV_PAVGB)
uint8_t ab = AVGB(b0, b2);
uint8_t ag = AVGB(g0, g2);
uint8_t ar = AVGB(r0, r2);
dst_u[0] = RGBToU(ar, ag, ab);
dst_v[0] = RGBToV(ar, ag, ab); #else
uint16_t b = b0 + b2;
uint16_t g = g0 + g2;
uint16_t r = r0 + r2;
dst_u[0] = RGB2xToU(r, g, b);
dst_v[0] = RGB2xToV(r, g, b); #endif
}
}
void ARGBToUV444Row_C(const uint8_t* src_argb,
uint8_t* dst_u,
uint8_t* dst_v, int width) { int x; for (x = 0; x < width; ++x) {
uint8_t ab = src_argb[0];
uint8_t ag = src_argb[1];
uint8_t ar = src_argb[2];
dst_u[0] = RGBToU(ar, ag, ab);
dst_v[0] = RGBToV(ar, ag, ab);
src_argb += 4;
dst_u += 1;
dst_v += 1;
}
}
void ARGBGrayRow_C(const uint8_t* src_argb, uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) {
uint8_t y = RGBToYJ(src_argb[2], src_argb[1], src_argb[0]);
dst_argb[2] = dst_argb[1] = dst_argb[0] = y;
dst_argb[3] = src_argb[3];
dst_argb += 4;
src_argb += 4;
}
}
// Convert a row of image to Sepia tone. void ARGBSepiaRow_C(uint8_t* dst_argb, int width) { int x; for (x = 0; x < width; ++x) { int b = dst_argb[0]; int g = dst_argb[1]; int r = dst_argb[2]; int sb = (b * 17 + g * 68 + r * 35) >> 7; int sg = (b * 22 + g * 88 + r * 45) >> 7; int sr = (b * 24 + g * 98 + r * 50) >> 7; // b does not over flow. a is preserved from original.
dst_argb[0] = sb;
dst_argb[1] = clamp255(sg);
dst_argb[2] = clamp255(sr);
dst_argb += 4;
}
}
// Apply color matrix to a row of image. Matrix is signed. // TODO(fbarchard): Consider adding rounding (+32). void ARGBColorMatrixRow_C(const uint8_t* src_argb,
uint8_t* dst_argb, const int8_t* matrix_argb, int width) { int x; for (x = 0; x < width; ++x) { int b = src_argb[0]; int g = src_argb[1]; int r = src_argb[2]; int a = src_argb[3]; int sb = (b * matrix_argb[0] + g * matrix_argb[1] + r * matrix_argb[2] +
a * matrix_argb[3]) >> 6; int sg = (b * matrix_argb[4] + g * matrix_argb[5] + r * matrix_argb[6] +
a * matrix_argb[7]) >> 6; int sr = (b * matrix_argb[8] + g * matrix_argb[9] + r * matrix_argb[10] +
a * matrix_argb[11]) >> 6; int sa = (b * matrix_argb[12] + g * matrix_argb[13] + r * matrix_argb[14] +
a * matrix_argb[15]) >> 6;
dst_argb[0] = Clamp(sb);
dst_argb[1] = Clamp(sg);
dst_argb[2] = Clamp(sr);
dst_argb[3] = Clamp(sa);
src_argb += 4;
dst_argb += 4;
}
}
// Apply color table to a row of image. void ARGBColorTableRow_C(uint8_t* dst_argb, const uint8_t* table_argb, int width) { int x; for (x = 0; x < width; ++x) { int b = dst_argb[0]; int g = dst_argb[1]; int r = dst_argb[2]; int a = dst_argb[3];
dst_argb[0] = table_argb[b * 4 + 0];
dst_argb[1] = table_argb[g * 4 + 1];
dst_argb[2] = table_argb[r * 4 + 2];
dst_argb[3] = table_argb[a * 4 + 3];
dst_argb += 4;
}
}
// Apply color table to a row of image. void RGBColorTableRow_C(uint8_t* dst_argb, const uint8_t* table_argb, int width) { int x; for (x = 0; x < width; ++x) { int b = dst_argb[0]; int g = dst_argb[1]; int r = dst_argb[2];
dst_argb[0] = table_argb[b * 4 + 0];
dst_argb[1] = table_argb[g * 4 + 1];
dst_argb[2] = table_argb[r * 4 + 2];
dst_argb += 4;
}
}
void ARGBQuantizeRow_C(uint8_t* dst_argb, int scale, int interval_size, int interval_offset, int width) { int x; for (x = 0; x < width; ++x) { int b = dst_argb[0]; int g = dst_argb[1]; int r = dst_argb[2];
dst_argb[0] = (b * scale >> 16) * interval_size + interval_offset;
dst_argb[1] = (g * scale >> 16) * interval_size + interval_offset;
dst_argb[2] = (r * scale >> 16) * interval_size + interval_offset;
dst_argb += 4;
}
}
void ARGBAddRow_C(const uint8_t* src_argb0, const uint8_t* src_argb1,
uint8_t* dst_argb, int width) { int i; for (i = 0; i < width; ++i) { constint b = src_argb0[0]; constint g = src_argb0[1]; constint r = src_argb0[2]; constint a = src_argb0[3]; constint b_add = src_argb1[0]; constint g_add = src_argb1[1]; constint r_add = src_argb1[2]; constint a_add = src_argb1[3];
dst_argb[0] = SHADE(b, b_add);
dst_argb[1] = SHADE(g, g_add);
dst_argb[2] = SHADE(r, r_add);
dst_argb[3] = SHADE(a, a_add);
src_argb0 += 4;
src_argb1 += 4;
dst_argb += 4;
}
} #undef SHADE
#define SHADE(f, v) clamp0(f - v)
void ARGBSubtractRow_C(const uint8_t* src_argb0, const uint8_t* src_argb1,
uint8_t* dst_argb, int width) { int i; for (i = 0; i < width; ++i) { constint b = src_argb0[0]; constint g = src_argb0[1]; constint r = src_argb0[2]; constint a = src_argb0[3]; constint b_sub = src_argb1[0]; constint g_sub = src_argb1[1]; constint r_sub = src_argb1[2]; constint a_sub = src_argb1[3];
dst_argb[0] = SHADE(b, b_sub);
dst_argb[1] = SHADE(g, g_sub);
dst_argb[2] = SHADE(r, r_sub);
dst_argb[3] = SHADE(a, a_sub);
src_argb0 += 4;
src_argb1 += 4;
dst_argb += 4;
}
} #undef SHADE
// Sobel functions which mimics SSSE3. void SobelXRow_C(const uint8_t* src_y0, const uint8_t* src_y1, const uint8_t* src_y2,
uint8_t* dst_sobelx, int width) { int i; for (i = 0; i < width; ++i) { int a = src_y0[i]; int b = src_y1[i]; int c = src_y2[i]; int a_sub = src_y0[i + 2]; int b_sub = src_y1[i + 2]; int c_sub = src_y2[i + 2]; int a_diff = a - a_sub; int b_diff = b - b_sub; int c_diff = c - c_sub; int sobel = Abs(a_diff + b_diff * 2 + c_diff);
dst_sobelx[i] = (uint8_t)(clamp255(sobel));
}
}
void SobelYRow_C(const uint8_t* src_y0, const uint8_t* src_y1,
uint8_t* dst_sobely, int width) { int i; for (i = 0; i < width; ++i) { int a = src_y0[i + 0]; int b = src_y0[i + 1]; int c = src_y0[i + 2]; int a_sub = src_y1[i + 0]; int b_sub = src_y1[i + 1]; int c_sub = src_y1[i + 2]; int a_diff = a - a_sub; int b_diff = b - b_sub; int c_diff = c - c_sub; int sobel = Abs(a_diff + b_diff * 2 + c_diff);
dst_sobely[i] = (uint8_t)(clamp255(sobel));
}
}
void SobelRow_C(const uint8_t* src_sobelx, const uint8_t* src_sobely,
uint8_t* dst_argb, int width) { int i; for (i = 0; i < width; ++i) { int r = src_sobelx[i]; int b = src_sobely[i]; int s = clamp255(r + b);
dst_argb[0] = (uint8_t)(s);
dst_argb[1] = (uint8_t)(s);
dst_argb[2] = (uint8_t)(s);
dst_argb[3] = (uint8_t)(255u);
dst_argb += 4;
}
}
void SobelToPlaneRow_C(const uint8_t* src_sobelx, const uint8_t* src_sobely,
uint8_t* dst_y, int width) { int i; for (i = 0; i < width; ++i) { int r = src_sobelx[i]; int b = src_sobely[i]; int s = clamp255(r + b);
dst_y[i] = (uint8_t)(s);
}
}
void SobelXYRow_C(const uint8_t* src_sobelx, const uint8_t* src_sobely,
uint8_t* dst_argb, int width) { int i; for (i = 0; i < width; ++i) { int r = src_sobelx[i]; int b = src_sobely[i]; int g = clamp255(r + b);
dst_argb[0] = (uint8_t)(b);
dst_argb[1] = (uint8_t)(g);
dst_argb[2] = (uint8_t)(r);
dst_argb[3] = (uint8_t)(255u);
dst_argb += 4;
}
}
void J400ToARGBRow_C(const uint8_t* src_y, uint8_t* dst_argb, int width) { // Copy a Y to RGB. int x; for (x = 0; x < width; ++x) {
uint8_t y = src_y[0];
dst_argb[2] = dst_argb[1] = dst_argb[0] = y;
dst_argb[3] = 255u;
dst_argb += 4;
++src_y;
}
}
// TODO(fbarchard): Unify these structures to be platform independent. // TODO(fbarchard): Generate SIMD structures from float matrix.
// BT.601 YUV to RGB reference // R = (Y - 16) * 1.164 - V * -1.596 // G = (Y - 16) * 1.164 - U * 0.391 - V * 0.813 // B = (Y - 16) * 1.164 - U * -2.018
// U and V contributions to R,G,B. #define UB -128/* max(-128, round(-2.018 * 64)) */ #define UG 25/* round(0.391 * 64) */ #define VG 52/* round(0.813 * 64) */ #define VR -102/* round(-1.596 * 64) */
// Bias values to subtract 16 from Y and 128 from U and V. #define BB (UB * 128 + YGB) #define BG (UG * 128 + VG * 128 + YGB) #define BR (VR * 128 + YGB)
// BT.709 YUV to RGB reference // R = (Y - 16) * 1.164 - V * -1.793 // G = (Y - 16) * 1.164 - U * 0.213 - V * 0.533 // B = (Y - 16) * 1.164 - U * -2.112 // See also http://www.equasys.de/colorconversion.html
// TODO(fbarchard): Improve accuracy; the B channel is off by 7%. // U and V contributions to R,G,B. #define UB -128/* max(-128, round(-2.142 * 64)) */ #define UG 12/* round(0.187326 * 64) */ #define VG 42/* round(0.65042 * 64) */ #define VR -107/* round(-1.67867 * 64) */
// Bias values to round, and subtract 128 from U and V. #define BB (UB * 128 + YGB) #define BG (UG * 128 + VG * 128 + YGB) #define BR (VR * 128 + YGB)
// C reference code that mimics the YUV assembly. // Reads 8 bit YUV and leaves result as 16 bit. static __inlinevoid YuvPixel(uint8_t y,
uint8_t u,
uint8_t v,
uint8_t* b,
uint8_t* g,
uint8_t* r, conststruct YuvConstants* yuvconstants) { #ifdefined(__aarch64__) int ub = -yuvconstants->kUVToRB[0]; int ug = yuvconstants->kUVToG[0]; int vg = yuvconstants->kUVToG[1]; int vr = -yuvconstants->kUVToRB[1]; int bb = yuvconstants->kUVBiasBGR[0]; int bg = yuvconstants->kUVBiasBGR[1]; int br = yuvconstants->kUVBiasBGR[2]; int yg = yuvconstants->kYToRgb[1]; #elifdefined(__arm__) int ub = -yuvconstants->kUVToRB[0]; int ug = yuvconstants->kUVToG[0]; int vg = yuvconstants->kUVToG[4]; int vr = -yuvconstants->kUVToRB[4]; int bb = yuvconstants->kUVBiasBGR[0]; int bg = yuvconstants->kUVBiasBGR[1]; int br = yuvconstants->kUVBiasBGR[2]; int yg = yuvconstants->kYToRgb[1]; #else int ub = yuvconstants->kUVToB[0]; int ug = yuvconstants->kUVToG[0]; int vg = yuvconstants->kUVToG[1]; int vr = yuvconstants->kUVToR[1]; int bb = yuvconstants->kUVBiasB[0]; int bg = yuvconstants->kUVBiasG[0]; int br = yuvconstants->kUVBiasR[0]; int yg = yuvconstants->kYToRgb[0]; #endif
// Reads 8 bit YUV and leaves result as 16 bit. static __inlinevoid YuvPixel8_16(uint8_t y,
uint8_t u,
uint8_t v, int* b, int* g, int* r, conststruct YuvConstants* yuvconstants) { #ifdefined(__aarch64__) int ub = -yuvconstants->kUVToRB[0]; int ug = yuvconstants->kUVToG[0]; int vg = yuvconstants->kUVToG[1]; int vr = -yuvconstants->kUVToRB[1]; int bb = yuvconstants->kUVBiasBGR[0]; int bg = yuvconstants->kUVBiasBGR[1]; int br = yuvconstants->kUVBiasBGR[2]; int yg = yuvconstants->kYToRgb[1]; #elifdefined(__arm__) int ub = -yuvconstants->kUVToRB[0]; int ug = yuvconstants->kUVToG[0]; int vg = yuvconstants->kUVToG[4]; int vr = -yuvconstants->kUVToRB[4]; int bb = yuvconstants->kUVBiasBGR[0]; int bg = yuvconstants->kUVBiasBGR[1]; int br = yuvconstants->kUVBiasBGR[2]; int yg = yuvconstants->kYToRgb[1]; #else int ub = yuvconstants->kUVToB[0]; int ug = yuvconstants->kUVToG[0]; int vg = yuvconstants->kUVToG[1]; int vr = yuvconstants->kUVToR[1]; int bb = yuvconstants->kUVBiasB[0]; int bg = yuvconstants->kUVBiasG[0]; int br = yuvconstants->kUVBiasR[0]; int yg = yuvconstants->kYToRgb[0]; #endif
// C reference code that mimics the YUV 16 bit assembly. // Reads 10 bit YUV and leaves result as 16 bit. static __inlinevoid YuvPixel16(int16_t y,
int16_t u,
int16_t v, int* b, int* g, int* r, conststruct YuvConstants* yuvconstants) { #ifdefined(__aarch64__) int ub = -yuvconstants->kUVToRB[0]; int ug = yuvconstants->kUVToG[0]; int vg = yuvconstants->kUVToG[1]; int vr = -yuvconstants->kUVToRB[1]; int bb = yuvconstants->kUVBiasBGR[0]; int bg = yuvconstants->kUVBiasBGR[1]; int br = yuvconstants->kUVBiasBGR[2]; int yg = yuvconstants->kYToRgb[1]; #elifdefined(__arm__) int ub = -yuvconstants->kUVToRB[0]; int ug = yuvconstants->kUVToG[0]; int vg = yuvconstants->kUVToG[4]; int vr = -yuvconstants->kUVToRB[4]; int bb = yuvconstants->kUVBiasBGR[0]; int bg = yuvconstants->kUVBiasBGR[1]; int br = yuvconstants->kUVBiasBGR[2]; int yg = yuvconstants->kYToRgb[1]; #else int ub = yuvconstants->kUVToB[0]; int ug = yuvconstants->kUVToG[0]; int vg = yuvconstants->kUVToG[1]; int vr = yuvconstants->kUVToR[1]; int bb = yuvconstants->kUVBiasB[0]; int bg = yuvconstants->kUVBiasG[0]; int br = yuvconstants->kUVBiasR[0]; int yg = yuvconstants->kYToRgb[0]; #endif
// C reference code that mimics the YUV 10 bit assembly. // Reads 10 bit YUV and clamps down to 8 bit RGB. static __inlinevoid YuvPixel10(uint16_t y,
uint16_t u,
uint16_t v,
uint8_t* b,
uint8_t* g,
uint8_t* r, conststruct YuvConstants* yuvconstants) { int b16; int g16; int r16;
YuvPixel16(y, u, v, &b16, &g16, &r16, yuvconstants);
*b = Clamp(b16 >> 6);
*g = Clamp(g16 >> 6);
*r = Clamp(r16 >> 6);
}
// C reference code that mimics the YUV assembly. // Reads 8 bit YUV and leaves result as 16 bit. static __inlinevoid YPixel(uint8_t y,
uint8_t* b,
uint8_t* g,
uint8_t* r, conststruct YuvConstants* yuvconstants) { #ifdefined(__aarch64__) || defined(__arm__) int ygb = yuvconstants->kUVBiasBGR[3]; int yg = yuvconstants->kYToRgb[1]; #else int ygb = yuvconstants->kYBiasToRgb[0]; int yg = yuvconstants->kYToRgb[0]; #endif
uint32_t y1 = (uint32_t)(y * 0x0101 * yg) >> 16;
*b = Clamp(((int32_t)(y1) + ygb) >> 6);
*g = Clamp(((int32_t)(y1) + ygb) >> 6);
*r = Clamp(((int32_t)(y1) + ygb) >> 6);
}
staticvoid StoreAR30(uint8_t* rgb_buf, int b, int g, int r) {
uint32_t ar30;
b = b >> 4; // convert 10.6 to 10 bit.
g = g >> 4;
r = r >> 4;
b = Clamp10(b);
g = Clamp10(g);
r = Clamp10(r);
ar30 = b | ((uint32_t)g << 10) | ((uint32_t)r << 20) | 0xc0000000;
(*(uint32_t*)rgb_buf) = ar30;
}
// 10 bit YUV to 10 bit AR30 void I210ToAR30Row_C(const uint16_t* src_y, const uint16_t* src_u, const uint16_t* src_v,
uint8_t* rgb_buf, conststruct YuvConstants* yuvconstants, int width) { int x; int b; int g; int r; for (x = 0; x < width - 1; x += 2) {
YuvPixel16(src_y[0], src_u[0], src_v[0], &b, &g, &r, yuvconstants);
StoreAR30(rgb_buf, b, g, r);
YuvPixel16(src_y[1], src_u[0], src_v[0], &b, &g, &r, yuvconstants);
StoreAR30(rgb_buf + 4, b, g, r);
src_y += 2;
src_u += 1;
src_v += 1;
rgb_buf += 8; // Advance 2 pixels.
} if (width & 1) {
YuvPixel16(src_y[0], src_u[0], src_v[0], &b, &g, &r, yuvconstants);
StoreAR30(rgb_buf, b, g, r);
}
}
// 8 bit YUV to 10 bit AR30 // Uses same code as 10 bit YUV bit shifts the 8 bit values up to 10 bits. void I422ToAR30Row_C(const uint8_t* src_y, const uint8_t* src_u, const uint8_t* src_v,
uint8_t* rgb_buf, conststruct YuvConstants* yuvconstants, int width) { int x; int b; int g; int r; for (x = 0; x < width - 1; x += 2) {
YuvPixel8_16(src_y[0], src_u[0], src_v[0], &b, &g, &r, yuvconstants);
StoreAR30(rgb_buf, b, g, r);
YuvPixel8_16(src_y[1], src_u[0], src_v[0], &b, &g, &r, yuvconstants);
StoreAR30(rgb_buf + 4, b, g, r);
src_y += 2;
src_u += 1;
src_v += 1;
rgb_buf += 8; // Advance 2 pixels.
} if (width & 1) {
YuvPixel8_16(src_y[0], src_u[0], src_v[0], &b, &g, &r, yuvconstants);
StoreAR30(rgb_buf, b, g, r);
}
}
void SplitRGBRow_C(const uint8_t* src_rgb,
uint8_t* dst_r,
uint8_t* dst_g,
uint8_t* dst_b, int width) { int x; for (x = 0; x < width; ++x) {
dst_r[x] = src_rgb[0];
dst_g[x] = src_rgb[1];
dst_b[x] = src_rgb[2];
src_rgb += 3;
}
}
void MergeRGBRow_C(const uint8_t* src_r, const uint8_t* src_g, const uint8_t* src_b,
uint8_t* dst_rgb, int width) { int x; for (x = 0; x < width; ++x) {
dst_rgb[0] = src_r[x];
dst_rgb[1] = src_g[x];
dst_rgb[2] = src_b[x];
dst_rgb += 3;
}
}
// Use scale to convert lsb formats to msb, depending how many bits there are: // 128 = 9 bits // 64 = 10 bits // 16 = 12 bits // 1 = 16 bits void MergeUVRow_16_C(const uint16_t* src_u, const uint16_t* src_v,
uint16_t* dst_uv, int scale, int width) { int x; for (x = 0; x < width - 1; x += 2) {
dst_uv[0] = src_u[x] * scale;
dst_uv[1] = src_v[x] * scale;
dst_uv[2] = src_u[x + 1] * scale;
dst_uv[3] = src_v[x + 1] * scale;
dst_uv += 4;
} if (width & 1) {
dst_uv[0] = src_u[width - 1] * scale;
dst_uv[1] = src_v[width - 1] * scale;
}
}
void MultiplyRow_16_C(const uint16_t* src_y,
uint16_t* dst_y, int scale, int width) { int x; for (x = 0; x < width; ++x) {
dst_y[x] = src_y[x] * scale;
}
}
// Use scale to convert lsb formats to msb, depending how many bits there are: // 32768 = 9 bits // 16384 = 10 bits // 4096 = 12 bits // 256 = 16 bits void Convert16To8Row_C(const uint16_t* src_y,
uint8_t* dst_y, int scale, int width) { int x; for (x = 0; x < width; ++x) {
dst_y[x] = clamp255((src_y[x] * scale) >> 16);
}
}
// Use scale to convert lsb formats to msb, depending how many bits there are: // 1024 = 10 bits void Convert8To16Row_C(const uint8_t* src_y,
uint16_t* dst_y, int scale, int width) { int x;
scale *= 0x0101; // replicates the byte. for (x = 0; x < width; ++x) {
dst_y[x] = (src_y[x] * scale) >> 16;
}
}
void ARGBSetRow_C(uint8_t* dst_argb, uint32_t v32, int width) { int x; for (x = 0; x < width; ++x) {
memcpy(dst_argb + x * sizeof v32, &v32, sizeof v32);
}
}
// Filter 2 rows of YUY2 UV's (422) into U and V (420). void YUY2ToUVRow_C(const uint8_t* src_yuy2, int src_stride_yuy2,
uint8_t* dst_u,
uint8_t* dst_v, int width) { // Output a row of UV values, filtering 2 rows of YUY2. int x; for (x = 0; x < width; x += 2) {
dst_u[0] = (src_yuy2[1] + src_yuy2[src_stride_yuy2 + 1] + 1) >> 1;
dst_v[0] = (src_yuy2[3] + src_yuy2[src_stride_yuy2 + 3] + 1) >> 1;
src_yuy2 += 4;
dst_u += 1;
dst_v += 1;
}
}
// Copy row of YUY2 UV's (422) into U and V (422). void YUY2ToUV422Row_C(const uint8_t* src_yuy2,
uint8_t* dst_u,
uint8_t* dst_v, int width) { // Output a row of UV values. int x; for (x = 0; x < width; x += 2) {
dst_u[0] = src_yuy2[1];
dst_v[0] = src_yuy2[3];
src_yuy2 += 4;
dst_u += 1;
dst_v += 1;
}
}
// Copy row of YUY2 Y's (422) into Y (420/422). void YUY2ToYRow_C(const uint8_t* src_yuy2, uint8_t* dst_y, int width) { // Output a row of Y values. int x; for (x = 0; x < width - 1; x += 2) {
dst_y[x] = src_yuy2[0];
dst_y[x + 1] = src_yuy2[2];
src_yuy2 += 4;
} if (width & 1) {
dst_y[width - 1] = src_yuy2[0];
}
}
// Filter 2 rows of UYVY UV's (422) into U and V (420). void UYVYToUVRow_C(const uint8_t* src_uyvy, int src_stride_uyvy,
uint8_t* dst_u,
uint8_t* dst_v, int width) { // Output a row of UV values. int x; for (x = 0; x < width; x += 2) {
dst_u[0] = (src_uyvy[0] + src_uyvy[src_stride_uyvy + 0] + 1) >> 1;
dst_v[0] = (src_uyvy[2] + src_uyvy[src_stride_uyvy + 2] + 1) >> 1;
src_uyvy += 4;
dst_u += 1;
dst_v += 1;
}
}
// Copy row of UYVY UV's (422) into U and V (422). void UYVYToUV422Row_C(const uint8_t* src_uyvy,
uint8_t* dst_u,
uint8_t* dst_v, int width) { // Output a row of UV values. int x; for (x = 0; x < width; x += 2) {
dst_u[0] = src_uyvy[0];
dst_v[0] = src_uyvy[2];
src_uyvy += 4;
dst_u += 1;
dst_v += 1;
}
}
// Copy row of UYVY Y's (422) into Y (420/422). void UYVYToYRow_C(const uint8_t* src_uyvy, uint8_t* dst_y, int width) { // Output a row of Y values. int x; for (x = 0; x < width - 1; x += 2) {
dst_y[x] = src_uyvy[1];
dst_y[x + 1] = src_uyvy[3];
src_uyvy += 4;
} if (width & 1) {
dst_y[width - 1] = src_uyvy[1];
}
}
#define BLEND(f, b, a) clamp255((((256 - a) * b) >> 8) + f)
// Blend src_argb0 over src_argb1 and store to dst_argb. // dst_argb may be src_argb0 or src_argb1. // This code mimics the SSSE3 version for better testability. void ARGBBlendRow_C(const uint8_t* src_argb0, const uint8_t* src_argb1,
uint8_t* dst_argb, int width) { int x; for (x = 0; x < width - 1; x += 2) {
uint32_t fb = src_argb0[0];
uint32_t fg = src_argb0[1];
uint32_t fr = src_argb0[2];
uint32_t a = src_argb0[3];
uint32_t bb = src_argb1[0];
uint32_t bg = src_argb1[1];
uint32_t br = src_argb1[2];
dst_argb[0] = BLEND(fb, bb, a);
dst_argb[1] = BLEND(fg, bg, a);
dst_argb[2] = BLEND(fr, br, a);
dst_argb[3] = 255u;
#define UBLEND(f, b, a) (((a)*f) + ((255 - a) * b) + 255) >> 8 void BlendPlaneRow_C(const uint8_t* src0, const uint8_t* src1, const uint8_t* alpha,
uint8_t* dst, int width) { int x; for (x = 0; x < width - 1; x += 2) {
dst[0] = UBLEND(src0[0], src1[0], alpha[0]);
dst[1] = UBLEND(src0[1], src1[1], alpha[1]);
src0 += 2;
src1 += 2;
alpha += 2;
dst += 2;
} if (width & 1) {
dst[0] = UBLEND(src0[0], src1[0], alpha[0]);
}
} #undef UBLEND
#ifdefined(__aarch64__) || defined(__arm__) #define ATTENUATE(f, a) (f * a + 128) >> 8 #else // This code mimics the SSSE3 version for better testability. #define ATTENUATE(f, a) (a | (a << 8)) * (f | (f << 8)) >> 24 #endif
// Multiply source RGB by alpha and store to destination. void ARGBAttenuateRow_C(const uint8_t* src_argb, uint8_t* dst_argb, int width) { int i; for (i = 0; i < width - 1; i += 2) {
uint32_t b = src_argb[0];
uint32_t g = src_argb[1];
uint32_t r = src_argb[2];
uint32_t a = src_argb[3];
dst_argb[0] = ATTENUATE(b, a);
dst_argb[1] = ATTENUATE(g, a);
dst_argb[2] = ATTENUATE(r, a);
dst_argb[3] = a;
b = src_argb[4];
g = src_argb[5];
r = src_argb[6];
a = src_argb[7];
dst_argb[4] = ATTENUATE(b, a);
dst_argb[5] = ATTENUATE(g, a);
dst_argb[6] = ATTENUATE(r, a);
dst_argb[7] = a;
src_argb += 8;
dst_argb += 8;
}
if (width & 1) { const uint32_t b = src_argb[0]; const uint32_t g = src_argb[1]; const uint32_t r = src_argb[2]; const uint32_t a = src_argb[3];
dst_argb[0] = ATTENUATE(b, a);
dst_argb[1] = ATTENUATE(g, a);
dst_argb[2] = ATTENUATE(r, a);
dst_argb[3] = a;
}
} #undef ATTENUATE
void ARGBUnattenuateRow_C(const uint8_t* src_argb,
uint8_t* dst_argb, int width) { int i; for (i = 0; i < width; ++i) {
uint32_t b = src_argb[0];
uint32_t g = src_argb[1];
uint32_t r = src_argb[2]; const uint32_t a = src_argb[3]; const uint32_t ia = fixed_invtbl8[a] & 0xffff; // 8.8 fixed point
b = (b * ia) >> 8;
g = (g * ia) >> 8;
r = (r * ia) >> 8; // Clamping should not be necessary but is free in assembly.
dst_argb[0] = clamp255(b);
dst_argb[1] = clamp255(g);
dst_argb[2] = clamp255(r);
dst_argb[3] = a;
src_argb += 4;
dst_argb += 4;
}
}
// Copy pixels from rotated source to destination row with a slope.
LIBYUV_API void ARGBAffineRow_C(const uint8_t* src_argb, int src_argb_stride,
uint8_t* dst_argb, constfloat* uv_dudv, int width) { int i; // Render a row of pixels from source into a buffer. float uv[2];
uv[0] = uv_dudv[0];
uv[1] = uv_dudv[1]; for (i = 0; i < width; ++i) { int x = (int)(uv[0]); int y = (int)(uv[1]);
*(uint32_t*)(dst_argb) =
*(const uint32_t*)(src_argb + y * src_argb_stride + x * 4);
dst_argb += 4;
uv[0] += uv_dudv[2];
uv[1] += uv_dudv[3];
}
}
// Blend 2 rows into 1. staticvoid HalfRow_C(const uint8_t* src_uv,
ptrdiff_t src_uv_stride,
uint8_t* dst_uv, int width) { int x; for (x = 0; x < width; ++x) {
dst_uv[x] = (src_uv[x] + src_uv[src_uv_stride + x] + 1) >> 1;
}
}
staticvoid HalfRow_16_C(const uint16_t* src_uv,
ptrdiff_t src_uv_stride,
uint16_t* dst_uv, int width) { int x; for (x = 0; x < width; ++x) {
dst_uv[x] = (src_uv[x] + src_uv[src_uv_stride + x] + 1) >> 1;
}
}
// C version 2x2 -> 2x1. void InterpolateRow_C(uint8_t* dst_ptr, const uint8_t* src_ptr,
ptrdiff_t src_stride, int width, int source_y_fraction) { int y1_fraction = source_y_fraction; int y0_fraction = 256 - y1_fraction; const uint8_t* src_ptr1 = src_ptr + src_stride; int x; if (y1_fraction == 0) {
memcpy(dst_ptr, src_ptr, width); return;
} if (y1_fraction == 128) {
HalfRow_C(src_ptr, src_stride, dst_ptr, width); return;
} for (x = 0; x < width - 1; x += 2) {
dst_ptr[0] =
(src_ptr[0] * y0_fraction + src_ptr1[0] * y1_fraction + 128) >> 8;
dst_ptr[1] =
(src_ptr[1] * y0_fraction + src_ptr1[1] * y1_fraction + 128) >> 8;
src_ptr += 2;
src_ptr1 += 2;
dst_ptr += 2;
} if (width & 1) {
dst_ptr[0] =
(src_ptr[0] * y0_fraction + src_ptr1[0] * y1_fraction + 128) >> 8;
}
}
// Samples assumed to be unsigned in low 9, 10 or 12 bits. Scale factor // adjust the source integer range to the half float range desired.
// This magic constant is 2^-112. Multiplying by this // is the same as subtracting 112 from the exponent, which // is the difference in exponent bias between 32-bit and // 16-bit floats. Once we've done this subtraction, we can // simply extract the low bits of the exponent and the high // bits of the mantissa from our float and we're done.
// Work around GCC 7 punning warning -Wstrict-aliasing #ifdefined(__GNUC__) typedef uint32_t __attribute__((__may_alias__)) uint32_alias_t; #else typedef uint32_t uint32_alias_t; #endif
void HalfFloatRow_C(const uint16_t* src,
uint16_t* dst, float scale, int width) { int i; float mult = 1.9259299444e-34f * scale; for (i = 0; i < width; ++i) { float value = src[i] * mult;
dst[i] = (uint16_t)((*(const uint32_alias_t*)&value) >> 13);
}
}
void ByteToFloatRow_C(const uint8_t* src, float* dst, float scale, int width) { int i; for (i = 0; i < width; ++i) { float value = src[i] * scale;
dst[i] = value;
}
}
// Filter 2 rows of AYUV UV's (444) into VU (420). void AYUVToVURow_C(const uint8_t* src_ayuv, int src_stride_ayuv,
uint8_t* dst_vu, int width) { // Output a row of VU values, filtering 2x2 rows of AYUV. int x; for (x = 0; x < width; x += 2) {
dst_vu[0] = (src_ayuv[0] + src_ayuv[4] + src_ayuv[src_stride_ayuv + 0] +
src_ayuv[src_stride_ayuv + 4] + 2) >> 2;
dst_vu[1] = (src_ayuv[1] + src_ayuv[5] + src_ayuv[src_stride_ayuv + 1] +
src_ayuv[src_stride_ayuv + 5] + 2) >> 2;
src_ayuv += 8;
dst_vu += 2;
} if (width & 1) {
dst_vu[0] = (src_ayuv[0] + src_ayuv[0] + src_ayuv[src_stride_ayuv + 0] +
src_ayuv[src_stride_ayuv + 0] + 2) >> 2;
dst_vu[1] = (src_ayuv[1] + src_ayuv[1] + src_ayuv[src_stride_ayuv + 1] +
src_ayuv[src_stride_ayuv + 1] + 2) >> 2;
}
}
// Copy row of AYUV Y's into Y void AYUVToYRow_C(const uint8_t* src_ayuv, uint8_t* dst_y, int width) { // Output a row of Y values. int x; for (x = 0; x < width; ++x) {
dst_y[x] = src_ayuv[2]; // v,u,y,a
src_ayuv += 4;
}
}
// Convert UV plane of NV12 to VU of NV21. void SwapUVRow_C(const uint8_t* src_uv, uint8_t* dst_vu, int width) { int x; for (x = 0; x < width; ++x) {
uint8_t u = src_uv[0];
uint8_t v = src_uv[1];
dst_vu[0] = v;
dst_vu[1] = u;
src_uv += 2;
dst_vu += 2;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.