screenrecord.cpp revision 2533c83b4ed8e1ca5b259d59373f941c8f0e9635
11f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
21f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Copyright 2013 The Android Open Source Project
31f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
41f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Licensed under the Apache License, Version 2.0 (the "License");
51f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * you may not use this file except in compliance with the License.
61f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * You may obtain a copy of the License at
71f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
81f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *      http://www.apache.org/licenses/LICENSE-2.0
91f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Unless required by applicable law or agreed to in writing, software
111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * distributed under the License is distributed on an "AS IS" BASIS,
121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * See the License for the specific language governing permissions and
141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * limitations under the License.
151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#define LOG_TAG "ScreenRecord"
181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden//#define LOG_NDEBUG 0
191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Log.h>
201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <binder/IPCThreadState.h>
221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Errors.h>
231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Thread.h>
241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/Surface.h>
261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/SurfaceComposerClient.h>
271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/ISurfaceComposer.h>
281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <ui/DisplayInfo.h>
291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/openmax/OMX_IVCommon.h>
301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ABuffer.h>
311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ADebug.h>
321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/AMessage.h>
331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaCodec.h>
341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaErrors.h>
351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaMuxer.h>
361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/ICrypto.h>
371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <stdio.h>
391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <signal.h>
401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <getopt.h>
411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
421f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenusing namespace android;
431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Command-line parameters.
451f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gVerbose = false;               // chatty on stdout
461f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gRotate = false;                // rotate 90 degrees
47f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool gSizeSpecified = false;         // was size explicitly requested?
48f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoWidth = 0;            // default width+height
49f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoHeight = 0;
501f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic uint32_t gBitRate = 4000000;         // 4Mbps
511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Set by signal handler to stop recording.
531f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gStopRequested;
541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Previous signal handler state, restored after first hit.
561f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionINT;
571f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionHUP;
581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
591f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic const uint32_t kMinBitRate = 100000;         // 0.1Mbps
601f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic const uint32_t kMaxBitRate = 100 * 1000000;  // 100Mbps
611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Catch keyboard interrupt signals.  On receipt, the "stop requested"
641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * flag is raised, and the original handler is restored (so that, if
651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * we get stuck finishing, a second Ctrl-C will kill the process).
661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
671f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void signalCatcher(int signum)
681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{
691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    gStopRequested = true;
701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    switch (signum) {
711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    case SIGINT:
721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sigaction(SIGINT, &gOrigSigactionINT, NULL);
731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        break;
741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    case SIGHUP:
751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sigaction(SIGHUP, &gOrigSigactionHUP, NULL);
761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        break;
771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    default:
781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        abort();
791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        break;
801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures signal handlers.  The previous handlers are saved.
851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * If the command is run from an interactive adb shell, we get SIGINT
871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * when Ctrl-C is hit.  If we're run from the host, the local adb process
881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * gets the signal, and we get a SIGHUP when the terminal disconnects.
891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
901f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t configureSignals()
911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{
921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    struct sigaction act;
931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    memset(&act, 0, sizeof(act));
941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    act.sa_handler = signalCatcher;
951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) {
961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        status_t err = -errno;
971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Unable to configure SIGINT handler: %s\n",
981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                strerror(errno));
991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) {
1021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        status_t err = -errno;
1031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Unable to configure SIGHUP handler: %s\n",
1041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                strerror(errno));
1051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return NO_ERROR;
1081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
1091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
111f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden * Returns "true" if the device is rotated 90 degrees.
112f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden */
113f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool isDeviceRotated(int orientation) {
114f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    return orientation != DISPLAY_ORIENTATION_0 &&
115f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            orientation != DISPLAY_ORIENTATION_180;
116f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden}
117f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
118f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden/*
1191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures and starts the MediaCodec encoder.  Obtains an input surface
1201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * from the codec.
1211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
1221f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec,
1231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sp<IGraphicBufferProducer>* pBufferProducer) {
1241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
1251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
126f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (gVerbose) {
127f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        printf("Configuring recorder for %dx%d video at %.2fMbps\n",
128f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                gVideoWidth, gVideoHeight, gBitRate / 1000000.0);
129f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
130f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
1311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<AMessage> format = new AMessage;
1321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("width", gVideoWidth);
1331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("height", gVideoHeight);
1341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setString("mime", "video/avc");
1351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
1361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("bitrate", gBitRate);
1371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setFloat("frame-rate", displayFps);
1381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("i-frame-interval", 10);
1391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    /// MediaCodec
1411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<ALooper> looper = new ALooper;
1421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    looper->setName("screenrecord_looper");
1431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    looper->start();
1441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Creating codec");
1451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true);
1461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = codec->configure(format, NULL, NULL,
1471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            MediaCodec::CONFIGURE_FLAG_ENCODE);
1481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
1491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err);
1501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Creating buffer producer");
1541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IGraphicBufferProducer> bufferProducer;
1551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = codec->createInputSurface(&bufferProducer);
1561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
1571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr,
1581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            "ERROR: unable to create encoder input surface (err=%d)\n", err);
1591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Starting codec");
1631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = codec->start();
1641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
1651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err);
1661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
169f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    ALOGV("Codec prepared");
1701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pCodec = codec;
1711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pBufferProducer = bufferProducer;
1721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return 0;
1731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
1741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
1761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures the virtual display.  When this completes, virtual display
1771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * frames will start being sent to the encoder's surface.
1781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
1791f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
1801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        const sp<IGraphicBufferProducer>& bufferProducer,
1811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sp<IBinder>* pDisplayHandle) {
1821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
1831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Set the region of the layer stack we're interested in, which in our
1851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // case is "all of it".  If the app is rotated (so that the width of the
1861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // app is based on the height of the display), reverse width/height.
187f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation);
1881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t sourceWidth, sourceHeight;
1891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (!deviceRotated) {
1901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceWidth = mainDpyInfo.w;
1911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceHeight = mainDpyInfo.h;
1921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    } else {
1931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        ALOGV("using rotated width/height");
1941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceHeight = mainDpyInfo.w;
1951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceWidth = mainDpyInfo.h;
1961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    Rect layerStackRect(sourceWidth, sourceHeight);
1981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // We need to preserve the aspect ratio of the display.
2001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    float displayAspect = (float) sourceHeight / (float) sourceWidth;
2011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Set the way we map the output onto the display surface (which will
2041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // be e.g. 1280x720 for a 720p video).  The rect is interpreted
2051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // post-rotation, so if the display is rotated 90 degrees we need to
2061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // "pre-rotate" it by flipping width/height, so that the orientation
2071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // adjustment changes it back.
2081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    //
2091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // We might want to encode a portrait display as landscape to use more
2101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // of the screen real estate.  (If players respect a 90-degree rotation
2111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // hint, we can essentially get a 720x1280 video instead of 1280x720.)
2121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // In that case, we swap the configured video width/height and then
2131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // supply a rotation value to the display projection.
2141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t videoWidth, videoHeight;
2151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t outWidth, outHeight;
2161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (!gRotate) {
2171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoWidth = gVideoWidth;
2181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoHeight = gVideoHeight;
2191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    } else {
2201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoWidth = gVideoHeight;
2211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoHeight = gVideoWidth;
2221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (videoHeight > (uint32_t)(videoWidth * displayAspect)) {
2241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // limited by narrow width; reduce height
2251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outWidth = videoWidth;
2261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outHeight = (uint32_t)(videoWidth * displayAspect);
2271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    } else {
2281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // limited by short height; restrict width
2291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outHeight = videoHeight;
2301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outWidth = (uint32_t)(videoHeight / displayAspect);
2311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t offX, offY;
2331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    offX = (videoWidth - outWidth) / 2;
2341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    offY = (videoHeight - outHeight) / 2;
2351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    Rect displayRect(offX, offY, offX + outWidth, offY + outHeight);
2361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
2381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        if (gRotate) {
2391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            printf("Rotated content area is %ux%u at offset x=%d y=%d\n",
2401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    outHeight, outWidth, offY, offX);
2411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        } else {
2421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            printf("Content area is %ux%u at offset x=%d y=%d\n",
2431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    outWidth, outHeight, offX, offY);
2441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
2451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
2491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            String8("ScreenRecorder"), false /* secure */);
2501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::openGlobalTransaction();
2521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
2531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::setDisplayProjection(dpy,
2541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
2551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            layerStackRect, displayRect);
2561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::setDisplayLayerStack(dpy, 0);    // default stack
2571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::closeGlobalTransaction();
2581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pDisplayHandle = dpy;
2601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return NO_ERROR;
2621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
2631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
2651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Runs the MediaCodec encoder, sending the output to the MediaMuxer.  The
2661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * input frames are coming from the virtual display as fast as SurfaceFlinger
2671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * wants to send them.
2681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
2691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * The muxer must *not* have been started before calling.
2701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
2711f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t runEncoder(const sp<MediaCodec>& encoder,
2721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        const sp<MediaMuxer>& muxer) {
2731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    static int kTimeout = 250000;   // be responsive on signal
2741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
2751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ssize_t trackIdx = -1;
2761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t debugNumFrames = 0;
2771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    time_t debugStartWhen = time(NULL);
2781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    Vector<sp<ABuffer> > buffers;
2801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = encoder->getOutputBuffers(&buffers);
2811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
2821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Unable to get output buffers (err=%d)\n", err);
2831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
2841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // This is set by the signal handler.
2871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    gStopRequested = false;
2881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Run until we're signaled.
2901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    while (!gStopRequested) {
2911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        size_t bufIndex, offset, size;
2921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        int64_t ptsUsec;
2931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        uint32_t flags;
2941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        ALOGV("Calling dequeueOutputBuffer");
2951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
2961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                &flags, kTimeout);
2971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        ALOGV("dequeueOutputBuffer returned %d", err);
2981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        switch (err) {
2991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case NO_ERROR:
3001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            // got a buffer
3011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
3021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // ignore this -- we passed the CSD into MediaMuxer when
3031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // we got the format change notification
3041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGV("Got codec config buffer (%u bytes); ignoring", size);
3051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                size = 0;
3061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (size != 0) {
3081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGV("Got data in buffer %d, size=%d, pts=%lld",
3091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        bufIndex, size, ptsUsec);
3101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                CHECK(trackIdx != -1);
3111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
312f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                // If the virtual display isn't providing us with timestamps,
313f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                // use the current time.
314f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                if (ptsUsec == 0) {
315f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                    ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000;
316f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                }
317f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
3181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // The MediaMuxer docs are unclear, but it appears that we
3191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // need to pass either the full set of BufferInfo flags, or
3201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // (flags & BUFFER_FLAG_SYNCFRAME).
3211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
3221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        ptsUsec, flags);
3231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                if (err != NO_ERROR) {
3241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    fprintf(stderr, "Failed writing data to muxer (err=%d)\n",
3251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                            err);
3261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    return err;
3271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                }
3281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                debugNumFrames++;
3291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            err = encoder->releaseOutputBuffer(bufIndex);
3311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (err != NO_ERROR) {
3321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr, "Unable to release output buffer (err=%d)\n",
3331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        err);
3341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return err;
3351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) {
3371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // Not expecting EOS from SurfaceFlinger.  Go with it.
3381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGD("Received end-of-stream");
3391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                gStopRequested = false;
3401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
3421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case -EAGAIN:                       // INFO_TRY_AGAIN_LATER
3431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            // not expected with infinite timeout
3441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ALOGV("Got -EAGAIN, looping");
3451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
3461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case INFO_FORMAT_CHANGED:           // INFO_OUTPUT_FORMAT_CHANGED
3471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            {
3481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // format includes CSD, which we must provide to muxer
3491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGV("Encoder format changed");
3501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                sp<AMessage> newFormat;
3511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                encoder->getOutputFormat(&newFormat);
3521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                trackIdx = muxer->addTrack(newFormat);
3531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGV("Starting muxer");
3541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                err = muxer->start();
3551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                if (err != NO_ERROR) {
3561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
3571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    return err;
3581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                }
3591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
3611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case INFO_OUTPUT_BUFFERS_CHANGED:   // INFO_OUTPUT_BUFFERS_CHANGED
3621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            // not expected for an encoder; handle it anyway
3631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ALOGV("Encoder buffers changed");
3641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            err = encoder->getOutputBuffers(&buffers);
3651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (err != NO_ERROR) {
3661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr,
3671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        "Unable to get new output buffers (err=%d)\n", err);
3681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
3701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        default:
3711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ALOGW("Got weird result %d from dequeueOutputBuffer", err);
3721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            return err;
3731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
3741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
3751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Encoder stopping (req=%d)", gStopRequested);
3771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
3781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        printf("Encoder stopping; recorded %u frames in %ld seconds\n",
3791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                debugNumFrames, time(NULL) - debugStartWhen);
3801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
3811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return NO_ERROR;
3821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
3831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
3851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Main "do work" method.
3861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
3871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures codec, muxer, and virtual display, then starts moving bits
3881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * around.
3891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
3901f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t recordScreen(const char* fileName) {
3911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
3921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure signal handler.
3941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = configureSignals();
3951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) return err;
3961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Start Binder thread pool.  MediaCodec needs to be able to receive
3981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // messages from mediaserver.
3991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<ProcessState> self = ProcessState::self();
4001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    self->startThreadPool();
4011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Get main display parameters.
4031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
4041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ISurfaceComposer::eDisplayIdMain);
4051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    DisplayInfo mainDpyInfo;
4061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
4071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
4081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "ERROR: unable to get display characteristics\n");
4091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
4101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
4121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
4131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
4141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                mainDpyInfo.orientation);
4151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
417f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    bool rotated = isDeviceRotated(mainDpyInfo.orientation);
418f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (gVideoWidth == 0) {
419f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w;
420f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
421f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (gVideoHeight == 0) {
422f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h;
423f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
424f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
4251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure and start the encoder.
4261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<MediaCodec> encoder;
4271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IGraphicBufferProducer> bufferProducer;
4281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
429f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (err != NO_ERROR && !gSizeSpecified) {
430f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        ALOGV("Retrying with 720p");
431f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        if (gVideoWidth != 1280 && gVideoHeight != 720) {
432f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            fprintf(stderr, "WARNING: failed at %dx%d, retrying at 720p\n",
433f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                    gVideoWidth, gVideoHeight);
434f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            gVideoWidth = 1280;
435f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            gVideoHeight = 720;
436f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
437f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        }
438f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
439f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (err != NO_ERROR) {
440f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        return err;
441f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
4421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure virtual display.
4441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IBinder> dpy;
4451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
4461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) return err;
4471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure, but do not start, muxer.
4491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<MediaMuxer> muxer = new MediaMuxer(fileName,
4501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            MediaMuxer::OUTPUT_FORMAT_MPEG_4);
4511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gRotate) {
4521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        muxer->setOrientationHint(90);
4531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Main encoder loop.
4561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = runEncoder(encoder, muxer);
4571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) return err;
4581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
4601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        printf("Stopping encoder and muxer\n");
4611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4632533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden    // Shut everything down, starting with the producer side.
4641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    bufferProducer = NULL;
4652533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden    SurfaceComposerClient::destroyDisplay(dpy);
4661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    encoder->stop();
4681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    muxer->stop();
4691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    encoder->release();
4701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return 0;
4721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
4731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
4751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses a string of the form "1280x720".
4761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
4771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Returns true on success.
4781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
4791f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth,
4801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        uint32_t* pHeight) {
4811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    long width, height;
4821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    char* end;
4831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Must specify base 10, or "0x0" gets parsed differently.
4851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    width = strtol(widthHeight, &end, 10);
4861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (end == widthHeight || *end != 'x' || *(end+1) == '\0') {
4871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // invalid chars in width, or missing 'x', or missing height
4881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return false;
4891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    height = strtol(end + 1, &end, 10);
4911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (*end != '\0') {
4921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // invalid chars in height
4931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return false;
4941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pWidth = width;
4971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pHeight = height;
4981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return true;
4991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
5001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
5021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Dumps usage on stderr.
5031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
5041f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void usage() {
5051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    fprintf(stderr,
5061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "Usage: screenrecord [options] <filename>\n"
5071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "\n"
508f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        "Records the device's display to a .mp4 file.\n"
509f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        "\n"
5101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "Options:\n"
5111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--size WIDTHxHEIGHT\n"
5121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "    Set the video size, e.g. \"1280x720\".  For best results, use\n"
5131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "    a size supported by the AVC encoder.\n"
5141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--bit-rate RATE\n"
5151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "    Set the video bit rate, in megabits per second.  Default 4Mbps.\n"
5161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--rotate\n"
517f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        "    Rotate the output 90 degrees.\n"
5181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--verbose\n"
5191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "    Display interesting information on stdout.\n"
5201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--help\n"
5211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "    Show this message.\n"
5221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "\n"
5231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "Recording continues until Ctrl-C is hit.\n"
5241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "\n"
5251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        );
5261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
5271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
5291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses args and kicks things off.
5301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
5311f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenint main(int argc, char* const argv[]) {
5321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    static const struct option longOptions[] = {
5331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "help",       no_argument,        NULL, 'h' },
5341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "verbose",    no_argument,        NULL, 'v' },
5351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "size",       required_argument,  NULL, 's' },
5361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "bit-rate",   required_argument,  NULL, 'b' },
5371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "rotate",     no_argument,        NULL, 'r' },
5381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { NULL,         0,                  NULL, 0 }
5391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    };
5401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    while (true) {
5421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        int optionIndex = 0;
5431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
5441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        if (ic == -1) {
5451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
5461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
5471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        switch (ic) {
5491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'h':
5501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            usage();
5511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            return 0;
5521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'v':
5531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gVerbose = true;
5541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
5551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 's':
5561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) {
5571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr, "Invalid size '%s', must be width x height\n",
5581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        optarg);
5591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return 2;
5601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
5611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (gVideoWidth == 0 || gVideoHeight == 0) {
5621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr,
5631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    "Invalid size %ux%u, width and height may not be zero\n",
5641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    gVideoWidth, gVideoHeight);
5651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return 2;
5661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
567f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            gSizeSpecified = true;
5681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
5691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'b':
5701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gBitRate = atoi(optarg);
5711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) {
5721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr,
5731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        "Bit rate %dbps outside acceptable range [%d,%d]\n",
5741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        gBitRate, kMinBitRate, kMaxBitRate);
5751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return 2;
5761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
5771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
5781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'r':
5791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gRotate = true;
5801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
5811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        default:
5821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (ic != '?') {
5831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
5841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
5851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            return 2;
5861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
5871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
5881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (optind != argc - 1) {
5901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Must specify output file (see --help).\n");
5911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return 2;
5921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
5931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err = recordScreen(argv[optind]);
5951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGD(err == NO_ERROR ? "success" : "failed");
5961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return (int) err;
5971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
598