add support for RGB565, ARGB4444 and ARGB colorspace (decoder)

RGB565 and ARGB4444 are only supported through the advanced decoding API.
ARGB being somewhat generic, there's an easy WebPDecodeARGB()
new function for convenience.

Patch by Vikas Arora (vikaas dot arora at gmail dot com)

Change-Id: Ic7b6f72bd70aca458d14e7fdd23679212430ebca
This commit is contained in:
Pascal Massimino 2011-07-13 09:08:58 -07:00
parent c915fb2aa7
commit 19db59f80f
7 changed files with 123 additions and 45 deletions

View File

@ -20,6 +20,9 @@ extern "C" {
//-----------------------------------------------------------------------------
// WebPDecBuffer
// Number of bytes per pixel for the different color-spaces.
static const int kModeBpp[MODE_LAST] = { 3, 4, 3, 4, 4, 2, 2, 1, 1 };
static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
int ok = 1;
WEBP_CSP_MODE mode = buffer->colorspace;
@ -44,11 +47,7 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
} else { // RGB checks
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
ok &= (buf->stride * height <= buf->size);
if (mode == MODE_RGB || mode == MODE_BGR) {
ok &= (buf->stride >= width * 3);
} else if (mode == MODE_RGBA || mode == MODE_BGRA) {
ok &= (buf->stride >= width * 4);
}
ok &= (buf->stride >= width * kModeBpp[mode]);
}
return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
}
@ -70,9 +69,7 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
uint64_t size, a_size = 0, total_size;
// We need memory and it hasn't been allocated yet.
// => initialize output buffer, now that dimensions are known.
stride = (mode == MODE_RGB || mode == MODE_BGR) ? 3 * w
: (mode == MODE_RGBA || mode == MODE_BGRA) ? 4 * w
: w;
stride = w * kModeBpp[mode];
size = (uint64_t)stride * h;
if (mode >= MODE_YUV) {

View File

@ -21,9 +21,6 @@ extern "C" {
#define FANCY_UPSAMPLING // undefined to remove fancy upsampling support
// mask to apply to WEBP_CSP_MODE, to know if there's alpha channel or not.
#define MODE_ALPHA_MASK 1
//------------------------------------------------------------------------------
// Fancy upsampler
@ -101,27 +98,38 @@ UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
UPSAMPLE_FUNC(UpsampleArgb4444LinePair, VP8YuvToArgb4444, 2)
UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
// These two don't erase the alpha value
UPSAMPLE_FUNC(UpsampleRgbKeepAlphaLinePair, VP8YuvToRgb, 4)
UPSAMPLE_FUNC(UpsampleBgrKeepAlphaLinePair, VP8YuvToBgr, 4)
UPSAMPLE_FUNC(UpsampleArgbKeepAlphaLinePair, VP8YuvToArgbKeepA, 4)
UPSAMPLE_FUNC(UpsampleArgb4444KeepAlphaLinePair, VP8YuvToArgb4444KeepA, 2)
#undef LOAD_UV
#undef UPSAMPLE_FUNC
// Fancy upsampling functions to convert YUV to RGB
WebPUpsampleLinePairFunc WebPUpsamplers[MODE_BGRA + 1];
WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_BGRA + 1];
WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_LAST];
static void InitUpsamplers(void) {
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
WebPUpsamplers[MODE_ARGB_4444] = UpsampleArgb4444LinePair;
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
WebPUpsamplersKeepAlpha[MODE_RGB] = UpsampleRgbLinePair;
WebPUpsamplersKeepAlpha[MODE_RGBA] = UpsampleRgbKeepAlphaLinePair;
WebPUpsamplersKeepAlpha[MODE_BGR] = UpsampleBgrLinePair;
WebPUpsamplersKeepAlpha[MODE_BGRA] = UpsampleBgrKeepAlphaLinePair;
WebPUpsamplersKeepAlpha[MODE_ARGB] = UpsampleArgbKeepAlphaLinePair;
WebPUpsamplersKeepAlpha[MODE_ARGB_4444] = UpsampleArgb4444KeepAlphaLinePair;
WebPUpsamplersKeepAlpha[MODE_RGB_565] = UpsampleRgb565LinePair;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8DecGetCPUInfo) {
@ -166,6 +174,9 @@ SAMPLE_FUNC(SampleRgbLinePair, VP8YuvToRgb, 3)
SAMPLE_FUNC(SampleBgrLinePair, VP8YuvToBgr, 3)
SAMPLE_FUNC(SampleRgbaLinePair, VP8YuvToRgba, 4)
SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4)
SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4)
SAMPLE_FUNC(SampleArgb4444LinePair, VP8YuvToArgb4444, 2)
SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2)
#undef SAMPLE_FUNC
@ -175,11 +186,14 @@ typedef void (*SampleLinePairFunc)(
const uint8_t* u, const uint8_t* v,
uint8_t* top_dst, uint8_t* bottom_dst, int len);
static const SampleLinePairFunc kSamplers[MODE_BGRA + 1] = {
static const SampleLinePairFunc kSamplers[MODE_LAST] = {
SampleRgbLinePair, // MODE_RGB
SampleRgbaLinePair, // MODE_RGBA
SampleBgrLinePair, // MODE_BGR
SampleBgraLinePair // MODE_BGRA
SampleBgraLinePair, // MODE_BGRA
SampleArgbLinePair, // MODE_ARGB
SampleArgb4444LinePair, // MODE_ARGB_4444
SampleRgb565LinePair // MODE_RGB_565
};
//------------------------------------------------------------------------------
@ -196,17 +210,23 @@ YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb, 3)
YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr, 3)
YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba, 4)
YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra, 4)
YUV444_FUNC(Yuv444ToArgb, VP8YuvToArgb, 4)
YUV444_FUNC(Yuv444ToArgb4444, VP8YuvToArgb4444, 2)
YUV444_FUNC(Yuv444ToRgb565, VP8YuvToRgb565, 2)
#undef YUV444_FUNC
typedef void (*YUV444Func)(const uint8_t* y, const uint8_t* u, const uint8_t* v,
uint8_t* dst, int len);
static const YUV444Func kYUV444Converters[MODE_BGRA + 1] = {
static const YUV444Func kYUV444Converters[MODE_LAST] = {
Yuv444ToRgb, // MODE_RGB
Yuv444ToRgba, // MODE_RGBA
Yuv444ToBgr, // MODE_BGR
Yuv444ToBgra // MODE_BGRA
Yuv444ToBgra, // MODE_BGRA
Yuv444ToArgb, // MODE_ARGB
Yuv444ToArgb4444, // MODE_ARGB_4444
Yuv444ToRgb565 // MODE_RGB_565
};
//------------------------------------------------------------------------------
@ -517,8 +537,13 @@ static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
return 0;
}
static int IsAlphaMode(WEBP_CSP_MODE mode) {
return (mode == MODE_RGBA || mode == MODE_BGRA || mode == MODE_ARGB ||
mode == MODE_ARGB_4444 || mode == MODE_YUVA);
}
static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int has_alpha = (p->output->colorspace & MODE_ALPHA_MASK);
const int has_alpha = IsAlphaMode(p->output->colorspace);
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
const int out_width = io->scaled_width;
const int out_height = io->scaled_height;
@ -653,7 +678,7 @@ static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
}
static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int has_alpha = (p->output->colorspace & MODE_ALPHA_MASK);
const int has_alpha = IsAlphaMode(p->output->colorspace);
const int out_width = io->scaled_width;
const int out_height = io->scaled_height;
const int uv_in_width = (io->mb_w + 1) >> 1;
@ -793,7 +818,7 @@ static int CustomSetup(VP8Io* io) {
p->emit = EmitYUV;
}
#ifdef WEBP_EXPERIMENTAL_FEATURES
if (p->output->colorspace & MODE_ALPHA_MASK) {
if (IsAlphaMode(p->output->colorspace)) {
// We need transparency output
p->emit_alpha = is_rgb ? EmitAlphaRGB : EmitAlphaYUV;
}

View File

@ -224,6 +224,11 @@ uint8_t* WebPDecodeRGBA(const uint8_t* data, uint32_t data_size,
return Decode(MODE_RGBA, data, data_size, width, height, NULL);
}
uint8_t* WebPDecodeARGB(const uint8_t* data, uint32_t data_size,
int* width, int* height) {
return Decode(MODE_ARGB, data, data_size, width, height, NULL);
}
uint8_t* WebPDecodeBGR(const uint8_t* data, uint32_t data_size,
int* width, int* height) {
return Decode(MODE_BGR, data, data_size, width, height, NULL);

View File

@ -67,8 +67,8 @@ typedef void (*WebPUpsampleLinePairFunc)(
uint8_t* top_dst, uint8_t* bottom_dst, int len);
// Upsampler functions to be used to convert YUV to RGB(A) modes
extern WebPUpsampleLinePairFunc WebPUpsamplers[MODE_BGRA + 1];
extern WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_BGRA + 1];
extern WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
extern WebPUpsampleLinePairFunc WebPUpsamplersKeepAlpha[MODE_LAST];
// Initializes SSE2 version of the fancy upsamplers.
void WebPInitUpsamplersSSE2(void);

View File

@ -20,6 +20,7 @@ enum { YUV_HALF = 1 << (YUV_FIX - 1) };
int16_t VP8kVToR[256], VP8kUToB[256];
int32_t VP8kVToG[256], VP8kUToG[256];
uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
static int done = 0;
@ -37,6 +38,7 @@ void VP8YUVInit(void) {
for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
VP8kClip[i - YUV_RANGE_MIN] = (k < 0) ? 0 : (k > 255) ? 255 : k;
VP8kClip4Bits[i - YUV_RANGE_MIN] = (VP8kClip[i - YUV_RANGE_MIN] + 8) >> 4;
}
done = 1;
}

View File

@ -25,6 +25,7 @@ enum { YUV_FIX = 16, // fixed-point precision
extern int16_t VP8kVToR[256], VP8kUToB[256];
extern int32_t VP8kVToG[256], VP8kUToG[256];
extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
static inline void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgb) {
@ -36,6 +37,46 @@ static inline void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
}
static inline void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const rgb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
rgb[0] = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
(VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
rgb[1] = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
(VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
}
static inline void VP8YuvToArgbKeepA(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
// Don't update Aplha (argb[0])
VP8YuvToRgb(y, u, v, argb + 1);
}
static inline void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
argb[0] = 0xff;
VP8YuvToArgbKeepA(y, u, v, argb);
}
static inline void VP8YuvToArgb4444KeepA(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
// Don't update Aplha (first 4 bits of argb[0])
argb[0] = VP8kClip4Bits[y + r_off - YUV_RANGE_MIN];
argb[1] = ((VP8kClip[y + g_off - YUV_RANGE_MIN] & 0xf0) |
VP8kClip4Bits[y + b_off - YUV_RANGE_MIN]);
}
static inline void VP8YuvToArgb4444(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const argb) {
argb[0] = 0xf0;
VP8YuvToArgb4444KeepA(y, u, v, argb);
}
static inline void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
uint8_t* const bgr) {
const int r_off = VP8kVToR[v];

View File

@ -42,6 +42,10 @@ uint8_t* WebPDecodeRGB(const uint8_t* data, uint32_t data_size,
uint8_t* WebPDecodeRGBA(const uint8_t* data, uint32_t data_size,
int* width, int* height);
// Same as WebPDecodeRGBA, but returning ARGB data.
uint8_t* WebPDecodeARGB(const uint8_t* data, uint32_t data_size,
int* width, int* height);
// This variant decode to BGR instead of RGB.
uint8_t* WebPDecodeBGR(const uint8_t* data, uint32_t data_size,
int* width, int* height);
@ -102,7 +106,11 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size,
// Colorspaces
typedef enum { MODE_RGB = 0, MODE_RGBA = 1,
MODE_BGR = 2, MODE_BGRA = 3,
MODE_YUV = 4, MODE_YUVA = 5 // yuv 4:2:0
MODE_ARGB = 4, MODE_ARGB_4444 = 5,
MODE_RGB_565 = 6,
// YUV modes must come after RGB ones.
MODE_YUV = 7, MODE_YUVA = 8, // yuv 4:2:0
MODE_LAST = 9
} WEBP_CSP_MODE;
// Generic structure for describing the sample buffer.