summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libwebp/src/enc/picture_csp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/libwebp/src/enc/picture_csp.c')
-rw-r--r--src/3rdparty/libwebp/src/enc/picture_csp.c350
1 files changed, 196 insertions, 154 deletions
diff --git a/src/3rdparty/libwebp/src/enc/picture_csp.c b/src/3rdparty/libwebp/src/enc/picture_csp.c
index 7875f62..0ef5f9e 100644
--- a/src/3rdparty/libwebp/src/enc/picture_csp.c
+++ b/src/3rdparty/libwebp/src/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;