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>
242c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden#include <utils/Timers.h>
251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/Surface.h>
271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/SurfaceComposerClient.h>
281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/ISurfaceComposer.h>
291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <ui/DisplayInfo.h>
301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/openmax/OMX_IVCommon.h>
311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ABuffer.h>
321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ADebug.h>
331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/AMessage.h>
341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaCodec.h>
351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaErrors.h>
361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaMuxer.h>
371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/ICrypto.h>
381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3948326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden#include <stdlib.h>
40f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden#include <unistd.h>
4148326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden#include <string.h>
421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <stdio.h>
4346052913f307b1561f1661bb776fa29c0775758cAndy McFadden#include <fcntl.h>
441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <signal.h>
451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <getopt.h>
46f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden#include <sys/wait.h>
471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
481f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenusing namespace android;
491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
502c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMinBitRate = 100000;         // 0.1Mbps
512c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMaxBitRate = 100 * 1000000;  // 100Mbps
522c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMaxTimeLimitSec = 180;       // 3 minutes
532c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kFallbackWidth = 1280;        // 720p
542c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kFallbackHeight = 720;
552c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden
561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Command-line parameters.
571f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gVerbose = false;               // chatty on stdout
581f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gRotate = false;                // rotate 90 degrees
59f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool gSizeSpecified = false;         // was size explicitly requested?
60f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoWidth = 0;            // default width+height
61f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoHeight = 0;
621f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic uint32_t gBitRate = 4000000;         // 4Mbps
632c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic uint32_t gTimeLimitSec = kMaxTimeLimitSec;
641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Set by signal handler to stop recording.
661f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gStopRequested;
671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Previous signal handler state, restored after first hit.
691f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionINT;
701f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionHUP;
711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Catch keyboard interrupt signals.  On receipt, the "stop requested"
751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * flag is raised, and the original handler is restored (so that, if
761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * we get stuck finishing, a second Ctrl-C will kill the process).
771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
781f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void signalCatcher(int signum)
791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{
801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    gStopRequested = true;
811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    switch (signum) {
821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    case SIGINT:
831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    case SIGHUP:
842c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        sigaction(SIGINT, &gOrigSigactionINT, NULL);
851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sigaction(SIGHUP, &gOrigSigactionHUP, NULL);
861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        break;
871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    default:
881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        abort();
891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        break;
901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures signal handlers.  The previous handlers are saved.
951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * If the command is run from an interactive adb shell, we get SIGINT
971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * when Ctrl-C is hit.  If we're run from the host, the local adb process
981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * gets the signal, and we get a SIGHUP when the terminal disconnects.
991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
1001f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t configureSignals()
1011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{
1021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    struct sigaction act;
1031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    memset(&act, 0, sizeof(act));
1041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    act.sa_handler = signalCatcher;
1051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) {
1061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        status_t err = -errno;
1071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Unable to configure SIGINT handler: %s\n",
1081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                strerror(errno));
1091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) {
1121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        status_t err = -errno;
1131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Unable to configure SIGHUP handler: %s\n",
1141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                strerror(errno));
1151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return NO_ERROR;
1181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
1191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
121f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden * Returns "true" if the device is rotated 90 degrees.
122f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden */
123f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool isDeviceRotated(int orientation) {
124f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    return orientation != DISPLAY_ORIENTATION_0 &&
125f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            orientation != DISPLAY_ORIENTATION_180;
126f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden}
127f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
128f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden/*
1291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures and starts the MediaCodec encoder.  Obtains an input surface
1301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * from the codec.
1311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
1321f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec,
1331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sp<IGraphicBufferProducer>* pBufferProducer) {
1341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
1351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
136f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (gVerbose) {
137f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        printf("Configuring recorder for %dx%d video at %.2fMbps\n",
138f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                gVideoWidth, gVideoHeight, gBitRate / 1000000.0);
139f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
140f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
1411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<AMessage> format = new AMessage;
1421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("width", gVideoWidth);
1431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("height", gVideoHeight);
1441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setString("mime", "video/avc");
1451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
1461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("bitrate", gBitRate);
1471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setFloat("frame-rate", displayFps);
1481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("i-frame-interval", 10);
1491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<ALooper> looper = new ALooper;
1511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    looper->setName("screenrecord_looper");
1521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    looper->start();
1531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Creating codec");
1541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true);
155a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden    if (codec == NULL) {
156a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden        fprintf(stderr, "ERROR: unable to create video/avc codec instance\n");
157a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden        return UNKNOWN_ERROR;
158a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden    }
1591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = codec->configure(format, NULL, NULL,
1601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            MediaCodec::CONFIGURE_FLAG_ENCODE);
1611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
162e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        codec->release();
163e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        codec.clear();
164e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber
1651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err);
1661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Creating buffer producer");
1701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IGraphicBufferProducer> bufferProducer;
1711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = codec->createInputSurface(&bufferProducer);
1721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
173e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        codec->release();
174e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        codec.clear();
175e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber
1761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr,
1771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            "ERROR: unable to create encoder input surface (err=%d)\n", err);
1781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Starting codec");
1821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = codec->start();
1831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
184e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        codec->release();
185e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        codec.clear();
186e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber
1871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err);
1881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
191f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    ALOGV("Codec prepared");
1921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pCodec = codec;
1931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pBufferProducer = bufferProducer;
1941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return 0;
1951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
1961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
1981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures the virtual display.  When this completes, virtual display
1991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * frames will start being sent to the encoder's surface.
2001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
2011f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
2021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        const sp<IGraphicBufferProducer>& bufferProducer,
2031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sp<IBinder>* pDisplayHandle) {
2041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
2051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Set the region of the layer stack we're interested in, which in our
2071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // case is "all of it".  If the app is rotated (so that the width of the
2081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // app is based on the height of the display), reverse width/height.
209f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation);
2101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t sourceWidth, sourceHeight;
2111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (!deviceRotated) {
2121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceWidth = mainDpyInfo.w;
2131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceHeight = mainDpyInfo.h;
2141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    } else {
2151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        ALOGV("using rotated width/height");
2161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceHeight = mainDpyInfo.w;
2171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceWidth = mainDpyInfo.h;
2181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    Rect layerStackRect(sourceWidth, sourceHeight);
2201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // We need to preserve the aspect ratio of the display.
2221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    float displayAspect = (float) sourceHeight / (float) sourceWidth;
2231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Set the way we map the output onto the display surface (which will
2261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // be e.g. 1280x720 for a 720p video).  The rect is interpreted
2271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // post-rotation, so if the display is rotated 90 degrees we need to
2281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // "pre-rotate" it by flipping width/height, so that the orientation
2291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // adjustment changes it back.
2301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    //
2311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // We might want to encode a portrait display as landscape to use more
2321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // of the screen real estate.  (If players respect a 90-degree rotation
2331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // hint, we can essentially get a 720x1280 video instead of 1280x720.)
2341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // In that case, we swap the configured video width/height and then
2351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // supply a rotation value to the display projection.
2361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t videoWidth, videoHeight;
2371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t outWidth, outHeight;
2381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (!gRotate) {
2391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoWidth = gVideoWidth;
2401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoHeight = gVideoHeight;
2411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    } else {
2421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoWidth = gVideoHeight;
2431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoHeight = gVideoWidth;
2441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (videoHeight > (uint32_t)(videoWidth * displayAspect)) {
2461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // limited by narrow width; reduce height
2471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outWidth = videoWidth;
2481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outHeight = (uint32_t)(videoWidth * displayAspect);
2491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    } else {
2501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // limited by short height; restrict width
2511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outHeight = videoHeight;
2521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outWidth = (uint32_t)(videoHeight / displayAspect);
2531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t offX, offY;
2551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    offX = (videoWidth - outWidth) / 2;
2561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    offY = (videoHeight - outHeight) / 2;
2571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    Rect displayRect(offX, offY, offX + outWidth, offY + outHeight);
2581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
2601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        if (gRotate) {
2611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            printf("Rotated content area is %ux%u at offset x=%d y=%d\n",
2621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    outHeight, outWidth, offY, offX);
2631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        } else {
2641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            printf("Content area is %ux%u at offset x=%d y=%d\n",
2651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    outWidth, outHeight, offX, offY);
2661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
2671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
2711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            String8("ScreenRecorder"), false /* secure */);
2721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::openGlobalTransaction();
2741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
2751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::setDisplayProjection(dpy,
2761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
2771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            layerStackRect, displayRect);
2781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::setDisplayLayerStack(dpy, 0);    // default stack
2791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::closeGlobalTransaction();
2801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pDisplayHandle = dpy;
2821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return NO_ERROR;
2841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
2851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
2871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Runs the MediaCodec encoder, sending the output to the MediaMuxer.  The
2881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * input frames are coming from the virtual display as fast as SurfaceFlinger
2891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * wants to send them.
2901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
2911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * The muxer must *not* have been started before calling.
2921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
2931f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t runEncoder(const sp<MediaCodec>& encoder,
2941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        const sp<MediaMuxer>& muxer) {
2951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    static int kTimeout = 250000;   // be responsive on signal
2961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
2971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ssize_t trackIdx = -1;
2981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t debugNumFrames = 0;
2992c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden    int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC);
3002c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden    int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
3011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    Vector<sp<ABuffer> > buffers;
3031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = encoder->getOutputBuffers(&buffers);
3041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
3051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Unable to get output buffers (err=%d)\n", err);
3061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
3071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
3081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // This is set by the signal handler.
3101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    gStopRequested = false;
3111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Run until we're signaled.
3131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    while (!gStopRequested) {
3141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        size_t bufIndex, offset, size;
3151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        int64_t ptsUsec;
3161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        uint32_t flags;
3172c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden
3182c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) {
3192c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            if (gVerbose) {
3202c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                printf("Time limit reached\n");
3212c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            }
3222c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            break;
3232c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        }
3242c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden
3251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        ALOGV("Calling dequeueOutputBuffer");
3261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
3271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                &flags, kTimeout);
3281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        ALOGV("dequeueOutputBuffer returned %d", err);
3291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        switch (err) {
3301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case NO_ERROR:
3311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            // got a buffer
3321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
3331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // ignore this -- we passed the CSD into MediaMuxer when
3341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // we got the format change notification
3351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGV("Got codec config buffer (%u bytes); ignoring", size);
3361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                size = 0;
3371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (size != 0) {
3391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGV("Got data in buffer %d, size=%d, pts=%lld",
3401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        bufIndex, size, ptsUsec);
3411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                CHECK(trackIdx != -1);
3421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
343f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                // If the virtual display isn't providing us with timestamps,
344f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                // use the current time.
345f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                if (ptsUsec == 0) {
346f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                    ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000;
347f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                }
348f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
3491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // The MediaMuxer docs are unclear, but it appears that we
3501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // need to pass either the full set of BufferInfo flags, or
3511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // (flags & BUFFER_FLAG_SYNCFRAME).
3521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
3531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        ptsUsec, flags);
3541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                if (err != NO_ERROR) {
3551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    fprintf(stderr, "Failed writing data to muxer (err=%d)\n",
3561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                            err);
3571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    return err;
3581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                }
3591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                debugNumFrames++;
3601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            err = encoder->releaseOutputBuffer(bufIndex);
3621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (err != NO_ERROR) {
3631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr, "Unable to release output buffer (err=%d)\n",
3641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        err);
3651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return err;
3661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) {
3681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // Not expecting EOS from SurfaceFlinger.  Go with it.
3691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGD("Received end-of-stream");
3701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                gStopRequested = false;
3711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
3731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case -EAGAIN:                       // INFO_TRY_AGAIN_LATER
3741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ALOGV("Got -EAGAIN, looping");
3751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
3761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case INFO_FORMAT_CHANGED:           // INFO_OUTPUT_FORMAT_CHANGED
3771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            {
3781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // format includes CSD, which we must provide to muxer
3791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGV("Encoder format changed");
3801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                sp<AMessage> newFormat;
3811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                encoder->getOutputFormat(&newFormat);
3821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                trackIdx = muxer->addTrack(newFormat);
3831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGV("Starting muxer");
3841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                err = muxer->start();
3851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                if (err != NO_ERROR) {
3861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
3871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    return err;
3881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                }
3891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
3911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case INFO_OUTPUT_BUFFERS_CHANGED:   // INFO_OUTPUT_BUFFERS_CHANGED
3921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            // not expected for an encoder; handle it anyway
3931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ALOGV("Encoder buffers changed");
3941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            err = encoder->getOutputBuffers(&buffers);
3951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (err != NO_ERROR) {
3961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr,
3971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        "Unable to get new output buffers (err=%d)\n", err);
39848326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden                return err;
3991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
4001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
40148326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden        case INVALID_OPERATION:
40248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden            fprintf(stderr, "Request for encoder buffer failed\n");
40348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden            return err;
4041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        default:
40548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden            fprintf(stderr,
40648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden                    "Got weird result %d from dequeueOutputBuffer\n", err);
4071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            return err;
4081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
4091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Encoder stopping (req=%d)", gStopRequested);
4121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
4132c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        printf("Encoder stopping; recorded %u frames in %lld seconds\n",
4142c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                debugNumFrames,
4152c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                nanoseconds_to_seconds(systemTime(CLOCK_MONOTONIC) - startWhenNsec));
4161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return NO_ERROR;
4181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
4191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
4211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Main "do work" method.
4221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
4231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures codec, muxer, and virtual display, then starts moving bits
4241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * around.
4251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
4261f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t recordScreen(const char* fileName) {
4271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
4281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure signal handler.
4301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = configureSignals();
4311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) return err;
4321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Start Binder thread pool.  MediaCodec needs to be able to receive
4341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // messages from mediaserver.
4351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<ProcessState> self = ProcessState::self();
4361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    self->startThreadPool();
4371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Get main display parameters.
4391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
4401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ISurfaceComposer::eDisplayIdMain);
4411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    DisplayInfo mainDpyInfo;
4421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
4431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
4441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "ERROR: unable to get display characteristics\n");
4451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
4461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
4481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
4491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
4501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                mainDpyInfo.orientation);
4511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
453f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    bool rotated = isDeviceRotated(mainDpyInfo.orientation);
454f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (gVideoWidth == 0) {
455f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w;
456f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
457f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (gVideoHeight == 0) {
458f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h;
459f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
460f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
4611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure and start the encoder.
4621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<MediaCodec> encoder;
4631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IGraphicBufferProducer> bufferProducer;
4641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
465e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber
466f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (err != NO_ERROR && !gSizeSpecified) {
467253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden        // fallback is defined for landscape; swap if we're in portrait
468253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden        bool needSwap = gVideoWidth < gVideoHeight;
469253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden        uint32_t newWidth = needSwap ? kFallbackHeight : kFallbackWidth;
470253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden        uint32_t newHeight = needSwap ? kFallbackWidth : kFallbackHeight;
471253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden        if (gVideoWidth != newWidth && gVideoHeight != newHeight) {
4722c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            ALOGV("Retrying with 720p");
473253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden            fprintf(stderr, "WARNING: failed at %dx%d, retrying at %dx%d\n",
474253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden                    gVideoWidth, gVideoHeight, newWidth, newHeight);
475253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden            gVideoWidth = newWidth;
476253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden            gVideoHeight = newHeight;
477f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
478f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        }
479f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
480f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (err != NO_ERROR) {
481f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        return err;
482f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
4831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure virtual display.
4851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IBinder> dpy;
4861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
487e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber    if (err != NO_ERROR) {
488e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        encoder->release();
489e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        encoder.clear();
490e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber
491e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        return err;
492e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber    }
4931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure, but do not start, muxer.
4951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<MediaMuxer> muxer = new MediaMuxer(fileName,
4961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            MediaMuxer::OUTPUT_FORMAT_MPEG_4);
4971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gRotate) {
4981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        muxer->setOrientationHint(90);
4991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
5001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Main encoder loop.
5021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = runEncoder(encoder, muxer);
503e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber    if (err != NO_ERROR) {
504e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        encoder->release();
505e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        encoder.clear();
506e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber
507e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        return err;
508e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber    }
5091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
5111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        printf("Stopping encoder and muxer\n");
5121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
5131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5142533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden    // Shut everything down, starting with the producer side.
5151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    bufferProducer = NULL;
5162533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden    SurfaceComposerClient::destroyDisplay(dpy);
5171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    encoder->stop();
5191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    muxer->stop();
5201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    encoder->release();
5211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return 0;
5231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
5241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
52648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden * Sends a broadcast to the media scanner to tell it about the new video.
527f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden *
528f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden * This is optional, but nice to have.
52948326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden */
53048326940f48390e79476e5ce7c2a18b8201cdafcAndy McFaddenstatic status_t notifyMediaScanner(const char* fileName) {
531f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden    pid_t pid = fork();
532f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden    if (pid < 0) {
533f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        int err = errno;
534f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        ALOGW("fork() failed: %s", strerror(err));
535f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        return -err;
536f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden    } else if (pid > 0) {
537f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        // parent; wait for the child, mostly to make the verbose-mode output
538f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        // look right, but also to check for and log failures
539f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        int status;
540f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
541f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        if (actualPid != pid) {
542f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            ALOGW("waitpid() returned %d (errno=%d)", actualPid, errno);
543f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        } else if (status != 0) {
544f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            ALOGW("'am broadcast' exited with status=%d", status);
545f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        } else {
546f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            ALOGV("'am broadcast' exited successfully");
547f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        }
548f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden    } else {
549f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        const char* kCommand = "/system/bin/am";
550f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden
551f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        // child; we're single-threaded, so okay to alloc
552f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        String8 fileUrl("file://");
553f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        fileUrl.append(fileName);
554f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        const char* const argv[] = {
555f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                kCommand,
556f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                "broadcast",
557f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                "-a",
558f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                "android.intent.action.MEDIA_SCANNER_SCAN_FILE",
559f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                "-d",
560f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                fileUrl.string(),
561f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                NULL
562f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        };
563f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        if (gVerbose) {
564f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            printf("Executing:");
565f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            for (int i = 0; argv[i] != NULL; i++) {
566f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                printf(" %s", argv[i]);
567f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            }
568f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            putchar('\n');
569f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        } else {
570f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            // non-verbose, suppress 'am' output
571f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            ALOGV("closing stdout/stderr in child");
572f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            int fd = open("/dev/null", O_WRONLY);
573f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            if (fd >= 0) {
574f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                dup2(fd, STDOUT_FILENO);
575f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                dup2(fd, STDERR_FILENO);
576f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                close(fd);
577f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            }
578f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        }
579f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        execv(kCommand, const_cast<char* const*>(argv));
580f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno));
581f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        exit(1);
58248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden    }
58348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden    return NO_ERROR;
58448326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden}
58548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden
58648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden/*
5871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses a string of the form "1280x720".
5881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
5891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Returns true on success.
5901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
5911f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth,
5921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        uint32_t* pHeight) {
5931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    long width, height;
5941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    char* end;
5951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Must specify base 10, or "0x0" gets parsed differently.
5971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    width = strtol(widthHeight, &end, 10);
5981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (end == widthHeight || *end != 'x' || *(end+1) == '\0') {
5991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // invalid chars in width, or missing 'x', or missing height
6001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return false;
6011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
6021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    height = strtol(end + 1, &end, 10);
6031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (*end != '\0') {
6041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // invalid chars in height
6051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return false;
6061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
6071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
6081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pWidth = width;
6091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pHeight = height;
6101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return true;
6111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
6121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
6131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
6141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Dumps usage on stderr.
6151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
6161f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void usage() {
6171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    fprintf(stderr,
6181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "Usage: screenrecord [options] <filename>\n"
6191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "\n"
620f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        "Records the device's display to a .mp4 file.\n"
621f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        "\n"
6221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "Options:\n"
6231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--size WIDTHxHEIGHT\n"
6242c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "    Set the video size, e.g. \"1280x720\".  Default is the device's main\n"
6252c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "    display resolution (if supported), 1280x720 if not.  For best results,\n"
6262c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "    use a size supported by the AVC encoder.\n"
6271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--bit-rate RATE\n"
6282c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "    Set the video bit rate, in megabits per second.  Default %dMbps.\n"
6292c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "--time-limit TIME\n"
6302c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "    Set the maximum recording time, in seconds.  Default / maximum is %d.\n"
6311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--rotate\n"
632f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        "    Rotate the output 90 degrees.\n"
6331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--verbose\n"
6341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "    Display interesting information on stdout.\n"
6351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--help\n"
6361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "    Show this message.\n"
6371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "\n"
6382c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "Recording continues until Ctrl-C is hit or the time limit is reached.\n"
6392c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "\n",
6402c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        gBitRate / 1000000, gTimeLimitSec
6411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        );
6421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
6431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
6441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
6451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses args and kicks things off.
6461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
6471f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenint main(int argc, char* const argv[]) {
6481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    static const struct option longOptions[] = {
6491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "help",       no_argument,        NULL, 'h' },
6501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "verbose",    no_argument,        NULL, 'v' },
6511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "size",       required_argument,  NULL, 's' },
6521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "bit-rate",   required_argument,  NULL, 'b' },
6532c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        { "time-limit", required_argument,  NULL, 't' },
6541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { "rotate",     no_argument,        NULL, 'r' },
6551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        { NULL,         0,                  NULL, 0 }
6561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    };
6571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
6581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    while (true) {
6591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        int optionIndex = 0;
6601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
6611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        if (ic == -1) {
6621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
6631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
6641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
6651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        switch (ic) {
6661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'h':
6671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            usage();
6681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            return 0;
6691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'v':
6701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gVerbose = true;
6711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
6721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 's':
6731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) {
6741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr, "Invalid size '%s', must be width x height\n",
6751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        optarg);
6761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return 2;
6771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
6781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (gVideoWidth == 0 || gVideoHeight == 0) {
6791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr,
6801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    "Invalid size %ux%u, width and height may not be zero\n",
6811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    gVideoWidth, gVideoHeight);
6821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return 2;
6831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
684f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            gSizeSpecified = true;
6851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
6861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'b':
6871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gBitRate = atoi(optarg);
6881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) {
6891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr,
6901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        "Bit rate %dbps outside acceptable range [%d,%d]\n",
6911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        gBitRate, kMinBitRate, kMaxBitRate);
6921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return 2;
6931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
6941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
6952c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        case 't':
6962c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            gTimeLimitSec = atoi(optarg);
6972c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            if (gTimeLimitSec == 0 || gTimeLimitSec > kMaxTimeLimitSec) {
6982c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                fprintf(stderr,
6992c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                        "Time limit %ds outside acceptable range [1,%d]\n",
7002c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                        gTimeLimitSec, kMaxTimeLimitSec);
7012c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                return 2;
7022c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            }
7032c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            break;
7041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'r':
7051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gRotate = true;
7061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
7071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        default:
7081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (ic != '?') {
7091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
7101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
7111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            return 2;
7121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
7131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
7141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
7151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (optind != argc - 1) {
7161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Must specify output file (see --help).\n");
7171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return 2;
7181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
7191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
72046052913f307b1561f1661bb776fa29c0775758cAndy McFadden    // MediaMuxer tries to create the file in the constructor, but we don't
72146052913f307b1561f1661bb776fa29c0775758cAndy McFadden    // learn about the failure until muxer.start(), which returns a generic
72246052913f307b1561f1661bb776fa29c0775758cAndy McFadden    // error code without logging anything.  We attempt to create the file
72346052913f307b1561f1661bb776fa29c0775758cAndy McFadden    // now for better diagnostics.
72446052913f307b1561f1661bb776fa29c0775758cAndy McFadden    const char* fileName = argv[optind];
72546052913f307b1561f1661bb776fa29c0775758cAndy McFadden    int fd = open(fileName, O_CREAT | O_RDWR, 0644);
72646052913f307b1561f1661bb776fa29c0775758cAndy McFadden    if (fd < 0) {
72746052913f307b1561f1661bb776fa29c0775758cAndy McFadden        fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno));
72846052913f307b1561f1661bb776fa29c0775758cAndy McFadden        return 1;
72946052913f307b1561f1661bb776fa29c0775758cAndy McFadden    }
73046052913f307b1561f1661bb776fa29c0775758cAndy McFadden    close(fd);
73146052913f307b1561f1661bb776fa29c0775758cAndy McFadden
73246052913f307b1561f1661bb776fa29c0775758cAndy McFadden    status_t err = recordScreen(fileName);
73348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden    if (err == NO_ERROR) {
73448326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden        // Try to notify the media scanner.  Not fatal if this fails.
73548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden        notifyMediaScanner(fileName);
73648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden    }
7371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGD(err == NO_ERROR ? "success" : "failed");
7381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return (int) err;
7391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
740