1c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood/*
2c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
3c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood *
4c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
5c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * you may not use this file except in compliance with the License.
6c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * You may obtain a copy of the License at
7c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood *
8c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
9c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood *
10c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * Unless required by applicable law or agreed to in writing, software
11c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
12c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * See the License for the specific language governing permissions and
14c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * limitations under the License.
15c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood */
16c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
17c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <errno.h>
18c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <unistd.h>
19c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <stdio.h>
20c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <fcntl.h>
21c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
22c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <linux/fb.h>
23c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <sys/ioctl.h>
24c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <sys/mman.h>
25c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
260678a8c250832a5549703f533f6afea9d8729e43Mathias Agopian#include <binder/ProcessState.h>
270678a8c250832a5549703f533f6afea9d8729e43Mathias Agopian
28c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <gui/SurfaceComposerClient.h>
29c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <gui/ISurfaceComposer.h>
30c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
310137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian#include <ui/PixelFormat.h>
320137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian
33c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <SkImageEncoder.h>
34c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <SkBitmap.h>
35c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <SkData.h>
36c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <SkStream.h>
37c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
38c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwoodusing namespace android;
39c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
40c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwoodstatic uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
41c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
42c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwoodstatic void usage(const char* pname)
43c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood{
44c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    fprintf(stderr,
45c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "usage: %s [-hp] [-d display-id] [FILENAME]\n"
46c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "   -h: this message\n"
47c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "   -p: save the file as a png.\n"
48c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "   -d: specify the display id to capture, default %d.\n"
49c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "If FILENAME ends with .png it will be saved as a png.\n"
50c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "If FILENAME is not given, the results will be printed to stdout.\n",
51c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            pname, DEFAULT_DISPLAY_ID
52c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    );
53c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood}
54c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
55b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reedstatic SkColorType flinger2skia(PixelFormat f)
56c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood{
57c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    switch (f) {
58c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        case PIXEL_FORMAT_RGB_565:
59b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reed            return kRGB_565_SkColorType;
60c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        default:
61b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reed            return kN32_SkColorType;
62c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
63c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood}
64c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
65c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwoodstatic status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo,
66c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        uint32_t* bytespp, uint32_t* f)
67c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood{
68c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
69c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    switch (vinfo.bits_per_pixel) {
70c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        case 16:
71c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            *f = PIXEL_FORMAT_RGB_565;
72c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            *bytespp = 2;
73c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            break;
74c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        case 24:
75c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            *f = PIXEL_FORMAT_RGB_888;
76c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            *bytespp = 3;
77c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            break;
78c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        case 32:
79c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            // TODO: do better decoding of vinfo here
80c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            *f = PIXEL_FORMAT_RGBX_8888;
81c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            *bytespp = 4;
82c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            break;
83c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        default:
84c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            return BAD_VALUE;
85c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
86c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    return NO_ERROR;
87c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood}
88c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
89c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwoodint main(int argc, char** argv)
90c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood{
910678a8c250832a5549703f533f6afea9d8729e43Mathias Agopian    ProcessState::self()->startThreadPool();
920678a8c250832a5549703f533f6afea9d8729e43Mathias Agopian
93c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    const char* pname = argv[0];
94c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    bool png = false;
95c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    int32_t displayId = DEFAULT_DISPLAY_ID;
96c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    int c;
97c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    while ((c = getopt(argc, argv, "phd:")) != -1) {
98c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        switch (c) {
99c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            case 'p':
100c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                png = true;
101c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                break;
102c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            case 'd':
103c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                displayId = atoi(optarg);
104c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                break;
105c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            case '?':
106c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            case 'h':
107c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                usage(pname);
108c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                return 1;
109c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        }
110c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
111c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    argc -= optind;
112c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    argv += optind;
113c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
114c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    int fd = -1;
115c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    if (argc == 0) {
116c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        fd = dup(STDOUT_FILENO);
117c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    } else if (argc == 1) {
118c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        const char* fn = argv[0];
119c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
120c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        if (fd == -1) {
121c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
122c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            return 1;
123c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        }
124c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        const int len = strlen(fn);
125c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) {
126c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            png = true;
127c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        }
128c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
129c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
130c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    if (fd == -1) {
131c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        usage(pname);
132c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        return 1;
133c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
134c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
135c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    void const* mapbase = MAP_FAILED;
136c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    ssize_t mapsize = -1;
137c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
138c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    void const* base = 0;
1390137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian    uint32_t w, s, h, f;
140c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    size_t size = 0;
141c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
142c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    ScreenshotClient screenshot;
143c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
1449890e341bf9d565309cd7db5e6c4194c66c0a1d8Dan Stoza    if (display != NULL && screenshot.update(display, Rect(), false) == NO_ERROR) {
145c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        base = screenshot.getPixels();
146c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        w = screenshot.getWidth();
147c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        h = screenshot.getHeight();
1480137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian        s = screenshot.getStride();
149c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        f = screenshot.getFormat();
150c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        size = screenshot.getSize();
151c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    } else {
152c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        const char* fbpath = "/dev/graphics/fb0";
153c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        int fb = open(fbpath, O_RDONLY);
154c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        if (fb >= 0) {
155c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            struct fb_var_screeninfo vinfo;
156c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) {
157c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                uint32_t bytespp;
158c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) {
159c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                    size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp;
160c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                    w = vinfo.xres;
161c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                    h = vinfo.yres;
1620137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian                    s = vinfo.xres;
163c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                    size = w*h*bytespp;
164c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                    mapsize = offset + size;
165c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                    mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);
166c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                    if (mapbase != MAP_FAILED) {
167c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                        base = (void const *)((char const *)mapbase + offset);
168c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                    }
169c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                }
170c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            }
171c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            close(fb);
172c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        }
173c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
174c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
175c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    if (base) {
176c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        if (png) {
177b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reed            const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f),
178b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reed                                                       kPremul_SkAlphaType);
179c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            SkBitmap b;
180b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reed            b.installPixels(info, const_cast<void*>(base), s*bytesPerPixel(f));
181c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            SkDynamicMemoryWStream stream;
182c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            SkImageEncoder::EncodeStream(&stream, b,
183c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                    SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
184c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            SkData* streamData = stream.copyToData();
185c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            write(fd, streamData->data(), streamData->size());
186c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            streamData->unref();
187c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        } else {
188c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            write(fd, &w, 4);
189c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            write(fd, &h, 4);
190c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            write(fd, &f, 4);
1910137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian            size_t Bpp = bytesPerPixel(f);
1920137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian            for (size_t y=0 ; y<h ; y++) {
1930137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian                write(fd, base, w*Bpp);
1940137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian                base = (void *)((char *)base + s*Bpp);
1950137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian            }
196c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        }
197c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
198c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    close(fd);
199c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    if (mapbase != MAP_FAILED) {
200c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        munmap((void *)mapbase, mapsize);
201c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
202c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    return 0;
203c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood}
204