//------------------------------------------------------------------- // rgbsplit.cpp // // This program demonstrates the use of a matrix multiplication // to transform a graphics image from RGB format to YUV format. // // to compile: $ g++ rgbsplit.cpp -o rgbsplit // to execute: $ ./rgbsplit // // NOTE: This program requires using a customized device-driver // (named 'gateway.c') for the ATI Radeon graphics processor in // the Gateway 53A laptop computer used for in-classroom demos, // because it directly writes to privileged frame-buffer memory // and it reads from a protected graphics processor register. // // NOTE: This program searches the current working directory to // find our "hawaii2.img" image-file. // // programmer: ALLAN CRUSE // written on: 07 MAR 2011 // revised on: 18 MAR 2011 -- to overcome relocation of the fb //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for read(), write(), close() #include // for memcpy() #include // for mmap() #include // for ioctl() #define VRAM_BASE 0x80000000 #define GET_CRTC_START_ADDRESS 0 char devname[] = "/dev/vram"; const unsigned int rowmax = 768; const unsigned int colmax = 1024; const unsigned int hpitch = 1024; unsigned int *fb; char imgname[] = "hawaii2.img"; const int hres = 360; const int vres = 256; typedef unsigned int Image[ hres * vres ]; Image tru, red, grn, blu; typedef double Vector[ 3 ]; typedef double Matrix[ 3 ][ 3 ]; Matrix trans = { 0.18300, 0.61400, 0.06200, -0.10100, -0.33900, 0.43900, 0.43900, -0.39900, -0.04000 }; unsigned int Screensave[ rowmax * hpitch ]; int main( int argc, char **argv ) { // open the device-file int dd = open( devname, O_RDWR ); if ( dd < 0 ) { perror( devname ); exit(1); } // memory-map the frame-buffer int size = lseek( dd, 0, SEEK_END ); int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void *)VRAM_BASE; if ( mmap( mm, size, prot, flag, dd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // obtain the frame-buffer's offset unsigned int crtc_start_address = 0; if ( ioctl( dd, GET_CRTC_START_ADDRESS, &crtc_start_address ) < 0 ) { perror( "ioctl" ); exit(1); } unsigned int fb_offset = crtc_start_address & 0x3FFFFFFF; printf( "\n FRAME_BUFFER_OFFSET = 0x%08X \n", fb_offset ); fb = (unsigned int *)( VRAM_BASE + fb_offset ); // save the screen's contents to restore later memcpy( Screensave, &fb[0], sizeof( Screensave ) ); // open and read image-capture file int fd = open( imgname, O_RDONLY ); if ( fd < 0 ) { perror( imgname ); exit(1); } int nbytes = read( fd, &tru, sizeof( Image ) ); if ( nbytes < 0 ) { perror( "read" ); exit(1); } close( fd ); // display the unmodified image int above = (rowmax - vres) / 10; int below = above + vres; int indent = (colmax - hres) / 4; int width = hres; unsigned int *src = (unsigned int *)&tru; for (int row = above; row < below; row++) { unsigned int *dst = &fb[ row * hpitch + indent ]; memcpy( dst, src, 4 * width ); src += width; } printf( "\n" ); printf( " Hit to seperate the RGB color-components " ); getchar(); // develop the color-split images int n = sizeof( Image ) / 4; for (int i = 0; i < n; i++) { red[ i ] = tru[ i ] & 0x00FF0000; grn[ i ] = tru[ i ] & 0x0000FF00; blu[ i ] = tru[ i ] & 0x000000FF; } // draw the color-split images unsigned int *ap = &fb[ above * hpitch + indent ]; unsigned int *rp = ap + hres;; unsigned int *gp = ap + (vres * hpitch); unsigned int *bp = rp + (vres * hpitch); for (int i = 0; i < vres; i++) for (int j = 0; j < hres; j++) { rp[ i * hpitch + j ] = red[ i * hres + j ]; gp[ i * hpitch + j ] = grn[ i * hres + j ]; bp[ i * hpitch + j ] = blu[ i * hres + j ]; } printf( "\n" ); printf( " Hit to transform RGB into YUV components " ); getchar(); // convert RGB image to YUV unsigned int *lum = red; unsigned int *chu = grn; unsigned int *chv = blu; for (int j = 0; j < n; j++) { unsigned int pel = tru[ j ]; unsigned char red = (pel >> 16); unsigned char green = (pel >> 8); unsigned char blue = (pel >> 0); Vector rgb, yuv; rgb[0] = red; rgb[1] = green; rgb[2] = blue; for (int i = 0; i < 3; i++) { double sum = 0.0; sum = (i == 0 ) ? 16.0 : 128.0; for (int k = 0; k < 3; k++) sum += trans[ i ][ k ] * rgb[ k ]; yuv[ i ] = sum; } unsigned char luminance = yuv[ 0 ]; pel = luminance; pel |= (pel << 16)|(pel << 8); lum[ j ] = pel; unsigned char chrominance_U = yuv[ 1 ]; pel = chrominance_U; pel |= (pel << 16)|(pel << 8); chu[ j ] = pel; chu[ j ] &= 0x0000FFFF; // omit red unsigned char chrominance_V = yuv[ 2 ]; pel = chrominance_V; pel |= (pel << 16)|(pel << 8); chv[ j ] = pel; chv[ j ] &= 0x00FFFF00; // omit blue } // draw the YUV images for (int i = 0; i < vres; i++) for (int j = 0; j < hres; j++) { rp[ i * hpitch + j ] = lum[ i * hres + j ]; gp[ i * hpitch + j ] = chu[ i * hres + j ]; bp[ i * hpitch + j ] = chv[ i * hres + j ]; } printf( "\n" ); printf( " Hit to restore the former desktop image " ); getchar(); // recover the screen's previously saved contents memcpy( &fb[0], Screensave, sizeof( Screensave ) ); }