Elliot Blackburn
Elliot Blackburn

Reputation: 4164

Convert big endian to little endian from AS3 ByteArray in C

I'm using FlasCC to allow me to render a video from AS3 using FFmpeg. Doing an endian swap in AS3 is very slow I was running some tests and removing my endian swap on my video ByteArray before sending the video bytes (for that frame) to rendered cuts out about half of my rendering time. I'm wanting to see if I can make the endian swap quicker by doing it in C but I've never done an endian swap before in C or C++ and some of the posts I've found are a bit complex.

I'm taking in a pointer as a uint8_t to my ByteArray and want to swap the endian from big to little using C. Could anyone point me in the right direction or give me some sample code to do so?

The ByteArray should be holding RGB32 data but it's in a big endian and I need it in a big endian for processing using ffmpeg.

Edit:

Currently using:

int i = 0;
int j = bufferSize - 1;
int temp;
while (i < j)
{
  temp = buffer[i];
  buffer[i] = buffer[j];
  buffer[j] = temp;
  i++;
  j--;
}

Upvotes: 0

Views: 641

Answers (3)

Elliot Blackburn
Elliot Blackburn

Reputation: 4164

Ok so I actually just figured it out myself. What everyone said so far has been technically correct but not what I've been looking for. Hopefully this may help someone else.

When using BitmapData.getPixels() in AS3 you get an array like so:

0 1 2 3 4 5 6...
A R G B A R G...

To swap the endianness you need to essentially need to swap the A and B values, and the R and G values. But keep the ARGB grouping for that pixel together. This is why the reversal of the array gave me the correct colours but the entire picture was inverted, I had changed the endian but mostly as a bi-product of moving the top right pixel to the bottom left (and so on).

To correctly switch the RGB32 endian I need to change the above representation to:

0 1 2 3 4 5 6...
B G R A B G R...

Which will give the correct input for FFmpeg in this instance.

However a fast way was to use the pixel format in my FFmpeg API that means I have no endian conversion. Instead of using PIX_FMT_RGB32 I used AV_PIX_FMT_ARGB.

Upvotes: 0

jtaylor
jtaylor

Reputation: 2424

the fastest way to byteswap is to use machine instructions designed for it, namely bswap and pshufb(SSSE3) on x86 processors. good compilers have pattern matchers to use the instructions for the common masking based implementations.

xswapped32 = ((x & 0xffu) << 24) | ((x & 0xff00u) << 8) |
             ((x & 0xff0000u) >> 8) | (x >> 24);

Take care to ensure your data is aligned when casting from int8 to uint32 on platform that do not allow unaligned loads.

the easiest way to use them reliably is to use compiler intrinsics, e.g. with GCC or clang:

__builtin_bswap32(var)

using pshufb can be faster if you your machine has SSSE3:

const __m128i cmask4 = _mm_set_epi8(12, 13, 14, 15, 
                                    8, 9, 10, 11, 
                                    4, 5, 6, 7,
                                    0, 1, 2 ,3);
_mm_shuffle_epi8(vectorvalue, cmask4);

Upvotes: 3

barak manos
barak manos

Reputation: 30136

If the size of each logical element in you data is 1 byte, then nothing needs to be done.

Otherwise, you can use the following function:

void Reverse(uint8_t* arr,int arr_size,int elem_size)
{
    int i,j;
    uint8_t temp;
    for (i=0; i<arr_size; i+=elem_size)
    {
        for (j=0; j<elem_size/2; j++)
        {
            temp = arr[i+j];
            arr[i+j] = arr[i+j+elem_size-1];
            arr[i+j+elem_size-1] = temp;
        }
    }
}

Upvotes: 1

Related Questions