Skip to content

Commit 846d07d

Browse files
Merge pull request #624 from ForksMD/32bit
Add support for 32-bit content
2 parents ac158b7 + d6fff4b commit 846d07d

File tree

10 files changed

+107
-34
lines changed

10 files changed

+107
-34
lines changed

YUViewLib/src/video/rgb/ConversionRGB.cpp

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,22 @@ namespace video::rgb
4040
namespace
4141
{
4242

43-
template <typename T> T swapLowestBytes(const T &val)
43+
template<int bitDepth>
44+
using UintValueType = typename std::conditional_t<bitDepth == 8,
45+
uint8_t*,
46+
std::conditional_t<bitDepth == 16, uint16_t*, uint32_t*>>;
47+
48+
template <int bitDepth, typename T> T swapLowestBytes(const T &val)
4449
{
45-
return ((val & 0xff) << 8) + ((val & 0xff00) >> 8);
50+
if (bitDepth <= 8) {
51+
return val;
52+
}
53+
if (bitDepth <= 16) {
54+
return ((val & 0xff) << 8) | ((val & 0xff00) >> 8);
55+
}
56+
if (bitDepth <= 32) {
57+
return ((val & 0xff) << 24) | ((val & 0xff00) << 8) | ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24);
58+
}
4659
};
4760

4861
int getOffsetToFirstByteOfComponent(const Channel channel,
@@ -73,7 +86,7 @@ void convertRGBToARGB(const QByteArray & sourceBuffer,
7386
const auto offsetToNextValue =
7487
srcPixelFormat.getDataLayout() == DataLayout::Planar ? 1 : srcPixelFormat.nrChannels();
7588

76-
typedef typename std::conditional<bitDepth == 8, uint8_t *, uint16_t *>::type InValueType;
89+
using InValueType = UintValueType<bitDepth>;
7790
const auto setAlpha = outputHasAlpha && srcPixelFormat.hasAlpha();
7891

7992
const auto rawData = (InValueType)sourceBuffer.data();
@@ -96,9 +109,9 @@ void convertRGBToARGB(const QByteArray & sourceBuffer,
96109
const auto isBigEndian = bitDepth > 8 && srcPixelFormat.getEndianess() == Endianness::Big;
97110
auto convertValue = [&isBigEndian, &rightShift](
98111
const InValueType sourceData, const int scale, const bool invert) {
99-
auto value = static_cast<int>(sourceData[0]);
112+
auto value = static_cast<int64_t>(sourceData[0]);
100113
if (isBigEndian)
101-
value = swapLowestBytes(value);
114+
value = swapLowestBytes<bitDepth>(value);
102115
value = ((value * scale) >> rightShift);
103116
value = functions::clip(value, 0, 255);
104117
if (invert)
@@ -161,7 +174,7 @@ void convertRGBPlaneToARGB(const QByteArray & sourceBuffer,
161174
const auto offsetToNextValue =
162175
srcPixelFormat.getDataLayout() == DataLayout::Planar ? 1 : srcPixelFormat.nrChannels();
163176

164-
typedef typename std::conditional<bitDepth == 8, uint8_t *, uint16_t *>::type InValueType;
177+
using InValueType = UintValueType<bitDepth>;
165178

166179
auto src = (InValueType)sourceBuffer.data();
167180
const auto displayComponentOffset = srcPixelFormat.getChannelPosition(displayChannel);
@@ -172,9 +185,9 @@ void convertRGBPlaneToARGB(const QByteArray & sourceBuffer,
172185

173186
for (size_t i = 0; i < frameSize.width * frameSize.height; i++)
174187
{
175-
auto val = static_cast<int>(src[0]);
188+
auto val = static_cast<int64_t>(src[0]);
176189
if (bitDepth > 8 && srcPixelFormat.getEndianess() == Endianness::Big)
177-
val = swapLowestBytes(val);
190+
val = swapLowestBytes<bitDepth>(val);
178191
val = (val * scale) >> shiftTo8Bit;
179192
val = functions::clip(val, 0, 255);
180193
if (invert)
@@ -202,7 +215,7 @@ rgba_t getPixelValue(const QByteArray & sourceBuffer,
202215
srcPixelFormat.getDataLayout() == DataLayout::Planar ? 1 : srcPixelFormat.nrChannels();
203216
const auto offsetPixelPos = frameSize.width * pixelPos.y() + pixelPos.x();
204217

205-
typedef typename std::conditional<bitDepth == 8, uint8_t *, uint16_t *>::type InValueType;
218+
using InValueType = UintValueType<bitDepth>;
206219

207220
const auto rawData = (InValueType)sourceBuffer.data();
208221
auto srcPixel = rawData + offsetPixelPos * offsetToNextValue;
@@ -218,7 +231,7 @@ rgba_t getPixelValue(const QByteArray & sourceBuffer,
218231
auto src = srcPixel + offset;
219232
auto val = (unsigned)src[0];
220233
if (bitDepth > 8 && srcPixelFormat.getEndianess() == Endianness::Big)
221-
val = swapLowestBytes(val);
234+
val = swapLowestBytes<bitDepth>(val);
222235
value[channel] = val;
223236
}
224237

@@ -238,7 +251,7 @@ void convertInputRGBToARGB(const QByteArray & sourceBuffer,
238251
const bool premultiplyAlpha)
239252
{
240253
const auto bitsPerSample = srcPixelFormat.getBitsPerSample();
241-
if (bitsPerSample < 8 || bitsPerSample > 16)
254+
if (bitsPerSample < 8 || bitsPerSample > 32)
242255
throw std::invalid_argument("Invalid bit depth in pixel format for conversion");
243256

244257
if (bitsPerSample == 8)
@@ -251,7 +264,7 @@ void convertInputRGBToARGB(const QByteArray & sourceBuffer,
251264
limitedRange,
252265
outputHasAlpha,
253266
premultiplyAlpha);
254-
else
267+
else if (9 <= bitsPerSample && bitsPerSample <= 16)
255268
convertRGBToARGB<16>(sourceBuffer,
256269
srcPixelFormat,
257270
targetBuffer,
@@ -261,6 +274,16 @@ void convertInputRGBToARGB(const QByteArray & sourceBuffer,
261274
limitedRange,
262275
outputHasAlpha,
263276
premultiplyAlpha);
277+
else
278+
convertRGBToARGB<32>(sourceBuffer,
279+
srcPixelFormat,
280+
targetBuffer,
281+
frameSize,
282+
componentInvert,
283+
componentScale,
284+
limitedRange,
285+
outputHasAlpha,
286+
premultiplyAlpha);
264287
}
265288

266289
void convertSinglePlaneOfRGBToGreyscaleARGB(const QByteArray & sourceBuffer,
@@ -273,7 +296,7 @@ void convertSinglePlaneOfRGBToGreyscaleARGB(const QByteArray & sourceBuffer,
273296
const bool limitedRange)
274297
{
275298
const auto bitsPerSample = srcPixelFormat.getBitsPerSample();
276-
if (bitsPerSample < 8 || bitsPerSample > 16)
299+
if (bitsPerSample < 8 || bitsPerSample > 32)
277300
throw std::invalid_argument("Invalid bit depth in pixel format for conversion");
278301

279302
if (bitsPerSample == 8)
@@ -285,7 +308,7 @@ void convertSinglePlaneOfRGBToGreyscaleARGB(const QByteArray & sourceBuffer,
285308
scale,
286309
invert,
287310
limitedRange);
288-
else
311+
else if (9 <= bitsPerSample && bitsPerSample <= 16)
289312
convertRGBPlaneToARGB<16>(sourceBuffer,
290313
srcPixelFormat,
291314
targetBuffer,
@@ -294,6 +317,15 @@ void convertSinglePlaneOfRGBToGreyscaleARGB(const QByteArray & sourceBuffer,
294317
scale,
295318
invert,
296319
limitedRange);
320+
else
321+
convertRGBPlaneToARGB<32>(sourceBuffer,
322+
srcPixelFormat,
323+
targetBuffer,
324+
frameSize,
325+
displayChannel,
326+
scale,
327+
invert,
328+
limitedRange);
297329
}
298330

299331
rgba_t getPixelValueFromBuffer(const QByteArray & sourceBuffer,
@@ -302,13 +334,15 @@ rgba_t getPixelValueFromBuffer(const QByteArray & sourceBuffer,
302334
const QPoint & pixelPos)
303335
{
304336
const auto bitsPerSample = srcPixelFormat.getBitsPerSample();
305-
if (bitsPerSample < 8 || bitsPerSample > 16)
337+
if (bitsPerSample < 8 || bitsPerSample > 32)
306338
throw std::invalid_argument("Invalid bit depth in pixel format for conversion");
307339

308340
if (bitsPerSample == 8)
309341
return getPixelValue<8>(sourceBuffer, srcPixelFormat, frameSize, pixelPos);
310-
else
342+
else if (9 <= bitsPerSample && bitsPerSample <= 16)
311343
return getPixelValue<16>(sourceBuffer, srcPixelFormat, frameSize, pixelPos);
344+
else
345+
return getPixelValue<32>(sourceBuffer, srcPixelFormat, frameSize, pixelPos);
312346
}
313347

314348
} // namespace video::rgb

YUViewLib/src/video/rgb/PixelFormatRGB.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ PixelFormatRGB::PixelFormatRGB(const std::string &name)
8585

8686
bool PixelFormatRGB::isValid() const
8787
{
88-
return this->bitsPerSample >= 8 && this->bitsPerSample <= 16;
88+
return this->bitsPerSample >= 8 && this->bitsPerSample <= 32;
8989
}
9090

9191
unsigned PixelFormatRGB::nrChannels() const
@@ -123,7 +123,7 @@ std::string PixelFormatRGB::getName() const
123123
*/
124124
std::size_t PixelFormatRGB::bytesPerFrame(Size frameSize) const
125125
{
126-
auto bpsValid = this->bitsPerSample >= 8 && this->bitsPerSample <= 16;
126+
auto bpsValid = this->bitsPerSample >= 8 && this->bitsPerSample <= 32;
127127
if (!bpsValid || !frameSize.isValid())
128128
return 0;
129129

YUViewLib/src/video/rgb/PixelFormatRGB.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,23 @@ struct rgba_t
9797
};
9898
};
9999

100+
template<typename T>
101+
inline T convertBitness(T value, unsigned src_bitness, unsigned dst_bitness) {
102+
if (src_bitness > dst_bitness)
103+
return value >> (src_bitness - dst_bitness);
104+
else
105+
return value << (dst_bitness - src_bitness);
106+
}
107+
108+
inline rgba_t convertBitness(rgba_t value, unsigned src_bitness, unsigned dst_bitness) {
109+
return rgba_t({
110+
convertBitness(value.R, src_bitness, dst_bitness),
111+
convertBitness(value.G, src_bitness, dst_bitness),
112+
convertBitness(value.B, src_bitness, dst_bitness),
113+
convertBitness(value.A, src_bitness, dst_bitness)
114+
});
115+
}
116+
100117
enum class ChannelOrder
101118
{
102119
RGB,

YUViewLib/src/video/rgb/PixelFormatRGBGuess.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ std::optional<PixelFormatRGB> checkForPixelFormatIndicatorInName(
9797
{12, "12"},
9898
{16, "16"},
9999
{16, "64"},
100-
{16, "48"}})
100+
{16, "48"},
101+
{32, "32"},
102+
{32, "96"},
103+
{32, "128"}})
101104
{
102105
for (auto [endianness, endiannessName] :
103106
{std::pair<Endianness, std::string>{Endianness::Little, ""},

YUViewLib/src/video/rgb/videoHandlerRGB.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ void videoHandlerRGB::convertRGBToImage(const QByteArray &sourceBuffer, QImage &
624624
}
625625

626626
const auto bps = this->srcPixelFormat.getBitsPerSample();
627-
if (bps < 8 || bps > 16)
627+
if (bps < 8 || bps > 32)
628628
{
629629
DEBUG_RGB("Unsupported bit depth. 8-16 bit are supported.");
630630
return;
@@ -902,15 +902,15 @@ QImage videoHandlerRGB::calculateDifference(FrameHandler *item2,
902902
const auto posG = srcPixelFormat.getChannelPosition(Channel::Green);
903903
const auto posB = srcPixelFormat.getChannelPosition(Channel::Blue);
904904

905-
if (bitDepth >= 8 && bitDepth <= 16)
905+
if (bitDepth >= 8 && bitDepth <= 32)
906906
{
907907
// How many values do we have to skip in src to get to the next input value?
908908
// In case of 8 or less bits this is 1 byte per value, for 9 to 16 bits it is 2 bytes per value.
909909
int offsetToNextValue = srcPixelFormat.nrChannels();
910910
if (srcPixelFormat.getDataLayout() == DataLayout::Planar)
911911
offsetToNextValue = 1;
912912

913-
if (bitDepth > 8 && bitDepth <= 16)
913+
if (bitDepth > 8 && bitDepth <= 32)
914914
{
915915
// 9 to 16 bits per component. We assume two bytes per value.
916916
// First get the pointer to the first value of each channel. (this item)

YUViewUnitTest/video/rgb/ConversionRGBTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ int scaleShiftClipInvertValue(const int value,
8282
const int scale,
8383
const bool invert)
8484
{
85-
const auto valueOriginalDepth = (value >> (12 - bitDepth));
85+
const auto valueOriginalDepth = static_cast<int64_t>(convertBitness(value, 12, bitDepth));
8686
const auto valueScaled = valueOriginalDepth * scale;
8787
const auto value8BitDepth = (valueScaled >> (bitDepth - 8));
8888
const auto valueClipped = functions::clip(value8BitDepth, 0, 255);
@@ -244,7 +244,7 @@ void runTestForAllParameters(TestingFunction testingFunction)
244244
{
245245
for (const auto endianness : {Endianness::Little, Endianness::Big})
246246
{
247-
for (const auto bitDepth : {8, 10, 12})
247+
for (const auto bitDepth : {8, 10, 12, 16, 32})
248248
{
249249
for (const auto &alphaMode : AlphaModeMapper.getValues())
250250
{

YUViewUnitTest/video/rgb/CreateTestData.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ void scaleValueToBitDepthAndPushIntoArra(QByteArray &data,
4343
const int bitDepth,
4444
const Endianness endianness)
4545
{
46-
const auto shift = 12 - bitDepth;
46+
const auto scaledValue = convertBitness(value, 12, bitDepth);
47+
4748
if (bitDepth == 8)
48-
data.push_back(value >> shift);
49-
else
49+
data.push_back(scaledValue);
50+
else if (bitDepth <= 16)
5051
{
51-
const auto scaledValue = (value >> shift);
5252
const auto upperByte = ((scaledValue & 0xff00) >> 8);
5353
const auto lowerByte = (scaledValue & 0xff);
5454
if (endianness == Endianness::Little)
@@ -61,6 +61,21 @@ void scaleValueToBitDepthAndPushIntoArra(QByteArray &data,
6161
data.push_back(upperByte);
6262
data.push_back(lowerByte);
6363
}
64+
} else {
65+
if (endianness == Endianness::Little)
66+
{
67+
data.push_back((scaledValue >> 0) & 0xFF);
68+
data.push_back((scaledValue >> 8) & 0xFF);
69+
data.push_back((scaledValue >> 16) & 0xFF);
70+
data.push_back((scaledValue >> 24) & 0xFF);
71+
}
72+
else
73+
{
74+
data.push_back((scaledValue >> 24) & 0xFF);
75+
data.push_back((scaledValue >> 16) & 0xFF);
76+
data.push_back((scaledValue >> 8) & 0xFF);
77+
data.push_back((scaledValue >> 0) & 0xFF);
78+
}
6479
}
6580
}
6681

YUViewUnitTest/video/rgb/GetPixelValueTest.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ void testGetPixelValueFromBuffer(const QByteArray &sourceBuffer,
4848
const PixelFormatRGB &srcPixelFormat)
4949
{
5050
const auto bitDepth = srcPixelFormat.getBitsPerSample();
51-
const auto shift = 12 - bitDepth;
5251

5352
int testValueIndex = 0;
5453
for (int y : {0, 1, 2, 3})
@@ -60,8 +59,7 @@ void testGetPixelValueFromBuffer(const QByteArray &sourceBuffer,
6059
getPixelValueFromBuffer(sourceBuffer, srcPixelFormat, TEST_FRAME_SIZE, pixelPos);
6160

6261
const auto testValue = TEST_VALUES_12BIT[testValueIndex++];
63-
auto expectedValue = rgba_t(
64-
{testValue.R >> shift, testValue.G >> shift, testValue.B >> shift, testValue.A >> shift});
62+
auto expectedValue = convertBitness(testValue, 12, bitDepth);
6563
if (!srcPixelFormat.hasAlpha())
6664
expectedValue.A = 0;
6765

@@ -78,7 +76,7 @@ TEST(GetPixelValueTest, TestGetPixelValueFromBuffer)
7876
{
7977
for (const auto endianness : EndianessMapper.getValues())
8078
{
81-
for (auto bitDepth : {8, 10, 12})
79+
for (auto bitDepth : {8, 10, 12, 16, 32})
8280
{
8381
for (const auto &alphaMode : AlphaModeMapper.getValues())
8482
{

YUViewUnitTest/video/rgb/PixelFormatRGBGuessTest.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ INSTANTIATE_TEST_SUITE_P(
148148
PixelFormatRGB(16, DataLayout::Packed, ChannelOrder::RGB)}),
149149
TestParameters({FileInfoForGuess({"something_1920x1080_rgb64.yuv", "", BytesNoAlpha}),
150150
PixelFormatRGB(16, DataLayout::Packed, ChannelOrder::RGB)}),
151+
TestParameters({FileInfoForGuess({"something_1920x1080_rgb32.yuv", "", BytesNoAlpha}),
152+
PixelFormatRGB(32, DataLayout::Packed, ChannelOrder::RGB)}),
153+
TestParameters({FileInfoForGuess({"something_1920x1080_rgb96.yuv", "", BytesNoAlpha}),
154+
PixelFormatRGB(32, DataLayout::Packed, ChannelOrder::RGB)}),
155+
TestParameters({FileInfoForGuess({"something_1920x1080_rgb128.yuv", "", BytesNoAlpha}),
156+
PixelFormatRGB(32, DataLayout::Packed, ChannelOrder::RGB)}),
151157
TestParameters({FileInfoForGuess({"something_1920x1080_rgb11.yuv", "", BytesNoAlpha}),
152158
PixelFormatRGB(8, DataLayout::Packed, ChannelOrder::RGB)}),
153159

YUViewUnitTest/video/rgb/PixelFormatRGBTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ std::vector<PixelFormatRGB> getAllFormats()
4444
{
4545
std::vector<PixelFormatRGB> allFormats;
4646

47-
for (int bitsPerPixel = 8; bitsPerPixel <= 16; bitsPerPixel++)
47+
for (int bitsPerPixel = 8; bitsPerPixel <= 32; bitsPerPixel++)
4848
for (auto dataLayout : DataLayoutMapper.getValues())
4949
for (auto channelOrder : ChannelOrderMapper.getValues())
5050
for (auto alphaMode : AlphaModeMapper.getValues())
@@ -99,7 +99,7 @@ TEST(PixelFormatRGBTest, testInvalidFormats)
9999
invalidFormats.push_back(PixelFormatRGB(0, video::DataLayout::Packed, ChannelOrder::RGB));
100100
invalidFormats.push_back(PixelFormatRGB(1, video::DataLayout::Packed, ChannelOrder::RGB));
101101
invalidFormats.push_back(PixelFormatRGB(7, video::DataLayout::Packed, ChannelOrder::RGB));
102-
invalidFormats.push_back(PixelFormatRGB(17, video::DataLayout::Packed, ChannelOrder::RGB));
102+
invalidFormats.push_back(PixelFormatRGB(33, video::DataLayout::Packed, ChannelOrder::RGB));
103103
invalidFormats.push_back(PixelFormatRGB(200, video::DataLayout::Packed, ChannelOrder::RGB));
104104

105105
for (auto fmt : invalidFormats)

0 commit comments

Comments
 (0)