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 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) { 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; }