188a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian/*
288a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian * Copyright (C) 2010 The Android Open Source Project
388a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian *
488a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian * Licensed under the Apache License, Version 2.0 (the "License");
588a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian * you may not use this file except in compliance with the License.
688a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian * You may obtain a copy of the License at
788a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian *
888a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian *      http://www.apache.org/licenses/LICENSE-2.0
988a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian *
1088a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian * Unless required by applicable law or agreed to in writing, software
1188a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian * distributed under the License is distributed on an "AS IS" BASIS,
1288a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1388a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian * See the License for the specific language governing permissions and
1488a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian * limitations under the License.
1588a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian */
1688a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian
175cff0630eb970faf1682095ca434b204628b4d62Joe Onorato#include <errno.h>
1888a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian#include <unistd.h>
195cff0630eb970faf1682095ca434b204628b4d62Joe Onorato#include <stdio.h>
2088a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian#include <fcntl.h>
2188a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian
229afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian#include <linux/fb.h>
239afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian#include <sys/ioctl.h>
249afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian#include <sys/mman.h>
259afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian
2688a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian#include <binder/IMemory.h>
278335f1ccccedb6655d96d9d5b697a7f0938235ddMathias Agopian#include <gui/SurfaceComposerClient.h>
280b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown#include <gui/ISurfaceComposer.h>
2988a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian
305cff0630eb970faf1682095ca434b204628b4d62Joe Onorato#include <SkImageEncoder.h>
315cff0630eb970faf1682095ca434b204628b4d62Joe Onorato#include <SkBitmap.h>
32889a3fa6ab9710104af60db5f73d69f253ddf254Derek Sollenberger#include <SkData.h>
335cff0630eb970faf1682095ca434b204628b4d62Joe Onorato#include <SkStream.h>
345cff0630eb970faf1682095ca434b204628b4d62Joe Onorato
3588a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopianusing namespace android;
3688a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian
370b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brownstatic uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
380b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown
399afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopianstatic void usage(const char* pname)
405cff0630eb970faf1682095ca434b204628b4d62Joe Onorato{
415cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    fprintf(stderr,
420b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            "usage: %s [-hp] [-d display-id] [FILENAME]\n"
435cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            "   -h: this message\n"
445cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            "   -p: save the file as a png.\n"
450b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            "   -d: specify the display id to capture, default %d.\n"
465cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            "If FILENAME ends with .png it will be saved as a png.\n"
479afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            "If FILENAME is not given, the results will be printed to stdout.\n",
480b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            pname, DEFAULT_DISPLAY_ID
495cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    );
505cff0630eb970faf1682095ca434b204628b4d62Joe Onorato}
515cff0630eb970faf1682095ca434b204628b4d62Joe Onorato
525cff0630eb970faf1682095ca434b204628b4d62Joe Onoratostatic SkBitmap::Config flinger2skia(PixelFormat f)
535cff0630eb970faf1682095ca434b204628b4d62Joe Onorato{
545cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    switch (f) {
555cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        case PIXEL_FORMAT_A_8:
565cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            return SkBitmap::kA8_Config;
575cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        case PIXEL_FORMAT_RGB_565:
585cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            return SkBitmap::kRGB_565_Config;
595cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        case PIXEL_FORMAT_RGBA_4444:
605cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            return SkBitmap::kARGB_4444_Config;
615cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        default:
625cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            return SkBitmap::kARGB_8888_Config;
635cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    }
645cff0630eb970faf1682095ca434b204628b4d62Joe Onorato}
655cff0630eb970faf1682095ca434b204628b4d62Joe Onorato
669afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopianstatic status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo,
679afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        uint32_t* bytespp, uint32_t* f)
689afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian{
699afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian
709afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    switch (vinfo.bits_per_pixel) {
719afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        case 16:
729afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            *f = PIXEL_FORMAT_RGB_565;
739afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            *bytespp = 2;
749afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            break;
759afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        case 24:
769afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            *f = PIXEL_FORMAT_RGB_888;
779afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            *bytespp = 3;
789afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            break;
799afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        case 32:
809afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            // TODO: do better decoding of vinfo here
819afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            *f = PIXEL_FORMAT_RGBX_8888;
829afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            *bytespp = 4;
839afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            break;
849afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        default:
859afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            return BAD_VALUE;
869afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    }
879afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    return NO_ERROR;
889afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian}
899afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian
9088a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopianint main(int argc, char** argv)
9188a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian{
929afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    const char* pname = argv[0];
935cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    bool png = false;
940b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    int32_t displayId = DEFAULT_DISPLAY_ID;
955cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    int c;
960b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    while ((c = getopt(argc, argv, "phd:")) != -1) {
975cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        switch (c) {
985cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            case 'p':
995cff0630eb970faf1682095ca434b204628b4d62Joe Onorato                png = true;
1005cff0630eb970faf1682095ca434b204628b4d62Joe Onorato                break;
1010b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown            case 'd':
1020b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown                displayId = atoi(optarg);
1030b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown                break;
1045cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            case '?':
1055cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            case 'h':
1069afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                usage(pname);
1075cff0630eb970faf1682095ca434b204628b4d62Joe Onorato                return 1;
1085cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        }
1095cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    }
1105cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    argc -= optind;
1115cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    argv += optind;
1125cff0630eb970faf1682095ca434b204628b4d62Joe Onorato
1135cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    int fd = -1;
1145cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    if (argc == 0) {
1155cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        fd = dup(STDOUT_FILENO);
1165cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    } else if (argc == 1) {
1175cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        const char* fn = argv[0];
1185cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
1195cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        if (fd == -1) {
1209afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
1215cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            return 1;
1225cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        }
1235cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        const int len = strlen(fn);
1245cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) {
1255cff0630eb970faf1682095ca434b204628b4d62Joe Onorato            png = true;
1265cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        }
1275cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    }
1285cff0630eb970faf1682095ca434b204628b4d62Joe Onorato
1295cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    if (fd == -1) {
1309afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        usage(pname);
1315cff0630eb970faf1682095ca434b204628b4d62Joe Onorato        return 1;
1325cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    }
1335cff0630eb970faf1682095ca434b204628b4d62Joe Onorato
1349afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    void const* mapbase = MAP_FAILED;
1359afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    ssize_t mapsize = -1;
13688a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian
1379afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    void const* base = 0;
1389afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    uint32_t w, h, f;
1399afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    size_t size = 0;
1405cff0630eb970faf1682095ca434b204628b4d62Joe Onorato
1419afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    ScreenshotClient screenshot;
1420b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
1430b722fe9ce98d97dbcb6fefd170b85ab7037e528Jeff Brown    if (display != NULL && screenshot.update(display) == NO_ERROR) {
1449afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        base = screenshot.getPixels();
1459afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        w = screenshot.getWidth();
1469afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        h = screenshot.getHeight();
1479afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        f = screenshot.getFormat();
1489afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        size = screenshot.getSize();
1495cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    } else {
1509afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        const char* fbpath = "/dev/graphics/fb0";
1519afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        int fb = open(fbpath, O_RDONLY);
1529afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        if (fb >= 0) {
1539afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            struct fb_var_screeninfo vinfo;
1549afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) {
1559afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                uint32_t bytespp;
1569afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) {
1579afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                    size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp;
1589afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                    w = vinfo.xres;
1599afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                    h = vinfo.yres;
1609afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                    size = w*h*bytespp;
1619afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                    mapsize = offset + size;
1629afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                    mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);
1639afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                    if (mapbase != MAP_FAILED) {
1649afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                        base = (void const *)((char const *)mapbase + offset);
1659afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                    }
1669afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                }
1679afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            }
1689afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            close(fb);
1699afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        }
1709afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    }
1719afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian
1729afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    if (base) {
1739afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        if (png) {
1749afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            SkBitmap b;
1759afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            b.setConfig(flinger2skia(f), w, h);
1769afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            b.setPixels((void*)base);
1779afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            SkDynamicMemoryWStream stream;
1789afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            SkImageEncoder::EncodeStream(&stream, b,
1799afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian                    SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
180889a3fa6ab9710104af60db5f73d69f253ddf254Derek Sollenberger            SkData* streamData = stream.copyToData();
181889a3fa6ab9710104af60db5f73d69f253ddf254Derek Sollenberger            write(fd, streamData->data(), streamData->size());
182889a3fa6ab9710104af60db5f73d69f253ddf254Derek Sollenberger            streamData->unref();
1839afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        } else {
1849afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            write(fd, &w, 4);
1859afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            write(fd, &h, 4);
1869afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            write(fd, &f, 4);
1879afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian            write(fd, base, size);
1889afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        }
1895cff0630eb970faf1682095ca434b204628b4d62Joe Onorato    }
19088a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian    close(fd);
1919afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    if (mapbase != MAP_FAILED) {
1929afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian        munmap((void *)mapbase, mapsize);
1939afc7b02facf4918d3033ebb4548b76a59b1373cMathias Agopian    }
19488a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian    return 0;
19588a5df93668cb2079d10fd55de25a333f5f43842Mathias Agopian}
196