[Interest] QVideoFrame 32 bit formats byte order

Stefan Fabian stefan.fabian.dev at hotmail.com
Thu Nov 14 21:17:38 CET 2019

That may be explained by the endianness, though, since ARGB as 32bit uint on little-endian (what most if not all consumer pcs use) would be BGRA in memory.
In the case of BGRA32, endianness could change it to ARGB but not ABGR or RGBA as in my test.
Either way, it should be documented how raw memory is interpreted (consecutive bytes [big-endian] or one 4 byte word per pixel [cpu dependent]).
Von: David M. Cotter <dave at kjams.com>
Gesendet: Donnerstag, 14. November 2019 21:04
An: interest at qt-project.org <interest at qt-project.org>
Cc: Stefan Fabian <stefan.fabian.dev at hotmail.com>
Betreff: Re: [Interest] QVideoFrame 32 bit formats byte order

I had a similar finding.

i find that QImage::Format_ARGB32 is always 0xBBGGRRAA on both mac and windows

unrelated to video,  but just allocating a QImage

On Nov 14, 2019, at 11:54 AM, Stefan Fabian <stefan.fabian.dev at hotmail.com<mailto:stefan.fabian.dev at hotmail.com>> wrote:

Hey guys,

I'm interfacing external camera input to Qt/QML (version 5.9.5 on Ubuntu 18.04).
For this, I'm using a custom video source and present the frames using QVideoFrame and QAbstractVideoBuffer.
The image is displayed in QML using a VideoOutput.
Since not all formats can be mapped directly, I have to do some conversions.
The issue:

The formats RGB32 and BGR32 don't act as expected.
According to the docs, the former is 0xffRRGGBB and the latter 0xBBGGRRff. Unfortunately, it is not specified whether the endianness of the computer is used or big-endian.

Here's the conversion to RGB32:

auto output = reinterpret_cast<uint32_t *>(*data);
iterateImage( img, bytes_per_pixel, [ & ]( const uint8_t *stream )
  *output = (255U << 24U) | (static_cast<uint32_t>(static_cast<uint8_t>(R( stream, 0, 255 ))) << 16U) |
            (static_cast<uint32_t>(static_cast<uint8_t>(G( stream, 0, 255 ))) << 8U) |
            static_cast<uint32_t>(static_cast<uint8_t>(B( stream, 0, 255 )));
} );

and this is to BGR32:

auto output = reinterpret_cast<uint32_t *>(*data);
iterateImage( img, bytes_per_pixel, [ & ]( const uint8_t *stream )
  *output = (static_cast<uint32_t>(static_cast<uint8_t>(B( stream, 0, 255 ))) << 24U) |
            (static_cast<uint32_t>(static_cast<uint8_t>(G( stream, 0, 255 ))) << 16U) |
            (static_cast<uint32_t>(static_cast<uint8_t>(R( stream, 0, 255 ))) << 8U) |
} );

The functions B, G, R extract the channels from the pixel at stream and map the values to the given range.
The problem:
Whereas for RGB32, the image is as expected (gray), for BGR32 for some reason the image is semi-transparent red which shouldn't be possible since the B, G, R functions are the same in this case (input is a single channel image).

To test my hypothesis that the order is not as expected I used the following test:

auto output = reinterpret_cast<uint32_t *>(*data);
int count = img.width * img.height / 4;
int i = 0;
iterateImage( img, bytes_per_pixel, [ & ]( const uint8_t *stream )
  if ((i / count) == 0) *output = 0xff000000;
  else if ((i / count) == 1) *output = 0x00ff0000;
  else if ((i / count) == 2) *output = 0x0000ff00;
  else if ((i / count) == 3) *output = 0x000000ff;
} );

And indeed the image is 4 bars, from top to bottom: black, blue, green and red.

It appears as if the format for BGR32 (and BGRA32) is actually either 0xAABBGGRR or 0xRRGGBBAA in big-endian. Is this a (known) bug in the docs/implementation or am I missing something?

Best regards,
Stefan Fabian
Interest mailing list
Interest at qt-project.org<mailto:Interest at qt-project.org>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20191114/02e9b475/attachment.html>

More information about the Interest mailing list