int main(int argc, char** argv) { if (argc != 2) { printf("usage: %s path\n", argv[0]); exit(0); } void const* base = 0; uint32_t w, s, h, f; size_t size = 0; ScreenshotClient screenshot; const String16 name("SurfaceFlinger"); sp<ISurfaceComposer> composer; getService(name, &composer); sp<IBinder> display(composer->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); if (display != NULL && screenshot.update(display) == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); s = screenshot.getStride(); f = screenshot.getFormat(); size = screenshot.getSize(); } printf("screen capture success: w=%u, h=%u, pixels=%p\n", w, h, base); printf("saving file as PNG in %s ...\n", argv[1]); SkBitmap b; b.setConfig(flinger2skia(f), w, h, s*bytesPerPixel(f)); b.setPixels((void*)base); SkImageEncoder::EncodeFile(argv[1], b, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality); return 0; }
int main(int argc, char** argv) { const char* pname = argv[0]; bool png = false; int c; while ((c = getopt(argc, argv, "ph")) != -1) { switch (c) { case 'p': png = true; break; case '?': case 'h': usage(pname); return 1; } } argc -= optind; argv += optind; int fd = -1; if (argc == 0) { fd = dup(STDOUT_FILENO); } else if (argc == 1) { const char* fn = argv[0]; fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (fd == -1) { fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno)); return 1; } const int len = strlen(fn); if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) { png = true; } } if (fd == -1) { usage(pname); return 1; } void const* mapbase = MAP_FAILED; ssize_t mapsize = -1; void const* base = 0; uint32_t w, h, f; size_t size = 0; ScreenshotClient screenshot; if (screenshot.update() == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); f = screenshot.getFormat(); size = screenshot.getSize(); } else { const char* fbpath = "/dev/graphics/fb0"; int fb = open(fbpath, O_RDONLY); if (fb >= 0) { struct fb_var_screeninfo vinfo; if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) { uint32_t bytespp; if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) { size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp; w = vinfo.xres; h = vinfo.yres; size = w*h*bytespp; mapsize = offset + size; mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0); if (mapbase != MAP_FAILED) { base = (void const *)((char const *)mapbase + offset); } } } close(fb); } } if (base) { if (png) { SkBitmap b; b.setConfig(flinger2skia(f), w, h); b.setPixels((void*)base); SkDynamicMemoryWStream stream; SkImageEncoder::EncodeStream(&stream, b, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality); write(fd, stream.getStream(), stream.getOffset()); } else { write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); write(fd, base, size); } } close(fd); if (mapbase != MAP_FAILED) { munmap((void *)mapbase, mapsize); } return 0; }
int read_rgb_framebuffer_screencap_to_jpeg(svcInfoPtr psvc) { #ifdef PERFORMANCE_REPORT struct timeval tS, tE; gettimeofday(&tS,NULL); #endif void const* mapbase = 0; size_t size = 0; int nRtn; /* if (pscreenshot->update() == NO_ERROR) { mapbase = pscreenshot->getPixels(); //w = pscreenshot->getWidth(); //h = pscreenshot->getHeight(); //f = pscreenshot->getFormat(); size = pscreenshot->getSize(); } else { Err("Error:ScreenshotClient init failed.\n"); return 0; }*/ unsigned int sw, sh, xsize, gsize; sw = g_fbinfo.width; sh = g_fbinfo.height; xsize = g_xsize; gsize = g_fbinfo.size; if( g_halfmode) { sw /= 2; sh /= 2; xsize /= 2; gsize /= 4; } uint32_t w=0, h=0; PixelFormat fmt=0; //Log("w(%d) h(%d) sw(%d) sh(%d) xsize(%d) gsize(%d)\n", w, h, sw, sh, xsize, gsize); ScreenshotClient sc; sc.update(sw,sh); /* sp<IMemoryHeap> heap; sp<ISurfaceComposer> sf(ComposerService::getComposerService()); sf->captureScreen(0, &heap, &w, &h, &fmt, sw, sh, 0, 0x7fffffff); mapbase = heap->getBase(); */ mapbase = sc.getPixels(); //Log("w(%d) h(%d) sw(%d) sh(%d) xsize(%d) gsize(%d)\n", w, h, sw, sh, xsize, gsize); if( mapbase != NULL) { unsigned char* base = (unsigned char*)((char const *)mapbase); unsigned char* p = g_fbbuffer; unsigned int i,j; #ifdef PERFORMANCE_REPORT gettimeofday(&tE,NULL); psvc->frame_capture += ELAPSED(tS, tE); tS = tE; #endif init_jpeg(psvc->jpegquality); #ifdef PERFORMANCE_REPORT gettimeofday(&tE,NULL); psvc->frame_compress += ELAPSED(tS, tE); tS = tE; #endif for(i=0; i< gsize; i += xsize) { #ifdef USE_XOR_MODE for(unsigned int t=0; t< xsize; t++) { *(g_x + t) = (*(fbc_output[1].jpegBuf + i + t) ^ *(base + t)); } #else memcpy(g_x, base, xsize); #endif #ifdef PERFORMANCE_REPORT gettimeofday(&tE,NULL); psvc->frame_capture += ELAPSED(tS, tE); tS = tE; #endif nRtn = convert_to_rgb(g_x, xsize, p); #ifdef PERFORMANCE_REPORT gettimeofday(&tE,NULL); psvc->frame_colorspace += ELAPSED(tS, tE); tS = tE; #endif rowPointer[0] = p; jpeg_write_scanlines(&cinfo, rowPointer, 1); p += nRtn; #ifdef PERFORMANCE_REPORT gettimeofday(&tE,NULL); psvc->frame_compress += ELAPSED(tS, tE); tS = tE; #endif base += xsize; } if( gsize % xsize > 0 ) { memcpy(g_x, base, gsize % xsize ); #ifdef PERFORMANCE_REPORT gettimeofday(&tE,NULL); psvc->frame_capture += ELAPSED(tS, tE); tS = tE; #endif nRtn = convert_to_rgb(g_x, xsize, p); #ifdef PERFORMANCE_REPORT gettimeofday(&tE,NULL); psvc->frame_colorspace += ELAPSED(tS, tE); tS = tE; #endif rowPointer[0] = p; jpeg_write_scanlines(&cinfo, rowPointer, 1); p += nRtn; #ifdef PERFORMANCE_REPORT gettimeofday(&tE,NULL); psvc->frame_compress += ELAPSED(tS, tE); tS = tE; #endif } #ifdef USE_XOR_MODE memcpy(fbc_output[1].jpegBuf , (unsigned char*)((char const *)mapbase), gsize); #endif int nSize = exit_jpeg(); // release sc sc.release(); //Log("jpeg size:%d - ", nSize); if( nSize > 0 ) { //FBCCMD res; fbc_output[fbc_output_current].cmd = g_halfmode ? 'h' : 'u'; fbc_output[fbc_output_current].size = htonl(FBCCMD_HEADER + nSize); LOCK(psvc->output_mutex); int r1,r2; r1 = WriteExact(psvc, (const char*)&fbc_output[fbc_output_current], FBCCMD_HEADER); // actual data //char * test = (char*)&fbc_output[fbc_output_current]; r2 = WriteExact(psvc, fbc_output[fbc_output_current].jpegBuf, nSize); //Log("W1:%d W2:%d (%02x %02x %02x %02x %02x %02x %02x %02x\n", r1, r2, // test[0], test[1], test[2], test[3], test[4], test[5], test[6], test[7] ); UNLOCK(psvc->output_mutex); } #ifdef PERFORMANCE_REPORT gettimeofday(&tE,NULL); psvc->frame_tx += ELAPSED(tS, tE); tS = tE; #endif return nSize; } else { Err("map failed!!!\n"); } return 0; }
int main(int argc, char** argv) { #ifdef MTK_AOSP_ENHANCEMENT // work around for SIGPIPE NE caused by abnormal system status signal(SIGPIPE, SIG_IGN); ALOGD("[Screencap] main"); #endif ProcessState::self()->startThreadPool(); const char* pname = argv[0]; bool png = false; int32_t displayId = DEFAULT_DISPLAY_ID; int c; while ((c = getopt(argc, argv, "phd:")) != -1) { switch (c) { case 'p': png = true; break; case 'd': displayId = atoi(optarg); break; case '?': case 'h': usage(pname); return 1; } } argc -= optind; argv += optind; int fd = -1; if (argc == 0) { fd = dup(STDOUT_FILENO); } else if (argc == 1) { const char* fn = argv[0]; fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (fd == -1) { fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno)); return 1; } const int len = strlen(fn); if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) { png = true; } } if (fd == -1) { usage(pname); return 1; } void const* mapbase = MAP_FAILED; ssize_t mapsize = -1; void const* base = 0; uint32_t w, s, h, f; size_t size = 0; ScreenshotClient screenshot; sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId); if (display != NULL && screenshot.update(display, Rect(), false) == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); s = screenshot.getStride(); f = screenshot.getFormat(); size = screenshot.getSize(); #ifdef MTK_AOSP_ENHANCEMENT ALOGD("[Screencap] screenshot w:%d h:%d s:%d f:%d", w, h, s, f); #endif } else { const char* fbpath = "/dev/graphics/fb0"; int fb = open(fbpath, O_RDONLY); if (fb >= 0) { struct fb_var_screeninfo vinfo; if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) { uint32_t bytespp; if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) { #ifdef MTK_AOSP_ENHANCEMENT size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres_virtual) * bytespp; w = vinfo.xres; h = vinfo.yres; s = vinfo.xres_virtual; ALOGD("[Screencap] VSCREENINFO w:%d h:%d s:%d f:%d", w, h, s, f); #else size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp; w = vinfo.xres; h = vinfo.yres; s = vinfo.xres; #endif size = w*h*bytespp; mapsize = offset + size; mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0); if (mapbase != MAP_FAILED) { base = (void const *)((char const *)mapbase + offset); } } } close(fb); } } if (base) { if (png) { const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType); SkBitmap b; b.installPixels(info, const_cast<void*>(base), s*bytesPerPixel(f)); SkDynamicMemoryWStream stream; SkImageEncoder::EncodeStream(&stream, b, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality); SkData* streamData = stream.copyToData(); write(fd, streamData->data(), streamData->size()); streamData->unref(); } else { write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); size_t Bpp = bytesPerPixel(f); for (size_t y=0 ; y<h ; y++) { write(fd, base, w*Bpp); base = (void *)((char *)base + s*Bpp); } } } close(fd); if (mapbase != MAP_FAILED) { munmap((void *)mapbase, mapsize); } return 0; }
int main(int argc, char** argv) { const char* pname = argv[0]; bool png = false; int c; while ((c = getopt(argc, argv, "ph")) != -1) { switch (c) { case 'p': png = true; break; case '?': case 'h': usage(pname); return 1; } } argc -= optind; argv += optind; int fd = -1; /* if (argc == 0) { fd = dup(STDOUT_FILENO); } else if (argc == 1) { const char* fn = argv[0]; fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (fd == -1) { fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno)); return 1; } const int len = strlen(fn); if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) { png = true; } } if (fd == -1) { usage(pname); return 1; } */ void const* mapbase = MAP_FAILED; ssize_t mapsize = -1; void const* base = 0; uint32_t w, h, f; size_t size = 0; int i = 0; int ntest = 100; char fname[256]; struct timeval tS, tE; double utime, mtime, seconds, useconds, average; gettimeofday(&tS, NULL); ScreenshotClient screenshot; for(i=0; i< ntest; i++) { sprintf(fname,"fb%02d.raw",i); fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (screenshot.update() == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); f = screenshot.getFormat(); size = screenshot.getSize(); } else { printf("screenshot update failed - 2 \n"); /* const char* fbpath = "/dev/graphics/fb0"; int fb = open(fbpath, O_RDONLY); if (fb >= 0) { struct fb_var_screeninfo vinfo; if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) { uint32_t bytespp; if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) { size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp; w = vinfo.xres; h = vinfo.yres; size = w*h*bytespp; mapsize = offset + size; mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0); if (mapbase != MAP_FAILED) { base = (void const *)((char const *)mapbase + offset); } } } close(fb); } */ } if (base) { /* if (png) { SkBitmap b; b.setConfig(flinger2skia(f), w, h); b.setPixels((void*)base); SkDynamicMemoryWStream stream; SkImageEncoder::EncodeStream(&stream, b, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality); SkData* streamData = stream.copyToData(); write(fd, streamData->data(), streamData->size()); streamData->unref(); } else */ { write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); write(fd, base, size); } } close(fd); if (mapbase != MAP_FAILED) { munmap((void *)mapbase, mapsize); } screenshot.release(); printf("%d:%s\n", i+1, fname); gettimeofday(&tE, NULL); seconds = tE.tv_sec - tS.tv_sec; useconds= tE.tv_usec- tS.tv_usec; utime = seconds * 1000000 + useconds; printf("Elapsed:%.2f\n", utime/1000000 ); usleep(1); } average = (double)ntest * 1000000 / utime ; printf("Elapsed:%.2f, Average:%.2f\n", utime/1000000, average); return 0; }
int main(int argc, char **argv) { int framebufferHandle = -1; int mapSize = 0; int ret = 1; char ssPath[128]; int screenshotHandle; void* base = NULL; uint32_t w = 0; uint32_t h = 0; uint32_t depth = 0; int totalPixels = 0; int pixelOrder = PIXEL_ORDER_RGBA; sprintf(ssPath,"%s/tmpshot.bmp",getenv("EXTERNAL_STORAGE")); ScreenshotClient screenshot; if (screenshot.update() != NO_ERROR) { struct fb_var_screeninfo vinfo; LOGD("surfaceflinger capture failed. Falling back to fb and hoping for the best"); framebufferHandle = open("/dev/graphics/fb0", O_RDONLY); if(framebufferHandle < 0) return 0; if(ioctl(framebufferHandle, FBIOGET_VSCREENINFO, &vinfo) < 0) { close(framebufferHandle); return 0; } w = vinfo.xres; h = vinfo.yres; totalPixels = w * h; depth = vinfo.bits_per_pixel; mapSize = totalPixels * (depth/8); fcntl(framebufferHandle, F_SETFD, FD_CLOEXEC); LOGD("Got %dx%dx%d framebuffer",w,h,depth); base = tryfbmap(framebufferHandle, mapSize); pixelOrder = get_pixel_order(&vinfo); } else { uint32_t f = screenshot.getFormat(); base = (void *)screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); totalPixels = w * h; depth = format_map[f]; } int totalMem8888 = totalPixels * 4; int *rgbaPixels = (int*)malloc(totalMem8888); int *endOfImage = rgbaPixels + h * w; int *rgbaPixelsCopy; int *curline; int lineSize; int *srcline; if (depth == 16) { short *baseCursor = (short*)base; int *rgbaPixelsCursor = rgbaPixels; int *rgbaLast = rgbaPixels + totalPixels; LOGV("Working with 16 depth and a mapsize of %d",mapSize); for(; rgbaPixelsCursor < rgbaLast; rgbaPixelsCursor++, baseCursor++) { short pixel = *baseCursor; int r = (pixel & 0xF800) << 8; int g = (pixel & 0x7E0) << 5; int b = (pixel & 0x1F) << 3; int color = 0xFF000000 | r | g | b; *rgbaPixelsCursor = color; } } else if (depth == 32) { memcpy(rgbaPixels, base, totalMem8888); sort_pixels(pixelOrder, rgbaPixels, endOfImage); } else { ret = 2; goto done; } // flip it upside down! rgbaPixelsCopy = (int*)malloc(totalMem8888); curline = rgbaPixelsCopy + (h - 1) * w; lineSize = 4 * w; srcline = rgbaPixels; for (; srcline < endOfImage; curline -= w, srcline += w) { memcpy(curline, srcline, lineSize); } memcpy(rgbaPixels, rgbaPixelsCopy, totalMem8888); free(rgbaPixelsCopy); struct bmpfile_magic magic; struct bmpfile_header header; struct bmpfile_dibheader dibheader; magic.magic[0] = 0x42; magic.magic[1] = 0x4D; header.bmp_offset = sizeof(magic) + sizeof(header) + sizeof(dibheader); header.creator1 = 0; header.creator2 = 0; header.filesz = sizeof(magic) + sizeof(header) + sizeof(dibheader) + totalMem8888; dibheader.header_sz = sizeof(dibheader); dibheader.width = w; dibheader.height = h; dibheader.nplanes = 1; dibheader.bitspp = 32; dibheader.compress_type = 0; dibheader.bmp_bytesz = totalMem8888; dibheader.hres = w; dibheader.vres = h; dibheader.ncolors = 0; dibheader.nimpcolors = 0; screenshotHandle = open(ssPath, O_WRONLY | O_CREAT); write(screenshotHandle, &magic, sizeof(magic)); write(screenshotHandle, &header, sizeof(header)); write(screenshotHandle, &dibheader, sizeof(dibheader)); write(screenshotHandle, rgbaPixels, totalMem8888); close(screenshotHandle); ret = 0; done: if (rgbaPixels != NULL) free(rgbaPixels); if (framebufferHandle >= 0 && mapSize) { munmap(base, mapSize); close(framebufferHandle); } return ret; }
int main(int argc, char** argv) { ProcessState::self()->startThreadPool(); const char* pname = argv[0]; bool png = false; bool jpeg = false; int32_t displayId = DEFAULT_DISPLAY_ID; int c; while ((c = getopt(argc, argv, "pjhd:")) != -1) { switch (c) { case 'p': png = true; break; case 'j': jpeg = true; break; case 'd': displayId = atoi(optarg); break; case '?': case 'h': usage(pname); return 1; } } argc -= optind; argv += optind; int fd = -1; const char* fn = NULL; if (argc == 0) { fd = dup(STDOUT_FILENO); } else if (argc == 1) { fn = argv[0]; fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (fd == -1) { fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno)); return 1; } const int len = strlen(fn); if (len >= 4) { if (0 == strcmp(fn+len-4, ".png")) { png = true; } else if (0 == strcmp(fn+len-4, ".jpg")) { jpeg = true; } else if (len > 4 && 0 == strcmp(fn+len-5, ".jpeg")) { jpeg = true; } } } if (fd == -1) { usage(pname); return 1; } void const* mapbase = MAP_FAILED; ssize_t mapsize = -1; void const* base = NULL; uint32_t w, s, h, f; size_t size = 0; // Maps orientations from DisplayInfo to ISurfaceComposer static const uint32_t ORIENTATION_MAP[] = { ISurfaceComposer::eRotateNone, // 0 == DISPLAY_ORIENTATION_0 ISurfaceComposer::eRotate270, // 1 == DISPLAY_ORIENTATION_90 ISurfaceComposer::eRotate180, // 2 == DISPLAY_ORIENTATION_180 ISurfaceComposer::eRotate90, // 3 == DISPLAY_ORIENTATION_270 }; ScreenshotClient screenshot; sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId); if (display == NULL) { fprintf(stderr, "Unable to get handle for display %d\n", displayId); return 1; } Vector<DisplayInfo> configs; SurfaceComposerClient::getDisplayConfigs(display, &configs); int activeConfig = SurfaceComposerClient::getActiveConfig(display); if (static_cast<size_t>(activeConfig) >= configs.size()) { fprintf(stderr, "Active config %d not inside configs (size %zu)\n", activeConfig, configs.size()); return 1; } uint8_t displayOrientation = configs[activeConfig].orientation; uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation]; status_t result = screenshot.update(display, Rect(), 0, 0, 0, -1U, false, captureOrientation); if (result == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); s = screenshot.getStride(); f = screenshot.getFormat(); size = screenshot.getSize(); } else { const char* fbpath = "/dev/graphics/fb0"; int fb = open(fbpath, O_RDONLY); if (fb >= 0) { struct fb_var_screeninfo vinfo; if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) { uint32_t bytespp; if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) { size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp; w = vinfo.xres; h = vinfo.yres; s = vinfo.xres; size = w*h*bytespp; mapsize = offset + size; mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0); if (mapbase != MAP_FAILED) { base = (void const *)((char const *)mapbase + offset); } } } close(fb); } } if (base != NULL) { if (png || jpeg) { const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType); SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(info, base, s*bytesPerPixel(f), (png ? SkImageEncoder::kPNG_Type : SkImageEncoder::kJPEG_Type), SkImageEncoder::kDefaultQuality)); if (data.get()) { write(fd, data->data(), data->size()); } if (fn != NULL) { notifyMediaScanner(fn); } } else { write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); size_t Bpp = bytesPerPixel(f); for (size_t y=0 ; y<h ; y++) { write(fd, base, w*Bpp); base = (void *)((char *)base + s*Bpp); } } } close(fd); if (mapbase != MAP_FAILED) { munmap((void *)mapbase, mapsize); } return 0; }
int main(int argc, char** argv) { LOG("start. pid %d", getpid()); int64_t interval_mms = -1; bool isGetFormat = false; bool forceUseFbFormat = false; const char* tmps; int width, height, bytesPerPixel; //for fb0 int fb = -1; char* mapbase = NULL; size_t lastMapSize = 0; if (argc>1) { double fps = atof(argv[1]); if (fps==0) { // } else { interval_mms = ((double)1000000)/fps; LOG("use fps=%.3lf (interval=%.3lfms)", fps, (double)interval_mms/1000); } } else { isGetFormat = true; } if (isGetFormat && (tmps=getenv("forceUseFbFormat")) && 0==strcmp(tmps, "forceUseFbFormat")) { LOG("forceUseFbFormat"); forceUseFbFormat = true; } #if defined(TARGET_JB) || defined(TARGET_ICS) LOG("call ScreenshotClient init"); ScreenshotClient screenshot; #endif #if defined(TARGET_JB) LOG("call SurfaceComposerClient::getBuiltInDisplay"); sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(0 /*1 is hdmi*/); if (display.m_ptr==NULL) LOGERR("failed to getBuiltInDisplay. So use fb0"); #endif //LOG(isGetFormat ? "capture once" : "start capture"); int64_t count_start_mms = microSecondOfNow(); int64_t until_mms = count_start_mms + interval_mms; for (int count=1; ;count++, until_mms += interval_mms) { char* rawImageData; size_t rawImageSize; #if defined(TARGET_JB) || defined(TARGET_ICS) bool surfaceOK = false; uint32_t status; #endif #if defined(TARGET_JB) if (!forceUseFbFormat) { if (display.m_ptr != NULL) { if (count==1) LOG("call ScreenshotClient.update(mainDisplay)"); status = screenshot.update(display); surfaceOK = (status == 0); if (!surfaceOK) LOG("Error: failed to ScreenshotClient.update(mainDisplay). Result:%d. So use fb0 alternatively, maybe not useful", status); } } #endif #if defined(TARGET_ICS) if (!forceUseFbFormat) { if (count==1) LOG("call ScreenshotClient.update()"); status = screenshot.update(); surfaceOK = (status == 0); if (!surfaceOK) LOG("Error: failed to ScreenshotClient.update(). Result:%d. So use fb0 alternatively, maybe not useful", status); } #endif #if defined(TARGET_JB) || defined(TARGET_ICS) if (surfaceOK) { rawImageData = (char*)screenshot.getPixels(); rawImageSize = screenshot.getSize(); width = screenshot.getWidth(); height = screenshot.getHeight(); bytesPerPixel = rawImageSize/width/height; int fmt = screenshot.getFormat(); if (count==1) { LOG("ScreenshotClient.update result: imageSize:%d w:%d h:%d bytesPerPixel:%d fmt:%d", rawImageSize, width, height, bytesPerPixel, fmt); } if (isGetFormat) { printf("-s %dx%d -pix_fmt %s\n", width, height, (bytesPerPixel==4) ? "rgb0" : (bytesPerPixel==3) ? "rgb24" : (bytesPerPixel==2) ? "rgb565le" : (bytesPerPixel==5) ? "rgb48le" : (bytesPerPixel==6) ? "rgba64le" : (LOG("strange bytesPerPixel:%d", bytesPerPixel),"unknown")); LOG("end"); return 0; } } else #endif { if (fb < 0) { fb = open(FRAME_BUFFER_DEV, O_RDONLY); if (fb < 0) ABORT("open fb0"); } struct fb_var_screeninfo vinfo; if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) ABORT("ioctl fb0"); width = vinfo.xres; height = vinfo.yres; bytesPerPixel = vinfo.bits_per_pixel/8; rawImageSize = (width*height) * bytesPerPixel; if (count==1) { LOG("FBIOGET_VSCREENINFO result: imageSize:%d w:%d h:%d bytesPerPixel:%d virtualW:%d virtualH:%d" " bits:%d" " R:(offset:%d length:%d msb_right:%d)" " G:(offset:%d length:%d msb_right:%d)" " B:(offset:%d length:%d msb_right:%d)" " A:(offset:%d length:%d msb_right:%d)" " grayscale:%d nonstd:%d rotate:%d", rawImageSize, width, height, bytesPerPixel, vinfo.xres_virtual, vinfo.yres_virtual ,vinfo.bits_per_pixel ,vinfo.red.offset, vinfo.red.length, vinfo.red.msb_right ,vinfo.green.offset, vinfo.green.length, vinfo.green.msb_right ,vinfo.blue.offset, vinfo.blue.length, vinfo.blue.msb_right ,vinfo.transp.offset, vinfo.transp.length, vinfo.transp.msb_right ,vinfo.grayscale, vinfo.nonstd, vinfo.rotate ); } if (isGetFormat) { printf("-s %dx%d -pix_fmt %s\n", width, height, (vinfo.bits_per_pixel==32&&vinfo.red.offset==0) ? "rgb0" : (vinfo.bits_per_pixel==32&&vinfo.red.offset!=0) ? "bgr0" : (vinfo.bits_per_pixel==24&&vinfo.red.offset==0) ? "rgb24" : (vinfo.bits_per_pixel==24&&vinfo.red.offset!=0) ? "bgr24" : (vinfo.bits_per_pixel==16&&vinfo.red.offset==0) ? "rgb565le" : (vinfo.bits_per_pixel==16&&vinfo.red.offset!=0) ? "bgr565le" : (vinfo.bits_per_pixel==48&&vinfo.red.offset==0) ? "rgb48le" : (vinfo.bits_per_pixel==48&&vinfo.red.offset!=0) ? "bgr48le" : (vinfo.bits_per_pixel==64&&vinfo.red.offset==0) ? "rgba64le" : (vinfo.bits_per_pixel==64&&vinfo.red.offset!=0) ? "bgra64le" : (LOG("strange bits_per_pixel:%d", vinfo.bits_per_pixel),"unknown")); LOG("end"); return 0; } else { uint32_t offset = (vinfo.xoffset + vinfo.yoffset*width) *bytesPerPixel; int virtualSize = vinfo.xres_virtual*vinfo.yres_virtual*bytesPerPixel; if (offset+rawImageSize > virtualSize) { LOG("Strange! offset:%d+rawImageSize:%d > virtualSize:%d", offset, rawImageSize, virtualSize); virtualSize = offset+rawImageSize; } if (virtualSize > lastMapSize) { if (mapbase) { LOG("remap due to virtualSize %d is bigger than previous %d", virtualSize, lastMapSize); munmap(mapbase, lastMapSize); mapbase = NULL; } lastMapSize = virtualSize; } if (mapbase==NULL) { mapbase = (char*)mmap(0, virtualSize, PROT_READ, MAP_PRIVATE, fb, 0); if (mapbase==NULL) ABORT("mmap %d", virtualSize); } rawImageData = mapbase + offset; } } if (count==1) { //when first time, set SIGPIPE handler to default (terminate) signal(SIGPIPE, on_SIGPIPE); //this is very important!!! If not set, write will be very slow if data is too big LOG("rawImageSize:%d", rawImageSize); } #define MAX_WRITE_SIZE (32*1024*1024) // #define MAX_WRITE_SIZE (4*1024*1024) int rest = rawImageSize; int callCount = 0; while (rest > 0) { int request = rest <= MAX_WRITE_SIZE ? rest : MAX_WRITE_SIZE; if (callCount > 0 ||request < rest) LOG("data is too big so try to write %d of rest %d", request, rest); int bytesWritten = write(STDOUT_FILENO, rawImageData+(rawImageSize-rest), request); if (bytesWritten < 0) { ABORT("write() requested:%d", request); } else if (bytesWritten < request) { LOGERR("write() result:%d < requested:%d. Continue writing rest data", bytesWritten, request); } else { // if (callCount > 0) LOG("write %d OK", request); } rest -= bytesWritten; callCount++; } if (callCount > 1) LOG("write() finished. total:%d", rawImageSize); if (interval_mms==-1) { LOG("stop due to fps argument is 0"); close(STDOUT_FILENO); //let pipe peer known end, maybe unnecessary exit(0); } else { if (count==1) LOG("continue capturing......"); } int64_t now_mms = microSecondOfNow(); int64_t diff_mms = until_mms - now_mms; if (diff_mms > 0) { usleep(diff_mms); now_mms += diff_mms; } /* //show statistics at every about 10 seconds diff_mms = now_mms-count_start_mms; if (diff_mms >= 10*1000000) { //LOG("count: %d now-count_start_ms: %lld", count, diff_mms); LOG("raw fps: %.2lf ", ((double)count) / (((double)diff_mms)/1000000)); count_start_mms = now_mms; count = 0; } */ } return 0; }