interface: add colorspaces support for RGB48 and RGBA64

these colorspaces are packed as RGB or RGBA, not BGR or BGRA.
RGB48_BIG and RGBA64 only differ in the endianess of the channel the 2-byte value.

this is a big difference with RGB24_BIG and RGBA32_BIG, in which case _BIG
means the order is RGB (BGR) and not BGR (BGRA).
BGR48, BGRA64 could indeed be added, if needed.

I chose 0x11 and 0x12 arbitrarily, but given the order of channels 0x1011
and 0x1012 might make more sense. This would mean using another bit for "real"
bigendian colorspaces.

Only the color conversion to 32-bits is implemented.

Tested with the RAWTranslator modified to output 16bpp with success.

Found some references in enum AVPixelFormat in libavutil/pixfmt.h.

Change-Id: I4b023dec85d01f1e63e1b053139e5bb5d263a0e0
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4468
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
Jérôme Duval 2021-09-15 22:10:23 +02:00
parent c1432f757f
commit bb187c91d8
7 changed files with 277 additions and 4 deletions

View File

@ -149,6 +149,8 @@ typedef enum {
B_NO_COLOR_SPACE = 0x0000,
// linear color space (little endian)
B_RGBA64 = 0x2012, // RGBA RGBA 16:16:16:16
B_RGB48 = 0x0011, // RGB RGB 16:16:16
B_RGB32 = 0x0008, // BGR- -RGB 8:8:8:8
B_RGBA32 = 0x2008, // BGRA ARGB 8:8:8:8
B_RGB24 = 0x0003, // BGR RGB 8:8:8
@ -160,6 +162,8 @@ typedef enum {
B_GRAY1 = 0x0001, // Each bit represents a single pixel
// linear color space (big endian)
B_RGBA64_BIG = 0x3012, // RGBA RGBA 16:16:16:16
B_RGB48_BIG = 0x1011, // RGB RGB 16:16:16
B_RGB32_BIG = 0x1008, // -RGB BGR- 8:8:8:8
B_RGBA32_BIG = 0x3008, // ARGB BGRA 8:8:8:8
B_RGB24_BIG = 0x1003, // RGB BGR 8:8:8
@ -168,6 +172,8 @@ typedef enum {
B_RGBA15_BIG = 0x3010, // ARGB BGRA 5:5:5:1
// linear color space (little endian, for completeness)
B_RGBA64_LITTLE = B_RGBA64,
B_RGB48_LITTLE = B_RGB48,
B_RGB32_LITTLE = B_RGB32,
B_RGBA32_LITTLE = B_RGBA32,
B_RGB24_LITTLE = B_RGB24,

View File

@ -179,6 +179,12 @@ get_raw_bytes_per_row(color_space colorSpace, int32 width)
int32 bpr = 0;
switch (colorSpace) {
// supported
case B_RGBA64: case B_RGBA64_BIG:
bpr = 8 * width;
break;
case B_RGB48: case B_RGB48_BIG:
bpr = 6 * width;
break;
case B_RGB32: case B_RGBA32:
case B_RGB32_BIG: case B_RGBA32_BIG:
case B_UVL32: case B_UVLA32:

View File

@ -57,6 +57,14 @@ get_pixel_size_for(color_space space, size_t *pixelChunk, size_t *rowAlignment,
int32 pixPerChunk = 0;
switch (space) {
// supported
case B_RGBA64: case B_RGBA64_BIG:
bytesPerPixel = 8;
pixPerChunk = 2;
break;
case B_RGB48: case B_RGB48_BIG:
bytesPerPixel = 6;
pixPerChunk = 2;
break;
case B_RGB32: case B_RGBA32:
case B_RGB32_BIG: case B_RGBA32_BIG:
case B_UVL32: case B_UVLA32:
@ -150,6 +158,8 @@ bitmaps_support_space(color_space space, uint32 *supportFlags)
bool result = false;
switch (space) {
// supported
case B_RGBA64: case B_RGBA64_BIG:
case B_RGB48: case B_RGB48_BIG:
case B_RGB32: case B_RGBA32: case B_RGB24:
case B_RGB32_BIG: case B_RGBA32_BIG: case B_RGB24_BIG:
case B_RGB16: case B_RGB15: case B_RGBA15:

View File

@ -87,6 +87,12 @@ get_raw_bytes_per_row(color_space colorSpace, int32 width)
int32 bpr = 0;
switch (colorSpace) {
// supported
case B_RGBA64: case B_RGBA64_BIG:
bpr = 8 * width;
break;
case B_RGB48: case B_RGB48_BIG:
bpr = 6 * width;
break;
case B_RGB32: case B_RGBA32:
case B_RGB32_BIG: case B_RGBA32_BIG:
case B_UVL32: case B_UVLA32:

View File

@ -491,9 +491,20 @@ PaletteConverter::_InitializeDefaultNoAppServer()
typedef uint32 (readFunc)(const uint8 **source, int32 index);
typedef uint64 (read64Func)(const uint16 **source, int32 index);
typedef void (writeFunc)(uint8 **dest, uint8 *data, int32 index);
uint64
ReadRGB48(const uint16 **source, int32 index)
{
uint64 result = (*source)[0] | ((uint64)((*source)[1]) << 16)
| ((uint64)((*source)[2]) << 32);
*source += 3;
return result;
}
void
WriteRGB24(uint8 **dest, uint8 *data, int32 index)
{
@ -573,6 +584,145 @@ ReadCMAP8(const uint8 **source, int32 index)
}
template<typename srcByte, typename dstByte>
status_t
ConvertBits64To32(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength,
int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
int32 alphaShift, int32 alphaBits, uint32 redMask, uint32 greenMask,
uint32 blueMask, uint32 alphaMask, int32 srcBytesPerRow,
int32 dstBytesPerRow, int32 srcBitsPerPixel, int32 dstBitsPerPixel,
color_space srcColorSpace, color_space dstColorSpace, BPoint srcOffset,
BPoint dstOffset, int32 width, int32 height, bool srcSwap, bool dstSwap,
read64Func *srcFunc, writeFunc *dstFunc)
{
uint8* srcBitsEnd = (uint8*)srcBits + srcBitsLength;
uint8* dstBitsEnd = (uint8*)dstBits + dstBitsLength;
int32 srcBitsPerRow = srcBytesPerRow << 3;
int32 dstBitsPerRow = dstBytesPerRow << 3;
// Advance the buffers to reach their offsets
int32 srcOffsetX = (int32)srcOffset.x;
int32 dstOffsetX = (int32)dstOffset.x;
int32 srcOffsetY = (int32)srcOffset.y;
int32 dstOffsetY = (int32)dstOffset.y;
if (srcOffsetX < 0) {
dstOffsetX -= srcOffsetX;
srcOffsetX = 0;
}
if (srcOffsetY < 0) {
dstOffsetY -= srcOffsetY;
height += srcOffsetY;
srcOffsetY = 0;
}
if (dstOffsetX < 0) {
srcOffsetX -= dstOffsetX;
dstOffsetX = 0;
}
if (dstOffsetY < 0) {
srcOffsetY -= dstOffsetY;
height += dstOffsetY;
dstOffsetY = 0;
}
srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow
+ srcOffsetX * srcBitsPerPixel) >> 3));
dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow
+ dstOffsetX * dstBitsPerPixel) >> 3));
// Ensure that the width fits
int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel)
/ srcBitsPerPixel;
if (srcWidth < width)
width = srcWidth;
int32 dstWidth = (dstBitsPerRow - dstOffsetX * dstBitsPerPixel)
/ dstBitsPerPixel;
if (dstWidth < width)
width = dstWidth;
if (width < 0)
return B_OK;
int32 srcLinePad = (srcBitsPerRow - width * srcBitsPerPixel + 7) >> 3;
int32 dstLinePad = (dstBitsPerRow - width * dstBitsPerPixel + 7) >> 3;
uint64 result;
uint64 source;
// srcSwap, means the lower bits come first
if (srcSwap) {
redShift -= 8;
greenShift -= 8;
blueShift -= 8;
alphaShift -= 8;
}
for (int32 i = 0; i < height; i++) {
for (int32 j = 0; j < width; j++) {
if ((uint8 *)srcBits + sizeof(srcByte) > srcBitsEnd
|| (uint8 *)dstBits + sizeof(dstByte) > dstBitsEnd)
return B_OK;
if (srcFunc)
source = srcFunc((const uint16 **)&srcBits, srcOffsetX++);
else {
source = *srcBits;
srcBits++;
}
if (redShift > 0)
result = ((source >> redShift) & redMask);
else if (redShift < 0)
result = ((source << -redShift) & redMask);
else
result = source & redMask;
if (greenShift > 0)
result |= ((source >> greenShift) & greenMask);
else if (greenShift < 0)
result |= ((source << -greenShift) & greenMask);
else
result |= source & greenMask;
if (blueShift > 0)
result |= ((source >> blueShift) & blueMask);
else if (blueShift < 0)
result |= ((source << -blueShift) & blueMask);
else
result |= source & blueMask;
if (alphaBits > 0) {
if (alphaShift > 0)
result |= ((source >> alphaShift) & alphaMask);
else if (alphaShift < 0)
result |= ((source << -alphaShift) & alphaMask);
else
result |= source & alphaMask;
// if we only had one alpha bit we want it to be 0/255
if (alphaBits == 1 && result & alphaMask)
result |= alphaMask;
} else
result |= alphaMask;
if (dstFunc)
dstFunc((uint8 **)&dstBits, (uint8 *)&result, dstOffsetX++);
else {
*dstBits = result;
dstBits++;
}
}
srcBits = (srcByte*)((uint8*)srcBits + srcLinePad);
dstBits = (dstByte*)((uint8*)dstBits + dstLinePad);
dstOffsetX -= width;
srcOffsetX -= width;
}
return B_OK;
}
template<typename srcByte, typename dstByte>
status_t
ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength,
@ -614,10 +764,10 @@ ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength,
dstOffsetY = 0;
}
srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow + srcOffsetX
* srcBitsPerPixel) >> 3));
dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow + dstOffsetX
* dstBitsPerPixel) >> 3));
srcBits = (srcByte*)((uint8*)srcBits + ((srcOffsetY * srcBitsPerRow
+ srcOffsetX * srcBitsPerPixel) >> 3));
dstBits = (dstByte*)((uint8*)dstBits + ((dstOffsetY * dstBitsPerRow
+ dstOffsetX * dstBitsPerPixel) >> 3));
// Ensure that the width fits
int32 srcWidth = (srcBitsPerRow - srcOffsetX * srcBitsPerPixel)
@ -738,6 +888,64 @@ ConvertBits(const srcByte *srcBits, dstByte *dstBits, int32 srcBitsLength,
}
template<typename srcByte>
status_t
ConvertBits64(const srcByte *srcBits, void *dstBits, int32 srcBitsLength,
int32 dstBitsLength, int32 redShift, int32 greenShift, int32 blueShift,
int32 alphaShift, int32 alphaBits, int32 srcBytesPerRow,
int32 dstBytesPerRow, int32 srcBitsPerPixel, color_space srcColorSpace,
color_space dstColorSpace, BPoint srcOffset, BPoint dstOffset, int32 width,
int32 height, bool srcSwap, read64Func *srcFunc)
{
switch (dstColorSpace) {
case B_RGBA32:
ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength,
dstBitsLength, redShift - 24, greenShift - 16, blueShift - 8,
alphaShift - 32, alphaBits, 0x00ff0000, 0x0000ff00, 0x000000ff,
0xff000000, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel,
32, srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
height, srcSwap, false, srcFunc, NULL);
break;
case B_RGBA32_BIG:
ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength,
dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
alphaShift - 8, alphaBits, 0x0000ff00, 0x00ff0000, 0xff000000,
0x00000ff, srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
height, srcSwap, false, srcFunc, NULL);
break;
/* Note: we set the unused alpha to 255 here. This is because BeOS
uses the unused alpha for B_OP_ALPHA even though it should
not care about it. */
case B_RGB32:
ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength,
dstBitsLength, redShift - 24, greenShift - 32, blueShift - 16,
0, 0, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000,
srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
height, srcSwap, false, srcFunc, NULL);
break;
case B_RGB32_BIG:
ConvertBits64To32(srcBits, (uint32 *)dstBits, srcBitsLength,
dstBitsLength, redShift - 16, greenShift - 24, blueShift - 32,
0, 0, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff,
srcBytesPerRow, dstBytesPerRow, srcBitsPerPixel, 32,
srcColorSpace, dstColorSpace, srcOffset, dstOffset, width,
height, srcSwap, false, srcFunc, NULL);
break;
default:
return B_BAD_VALUE;
break;
}
return B_OK;
}
template<typename srcByte>
status_t
ConvertBits(const srcByte *srcBits, void *dstBits, int32 srcBitsLength,
@ -927,6 +1135,22 @@ ConvertBits(const void *srcBits, void *dstBits, int32 srcBitsLength,
return B_BAD_VALUE;
switch (srcColorSpace) {
case B_RGBA64:
case B_RGBA64_BIG:
return ConvertBits64((const uint64 *)srcBits, dstBits,
srcBitsLength, dstBitsLength, 16, 32, 48, 64, 16,
srcBytesPerRow, dstBytesPerRow, 64, srcColorSpace,
dstColorSpace, srcOffset, dstOffset, width, height,
srcColorSpace == B_RGBA64_BIG, NULL);
case B_RGB48:
case B_RGB48_BIG:
return ConvertBits64((const uint16 *)srcBits, dstBits,
srcBitsLength, dstBitsLength, 16, 32, 48, 0, 0, srcBytesPerRow,
dstBytesPerRow, 48, srcColorSpace, dstColorSpace, srcOffset,
dstOffset, width, height, srcColorSpace == B_RGB48_BIG,
ReadRGB48);
case B_RGBA32:
return ConvertBits((const uint32 *)srcBits, dstBits, srcBitsLength,
dstBitsLength, 24, 16, 8, 32, 8, srcBytesPerRow,

View File

@ -97,6 +97,14 @@ get_pixel_size_for(color_space space, size_t *pixelChunk, size_t *rowAlignment,
int32 pixPerChunk = 0;
switch (space) {
// supported
case B_RGBA64: case B_RGBA64_BIG:
bytesPerPixel = 8;
pixPerChunk = 2;
break;
case B_RGB48: case B_RGB48_BIG:
bytesPerPixel = 6;
pixPerChunk = 2;
break;
case B_RGB32: case B_RGBA32:
case B_RGB32_BIG: case B_RGBA32_BIG:
case B_UVL32: case B_UVLA32:
@ -217,6 +225,8 @@ bitmaps_support_space(color_space space, uint32 *supportFlags)
break;
// supported, but cannot draw
case B_RGBA64: case B_RGBA64_BIG:
case B_RGB48: case B_RGB48_BIG:
case B_YCbCr422: case B_YCbCr411: case B_YCbCr444: case B_YCbCr420:
case B_YUV422: case B_YUV411: case B_YUV444: case B_YUV420:
case B_UVL24: case B_UVL32: case B_UVLA32:

View File

@ -35,6 +35,12 @@ get_bytes_per_row(color_space colorSpace, int32 width)
int32 bpr = 0;
switch (colorSpace) {
// supported
case B_RGBA64: case B_RGBA64_BIG:
bpr = 8 * width;
break;
case B_RGB48: case B_RGB48_BIG:
bpr = 6 * width;
break;
case B_RGB32: case B_RGBA32:
case B_RGB32_BIG: case B_RGBA32_BIG:
case B_UVL32: case B_UVLA32:
@ -98,6 +104,11 @@ void TBBitmapTester::BBitmap1()
BRect bounds;
color_space space;
} testCases[] = {
{ BRect(0, 0, 39, 9), B_RGBA64 },
{ BRect(0, 0, 39, 9), B_RGBA64_BIG },
{ BRect(0, 0, 39, 9), B_RGB48 },
{ BRect(0, 0, 39, 9), B_RGB48_BIG },
{ BRect(0, 0, 39, 9), B_RGB32 },
{ BRect(0, 0, 39, 9), B_RGBA32 },
{ BRect(0, 0, 39, 9), B_RGB32_BIG },