XBox and the Case of the Mysterious Color order

By on 6/7/2008

I've been meaning to blog about how I finally got the lastest build of Scurvy.Media out the door. Those of you keeping track at home will remember that, though the previous build shipped with XBox platform support, the colors of the videos were unfortunately very "off".

After a large amount of experimentation, and tons of help from the guys over on the #Xna IRC channel, we were finally able to figure out the problem. To explain the solution, I must first explain a tiny bit about the architecture of the Scurvy.Media content pipeline.
  1. Decode each frame of the video as individual textures. The pipeline currently only supports AVI video using the AVIFile library from CodeProject.
  2. Write the contents of each frame sequentially into one large .XNB file through the content writer.
  3. At runtime, open a stream (and keep it open), and read each texture one at a time in a separate thread.
  4. use .SetData to set the contents of a texture based on whatever the current Frame is.� Technically speaking, there are two textures at play for the purpose of double buffering ... but that's largely irrelevant to the topic at hand :-)
So the confusing part was that the code ran perfectly on windows, but on XBox the colors were all messed up.

Now that I've explained the architecture, I'll explain the solution to one of the issues.� Mainly, it's the fact that the color order on the xbox platform is *different* than it is on windows.� Why that is I don't know, I wasn't able to find very many sources of information on this, but c'est la vie :-)

XBox:
  • RGBA
Windows:
  • BGRA
To get around this problem, I simply had to transpose the color channels as I imported the video when compiling for the xbox platform.
byte[] xpix = new byte[pix.Length]; for (int i = 0; i < pix.Length; i += 4) {

��� int first = i, second = i + 1, third = i + 2, fourth = i + 3; ��� xpix[first] = pix[third]; //x=red ��� xpix[second] = pix[second]; //x=green ��� xpix[third] = pix[first];//x=blue ��� xpix[fourth] = pix[fourth];//x=alpha� }

b.SetPixelData(xpix);
the code snippet above takes a byte array that uses four bytes per channel.� And it just puts it into a copy of the byte array.� Technically, I could have used the same array and just rearranged the byte values as I go ... but perhaps that's an improvement for another day.

But Avast! There still be problems on the high waters!

After making that change, the colors were still not right.� What we eventually realized is that I was writing byte data directly from windows (who's x86 architecture is little-endian), to be read from the xbox (who's powerpc architecture is big-endian).

Sooooo ... the answer was this:
byte[] xpix = new byte[pix.Length]; for (int i = 0; i < pix.Length; i += 2) {

��� int first = i, second = i + 1; ��� xpix[first] = pix[second]; ��� xpix[second] = pix[first]; }

output.Write(xpix.Length); output.Write(xpix);
Right before writing the byte array to disk ... I flip every other byte.� Once I did that, the video was alight with correct coloration :-)

Again, a huge thanks to the guys on the #xna IRC channel.� This wouldn't have been possible without them.

See more in the archives