diff options
author | Mathias Agopian <mathias@google.com> | 2011-02-08 20:43:00 -0800 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2011-02-08 20:43:00 -0800 |
commit | 9afc7b02facf4918d3033ebb4548b76a59b1373c (patch) | |
tree | 366eebda875a7a06647195969133e6552b86994e /cmds/screencap | |
parent | 5cf98da85c1698cacbeed8d4883373d0e0774fd8 (diff) | |
download | frameworks_base-9afc7b02facf4918d3033ebb4548b76a59b1373c.zip frameworks_base-9afc7b02facf4918d3033ebb4548b76a59b1373c.tar.gz frameworks_base-9afc7b02facf4918d3033ebb4548b76a59b1373c.tar.bz2 |
fix [3374821] Cannot take screenshot of HC preview
the screencap tool will now fallback to /dev/graphics/fb0 is the
screenshot API fails.
Change-Id: I3f593847c72f4ca5429d4f64ca22bd5436dd2051
Diffstat (limited to 'cmds/screencap')
-rw-r--r-- | cmds/screencap/screencap.cpp | 114 |
1 files changed, 88 insertions, 26 deletions
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index dcea968..7a599e9 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -19,6 +19,10 @@ #include <stdio.h> #include <fcntl.h> +#include <linux/fb.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + #include <binder/IMemory.h> #include <surfaceflinger/SurfaceComposerClient.h> @@ -28,14 +32,15 @@ using namespace android; -static void usage() +static void usage(const char* pname) { fprintf(stderr, - "usage: screenshot [-hp] [FILENAME]\n" + "usage: %s [-hp] [FILENAME]\n" " -h: this message\n" " -p: save the file as a png.\n" "If FILENAME ends with .png it will be saved as a png.\n" - "If FILENAME is not given, the results will be printed to stdout.\n" + "If FILENAME is not given, the results will be printed to stdout.\n", + pname ); } @@ -54,8 +59,33 @@ static SkBitmap::Config flinger2skia(PixelFormat f) } } +static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo, + uint32_t* bytespp, uint32_t* f) +{ + + switch (vinfo.bits_per_pixel) { + case 16: + *f = PIXEL_FORMAT_RGB_565; + *bytespp = 2; + break; + case 24: + *f = PIXEL_FORMAT_RGB_888; + *bytespp = 3; + break; + case 32: + // TODO: do better decoding of vinfo here + *f = PIXEL_FORMAT_RGBX_8888; + *bytespp = 4; + break; + default: + return BAD_VALUE; + } + return NO_ERROR; +} + int main(int argc, char** argv) { + const char* pname = argv[0]; bool png = false; int c; while ((c = getopt(argc, argv, "ph")) != -1) { @@ -65,7 +95,7 @@ int main(int argc, char** argv) break; case '?': case 'h': - usage(); + usage(pname); return 1; } } @@ -79,7 +109,7 @@ int main(int argc, char** argv) const char* fn = argv[0]; fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (fd == -1) { - fprintf(stderr, "Error opening file: (%d) %s\n", errno, strerror(errno)); + fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno)); return 1; } const int len = strlen(fn); @@ -89,34 +119,66 @@ int main(int argc, char** argv) } if (fd == -1) { - usage(); + usage(pname); return 1; } - ScreenshotClient screenshot; - if (screenshot.update() != NO_ERROR) { - return 0; - } + void const* mapbase = MAP_FAILED; + ssize_t mapsize = -1; - void const* base = screenshot.getPixels(); - uint32_t w = screenshot.getWidth(); - uint32_t h = screenshot.getHeight(); - uint32_t f = screenshot.getFormat(); + void const* base = 0; + uint32_t w, h, f; + size_t size = 0; - 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()); + ScreenshotClient screenshot; + if (screenshot.update() == NO_ERROR) { + base = screenshot.getPixels(); + w = screenshot.getWidth(); + h = screenshot.getHeight(); + f = screenshot.getFormat(); + size = screenshot.getSize(); } else { - write(fd, &w, 4); - write(fd, &h, 4); - write(fd, &f, 4); - write(fd, base, w*h*4); + 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; } |