Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing framebuffer OSX 10.7

I am currently working on a remote desktop type project, in particular I am trying to provide replacement code for the old depreceated methods that were used previously. I have managed this quite successfully, for the most part, but I seem to have reached a stumbling block.

As of OSX 10.7 the method call CGDisplayBaseAddress has been depreceated (1). Previously this gave me the base address of the framebuffer in memory, which was used elsewhere in order to see which parts of the screen had changed and to determine what needed to be sent to the remote display. Now it returns NULL.

My current solution has been to use CGDisplayCreateImage (2), which gives me an CGImageRef that I can then use to get a pointer to the raw data ( via a CFDataRef object - for code see below) for the image.

Is this the best way to do it? Surely their must be a better way of doing it!

To summarise : I dont want to do any drawing to the screen or anything I'm just trying to get a pointer to the first byte in memory that contains either the desktop framebuffer or ( as I'm currently doing) the image data.

Thanks for any help you can give! :)

Current solution code :

CFDataRef copy_image_pixels(CGImageRef inImage) {
    return CGDataProviderCopyData(CGImageGetDataProvider(inImage)); 
}

/**
 ret_byte_buffer is the byte buffer containing the pixel data for the image **/
void *getPixelDataForImage (CGImageRef image) 
{
    //Check image ref is not null
    if (!image){
        NSLog(@"Error - image was null");
        return -1;
    }

    //Gets a CFData reference for the specified image reference
    CFDataRef pixelData = copy_image_pixels(image);
    //Gets a readonly pointer to the image data
    const UInt8 *pointerToData = CFDataGetBytePtr(pixelData); //This returns a read only version
    //Casting to a void pointer to return, expected to be cast to a byte_t *
    CFIndex length_of_buffer = CFDataGetLength(pixelData);
    printf("Size of buffer is %zu\n",length_of_buffer);
    return (void *)pointerToData;

}

code snippet for getting the CGImageRef -

osx_disp= main_screen_details->main_screenid; //Returns CGDirectDisplayID
CGImageRef screenShot = CGDisplayCreateImage(osx_disp);
byte_t *image_byte_data = getPixelDataForImage(screenShot);

byte_t is typedef'd to be a unsigned char

like image 319
andrewktmeikle Avatar asked Dec 20 '12 21:12

andrewktmeikle


1 Answers

From my research it seems that you do no need access to the framebuffer anymore.

They way I have done it above may not be the best way but it certainly works for what I need it to do :)

Previously you would have to lock the display do what you wanted to do with it then release it, which could sometimes lead to screen flicker as you released the screen.

The new way, via creating the image, means you do not have to deal with any of that just create the image and your golden :)

One thing I would add to my existing code is that you must remember to free the CGImageRef or its a MAJOR memory leak.

In order to do this just call :

CFRelease(screenShot);

We also need to release the pixelData object in the same way.

CFRelease(pixelData);
like image 195
andrewktmeikle Avatar answered Oct 20 '22 07:10

andrewktmeikle