Android : Android, Adb, Framebuffer to BMP

on Sunday, November 2, 2014


Using Android ADB opensource I am able to read fbinfo framebuffer image from the USB connected device.


Having the framebuffer read, I am trying to save it as 24bpp BI_RGB BMP, the resulting image is skewed ( snap is attached bellow ).


The size of the framebuffer read from the device is verified to be a multiple of it's width and height.



_ASSERT((pfbInfo->width * pfbInfo->height * pfbInfo->bpp / 8) == pfbInfo->size);


The BMP stride is verified to be 32 bit aligned:



ULONG ulStride = 4 * ((pBMP->bmi.biBitCount * pBMP->bmi.biWidth + 31) / 32);


What have I missed? why does the resulting BMP skewed ?


The following is the fbinfo RGBA dump ( seems quite intact )



version 1
bpp 32
size 1536000
width 480
height 800
red_offset 0
red_length 8
blue_offset 16
blue_length 8
green_offset 8
green_length 8
alpha_offset 24
alpha_length 8


BMP generation code:



HRESULT fbinfo_to_bmp(IN fbinfo* pfbInfo, IN OUT PBYTE pBuffer, IN OUT ULONG& ulBytes) {
#pragma pack(push, 1)
struct BMPFILE {
BITMAPFILEHEADER hdr;
BITMAPINFOHEADER bmi;
struct {
BYTE R, G, B;
} pixels[0];
};
#pragma pack(pop)

const int iTotalPixels = pfbInfo->width * pfbInfo->height;
if ((iTotalPixels * 3) + sizeof(BMPFILE) > ulBytes) {
ulBytes = iTotalPixels * 3 + sizeof(BMPFILE);
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}

_ASSERT((pfbInfo->width * pfbInfo->height * pfbInfo->bpp / 8) == pfbInfo->size);

BMPFILE* pBMP = (BMPFILE*)pBuffer;
ZeroMemory(pBMP, sizeof(*pBMP));
pBMP->bmi.biSize = sizeof(pBMP->bmi);
pBMP->bmi.biWidth = pfbInfo->width;
pBMP->bmi.biHeight = pfbInfo->height;
pBMP->bmi.biPlanes = 1;
pBMP->bmi.biBitCount = 24;
pBMP->bmi.biCompression = BI_RGB;
pBMP->bmi.biSizeImage = 0;

ULONG ulStride = 4 * ((pBMP->bmi.biBitCount * pBMP->bmi.biWidth + 31) / 32);
_ASSERT(0 == (ulStride % 4));

pBMP->hdr.bfType = 'MB';
pBMP->hdr.bfSize = ulBytes = (ulStride * pBMP->bmi.biHeight) + sizeof(BMPFILE);
pBMP->hdr.bfOffBits = sizeof(*pBMP);

UINT uiPixelsBytes = (ulStride * pBMP->bmi.biHeight);
return fbinfo_to_rgb24(pfbInfo, (PBYTE)pBMP->pixels, ulStride, uiPixelsBytes);
}

HRESULT fbinfo_to_rgb24(IN fbinfo* pfbInfo, IN OUT unsigned char* pRGB24, IN ULONG ulStride, IN OUT unsigned int& ulBytes) {
const int iTotalPixels = pfbInfo->width * pfbInfo->height;
if ((ulStride * pfbInfo->height) > ulBytes) {
ulBytes = ulStride * pfbInfo->height;
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
ulBytes = ulStride * pfbInfo->height;

const int iDstBytesPerPixel = 3;

if (16 == pfbInfo->bpp) {// Can only be RGB565
auto pSrc = pfbInfo->pixels.pRGB565;
for (unsigned int y = 0, i = iTotalPixels - 1; y < pfbInfo->height; y++, pRGB24 += ulStride) {
PBYTE pStride = pRGB24;
for (unsigned int x = 0; x < pfbInfo->width; x++, i--, pStride += iDstBytesPerPixel) {
pStride[2] = pSrc[i].R << 3;
pStride[1] = pSrc[i].G << 2;
pStride[0] = pSrc[i].B << 3;
}
}
} else if (24 == pfbInfo->bpp) {
auto pSrc = pfbInfo->pixels.pRGB24;
for (unsigned int y = 0, i = iTotalPixels - 1; y < pfbInfo->height; y++, pRGB24 += ulStride) {
PBYTE pStride = pRGB24;
for (unsigned int x = 0; x < pfbInfo->width; x++, i--, pStride += iDstBytesPerPixel) {
pStride[2] = pSrc[i].R;
pStride[1] = pSrc[i].G;
pStride[0] = pSrc[i].B;
}
}
} else if (32 == pfbInfo->bpp) {
if ((24 == pfbInfo->alpha_offset) && (0 == pfbInfo->blue_offset)) { // pBGRA
auto pSrc = pfbInfo->pixels.pBGRA;
for (unsigned int y = 0, i = iTotalPixels - 1; y < pfbInfo->height; y++, pRGB24 += ulStride) {
PBYTE pStride = pRGB24;
for (unsigned int x = 0; x < pfbInfo->width; x++, i--, pStride += iDstBytesPerPixel) {
pStride[2] = pSrc[i].R;
pStride[1] = pSrc[i].G;
pStride[0] = pSrc[i].B;
}
}
} else if ((ULONG_MAX == pfbInfo->alpha_offset) && (0 == pfbInfo->red_offset)) { // pRGBX
auto pSrc = pfbInfo->pixels.pRGBX;
for (unsigned int y = 0, i = iTotalPixels - 1; y < pfbInfo->height; y++, pRGB24 += ulStride) {
PBYTE pStride = pRGB24;
for (unsigned int x = 0; x < pfbInfo->width; x++, i--, pStride += iDstBytesPerPixel) {
pStride[2] = pSrc[i].R;
pStride[1] = pSrc[i].G;
pStride[0] = pSrc[i].B;
}
}
} else if ((24 == pfbInfo->alpha_offset) && (0 == pfbInfo->red_offset)) { // pRGBA
auto pSrc = pfbInfo->pixels.pRGBA;
for (unsigned int y = 0, i = iTotalPixels - 1; y < pfbInfo->height; y++, pRGB24 += ulStride) {
PBYTE pStride = pRGB24;
for (unsigned int x = 0; x < pfbInfo->width; x++, i--, pStride += iDstBytesPerPixel) {
pStride[2] = pSrc[i].R;
pStride[1] = pSrc[i].G;
pStride[0] = pSrc[i].B;
}
}
} else {
_ASSERT(FALSE);
return E_UNEXPECTED;
}
}

return S_OK;
}


Skewed Image:


enter image description here


0 comments:

Post a Comment