CGImageRef getDesktopImage() { /* There are numerous functions to get any display * but we will stick to the main one for this example */ CGDirectDisplayID displayID = CGMainDisplayID(); /* Read out the size of our target display * nothing fancy here */ CGRect mainMonitor = CGDisplayBounds(displayID); CGFloat displayHeight = CGRectGetHeight(mainMonitor); CGFloat displayWidth = CGRectGetWidth(mainMonitor); std::cout << "Main Display ID: " << displayID << "\n"; std::cout << "Display width: " << displayWidth << " Display height: " << displayHeight << "\n"; /* Here we actually 'capture' the screen * the only problem is the data format... */ CGImageRef image = CGDisplayCreateImageForRect(displayID, CGRectMake(0, 0, displayWidth, displayHeight)); return image; }
block_t *screen_Capture(demux_t *p_demux) { demux_sys_t *p_sys = p_demux->p_sys; screen_data_t *p_data = (screen_data_t *)p_sys->p_data; block_t *p_block; CGRect capture_rect; CGImageRef image; /* forward cursor location */ CGPoint cursor_pos; CGEventRef event = CGEventCreate(NULL); cursor_pos = CGEventGetLocation(event); CFRelease(event); cursor_pos.x -= p_data->screen_left; cursor_pos.y -= p_data->screen_top; if (p_sys->b_follow_mouse) FollowMouse(p_sys, cursor_pos.x, cursor_pos.y); capture_rect.origin.x = p_sys->i_left; capture_rect.origin.y = p_sys->i_top; capture_rect.size.width = p_data->width; capture_rect.size.height = p_data->height; /* fetch image data */ image = CGDisplayCreateImageForRect(p_data->display_id, capture_rect); if (!image) { msg_Warn(p_demux, "no image!"); return NULL; } /* create offscreen context */ if (!p_data->offscreen_context) { CGColorSpaceRef colorspace; colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); p_data->offscreen_bitmap_size = p_sys->fmt.video.i_width * p_sys->fmt.video.i_height * 4; p_data->offscreen_bitmap = calloc(1, p_data->offscreen_bitmap_size); if (p_data->offscreen_bitmap == NULL) { msg_Warn(p_demux, "can't allocate offscreen bitmap"); CFRelease(image); return NULL; } p_data->offscreen_context = CGBitmapContextCreate(p_data->offscreen_bitmap, p_sys->fmt.video.i_width, p_sys->fmt.video.i_height, 8, p_sys->fmt.video.i_width * 4, colorspace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little); if (!p_data->offscreen_context) { msg_Warn(p_demux, "can't create offscreen bitmap context"); CFRelease(image); return NULL; } CGColorSpaceRelease(colorspace); p_data->offscreen_rect = CGRectMake(0, 0, p_sys->fmt.video.i_width, p_sys->fmt.video.i_height); } /* fetch cursor image */ CGImageRef cursor_image; int cid = CGSMainConnectionID(); CGPoint outHotSpot; cursor_image = CGSCreateRegisteredCursorImage(cid, (char *)"com.apple.coregraphics.GlobalCurrent", &outHotSpot); /* draw screen image and cursor image */ CGRect cursor_rect; cursor_rect.size.width = CGImageGetWidth(cursor_image); cursor_rect.size.height = CGImageGetHeight(cursor_image); cursor_rect.origin.x = cursor_pos.x - p_sys->i_left - outHotSpot.x; cursor_rect.origin.y = p_data->offscreen_rect.size.height - (cursor_pos.y + cursor_rect.size.height - p_sys->i_top - outHotSpot.y); CGContextDrawImage(p_data->offscreen_context, p_data->offscreen_rect, image); CGContextDrawImage(p_data->offscreen_context, cursor_rect, cursor_image); /* build block */ p_block = block_Alloc(p_data->offscreen_bitmap_size); if (!p_block) { msg_Warn(p_demux, "can't get block"); CFRelease(image); return NULL; } memmove(p_block->p_buffer, p_data->offscreen_bitmap, p_data->offscreen_bitmap_size); CFRelease(image); return p_block; }
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect) { #if defined(IS_MACOSX) size_t bytewidth; uint8_t bitsPerPixel, bytesPerPixel; uint8_t *buffer; CGDirectDisplayID displayID = CGMainDisplayID(); //Replacement for CGDisplayBitsPerPixel. CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayID); size_t depth = 0; CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(mode); if(CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) depth = 32; else if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) depth = 16; else if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) depth = 8; bitsPerPixel = (uint8_t) depth; bytesPerPixel = bitsPerPixel / 8; /* Align width to padding. */ bytewidth = ADD_PADDING(rect.size.width * bytesPerPixel); /* Convert Quartz point to postscript point. */ rect.origin.y = CGDisplayPixelsHigh(displayID) - rect.origin.y - rect.size.height; CGImageRef image = CGDisplayCreateImageForRect(displayID, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)); // Request access to the raw pixel data via the image's DataProvider. CGDataProviderRef provider = CGImageGetDataProvider(image); CFDataRef data = CGDataProviderCopyData(provider); size_t width, height; width = CGImageGetWidth(image); height = CGImageGetHeight(image); size_t bpp = CGImageGetBitsPerPixel(image) / 8; uint8 *pixels = malloc(width * height * bpp); memcpy(pixels, CFDataGetBytePtr(data), width * height * bpp); CFRelease(data); CGImageRelease(image); return createMMBitmap(pixels, rect.size.width, rect.size.height, bytewidth, bitsPerPixel, bytesPerPixel); #elif defined(USE_X11) MMBitmapRef bitmap; Display *display = XOpenDisplay(NULL); XImage *image = XGetImage(display, XDefaultRootWindow(display), (int)rect.origin.x, (int)rect.origin.y, (unsigned int)rect.size.width, (unsigned int)rect.size.height, AllPlanes, ZPixmap); XCloseDisplay(display); if (image == NULL) return NULL; bitmap = createMMBitmap((uint8_t *)image->data, rect.size.width, rect.size.height, (size_t)image->bytes_per_line, (uint8_t)image->bits_per_pixel, (uint8_t)image->bits_per_pixel / 8); image->data = NULL; /* Steal ownership of bitmap data so we don't have to * copy it. */ XDestroyImage(image); return bitmap; #elif defined(IS_WINDOWS) MMBitmapRef bitmap; void *data; HDC screen = NULL, screenMem = NULL; HBITMAP dib; BITMAPINFO bi; /* Initialize bitmap info. */ bi.bmiHeader.biSize = sizeof(bi.bmiHeader); bi.bmiHeader.biWidth = (long)rect.size.width; bi.bmiHeader.biHeight = -(long)rect.size.height; /* Non-cartesian, please */ bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biSizeImage = (DWORD)(4 * rect.size.width * rect.size.height); bi.bmiHeader.biXPelsPerMeter = 0; bi.bmiHeader.biYPelsPerMeter = 0; bi.bmiHeader.biClrUsed = 0; bi.bmiHeader.biClrImportant = 0; screen = GetDC(NULL); /* Get entire screen */ if (screen == NULL) return NULL; /* Get screen data in display device context. */ dib = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, &data, NULL, 0); /* Copy the data into a bitmap struct. */ if ((screenMem = CreateCompatibleDC(screen)) == NULL || SelectObject(screenMem, dib) == NULL || !BitBlt(screenMem, (int)rect.origin.x, (int)rect.origin.y, (int)rect.size.width, (int)rect.size.height, screen, 0, 0, SRCCOPY)) { /* Error copying data. */ ReleaseDC(NULL, screen); DeleteObject(dib); if (screenMem != NULL) DeleteDC(screenMem); return NULL; } bitmap = createMMBitmap(NULL, rect.size.width, rect.size.height, 4 * rect.size.width, (uint8_t)bi.bmiHeader.biBitCount, 4); /* Copy the data to our pixel buffer. */ if (bitmap != NULL) { bitmap->imageBuffer = malloc(bitmap->bytewidth * bitmap->height); memcpy(bitmap->imageBuffer, data, bitmap->bytewidth * bitmap->height); } ReleaseDC(NULL, screen); DeleteObject(dib); DeleteDC(screenMem); return bitmap; #endif }