Index: third_party/libwebp/enc/picture_csp.c |
diff --git a/third_party/libwebp/enc/picture_csp.c b/third_party/libwebp/enc/picture_csp.c |
index 7875f625b7c36368bb2787d6f5e271a37764edc2..0ef5f9eee2921d1b7355dbd6fd4d3684876f7fe4 100644 |
--- a/third_party/libwebp/enc/picture_csp.c |
+++ b/third_party/libwebp/enc/picture_csp.c |
@@ -32,10 +32,6 @@ static const union { |
} test_endian = { 0xff000000u }; |
#define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff) |
-static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) { |
- return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b); |
-} |
- |
//------------------------------------------------------------------------------ |
// Detection of non-trivial transparency |
@@ -89,9 +85,9 @@ int WebPPictureHasTransparency(const WebPPicture* picture) { |
static int kLinearToGammaTab[kGammaTabSize + 1]; |
static uint16_t kGammaToLinearTab[256]; |
-static int kGammaTablesOk = 0; |
+static volatile int kGammaTablesOk = 0; |
-static void InitGammaTables(void) { |
+static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) { |
if (!kGammaTablesOk) { |
int v; |
const double scale = (double)(1 << kGammaTabFix) / kGammaScale; |
@@ -130,7 +126,7 @@ static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { |
#else |
-static void InitGammaTables(void) {} |
+static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {} |
static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; } |
static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) { |
return (int)(base_value << shift); |
@@ -162,19 +158,15 @@ static int RGBToV(int r, int g, int b, VP8Random* const rg) { |
static const int kNumIterations = 6; |
static const int kMinDimensionIterativeConversion = 4; |
-// We use a-priori a different precision for storing RGB and Y/W components |
-// We could use YFIX=0 and only uint8_t for fixed_y_t, but it produces some |
+// We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some |
// banding sometimes. Better use extra precision. |
-// TODO(skal): cleanup once TFIX/YFIX values are fixed. |
+#define SFIX 2 // fixed-point precision of RGB and Y/W |
+typedef int16_t fixed_t; // signed type with extra SFIX precision for UV |
+typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W |
-typedef int16_t fixed_t; // signed type with extra TFIX precision for UV |
-typedef uint16_t fixed_y_t; // unsigned type with extra YFIX precision for W |
-#define TFIX 6 // fixed-point precision of RGB |
-#define YFIX 2 // fixed point precision for Y/W |
- |
-#define THALF ((1 << TFIX) >> 1) |
-#define MAX_Y_T ((256 << YFIX) - 1) |
-#define TROUNDER (1 << (YUV_FIX + TFIX - 1)) |
+#define SHALF (1 << SFIX >> 1) |
+#define MAX_Y_T ((256 << SFIX) - 1) |
+#define SROUNDER (1 << (YUV_FIX + SFIX - 1)) |
#if defined(USE_GAMMA_COMPRESSION) |
@@ -184,9 +176,9 @@ typedef uint16_t fixed_y_t; // unsigned type with extra YFIX precision for W |
#define kGammaF 2.2 |
static float kGammaToLinearTabF[MAX_Y_T + 1]; // size scales with Y_FIX |
static float kLinearToGammaTabF[kGammaTabSize + 2]; |
-static int kGammaTablesFOk = 0; |
+static volatile int kGammaTablesFOk = 0; |
-static void InitGammaTablesF(void) { |
+static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) { |
if (!kGammaTablesFOk) { |
int v; |
const double norm = 1. / MAX_Y_T; |
@@ -207,52 +199,31 @@ static WEBP_INLINE float GammaToLinearF(int v) { |
return kGammaToLinearTabF[v]; |
} |
-static WEBP_INLINE float LinearToGammaF(float value) { |
+static WEBP_INLINE int LinearToGammaF(float value) { |
const float v = value * kGammaTabSize; |
const int tab_pos = (int)v; |
const float x = v - (float)tab_pos; // fractional part |
const float v0 = kLinearToGammaTabF[tab_pos + 0]; |
const float v1 = kLinearToGammaTabF[tab_pos + 1]; |
const float y = v1 * x + v0 * (1.f - x); // interpolate |
- return y; |
+ return (int)(y + .5); |
} |
#else |
-static void InitGammaTablesF(void) {} |
+static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {} |
static WEBP_INLINE float GammaToLinearF(int v) { |
const float norm = 1.f / MAX_Y_T; |
return norm * v; |
} |
-static WEBP_INLINE float LinearToGammaF(float value) { |
- return MAX_Y_T * value; |
+static WEBP_INLINE int LinearToGammaF(float value) { |
+ return (int)(MAX_Y_T * value + .5); |
} |
#endif // USE_GAMMA_COMPRESSION |
//------------------------------------------------------------------------------ |
-// precision: YFIX -> TFIX |
-static WEBP_INLINE int FixedYToW(int v) { |
-#if TFIX == YFIX |
- return v; |
-#elif TFIX >= YFIX |
- return v << (TFIX - YFIX); |
-#else |
- return v >> (YFIX - TFIX); |
-#endif |
-} |
- |
-static WEBP_INLINE int FixedWToY(int v) { |
-#if TFIX == YFIX |
- return v; |
-#elif YFIX >= TFIX |
- return v << (YFIX - TFIX); |
-#else |
- return v >> (TFIX - YFIX); |
-#endif |
-} |
- |
static uint8_t clip_8b(fixed_t v) { |
return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u; |
} |
@@ -261,13 +232,6 @@ static fixed_y_t clip_y(int y) { |
return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T; |
} |
-// precision: TFIX -> YFIX |
-static fixed_y_t clip_fixed_t(fixed_t v) { |
- const int y = FixedWToY(v); |
- const fixed_y_t w = clip_y(y); |
- return w; |
-} |
- |
//------------------------------------------------------------------------------ |
static int RGBToGray(int r, int g, int b) { |
@@ -279,7 +243,7 @@ static float RGBToGrayF(float r, float g, float b) { |
return 0.299f * r + 0.587f * g + 0.114f * b; |
} |
-static float ScaleDown(int a, int b, int c, int d) { |
+static int ScaleDown(int a, int b, int c, int d) { |
const float A = GammaToLinearF(a); |
const float B = GammaToLinearF(b); |
const float C = GammaToLinearF(c); |
@@ -293,30 +257,36 @@ static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int len) { |
const float G = GammaToLinearF(src[1]); |
const float B = GammaToLinearF(src[2]); |
const float Y = RGBToGrayF(R, G, B); |
- *dst++ = (fixed_y_t)(LinearToGammaF(Y) + .5); |
+ *dst++ = (fixed_y_t)LinearToGammaF(Y); |
src += 3; |
} |
} |
-static WEBP_INLINE void UpdateChroma(const fixed_y_t* src1, |
- const fixed_y_t* src2, |
- fixed_t* dst, fixed_y_t* tmp, int len) { |
+static int UpdateChroma(const fixed_y_t* src1, |
+ const fixed_y_t* src2, |
+ fixed_t* dst, fixed_y_t* tmp, int len) { |
+ int diff = 0; |
while (len--> 0) { |
- const float r = ScaleDown(src1[0], src1[3], src2[0], src2[3]); |
- const float g = ScaleDown(src1[1], src1[4], src2[1], src2[4]); |
- const float b = ScaleDown(src1[2], src1[5], src2[2], src2[5]); |
- const float W = RGBToGrayF(r, g, b); |
- dst[0] = (fixed_t)FixedYToW((int)(r - W)); |
- dst[1] = (fixed_t)FixedYToW((int)(g - W)); |
- dst[2] = (fixed_t)FixedYToW((int)(b - W)); |
+ const int r = ScaleDown(src1[0], src1[3], src2[0], src2[3]); |
+ const int g = ScaleDown(src1[1], src1[4], src2[1], src2[4]); |
+ const int b = ScaleDown(src1[2], src1[5], src2[2], src2[5]); |
+ const int W = RGBToGray(r, g, b); |
+ const int r_avg = (src1[0] + src1[3] + src2[0] + src2[3] + 2) >> 2; |
+ const int g_avg = (src1[1] + src1[4] + src2[1] + src2[4] + 2) >> 2; |
+ const int b_avg = (src1[2] + src1[5] + src2[2] + src2[5] + 2) >> 2; |
+ dst[0] = (fixed_t)(r - W); |
+ dst[1] = (fixed_t)(g - W); |
+ dst[2] = (fixed_t)(b - W); |
dst += 3; |
src1 += 6; |
src2 += 6; |
if (tmp != NULL) { |
- tmp[0] = tmp[1] = clip_y((int)(W + .5)); |
+ tmp[0] = tmp[1] = clip_y(W); |
tmp += 2; |
} |
+ diff += abs(RGBToGray(r_avg, g_avg, b_avg) - W); |
} |
+ return diff; |
} |
//------------------------------------------------------------------------------ |
@@ -336,9 +306,8 @@ static WEBP_INLINE int Filter2(int A, int B) { return (A * 3 + B + 2) >> 2; } |
//------------------------------------------------------------------------------ |
-// 8bit -> YFIX |
-static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { |
- return ((fixed_y_t)a << YFIX) | (1 << (YFIX - 1)); |
+static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { // 8bit -> SFIX |
+ return ((fixed_y_t)a << SFIX) | SHALF; |
} |
static void ImportOneRow(const uint8_t* const r_ptr, |
@@ -368,50 +337,48 @@ static void InterpolateTwoRows(const fixed_y_t* const best_y, |
fixed_y_t* const out2) { |
int i, k; |
{ // special boundary case for i==0 |
- const int W0 = FixedYToW(best_y[0]); |
- const int W1 = FixedYToW(best_y[w]); |
+ const int W0 = best_y[0]; |
+ const int W1 = best_y[w]; |
for (k = 0; k <= 2; ++k) { |
- out1[k] = clip_fixed_t(Filter2(cur_uv[k], prev_uv[k]) + W0); |
- out2[k] = clip_fixed_t(Filter2(cur_uv[k], next_uv[k]) + W1); |
+ out1[k] = clip_y(Filter2(cur_uv[k], prev_uv[k]) + W0); |
+ out2[k] = clip_y(Filter2(cur_uv[k], next_uv[k]) + W1); |
} |
} |
for (i = 1; i < w - 1; ++i) { |
- const int W0 = FixedYToW(best_y[i + 0]); |
- const int W1 = FixedYToW(best_y[i + w]); |
+ const int W0 = best_y[i + 0]; |
+ const int W1 = best_y[i + w]; |
const int off = 3 * (i >> 1); |
for (k = 0; k <= 2; ++k) { |
const int tmp0 = Filter(cur_uv + off + k, prev_uv + off + k, i & 1); |
const int tmp1 = Filter(cur_uv + off + k, next_uv + off + k, i & 1); |
- out1[3 * i + k] = clip_fixed_t(tmp0 + W0); |
- out2[3 * i + k] = clip_fixed_t(tmp1 + W1); |
+ out1[3 * i + k] = clip_y(tmp0 + W0); |
+ out2[3 * i + k] = clip_y(tmp1 + W1); |
} |
} |
{ // special boundary case for i == w - 1 |
- const int W0 = FixedYToW(best_y[i + 0]); |
- const int W1 = FixedYToW(best_y[i + w]); |
+ const int W0 = best_y[i + 0]; |
+ const int W1 = best_y[i + w]; |
const int off = 3 * (i >> 1); |
for (k = 0; k <= 2; ++k) { |
- out1[3 * i + k] = |
- clip_fixed_t(Filter2(cur_uv[off + k], prev_uv[off + k]) + W0); |
- out2[3 * i + k] = |
- clip_fixed_t(Filter2(cur_uv[off + k], next_uv[off + k]) + W1); |
+ out1[3 * i + k] = clip_y(Filter2(cur_uv[off + k], prev_uv[off + k]) + W0); |
+ out2[3 * i + k] = clip_y(Filter2(cur_uv[off + k], next_uv[off + k]) + W1); |
} |
} |
} |
static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) { |
- const int luma = 16839 * r + 33059 * g + 6420 * b + TROUNDER; |
- return clip_8b(16 + (luma >> (YUV_FIX + TFIX))); |
+ const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER; |
+ return clip_8b(16 + (luma >> (YUV_FIX + SFIX))); |
} |
static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) { |
- const int u = -9719 * r - 19081 * g + 28800 * b + TROUNDER; |
- return clip_8b(128 + (u >> (YUV_FIX + TFIX))); |
+ const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER; |
+ return clip_8b(128 + (u >> (YUV_FIX + SFIX))); |
} |
static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) { |
- const int v = +28800 * r - 24116 * g - 4684 * b + TROUNDER; |
- return clip_8b(128 + (v >> (YUV_FIX + TFIX))); |
+ const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER; |
+ return clip_8b(128 + (v >> (YUV_FIX + SFIX))); |
} |
static int ConvertWRGBToYUV(const fixed_y_t* const best_y, |
@@ -426,7 +393,7 @@ static int ConvertWRGBToYUV(const fixed_y_t* const best_y, |
for (i = 0; i < picture->width; ++i) { |
const int off = 3 * ((i >> 1) + (j >> 1) * uv_w); |
const int off2 = i + j * picture->y_stride; |
- const int W = FixedYToW(best_y[i + j * w]); |
+ const int W = best_y[i + j * w]; |
const int r = best_uv[off + 0] + W; |
const int g = best_uv[off + 1] + W; |
const int b = best_uv[off + 2] + W; |
@@ -475,6 +442,10 @@ static int PreprocessARGB(const uint8_t* const r_ptr, |
fixed_t* const target_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t); |
fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t); |
int ok; |
+ int diff_sum = 0; |
+ const int first_diff_threshold = (int)(2.5 * w * h); |
+ const int min_improvement = 5; // stop if improvement is below this % |
+ const int min_first_improvement = 80; |
if (best_y == NULL || best_uv == NULL || |
target_y == NULL || target_uv == NULL || |
@@ -507,7 +478,7 @@ static int PreprocessARGB(const uint8_t* const r_ptr, |
} |
UpdateW(src1, target_y + (j + 0) * w, w); |
UpdateW(src2, target_y + (j + 1) * w, w); |
- UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w); |
+ diff_sum += UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w); |
memcpy(best_uv + uv_off, target_uv + uv_off, 3 * uv_w * sizeof(*best_uv)); |
memcpy(dst_y + w, dst_y, w * sizeof(*dst_y)); |
} |
@@ -517,10 +488,11 @@ static int PreprocessARGB(const uint8_t* const r_ptr, |
int k; |
const fixed_t* cur_uv = best_uv; |
const fixed_t* prev_uv = best_uv; |
+ const int old_diff_sum = diff_sum; |
+ diff_sum = 0; |
for (j = 0; j < h; j += 2) { |
fixed_y_t* const src1 = tmp_buffer; |
fixed_y_t* const src2 = tmp_buffer + 3 * w; |
- |
{ |
const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0); |
InterpolateTwoRows(best_y + j * w, prev_uv, cur_uv, next_uv, |
@@ -531,7 +503,7 @@ static int PreprocessARGB(const uint8_t* const r_ptr, |
UpdateW(src1, best_rgb_y + 0 * w, w); |
UpdateW(src2, best_rgb_y + 1 * w, w); |
- UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w); |
+ diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w); |
// update two rows of Y and one row of RGB |
for (i = 0; i < 2 * w; ++i) { |
@@ -553,7 +525,23 @@ static int PreprocessARGB(const uint8_t* const r_ptr, |
} |
} |
} |
- // TODO(skal): add early-termination criterion |
+ // test exit condition |
+ if (diff_sum > 0) { |
+ const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum; |
+ // Check if first iteration gave good result already, without a large |
+ // jump of improvement (otherwise it means we need to try few extra |
+ // iterations, just to be sure). |
+ if (iter == 0 && diff_sum < first_diff_threshold && |
+ improvement < min_first_improvement) { |
+ break; |
+ } |
+ // then, check if improvement is stalling. |
+ if (improvement < min_improvement) { |
+ break; |
+ } |
+ } else { |
+ break; |
+ } |
} |
// final reconstruction |
@@ -762,23 +750,20 @@ static WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr, |
int width, |
VP8Random* const rg) { |
int i, j; |
- for (i = 0, j = 0; i < width; ++i, j += step) { |
+ for (i = 0, j = 0; i < width; i += 1, j += step) { |
dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg); |
} |
} |
-static WEBP_INLINE void ConvertRowsToUVWithAlpha(const uint8_t* const r_ptr, |
- const uint8_t* const g_ptr, |
- const uint8_t* const b_ptr, |
- const uint8_t* const a_ptr, |
- int rgb_stride, |
- uint8_t* const dst_u, |
- uint8_t* const dst_v, |
- int width, |
- VP8Random* const rg) { |
+static WEBP_INLINE void AccumulateRGBA(const uint8_t* const r_ptr, |
+ const uint8_t* const g_ptr, |
+ const uint8_t* const b_ptr, |
+ const uint8_t* const a_ptr, |
+ int rgb_stride, |
+ uint16_t* dst, int width) { |
int i, j; |
- // we loop over 2x2 blocks and produce one U/V value for each. |
- for (i = 0, j = 0; i < (width >> 1); ++i, j += 2 * sizeof(uint32_t)) { |
+ // we loop over 2x2 blocks and produce one R/G/B/A value for each. |
+ for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * 4, dst += 4) { |
const uint32_t a = SUM4ALPHA(a_ptr + j); |
int r, g, b; |
if (a == 4 * 0xff || a == 0) { |
@@ -790,8 +775,10 @@ static WEBP_INLINE void ConvertRowsToUVWithAlpha(const uint8_t* const r_ptr, |
g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride); |
b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride); |
} |
- dst_u[i] = RGBToU(r, g, b, rg); |
- dst_v[i] = RGBToV(r, g, b, rg); |
+ dst[0] = r; |
+ dst[1] = g; |
+ dst[2] = b; |
+ dst[3] = a; |
} |
if (width & 1) { |
const uint32_t a = 2u * SUM2ALPHA(a_ptr + j); |
@@ -805,31 +792,39 @@ static WEBP_INLINE void ConvertRowsToUVWithAlpha(const uint8_t* const r_ptr, |
g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride); |
b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride); |
} |
- dst_u[i] = RGBToU(r, g, b, rg); |
- dst_v[i] = RGBToV(r, g, b, rg); |
+ dst[0] = r; |
+ dst[1] = g; |
+ dst[2] = b; |
+ dst[3] = a; |
+ } |
+} |
+ |
+static WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr, |
+ const uint8_t* const g_ptr, |
+ const uint8_t* const b_ptr, |
+ int step, int rgb_stride, |
+ uint16_t* dst, int width) { |
+ int i, j; |
+ for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * step, dst += 4) { |
+ dst[0] = SUM4(r_ptr + j, step); |
+ dst[1] = SUM4(g_ptr + j, step); |
+ dst[2] = SUM4(b_ptr + j, step); |
+ } |
+ if (width & 1) { |
+ dst[0] = SUM2(r_ptr + j); |
+ dst[1] = SUM2(g_ptr + j); |
+ dst[2] = SUM2(b_ptr + j); |
} |
} |
-static WEBP_INLINE void ConvertRowsToUV(const uint8_t* const r_ptr, |
- const uint8_t* const g_ptr, |
- const uint8_t* const b_ptr, |
- int step, int rgb_stride, |
+static WEBP_INLINE void ConvertRowsToUV(const uint16_t* rgb, |
uint8_t* const dst_u, |
uint8_t* const dst_v, |
int width, |
VP8Random* const rg) { |
- int i, j; |
- for (i = 0, j = 0; i < (width >> 1); ++i, j += 2 * step) { |
- const int r = SUM4(r_ptr + j, step); |
- const int g = SUM4(g_ptr + j, step); |
- const int b = SUM4(b_ptr + j, step); |
- dst_u[i] = RGBToU(r, g, b, rg); |
- dst_v[i] = RGBToV(r, g, b, rg); |
- } |
- if (width & 1) { |
- const int r = SUM2(r_ptr + j); |
- const int g = SUM2(g_ptr + j); |
- const int b = SUM2(b_ptr + j); |
+ int i; |
+ for (i = 0; i < width; i += 1, rgb += 4) { |
+ const int r = rgb[0], g = rgb[1], b = rgb[2]; |
dst_u[i] = RGBToU(r, g, b, rg); |
dst_v[i] = RGBToV(r, g, b, rg); |
} |
@@ -848,6 +843,7 @@ static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, |
const int width = picture->width; |
const int height = picture->height; |
const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride); |
+ const int is_rgb = (r_ptr < b_ptr); // otherwise it's bgr |
picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420; |
picture->use_argb = 0; |
@@ -864,7 +860,7 @@ static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, |
if (has_alpha) { |
WebPInitAlphaProcessing(); |
assert(step == 4); |
-#if defined(USE_INVERSE_ALPHA_TABLE) |
+#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE) |
assert(kAlphaFix + kGammaFix <= 31); |
#endif |
} |
@@ -879,6 +875,11 @@ static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, |
picture->a, picture->a_stride); |
} |
} else { |
+ const int uv_width = (width + 1) >> 1; |
+ int use_dsp = (step == 3); // use special function in this case |
+ // temporary storage for accumulated R/G/B values during conversion to U/V |
+ uint16_t* const tmp_rgb = |
+ (uint16_t*)WebPSafeMalloc(4 * uv_width, sizeof(*tmp_rgb)); |
uint8_t* dst_y = picture->y; |
uint8_t* dst_u = picture->u; |
uint8_t* dst_v = picture->v; |
@@ -889,19 +890,32 @@ static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, |
if (dithering > 0.) { |
VP8InitRandom(&base_rg, dithering); |
rg = &base_rg; |
+ use_dsp = 0; // can't use dsp in this case |
} |
- |
+ WebPInitConvertARGBToYUV(); |
InitGammaTables(); |
+ if (tmp_rgb == NULL) return 0; // malloc error |
+ |
// Downsample Y/U/V planes, two rows at a time |
for (y = 0; y < (height >> 1); ++y) { |
int rows_have_alpha = has_alpha; |
const int off1 = (2 * y + 0) * rgb_stride; |
const int off2 = (2 * y + 1) * rgb_stride; |
- ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step, |
- dst_y, width, rg); |
- ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step, |
- dst_y + picture->y_stride, width, rg); |
+ if (use_dsp) { |
+ if (is_rgb) { |
+ WebPConvertRGB24ToY(r_ptr + off1, dst_y, width); |
+ WebPConvertRGB24ToY(r_ptr + off2, dst_y + picture->y_stride, width); |
+ } else { |
+ WebPConvertBGR24ToY(b_ptr + off1, dst_y, width); |
+ WebPConvertBGR24ToY(b_ptr + off2, dst_y + picture->y_stride, width); |
+ } |
+ } else { |
+ ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step, |
+ dst_y, width, rg); |
+ ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step, |
+ dst_y + picture->y_stride, width, rg); |
+ } |
dst_y += 2 * picture->y_stride; |
if (has_alpha) { |
rows_have_alpha &= !WebPExtractAlpha(a_ptr + off1, rgb_stride, |
@@ -909,13 +923,19 @@ static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, |
dst_a, picture->a_stride); |
dst_a += 2 * picture->a_stride; |
} |
+ // Collect averaged R/G/B(/A) |
if (!rows_have_alpha) { |
- ConvertRowsToUV(r_ptr + off1, g_ptr + off1, b_ptr + off1, |
- step, rgb_stride, dst_u, dst_v, width, rg); |
+ AccumulateRGB(r_ptr + off1, g_ptr + off1, b_ptr + off1, |
+ step, rgb_stride, tmp_rgb, width); |
+ } else { |
+ AccumulateRGBA(r_ptr + off1, g_ptr + off1, b_ptr + off1, a_ptr + off1, |
+ rgb_stride, tmp_rgb, width); |
+ } |
+ // Convert to U/V |
+ if (rg == NULL) { |
+ WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); |
} else { |
- ConvertRowsToUVWithAlpha(r_ptr + off1, g_ptr + off1, b_ptr + off1, |
- a_ptr + off1, rgb_stride, |
- dst_u, dst_v, width, rg); |
+ ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); |
} |
dst_u += picture->uv_stride; |
dst_v += picture->uv_stride; |
@@ -923,20 +943,35 @@ static int ImportYUVAFromRGBA(const uint8_t* const r_ptr, |
if (height & 1) { // extra last row |
const int off = 2 * y * rgb_stride; |
int row_has_alpha = has_alpha; |
- ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step, |
- dst_y, width, rg); |
+ if (use_dsp) { |
+ if (r_ptr < b_ptr) { |
+ WebPConvertRGB24ToY(r_ptr + off, dst_y, width); |
+ } else { |
+ WebPConvertBGR24ToY(b_ptr + off, dst_y, width); |
+ } |
+ } else { |
+ ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step, |
+ dst_y, width, rg); |
+ } |
if (row_has_alpha) { |
row_has_alpha &= !WebPExtractAlpha(a_ptr + off, 0, width, 1, dst_a, 0); |
} |
+ // Collect averaged R/G/B(/A) |
if (!row_has_alpha) { |
- ConvertRowsToUV(r_ptr + off, g_ptr + off, b_ptr + off, |
- step, 0, dst_u, dst_v, width, rg); |
+ // Collect averaged R/G/B |
+ AccumulateRGB(r_ptr + off, g_ptr + off, b_ptr + off, |
+ step, /* rgb_stride = */ 0, tmp_rgb, width); |
+ } else { |
+ AccumulateRGBA(r_ptr + off, g_ptr + off, b_ptr + off, a_ptr + off, |
+ /* rgb_stride = */ 0, tmp_rgb, width); |
+ } |
+ if (rg == NULL) { |
+ WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width); |
} else { |
- ConvertRowsToUVWithAlpha(r_ptr + off, g_ptr + off, b_ptr + off, |
- a_ptr + off, 0, |
- dst_u, dst_v, width, rg); |
+ ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg); |
} |
} |
+ WebPSafeFree(tmp_rgb); |
} |
return 1; |
} |
@@ -978,11 +1013,9 @@ int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) { |
return PictureARGBToYUVA(picture, colorspace, 0.f, 0); |
} |
-#if WEBP_ENCODER_ABI_VERSION > 0x0204 |
int WebPPictureSmartARGBToYUVA(WebPPicture* picture) { |
return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1); |
} |
-#endif |
//------------------------------------------------------------------------------ |
// call for YUVA -> ARGB conversion |
@@ -1066,14 +1099,23 @@ static int Import(WebPPicture* const picture, |
} |
if (!WebPPictureAlloc(picture)) return 0; |
- assert(step >= (import_alpha ? 4 : 3)); |
- for (y = 0; y < height; ++y) { |
- uint32_t* const dst = &picture->argb[y * picture->argb_stride]; |
- int x; |
- for (x = 0; x < width; ++x) { |
- const int offset = step * x + y * rgb_stride; |
- dst[x] = MakeARGB32(import_alpha ? a_ptr[offset] : 0xff, |
- r_ptr[offset], g_ptr[offset], b_ptr[offset]); |
+ VP8EncDspARGBInit(); |
+ |
+ if (import_alpha) { |
+ assert(step == 4); |
+ for (y = 0; y < height; ++y) { |
+ uint32_t* const dst = &picture->argb[y * picture->argb_stride]; |
+ const int offset = y * rgb_stride; |
+ VP8PackARGB(a_ptr + offset, r_ptr + offset, g_ptr + offset, |
+ b_ptr + offset, width, dst); |
+ } |
+ } else { |
+ assert(step >= 3); |
+ for (y = 0; y < height; ++y) { |
+ uint32_t* const dst = &picture->argb[y * picture->argb_stride]; |
+ const int offset = y * rgb_stride; |
+ VP8PackRGB(r_ptr + offset, g_ptr + offset, b_ptr + offset, |
+ width, step, dst); |
} |
} |
return 1; |