unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool swap_red_blue) { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_RESOURCE_HANDLE_T resource; VC_RECT_T rect; unsigned char *image = NULL; uint32_t vc_image_ptr; int stride; display = vc_dispmanx_display_open( 0 /*screen*/ ); stride = ((width + 15) & ~15) * 4; image = new unsigned char [height * stride]; if (image) { resource = vc_dispmanx_resource_create( VC_IMAGE_RGBA32, width, height, &vc_image_ptr ); vc_dispmanx_snapshot(display, resource, (DISPMANX_TRANSFORM_T)0); vc_dispmanx_rect_set(&rect, 0, 0, width, height); vc_dispmanx_resource_read_data(resource, &rect, image, stride); vc_dispmanx_resource_delete( resource ); vc_dispmanx_display_close(display ); // we need to save in BGRA order so Swap RGBA -> BGRA if (swap_red_blue) { for (int y = 0; y < height; y++) { unsigned char *p = image + y * stride; for (int x = 0; x < width; x++, p+=4) { unsigned char t = p[0]; p[0] = p[2]; p[2] = t; } } } // assume we need to pack image if caller doesn't want stride if (!pstride && stride > width*4) { for (int y = 0; y < height; y++) { unsigned char *in = image + y * stride; unsigned char *out = image + y * width * 4; memmove(out, in, width*4); } } } if (pstride) *pstride = stride; return image; }
void save_snapshot(void) { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_MODEINFO_T info; DISPMANX_RESOURCE_HANDLE_T resource; VC_IMAGE_TYPE_T type = VC_IMAGE_RGB888; VC_IMAGE_TRANSFORM_T transform = 0; VC_RECT_T rect; void *image; uint32_t vc_image_ptr; int ret; uint32_t screen = 0; fprintf(stderr,"\nWriting snapshot...\n"); //fprintf(stderr,"Open display[%i]...\n", screen ); display = vc_dispmanx_display_open( screen ); ret = vc_dispmanx_display_get_info(display, &info); assert(ret == 0); //fprintf(stderr,"Display is %d x %d\n", info.width, info.height ); image = calloc( 1, info.width * 3 * info.height ); assert(image); resource = vc_dispmanx_resource_create(type, info.width, info.height,&vc_image_ptr); vc_dispmanx_snapshot(display, resource, transform); vc_dispmanx_rect_set(&rect, 0, 0, info.width, info.height); vc_dispmanx_resource_read_data(resource, &rect, image, info.width*3); char* home = getenv("HOME"); char filename[1024]; if (!home) home = "/tmp"; snprintf(filename,sizeof(filename),"%s/pidvbip-%u.ppm",home,(unsigned int)time(NULL)); FILE *fp = fopen(filename, "wb"); fprintf(fp, "P6\n%d %d\n255\n", info.width, info.height); fwrite(image, info.width*3*info.height, 1, fp); fclose(fp); fprintf(stderr,"\nSnapshot written to %s\n",filename); ret = vc_dispmanx_resource_delete( resource ); assert( ret == 0 ); ret = vc_dispmanx_display_close(display ); assert( ret == 0 ); free(image); }
int main(void) { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_MODEINFO_T info; DISPMANX_RESOURCE_HANDLE_T resource; VC_IMAGE_TYPE_T type = VC_IMAGE_RGB888; VC_IMAGE_TRANSFORM_T transform = 0; VC_RECT_T rect; void *image; uint32_t vc_image_ptr; int ret; uint32_t screen = 0; bcm_host_init(); printf("Open display[%i]...\n", screen ); display = vc_dispmanx_display_open( screen ); ret = vc_dispmanx_display_get_info(display, &info); assert(ret == 0); printf( "Display is %d x %d\n", info.width, info.height ); image = calloc( 1, info.width * 3 * info.height ); assert(image); resource = vc_dispmanx_resource_create( type, info.width, info.height, &vc_image_ptr ); vc_dispmanx_snapshot(display, resource, transform); vc_dispmanx_rect_set(&rect, 0, 0, info.width, info.height); vc_dispmanx_resource_read_data(resource, &rect, image, info.width*3); FILE *fp = fopen("out.ppm", "wb"); fprintf(fp, "P6\n%d %d\n255\n", info.width, info.height); fwrite(image, info.width*3*info.height, 1, fp); fclose(fp); ret = vc_dispmanx_resource_delete( resource ); assert( ret == 0 ); ret = vc_dispmanx_display_close(display ); assert( ret == 0 ); return 0; }
unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool swap_red_blue, bool video_only) { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_RESOURCE_HANDLE_T resource; VC_RECT_T rect; unsigned char *image = NULL; uint32_t vc_image_ptr; int stride; uint32_t flags = 0; if (video_only) flags |= DISPMANX_SNAPSHOT_NO_RGB|DISPMANX_SNAPSHOT_FILL; if (swap_red_blue) flags |= DISPMANX_SNAPSHOT_SWAP_RED_BLUE; if (!pstride) flags |= DISPMANX_SNAPSHOT_PACK; display = vc_dispmanx_display_open( 0 /*screen*/ ); stride = ((width + 15) & ~15) * 4; image = new unsigned char [height * stride]; if (image) { resource = vc_dispmanx_resource_create( VC_IMAGE_RGBA32, width, height, &vc_image_ptr ); vc_dispmanx_snapshot(display, resource, (DISPMANX_TRANSFORM_T)flags); vc_dispmanx_rect_set(&rect, 0, 0, width, height); vc_dispmanx_resource_read_data(resource, &rect, image, stride); vc_dispmanx_resource_delete( resource ); vc_dispmanx_display_close(display ); } if (pstride) *pstride = stride; return image; }
int main(int argc, char **argv) { DISPMANX_DISPLAY_HANDLE_T main_display_handle; DISPMANX_RESOURCE_HANDLE_T screen_resource_handle; VC_RECT_T rectangle; int ret; uint32_t image_prt; uint16_t image[2][ PICTURE_PIXELS ]; uint32_t current_frame = 0, old_frame=1; uint32_t i, x, y, start, end, count; uint16_t *p_current_frame, *p_old_frame, *p_start; bcm_host_init(); if ( !bcm2835_init() ) return ( -1 ); TFT_init_board(); TFT_hard_reset(); RAIO_init(); //clear old image p_old_frame = &image[ old_frame ][0]; for(x=0; x<76800; x++) { *p_old_frame++ = 0x1111; } // open main framebuffer device main_display_handle = vc_dispmanx_display_open( 0 ); if ( !main_display_handle ) { printf("\n Unable to open primary display"); return( -1 ); } // now build up the shadow area for RAIO screen_resource_handle = vc_dispmanx_resource_create( VC_IMAGE_RGB565, DISPLAY_WIDTH, DISPLAY_HEIGHT, &image_prt ); if ( !screen_resource_handle ) { printf("\n Unable to create screen buffer"); vc_dispmanx_display_close( main_display_handle ); return ( -1 ); } vc_dispmanx_rect_set( &rectangle, 0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT ); while( 1 ) { ret = vc_dispmanx_snapshot( main_display_handle, screen_resource_handle, DISPMANX_NO_ROTATE ); vc_dispmanx_resource_read_data( screen_resource_handle, &rectangle, &image[ current_frame ][0], DISPLAY_WIDTH*2 ); i=0; p_current_frame = &image[ current_frame ][ 0 ]; p_old_frame = &image[ old_frame ][ 0 ]; while (i<PICTURE_PIXELS) { while (( *p_current_frame == *p_old_frame) && (i<PICTURE_PIXELS) ) { p_current_frame++; p_old_frame++; i = i+1; } p_start = p_current_frame; start = i; while (( *p_current_frame != *p_old_frame) && (i<PICTURE_PIXELS) ) { p_current_frame++; p_old_frame++; i = i+1; } count = i - start; y=start/DISPLAY_WIDTH; x=start-y*DISPLAY_WIDTH; RAIO_set_cursor( x, y ); RAIO_Write_Picture( p_start, count ); } old_frame = current_frame; if ( current_frame == 0 ) current_frame = 1; else current_frame = 0; // 100ms -> 10 fps usleep( 100 * 1000 ); } return ( 0 ); }
int process() { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_MODEINFO_T display_info; DISPMANX_RESOURCE_HANDLE_T screen_resource; VC_IMAGE_TRANSFORM_T transform; uint32_t image_prt; VC_RECT_T rect1; int ret; int fbfd = 0; char *fbp = 0; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; bcm_host_init(); display = vc_dispmanx_display_open(0); if (!display) { syslog(LOG_ERR, "Unable to open primary display"); return -1; } ret = vc_dispmanx_display_get_info(display, &display_info); if (ret) { syslog(LOG_ERR, "Unable to get primary display information"); return -1; } syslog(LOG_INFO, "Primary display is %d x %d", display_info.width, display_info.height); fbfd = open("/dev/fb1", O_RDWR); if (!fbfd) { syslog(LOG_ERR, "Unable to open secondary display"); return -1; } if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { syslog(LOG_ERR, "Unable to get secondary display information"); return -1; } if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { syslog(LOG_ERR, "Unable to get secondary display information"); return -1; } syslog(LOG_INFO, "Second display is %d x %d %dbps\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, vinfo.xres, vinfo.yres, &image_prt); if (!screen_resource) { syslog(LOG_ERR, "Unable to create screen buffer"); close(fbfd); vc_dispmanx_display_close(display); return -1; } fbp = (char*) mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if (fbp <= 0) { syslog(LOG_ERR, "Unable to create mamory mapping"); close(fbfd); ret = vc_dispmanx_resource_delete(screen_resource); vc_dispmanx_display_close(display); return -1; } vc_dispmanx_rect_set(&rect1, 0, 0, vinfo.xres, vinfo.yres); while (1) { ret = vc_dispmanx_snapshot(display, screen_resource, 0); vc_dispmanx_resource_read_data(screen_resource, &rect1, fbp, vinfo.xres * vinfo.bits_per_pixel / 8); usleep(25 * 1000); } munmap(fbp, finfo.smem_len); close(fbfd); ret = vc_dispmanx_resource_delete(screen_resource); vc_dispmanx_display_close(display); }
/* * simulate grabbing a picture from some device */ int TakePicture(unsigned char *buffer) { static int last_line=0, fps=0, fcount=0; int line=0; int i,j; struct timeval now; int found; VC_IMAGE_TRANSFORM_T transform = 0; VC_RECT_T rect; vc_dispmanx_snapshot(display, resource, transform); vc_dispmanx_rect_set(&rect, 0, 0, info.width, info.height); vc_dispmanx_resource_read_data(resource, &rect, image, pitch); unsigned short *image_p = (unsigned short *)image; unsigned short *buffer_p = (unsigned short *)buffer; // find y0, y1 found = 0; unsigned short *back_image_p = (unsigned short *)back_image; for (i=0; i<info.height && !found; i++) { for (j = 0; j<info.width; j++) { if (back_image_p[i*padded_width + j] != image_p[i*padded_width + j]) { r_y0 = i; found = 1; break; } } } found = 0; for (i=info.height-1; i>=r_y0 && !found; i--) { for (j = 0; j<info.width; j++) { if (back_image_p[i*padded_width + j] != image_p[i*padded_width + j]) { r_y1 = i+1; found = 1; break; } } } found = 0; for (i=0; i<info.width && !found; i++) { for (j = r_y0; j< r_y1; j++) { if (back_image_p[j*padded_width + i] != image_p[j*padded_width + i]) { r_x0 = i; found = 1; break; } } } found = 0; for (i=info.width-1; i>=r_x0 && !found; i--) { for (j = r_y0; j< r_y1; j++) { if (back_image_p[j*padded_width + i] != image_p[j*padded_width + i]) { r_x1 = i+1; found = 1; break; } } } for(j=r_y0;j<r_y1;++j) { for(i=r_x0;i<r_x1;++i) { unsigned short tbi = image_p[j*padded_width + i]; unsigned short R5 = (tbi >> 11); unsigned short G5 = ((tbi >> 6) & 0x1f); unsigned short B5 = tbi & 0x1f; tbi = (B5 << 10) | (G5 << 5) | R5; buffer_p[j*padded_width +i] = tbi; } } /* swap image and back_image buffers */ void *tmp_image = back_image; back_image = image; image = tmp_image; /* * simulate the passage of time * * draw a simple black line that moves down the screen. The faster the * client, the more updates it will get, the smoother it will look! */ gettimeofday(&now,NULL); line = now.tv_usec / (1000000/info.height); if (line>info.height) line=info.height-1; //memset(&buffer[(info.width * BPP) * line], 0, (info.width * BPP)); /* frames per second (informational only) */ fcount++; if (last_line > line) { fps = fcount; fcount = 0; } last_line = line; fprintf(stderr,"%03d/%03d Picture (%03d fps) ", line, info.height, fps); fprintf(stderr, "x0=%d, y0=%d, x1=%d, y1=%d \r", r_x0, r_y0, r_x1, r_y1); /* success! We have a new picture! */ return (1==1); }
static jboolean fbDispmanRobotScreenCapture(jint x, jint y, jint width, jint height, jint *pixels) { FILE *fb; unsigned int *pixelBuffer = NULL; unsigned char *pixelBufferPtr = NULL; unsigned char *dst = (unsigned char *) pixels; int i = 0; int fbFileHandle; struct fb_var_screeninfo screenInfo; unsigned int dstByteStride = width * 4; VC_IMAGE_TRANSFORM_T transform = 0; DISPMANX_RESOURCE_HANDLE_T resource = 0; DISPMANX_DISPLAY_HANDLE_T display = 0; DISPMANX_RESOURCE_HANDLE_T screenResource = 0; uint32_t imagePtr; int rc; GLASS_LOG_FINE("Capture %i,%i+%ix%i", x, y, width, height); if (width < 1 || height < 1) { GLASS_LOG_SEVERE("Failed. width/height values must be at least = 1"); return JNI_FALSE; } GLASS_LOG_FINE("open(%s, O_RDONLY)", FB_DEVICE); fbFileHandle = open(FB_DEVICE, O_RDONLY); if (fbFileHandle < 0) { GLASS_LOG_SEVERE("Cannot open framebuffer"); return JNI_FALSE; } GLASS_LOG_FINE("ioctl(%s, FBIOGET_VSCREENINFO)", FB_DEVICE); if (ioctl(fbFileHandle, FBIOGET_VSCREENINFO, &screenInfo)) { GLASS_LOG_SEVERE("Cannot get screen info"); GLASS_LOG_FINE("close(%s)", FB_DEVICE); close(fbFileHandle); return JNI_FALSE; } GLASS_LOG_FINE("Read screen info: res=%ix%i, offset=%ix%i", screenInfo.xres, screenInfo.yres, screenInfo.xoffset, screenInfo.yoffset); GLASS_LOG_FINE("close(%s)", FB_DEVICE); close(fbFileHandle); VC_RECT_T pixelRect = { 0, 0, screenInfo.xres, screenInfo.yres }; int pixelBufferLength = screenInfo.xres * screenInfo.yres * 4; pixelBuffer = (unsigned int *) malloc(pixelBufferLength); pixelBufferPtr = (unsigned char *) pixelBuffer; if (pixelBuffer == NULL) { printf("Failed to allocate temporary pixel buffer\n"); return JNI_FALSE; } GLASS_LOG_FINE("fopen(%s, \"r\") to read %ix%i pixels at bit depth %i\n", FB_DEVICE, width, height, screenInfo.bits_per_pixel); display = vc_dispmanx_display_open(0 /* LCD */); if (display == 0) { fprintf(stderr, "fbRobotScreenCapture: Dispman: Cannot open display\n"); free(pixelBuffer); return JNI_FALSE; } // create the resource for the snapshot screenResource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, screenInfo.xres, screenInfo.yres, &imagePtr); if (!screenResource) { fprintf(stderr, "fbRobotScreenCapture: Cannot create resource\n"); vc_dispmanx_display_close(display); free(pixelBuffer); return JNI_FALSE; } rc = vc_dispmanx_snapshot(display, screenResource, transform); rc = 0; if (rc) { fprintf(stderr, "fbRobotScreenCapture: snapshot failed\n"); vc_dispmanx_display_close(display); free(pixelBuffer); return JNI_FALSE; } rc = vc_dispmanx_resource_read_data(screenResource, &pixelRect, pixelBuffer, screenInfo.xres * 4); if (rc) { fprintf(stderr, "fbRobotScreenCapture: Cannot read pixels %d\n", rc); vc_dispmanx_display_close(display); free(pixelBuffer); return JNI_FALSE; } rc = vc_dispmanx_resource_delete(screenResource); if (rc) { fprintf(stderr, "fbRobotScreenCapture: failed to free buffer %d\n", rc); vc_dispmanx_display_close(display); free(pixelBuffer); return JNI_FALSE; } screenResource = 0; if (x < 0) { pixelBuffer += -x; width += x; x = 0; } if (y < 0) { pixelBuffer += -y * (int)screenInfo.xres; height += y; y = 0; } int widthLimit = width; int heightLimit = height; // Required height is larger than screen's height if ((int) screenInfo.yres < height) { heightLimit = (int) screenInfo.yres; } // Required width is larger than screen's width if ((int) screenInfo.xres < width) { widthLimit = (int) screenInfo.xres; } // Required height is out of range if (((int) screenInfo.yres - y) < height) { heightLimit = (int) screenInfo.yres - y; } // Required width is out of range if (((int) screenInfo.xres - x) < width) { widthLimit = (int) screenInfo.xres - x; } if (widthLimit > 0 && heightLimit > 0) { // copy the relevant portion of the screen to the supplied pixel array int offset = y * screenInfo.xres * 4 + x * 4; for (i = 0; i < heightLimit; i++) { memcpy(dst + i * dstByteStride, pixelBufferPtr + offset, widthLimit * 4); offset += screenInfo.xres * 4; } } else { GLASS_LOG_SEVERE("Failed to take a snapshot, some of parameters are illegal"); free(pixelBuffer); return JNI_FALSE; } vc_dispmanx_display_close(display); free(pixelBuffer); return JNI_TRUE; }
int main( int argc, char *argv[]) { int opt = 0; bool writeToStdout = false; char *pngName = DEFAULT_NAME; int32_t requestedWidth = 0; int32_t requestedHeight = 0; uint32_t displayNumber = DEFAULT_DISPLAY_NUMBER; int compression = Z_DEFAULT_COMPRESSION; int delay = DEFAULT_DELAY; VC_IMAGE_TYPE_T imageType = VC_IMAGE_RGBA32; int8_t dmxBytesPerPixel = 4; int result = 0; program = basename(argv[0]); //------------------------------------------------------------------- char *sopts = "c:d:D:Hh:p:w:s"; struct option lopts[] = { { "compression", required_argument, NULL, 'c' }, { "delay", required_argument, NULL, 'd' }, { "display", required_argument, NULL, 'D' }, { "height", required_argument, NULL, 'h' }, { "help", no_argument, NULL, 'H' }, { "pngname", required_argument, NULL, 'p' }, { "width", required_argument, NULL, 'w' }, { "stdout", no_argument, NULL, 's' }, { NULL, no_argument, NULL, 0 } }; while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { switch (opt) { case 'c': compression = atoi(optarg); if ((compression < 0) || (compression > 9)) { compression = Z_DEFAULT_COMPRESSION; } break; case 'd': delay = atoi(optarg); break; case 'D': displayNumber = atoi(optarg); break; case 'h': requestedHeight = atoi(optarg); break; case 'p': pngName = optarg; break; case 'w': requestedWidth = atoi(optarg); break; case 's': writeToStdout = true; break; case 'H': default: usage(); if (opt == 'H') { exit(EXIT_SUCCESS); } else { exit(EXIT_FAILURE); } break; } } //------------------------------------------------------------------- bcm_host_init(); //------------------------------------------------------------------- // // When the display is rotate (either 90 or 270 degrees) we need to // swap the width and height of the snapshot // char response[1024]; int displayRotated = 0; if (vc_gencmd(response, sizeof(response), "get_config int") == 0) { vc_gencmd_number_property(response, "display_rotate", &displayRotated); } //------------------------------------------------------------------- if (delay) { sleep(delay); } //------------------------------------------------------------------- DISPMANX_DISPLAY_HANDLE_T displayHandle = vc_dispmanx_display_open(displayNumber); if (displayHandle == 0) { fprintf(stderr, "%s: unable to open display %d\n", program, displayNumber); exit(EXIT_FAILURE); } DISPMANX_MODEINFO_T modeInfo; result = vc_dispmanx_display_get_info(displayHandle, &modeInfo); if (result != 0) { fprintf(stderr, "%s: unable to get display information\n", program); exit(EXIT_FAILURE); } int32_t pngWidth = modeInfo.width; int32_t pngHeight = modeInfo.height; if (requestedWidth > 0) { pngWidth = requestedWidth; if (requestedHeight == 0) { double numerator = modeInfo.height * requestedWidth; double denominator = modeInfo.width; pngHeight = (int32_t)ceil(numerator / denominator); } } if (requestedHeight > 0) { pngHeight = requestedHeight; if (requestedWidth == 0) { double numerator = modeInfo.width * requestedHeight; double denominator = modeInfo.height; pngWidth = (int32_t)ceil(numerator / denominator); } } //------------------------------------------------------------------- // only need to check low bit of displayRotated (value of 1 or 3). // If the display is rotated either 90 or 270 degrees (value 1 or 3) // the width and height need to be transposed. int32_t dmxWidth = pngWidth; int32_t dmxHeight = pngHeight; if (displayRotated & 1) { dmxWidth = pngHeight; dmxHeight = pngWidth; } int32_t dmxPitch = dmxBytesPerPixel * ALIGN_TO_16(dmxWidth); void *dmxImagePtr = malloc(dmxPitch * dmxHeight); if (dmxImagePtr == NULL) { fprintf(stderr, "%s: unable to allocated image buffer\n", program); exit(EXIT_FAILURE); } //------------------------------------------------------------------- uint32_t vcImagePtr = 0; DISPMANX_RESOURCE_HANDLE_T resourceHandle; resourceHandle = vc_dispmanx_resource_create(imageType, dmxWidth, dmxHeight, &vcImagePtr); result = vc_dispmanx_snapshot(displayHandle, resourceHandle, DISPMANX_NO_ROTATE); if (result != 0) { vc_dispmanx_resource_delete(resourceHandle); vc_dispmanx_display_close(displayHandle); fprintf(stderr, "%s: vc_dispmanx_snapshot() failed\n", program); exit(EXIT_FAILURE); } VC_RECT_T rect; result = vc_dispmanx_rect_set(&rect, 0, 0, dmxWidth, dmxHeight); if (result != 0) { vc_dispmanx_resource_delete(resourceHandle); vc_dispmanx_display_close(displayHandle); fprintf(stderr, "%s: vc_dispmanx_rect_set() failed\n", program); exit(EXIT_FAILURE); } result = vc_dispmanx_resource_read_data(resourceHandle, &rect, dmxImagePtr, dmxPitch); if (result != 0) { vc_dispmanx_resource_delete(resourceHandle); vc_dispmanx_display_close(displayHandle); fprintf(stderr, "%s: vc_dispmanx_resource_read_data() failed\n", program); exit(EXIT_FAILURE); } vc_dispmanx_resource_delete(resourceHandle); vc_dispmanx_display_close(displayHandle); //------------------------------------------------------------------- // Convert from RGBA (32 bit) to RGB (24 bit) int8_t pngBytesPerPixel = 3; int32_t pngPitch = pngBytesPerPixel * pngWidth; void *pngImagePtr = malloc(pngPitch * pngHeight); int32_t j = 0; for (j = 0 ; j < pngHeight ; j++) { int32_t dmxXoffset = 0; int32_t dmxYoffset = 0; switch (displayRotated & 3) { case 0: // 0 degrees if (displayRotated & 0x20000) // flip vertical { dmxYoffset = (dmxHeight - j - 1) * dmxPitch; } else { dmxYoffset = j * dmxPitch; } break; case 1: // 90 degrees if (displayRotated & 0x20000) // flip vertical { dmxXoffset = j * dmxBytesPerPixel; } else { dmxXoffset = (dmxWidth - j - 1) * dmxBytesPerPixel; } break; case 2: // 180 degrees if (displayRotated & 0x20000) // flip vertical { dmxYoffset = j * dmxPitch; } else { dmxYoffset = (dmxHeight - j - 1) * dmxPitch; } break; case 3: // 270 degrees if (displayRotated & 0x20000) // flip vertical { dmxXoffset = (dmxWidth - j - 1) * dmxBytesPerPixel; } else { dmxXoffset = j * dmxBytesPerPixel; } break; } int32_t i = 0; for (i = 0 ; i < pngWidth ; i++) { uint8_t *pngPixelPtr = pngImagePtr + (i * pngBytesPerPixel) + (j * pngPitch); switch (displayRotated & 3) { case 0: // 0 degrees if (displayRotated & 0x10000) // flip horizontal { dmxXoffset = (dmxWidth - i - 1) * dmxBytesPerPixel; } else { dmxXoffset = i * dmxBytesPerPixel; } break; case 1: // 90 degrees if (displayRotated & 0x10000) // flip horizontal { dmxYoffset = (dmxHeight - i - 1) * dmxPitch; } else { dmxYoffset = i * dmxPitch; } break; case 2: // 180 degrees if (displayRotated & 0x10000) // flip horizontal { dmxXoffset = i * dmxBytesPerPixel; } else { dmxXoffset = (dmxWidth - i - 1) * dmxBytesPerPixel; } break; case 3: // 270 degrees if (displayRotated & 0x10000) // flip horizontal { dmxYoffset = i * dmxPitch; } else { dmxYoffset = (dmxHeight - i - 1) * dmxPitch; } break; } uint8_t *dmxPixelPtr = dmxImagePtr + dmxXoffset + dmxYoffset; memcpy(pngPixelPtr, dmxPixelPtr, 3); } } free(dmxImagePtr); dmxImagePtr = NULL; //------------------------------------------------------------------- png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (pngPtr == NULL) { fprintf(stderr, "%s: unable to allocated PNG write structure\n", program); exit(EXIT_FAILURE); } png_infop infoPtr = png_create_info_struct(pngPtr); if (infoPtr == NULL) { fprintf(stderr, "%s: unable to allocated PNG info structure\n", program); exit(EXIT_FAILURE); } if (setjmp(png_jmpbuf(pngPtr))) { fprintf(stderr, "%s: unable to create PNG\n", program); exit(EXIT_FAILURE); } FILE *pngfp = NULL; if (writeToStdout) { pngfp = stdout; } else { pngfp = fopen(pngName, "wb"); if (pngfp == NULL) { fprintf(stderr, "%s: unable to create %s - %s\n", program, pngName, strerror(errno)); exit(EXIT_FAILURE); } } png_init_io(pngPtr, pngfp); png_set_IHDR( pngPtr, infoPtr, pngWidth, pngHeight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (compression != Z_DEFAULT_COMPRESSION) { png_set_compression_level(pngPtr, compression); } png_write_info(pngPtr, infoPtr); int y = 0; for (y = 0; y < pngHeight; y++) { png_write_row(pngPtr, pngImagePtr + (pngPitch * y)); } png_write_end(pngPtr, NULL); png_destroy_write_struct(&pngPtr, &infoPtr); if (pngfp != stdout) { fclose(pngfp); } //------------------------------------------------------------------- free(pngImagePtr); pngImagePtr = NULL; return 0; }
void Copy() { vc_dispmanx_snapshot(display, screen_resource, (DISPMANX_TRANSFORM_T)0); vc_dispmanx_resource_read_data(screen_resource, &rect1, fbp, vinfo.xres * vinfo.bits_per_pixel / 8); }
static bool recreate_dispmanx(struct ra_ctx *ctx) { struct priv *p = ctx->priv; int display_nr = 0; int layer = 0; MP_VERBOSE(ctx, "Recreating DISPMANX state...\n"); destroy_dispmanx(ctx); p->display = vc_dispmanx_display_open(display_nr); p->update = vc_dispmanx_update_start(0); if (!p->display || !p->update) { MP_FATAL(ctx, "Could not get DISPMANX objects.\n"); goto fail; } uint32_t dispw, disph; if (graphics_get_display_size(0, &dispw, &disph) < 0) { MP_FATAL(ctx, "Could not get display size.\n"); goto fail; } p->w = dispw; p->h = disph; if (ctx->vo->opts->fullscreen) { p->x = p->y = 0; } else { struct vo_win_geometry geo; struct mp_rect screenrc = {0, 0, p->w, p->h}; vo_calc_window_geometry(ctx->vo, &screenrc, &geo); mp_rect_intersection(&geo.win, &screenrc); p->x = geo.win.x0; p->y = geo.win.y0; p->w = geo.win.x1 - geo.win.x0; p->h = geo.win.y1 - geo.win.y0; } // dispmanx is like a neanderthal version of Wayland - you can add an // overlay any place on the screen. VC_RECT_T dst = {.x = p->x, .y = p->y, .width = p->w, .height = p->h}; VC_RECT_T src = {.width = p->w << 16, .height = p->h << 16}; VC_DISPMANX_ALPHA_T alpha = { .flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE, .opacity = 0xFF, }; p->window = vc_dispmanx_element_add(p->update, p->display, layer, &dst, 0, &src, DISPMANX_PROTECTION_NONE, &alpha, 0, 0); if (!p->window) { MP_FATAL(ctx, "Could not add DISPMANX element.\n"); goto fail; } vc_dispmanx_update_submit_sync(p->update); p->update = vc_dispmanx_update_start(0); p->egl_window = (EGL_DISPMANX_WINDOW_T){ .element = p->window, .width = p->w, .height = p->h, }; p->egl_surface = eglCreateWindowSurface(p->egl_display, p->egl_config, &p->egl_window, NULL); if (p->egl_surface == EGL_NO_SURFACE) { MP_FATAL(ctx, "Could not create EGL surface!\n"); goto fail; } if (!eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface, p->egl_context)) { MP_FATAL(ctx, "Failed to set context!\n"); goto fail; } p->display_fps = 0; TV_GET_STATE_RESP_T tvstate; TV_DISPLAY_STATE_T tvstate_disp; if (!vc_tv_get_state(&tvstate) && !vc_tv_get_display_state(&tvstate_disp)) { if (tvstate_disp.state & (VC_HDMI_HDMI | VC_HDMI_DVI)) { p->display_fps = tvstate_disp.display.hdmi.frame_rate; HDMI_PROPERTY_PARAM_T param = { .property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE, }; if (!vc_tv_hdmi_get_property(¶m) && param.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC) p->display_fps = p->display_fps / 1.001; } else { p->display_fps = tvstate_disp.display.sdtv.frame_rate; } } p->win_params[0] = display_nr; p->win_params[1] = layer; p->win_params[2] = p->x; p->win_params[3] = p->y; ctx->vo->dwidth = p->w; ctx->vo->dheight = p->h; ra_gl_ctx_resize(ctx->swapchain, p->w, p->h, 0); ctx->vo->want_redraw = true; vo_event(ctx->vo, VO_EVENT_WIN_STATE); return true; fail: destroy_dispmanx(ctx); return false; } static void rpi_swap_buffers(struct ra_ctx *ctx) { struct priv *p = ctx->priv; eglSwapBuffers(p->egl_display, p->egl_surface); } static bool rpi_init(struct ra_ctx *ctx) { struct priv *p = ctx->priv = talloc_zero(ctx, struct priv); bcm_host_init(); vc_tv_register_callback(tv_callback, ctx); p->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (!eglInitialize(p->egl_display, NULL, NULL)) { MP_FATAL(ctx, "EGL failed to initialize.\n"); goto fail; } if (!mpegl_create_context(ctx, p->egl_display, &p->egl_context, &p->egl_config)) goto fail; if (recreate_dispmanx(ctx) < 0) goto fail; mpegl_load_functions(&p->gl, ctx->log); struct ra_gl_ctx_params params = { .swap_buffers = rpi_swap_buffers, .native_display_type = "MPV_RPI_WINDOW", .native_display = p->win_params, }; if (!ra_gl_ctx_init(ctx, &p->gl, params)) goto fail; return true; fail: rpi_uninit(ctx); return false; } static bool rpi_reconfig(struct ra_ctx *ctx) { return recreate_dispmanx(ctx); } static struct mp_image *take_screenshot(struct ra_ctx *ctx) { struct priv *p = ctx->priv; if (!p->display) return NULL; struct mp_image *img = mp_image_alloc(IMGFMT_BGR0, p->w, p->h); if (!img) return NULL; DISPMANX_RESOURCE_HANDLE_T resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, img->w | ((img->w * 4) << 16), img->h, &(int32_t){0}); if (!resource) goto fail; if (vc_dispmanx_snapshot(p->display, resource, 0)) goto fail; VC_RECT_T rc = {.width = img->w, .height = img->h}; if (vc_dispmanx_resource_read_data(resource, &rc, img->planes[0], img->stride[0])) goto fail; vc_dispmanx_resource_delete(resource); return img; fail: vc_dispmanx_resource_delete(resource); talloc_free(img); return NULL; } static int rpi_control(struct ra_ctx *ctx, int *events, int request, void *arg) { struct priv *p = ctx->priv; switch (request) { case VOCTRL_SCREENSHOT_WIN: *(struct mp_image **)arg = take_screenshot(ctx); return VO_TRUE; case VOCTRL_FULLSCREEN: recreate_dispmanx(ctx); return VO_TRUE; case VOCTRL_CHECK_EVENTS: if (atomic_fetch_and(&p->reload_display, 0)) { MP_WARN(ctx, "Recovering from display mode switch...\n"); recreate_dispmanx(ctx); } return VO_TRUE; case VOCTRL_GET_DISPLAY_FPS: *(double *)arg = p->display_fps; return VO_TRUE; } return VO_NOTIMPL; } const struct ra_ctx_fns ra_ctx_rpi = { .type = "opengl", .name = "rpi", .reconfig = rpi_reconfig, .control = rpi_control, .init = rpi_init, .uninit = rpi_uninit, };
int main(int argc, char *argv[]) { int quality = 75; if (argc == 2) { quality = atoi(argv[1]); if (quality < 10 || quality > 100) { fprintf(stderr, "invalid quality. must be between 10 and 100\n"); return 1; } } bcm_host_init(); uint32_t screen = 0; DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(screen); DISPMANX_MODEINFO_T info; int ret = vc_dispmanx_display_get_info(display, &info); assert(ret == 0); /* DispmanX expects buffer rows to be aligned to a 32 bit boundary */ int pitch = ALIGN_UP(2 * info.width, 32); uint32_t vc_image_ptr; VC_IMAGE_TYPE_T type = VC_IMAGE_RGB565; DISPMANX_RESOURCE_HANDLE_T resource = vc_dispmanx_resource_create( type, info.width, info.height, &vc_image_ptr ); VC_IMAGE_TRANSFORM_T transform = 0; vc_dispmanx_snapshot(display, resource, transform); VC_RECT_T rect; vc_dispmanx_rect_set(&rect, 0, 0, info.width, info.height); unsigned char *image = malloc(pitch * info.height); assert(image); vc_dispmanx_resource_read_data(resource, &rect, image, info.width * 2); ret = vc_dispmanx_resource_delete(resource); assert(ret == 0); ret = vc_dispmanx_display_close(display); assert(ret == 0); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, stdout); cinfo.image_width = info.width; cinfo.image_height = info.height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); int row_stride = cinfo.image_width * 3; while (cinfo.next_scanline < cinfo.image_height) { unsigned char row[row_stride]; unsigned char *dst = &row[0]; uint16_t *src = (uint16_t*)(image + pitch * cinfo.next_scanline); for (int x = 0; x < cinfo.image_width; x++, src++) { *dst++ = ((*src & 0xf800) >> 11) << 3; *dst++ = ((*src & 0x07e0) >> 5) << 2; *dst++ = ((*src & 0x001f) >> 0) << 3; } row_pointer[0] = row; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); return 0; }
void DMXResource::ReadData(VC_RECT_T& rect, void *image, int pitch) { vc_dispmanx_resource_read_data(m_resource, &rect, image, pitch); }