diff options
-rw-r--r-- | cmds/screencap/Android.mk | 26 | ||||
-rw-r--r-- | cmds/screencap/screencap.cpp | 195 | ||||
-rw-r--r-- | include/diskusage/dirsize.h | 30 | ||||
-rw-r--r-- | libs/diskusage/Android.mk | 24 | ||||
-rw-r--r-- | libs/diskusage/MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | libs/diskusage/dirsize.c | 74 |
6 files changed, 221 insertions, 128 deletions
diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk new file mode 100644 index 0000000..ca8008b --- /dev/null +++ b/cmds/screencap/Android.mk @@ -0,0 +1,26 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + screencap.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libbinder \ + libskia \ + libui \ + libgui + +LOCAL_MODULE:= screencap + +LOCAL_MODULE_TAGS := optional + +LOCAL_C_INCLUDES += \ + external/skia/include/core \ + external/skia/include/effects \ + external/skia/include/images \ + external/skia/src/ports \ + external/skia/include/utils + +include $(BUILD_EXECUTABLE) diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp new file mode 100644 index 0000000..a1ea81a --- /dev/null +++ b/cmds/screencap/screencap.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> + +#include <linux/fb.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include <binder/IMemory.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/ISurfaceComposer.h> + +#include <SkImageEncoder.h> +#include <SkBitmap.h> +#include <SkData.h> +#include <SkStream.h> + +using namespace android; + +static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain; + +static void usage(const char* pname) +{ + fprintf(stderr, + "usage: %s [-hp] [-d display-id] [FILENAME]\n" + " -h: this message\n" + " -p: save the file as a png.\n" + " -d: specify the display id to capture, default %d.\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", + pname, DEFAULT_DISPLAY_ID + ); +} + +static SkBitmap::Config flinger2skia(PixelFormat f) +{ + switch (f) { + case PIXEL_FORMAT_A_8: + return SkBitmap::kA8_Config; + case PIXEL_FORMAT_RGB_565: + return SkBitmap::kRGB_565_Config; + case PIXEL_FORMAT_RGBA_4444: + return SkBitmap::kARGB_4444_Config; + default: + return SkBitmap::kARGB_8888_Config; + } +} + +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; + 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, h, f; + size_t size = 0; + + ScreenshotClient screenshot; + sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId); + if (display != NULL && screenshot.update(display) == 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); + 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); + } + return 0; +} diff --git a/include/diskusage/dirsize.h b/include/diskusage/dirsize.h deleted file mode 100644 index 34236c0..0000000 --- a/include/diskusage/dirsize.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __LIBDISKUSAGE_DIRSIZE_H -#define __LIBDISKUSAGE_DIRSIZE_H - -#include <stdint.h> - -__BEGIN_DECLS - -int64_t stat_size(struct stat *s); -int64_t calculate_dir_size(int dfd); - -__END_DECLS - -#endif /* __LIBDISKUSAGE_DIRSIZE_H */ diff --git a/libs/diskusage/Android.mk b/libs/diskusage/Android.mk deleted file mode 100644 index d54f8ad..0000000 --- a/libs/diskusage/Android.mk +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) 2010 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE := libdiskusage - -LOCAL_MODULE_TAGS := optional - -LOCAL_SRC_FILES := dirsize.c - -include $(BUILD_STATIC_LIBRARY)
\ No newline at end of file diff --git a/libs/diskusage/MODULE_LICENSE_APACHE2 b/libs/diskusage/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/libs/diskusage/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/libs/diskusage/dirsize.c b/libs/diskusage/dirsize.c deleted file mode 100644 index 6703783..0000000 --- a/libs/diskusage/dirsize.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * - * Copyright (C) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <dirent.h> -#include <fcntl.h> -#include <sys/stat.h> - -#include <diskusage/dirsize.h> - -int64_t stat_size(struct stat *s) -{ - int64_t blksize = s->st_blksize; - int64_t size = s->st_size; - - if (blksize) { - /* round up to filesystem block size */ - size = (size + blksize - 1) & (~(blksize - 1)); - } - - return size; -} - -int64_t calculate_dir_size(int dfd) -{ - int64_t size = 0; - struct stat s; - DIR *d; - struct dirent *de; - - d = fdopendir(dfd); - if (d == NULL) { - close(dfd); - return 0; - } - - while ((de = readdir(d))) { - const char *name = de->d_name; - if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { - size += stat_size(&s); - } - if (de->d_type == DT_DIR) { - int subfd; - - /* always skip "." and ".." */ - if (name[0] == '.') { - if (name[1] == 0) - continue; - if ((name[1] == '.') && (name[2] == 0)) - continue; - } - - subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); - if (subfd >= 0) { - size += calculate_dir_size(subfd); - } - } - } - closedir(d); - return size; -} |