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
17884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <assert.h>
18884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <ctype.h>
19884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <fcntl.h>
20884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <inttypes.h>
21884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <getopt.h>
22884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <signal.h>
23884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <stdio.h>
24884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <stdlib.h>
25884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <string.h>
26884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <sys/wait.h>
27884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <termios.h>
28884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <unistd.h>
29884989c67081190ff864419328e9e81506db67caMark Salyzyn
301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#define LOG_TAG "ScreenRecord"
31aaa3f358410701710e31f31de62f0b4521989661Andy McFadden#define ATRACE_TAG ATRACE_TAG_GRAPHICS
321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden//#define LOG_NDEBUG 0
331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Log.h>
341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <binder/IPCThreadState.h>
361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Errors.h>
372c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden#include <utils/Timers.h>
38aaa3f358410701710e31f31de62f0b4521989661Andy McFadden#include <utils/Trace.h>
391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/Surface.h>
411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/SurfaceComposerClient.h>
421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/ISurfaceComposer.h>
431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <ui/DisplayInfo.h>
441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/openmax/OMX_IVCommon.h>
451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ABuffer.h>
461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/AMessage.h>
471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaCodec.h>
481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaErrors.h>
491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaMuxer.h>
501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/ICrypto.h>
511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
52aaa3f358410701710e31f31de62f0b4521989661Andy McFadden#include "screenrecord.h"
53aaa3f358410701710e31f31de62f0b4521989661Andy McFadden#include "Overlay.h"
5421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden#include "FrameOutput.h"
55aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
561f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenusing namespace android;
571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
582c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMinBitRate = 100000;         // 0.1Mbps
59aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic const uint32_t kMaxBitRate = 200 * 1000000;  // 200Mbps
602c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMaxTimeLimitSec = 180;       // 3 minutes
612c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kFallbackWidth = 1280;        // 720p
622c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kFallbackHeight = 720;
6321bde57f0099fed5cca78d9357571dc015a63227Andy McFaddenstatic const char* kMimeTypeAvc = "video/avc";
642c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden
651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Command-line parameters.
66aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gVerbose = false;           // chatty on stdout
67aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gRotate = false;            // rotate 90 degrees
6821bde57f0099fed5cca78d9357571dc015a63227Andy McFaddenstatic enum {
69e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby    FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES, FORMAT_RAW_FRAMES
7021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden} gOutputFormat = FORMAT_MP4;           // data format for output
71aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gSizeSpecified = false;     // was size explicitly requested?
72aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gWantInfoScreen = false;    // do we want initial info screen?
73aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gWantFrameTime = false;     // do we want times on each frame?
74aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic uint32_t gVideoWidth = 0;        // default width+height
75f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoHeight = 0;
76aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic uint32_t gBitRate = 4000000;     // 4Mbps
772c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic uint32_t gTimeLimitSec = kMaxTimeLimitSec;
781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Set by signal handler to stop recording.
80aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic volatile bool gStopRequested;
811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Previous signal handler state, restored after first hit.
831f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionINT;
841f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionHUP;
851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Catch keyboard interrupt signals.  On receipt, the "stop requested"
891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * flag is raised, and the original handler is restored (so that, if
901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * we get stuck finishing, a second Ctrl-C will kill the process).
911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
921f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void signalCatcher(int signum)
931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{
941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    gStopRequested = true;
951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    switch (signum) {
961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    case SIGINT:
971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    case SIGHUP:
982c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        sigaction(SIGINT, &gOrigSigactionINT, NULL);
991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sigaction(SIGHUP, &gOrigSigactionHUP, NULL);
1001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        break;
1011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    default:
1021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        abort();
1031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        break;
1041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
1061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
1081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures signal handlers.  The previous handlers are saved.
1091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
1101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * If the command is run from an interactive adb shell, we get SIGINT
1111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * when Ctrl-C is hit.  If we're run from the host, the local adb process
1121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * gets the signal, and we get a SIGHUP when the terminal disconnects.
1131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
114aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic status_t configureSignals() {
1151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    struct sigaction act;
1161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    memset(&act, 0, sizeof(act));
1171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    act.sa_handler = signalCatcher;
1181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) {
1191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        status_t err = -errno;
1201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Unable to configure SIGINT handler: %s\n",
1211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                strerror(errno));
1221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) {
1251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        status_t err = -errno;
1261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Unable to configure SIGHUP handler: %s\n",
1271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                strerror(errno));
1281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return NO_ERROR;
1311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
1321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
134f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden * Returns "true" if the device is rotated 90 degrees.
135f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden */
136f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool isDeviceRotated(int orientation) {
137f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    return orientation != DISPLAY_ORIENTATION_0 &&
138f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            orientation != DISPLAY_ORIENTATION_180;
139f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden}
140f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
141f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden/*
1421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures and starts the MediaCodec encoder.  Obtains an input surface
1431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * from the codec.
1441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
1451f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec,
1461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sp<IGraphicBufferProducer>* pBufferProducer) {
1471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
1481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
149f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (gVerbose) {
15021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        printf("Configuring recorder for %dx%d %s at %.2fMbps\n",
15121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                gVideoWidth, gVideoHeight, kMimeTypeAvc, gBitRate / 1000000.0);
152f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
153f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
1541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<AMessage> format = new AMessage;
1551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("width", gVideoWidth);
1561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("height", gVideoHeight);
15721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    format->setString("mime", kMimeTypeAvc);
1581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
1591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("bitrate", gBitRate);
1601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setFloat("frame-rate", displayFps);
1611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    format->setInt32("i-frame-interval", 10);
1621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<ALooper> looper = new ALooper;
1641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    looper->setName("screenrecord_looper");
1651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    looper->start();
1661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Creating codec");
16721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    sp<MediaCodec> codec = MediaCodec::CreateByType(looper, kMimeTypeAvc, true);
168a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden    if (codec == NULL) {
16921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        fprintf(stderr, "ERROR: unable to create %s codec instance\n",
17021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                kMimeTypeAvc);
171a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden        return UNKNOWN_ERROR;
172a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden    }
173aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
1741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = codec->configure(format, NULL, NULL,
1751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            MediaCodec::CONFIGURE_FLAG_ENCODE);
1761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
17721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        fprintf(stderr, "ERROR: unable to configure %s codec at %dx%d (err=%d)\n",
17821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                kMimeTypeAvc, gVideoWidth, gVideoHeight, err);
179aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        codec->release();
1801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
183aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    ALOGV("Creating encoder input surface");
1841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IGraphicBufferProducer> bufferProducer;
1851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = codec->createInputSurface(&bufferProducer);
1861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
1871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr,
1881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            "ERROR: unable to create encoder input surface (err=%d)\n", err);
189aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        codec->release();
1901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
1921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
1931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Starting codec");
1941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = codec->start();
1951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
1961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err);
197aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        codec->release();
1981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
1991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
201f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    ALOGV("Codec prepared");
2021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pCodec = codec;
2031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pBufferProducer = bufferProducer;
2041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return 0;
2051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
2061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
208aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * Sets the display projection, based on the display dimensions, video size,
209aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * and device orientation.
2101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
211aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic status_t setDisplayProjection(const sp<IBinder>& dpy,
212aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        const DisplayInfo& mainDpyInfo) {
2131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
2141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Set the region of the layer stack we're interested in, which in our
2161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // case is "all of it".  If the app is rotated (so that the width of the
2171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // app is based on the height of the display), reverse width/height.
218f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation);
2191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t sourceWidth, sourceHeight;
2201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (!deviceRotated) {
2211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceWidth = mainDpyInfo.w;
2221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceHeight = mainDpyInfo.h;
2231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    } else {
2241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        ALOGV("using rotated width/height");
2251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceHeight = mainDpyInfo.w;
2261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        sourceWidth = mainDpyInfo.h;
2271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    Rect layerStackRect(sourceWidth, sourceHeight);
2291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // We need to preserve the aspect ratio of the display.
2311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    float displayAspect = (float) sourceHeight / (float) sourceWidth;
2321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Set the way we map the output onto the display surface (which will
2351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // be e.g. 1280x720 for a 720p video).  The rect is interpreted
2361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // post-rotation, so if the display is rotated 90 degrees we need to
2371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // "pre-rotate" it by flipping width/height, so that the orientation
2381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // adjustment changes it back.
2391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    //
2401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // We might want to encode a portrait display as landscape to use more
2411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // of the screen real estate.  (If players respect a 90-degree rotation
2421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // hint, we can essentially get a 720x1280 video instead of 1280x720.)
2431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // In that case, we swap the configured video width/height and then
2441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // supply a rotation value to the display projection.
2451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t videoWidth, videoHeight;
2461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t outWidth, outHeight;
2471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (!gRotate) {
2481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoWidth = gVideoWidth;
2491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoHeight = gVideoHeight;
2501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    } else {
2511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoWidth = gVideoHeight;
2521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        videoHeight = gVideoWidth;
2531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (videoHeight > (uint32_t)(videoWidth * displayAspect)) {
2551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // limited by narrow width; reduce height
2561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outWidth = videoWidth;
2571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outHeight = (uint32_t)(videoWidth * displayAspect);
2581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    } else {
2591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // limited by short height; restrict width
2601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outHeight = videoHeight;
2611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        outWidth = (uint32_t)(videoHeight / displayAspect);
2621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t offX, offY;
2641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    offX = (videoWidth - outWidth) / 2;
2651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    offY = (videoHeight - outHeight) / 2;
2661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    Rect displayRect(offX, offY, offX + outWidth, offY + outHeight);
2671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
2691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        if (gRotate) {
2701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            printf("Rotated content area is %ux%u at offset x=%d y=%d\n",
2711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    outHeight, outWidth, offY, offX);
2721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        } else {
2731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            printf("Content area is %ux%u at offset x=%d y=%d\n",
2741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    outWidth, outHeight, offX, offY);
2751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
2761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
2771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
278aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    SurfaceComposerClient::setDisplayProjection(dpy,
279aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
280aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            layerStackRect, displayRect);
281aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    return NO_ERROR;
282aaa3f358410701710e31f31de62f0b4521989661Andy McFadden}
2831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
284aaa3f358410701710e31f31de62f0b4521989661Andy McFadden/*
285aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * Configures the virtual display.  When this completes, virtual display
286aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * frames will start arriving from the buffer producer.
287aaa3f358410701710e31f31de62f0b4521989661Andy McFadden */
288aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
289aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        const sp<IGraphicBufferProducer>& bufferProducer,
290aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        sp<IBinder>* pDisplayHandle) {
2911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
292aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            String8("ScreenRecorder"), false /*secure*/);
2931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
2941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::openGlobalTransaction();
2951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
296aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    setDisplayProjection(dpy, mainDpyInfo);
2971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::setDisplayLayerStack(dpy, 0);    // default stack
2981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    SurfaceComposerClient::closeGlobalTransaction();
2991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pDisplayHandle = dpy;
3011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return NO_ERROR;
3031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
3041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
3061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Runs the MediaCodec encoder, sending the output to the MediaMuxer.  The
3071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * input frames are coming from the virtual display as fast as SurfaceFlinger
3081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * wants to send them.
3091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
3102d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden * Exactly one of muxer or rawFp must be non-null.
3112d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden *
3121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * The muxer must *not* have been started before calling.
3131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
3141f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t runEncoder(const sp<MediaCodec>& encoder,
3152d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& mainDpy,
316aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        const sp<IBinder>& virtualDpy, uint8_t orientation) {
3171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    static int kTimeout = 250000;   // be responsive on signal
3181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
3191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ssize_t trackIdx = -1;
3201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    uint32_t debugNumFrames = 0;
3212c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden    int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC);
3222c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden    int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
323aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    DisplayInfo mainDpyInfo;
3241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3252d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    assert((rawFp == NULL && muxer != NULL) || (rawFp != NULL && muxer == NULL));
3262d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden
3271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    Vector<sp<ABuffer> > buffers;
3281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = encoder->getOutputBuffers(&buffers);
3291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
3301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Unable to get output buffers (err=%d)\n", err);
3311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
3321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
3331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // This is set by the signal handler.
3351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    gStopRequested = false;
3361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
3371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Run until we're signaled.
3381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    while (!gStopRequested) {
3391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        size_t bufIndex, offset, size;
3401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        int64_t ptsUsec;
3411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        uint32_t flags;
3422c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden
3432c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) {
3442c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            if (gVerbose) {
3452c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                printf("Time limit reached\n");
3462c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            }
3472c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            break;
3482c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        }
3492c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden
3501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        ALOGV("Calling dequeueOutputBuffer");
3511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
3521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                &flags, kTimeout);
3531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        ALOGV("dequeueOutputBuffer returned %d", err);
3541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        switch (err) {
3551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case NO_ERROR:
3561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            // got a buffer
3571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
358884989c67081190ff864419328e9e81506db67caMark Salyzyn                ALOGV("Got codec config buffer (%zu bytes)", size);
3592d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                if (muxer != NULL) {
3602d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // ignore this -- we passed the CSD into MediaMuxer when
3612d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // we got the format change notification
3622d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    size = 0;
3632d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                }
3641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
3651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (size != 0) {
366884989c67081190ff864419328e9e81506db67caMark Salyzyn                ALOGV("Got data in buffer %zu, size=%zu, pts=%" PRId64,
3671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        bufIndex, size, ptsUsec);
368aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
369aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                { // scope
370aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    ATRACE_NAME("orientation");
371aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    // Check orientation, update if it has changed.
372aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    //
373aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    // Polling for changes is inefficient and wrong, but the
374aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    // useful stuff is hard to get at without a Dalvik VM.
375aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    err = SurfaceComposerClient::getDisplayInfo(mainDpy,
376aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                            &mainDpyInfo);
377aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    if (err != NO_ERROR) {
378aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                        ALOGW("getDisplayInfo(main) failed: %d", err);
379aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    } else if (orientation != mainDpyInfo.orientation) {
380aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                        ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
381aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                        SurfaceComposerClient::openGlobalTransaction();
382aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                        setDisplayProjection(virtualDpy, mainDpyInfo);
383aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                        SurfaceComposerClient::closeGlobalTransaction();
384aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                        orientation = mainDpyInfo.orientation;
385aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    }
386aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                }
3871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
388f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                // If the virtual display isn't providing us with timestamps,
389aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                // use the current time.  This isn't great -- we could get
390aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                // decoded data in clusters -- but we're not expecting
391aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                // to hit this anyway.
392f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                if (ptsUsec == 0) {
393f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                    ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000;
394f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden                }
395f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
3962d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                if (muxer == NULL) {
3972d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    fwrite(buffers[bufIndex]->data(), 1, size, rawFp);
3982d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // Flush the data immediately in case we're streaming.
3992d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // We don't want to do this if all we've written is
4002d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // the SPS/PPS data because mplayer gets confused.
4012d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) == 0) {
4022d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                        fflush(rawFp);
4032d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    }
4042d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                } else {
4052d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // The MediaMuxer docs are unclear, but it appears that we
4062d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // need to pass either the full set of BufferInfo flags, or
4072d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // (flags & BUFFER_FLAG_SYNCFRAME).
4082d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    //
4092d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // If this blocks for too long we could drop frames.  We may
4102d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    // want to queue these up and do them on a different thread.
411aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    ATRACE_NAME("write sample");
4122d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    assert(trackIdx != -1);
413aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
414aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                            ptsUsec, flags);
415aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    if (err != NO_ERROR) {
416aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                        fprintf(stderr,
417aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                            "Failed writing data to muxer (err=%d)\n", err);
418aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                        return err;
419aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                    }
4201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                }
4211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                debugNumFrames++;
4221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
4231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            err = encoder->releaseOutputBuffer(bufIndex);
4241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (err != NO_ERROR) {
4251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr, "Unable to release output buffer (err=%d)\n",
4261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        err);
4271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return err;
4281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
4291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) {
4301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                // Not expecting EOS from SurfaceFlinger.  Go with it.
431aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                ALOGI("Received end-of-stream");
432aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                gStopRequested = true;
4331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
4341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
4351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case -EAGAIN:                       // INFO_TRY_AGAIN_LATER
4361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ALOGV("Got -EAGAIN, looping");
4371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
4381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case INFO_FORMAT_CHANGED:           // INFO_OUTPUT_FORMAT_CHANGED
4391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            {
440aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                // Format includes CSD, which we must provide to muxer.
4411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                ALOGV("Encoder format changed");
4421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                sp<AMessage> newFormat;
4431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                encoder->getOutputFormat(&newFormat);
4442d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                if (muxer != NULL) {
4452d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    trackIdx = muxer->addTrack(newFormat);
4462d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    ALOGV("Starting muxer");
4472d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    err = muxer->start();
4482d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    if (err != NO_ERROR) {
4492d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                        fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
4502d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                        return err;
4512d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                    }
4521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                }
4531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
4541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
4551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case INFO_OUTPUT_BUFFERS_CHANGED:   // INFO_OUTPUT_BUFFERS_CHANGED
456aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            // Not expected for an encoder; handle it anyway.
4571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ALOGV("Encoder buffers changed");
4581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            err = encoder->getOutputBuffers(&buffers);
4591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (err != NO_ERROR) {
4601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr,
4611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        "Unable to get new output buffers (err=%d)\n", err);
46248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden                return err;
4631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
4641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
46548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden        case INVALID_OPERATION:
466aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            ALOGW("dequeueOutputBuffer returned INVALID_OPERATION");
46748326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden            return err;
4681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        default:
46948326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden            fprintf(stderr,
47048326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden                    "Got weird result %d from dequeueOutputBuffer\n", err);
4711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            return err;
4721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
4731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGV("Encoder stopping (req=%d)", gStopRequested);
4761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
477884989c67081190ff864419328e9e81506db67caMark Salyzyn        printf("Encoder stopping; recorded %u frames in %" PRId64 " seconds\n",
478aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                debugNumFrames, nanoseconds_to_seconds(
479aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                        systemTime(CLOCK_MONOTONIC) - startWhenNsec));
4801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
4811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return NO_ERROR;
4821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
4831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
4841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
4852d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden * Raw H.264 byte stream output requested.  Send the output to stdout
4862d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden * if desired.  If the output is a tty, reconfigure it to avoid the
4872d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden * CRLF line termination that we see with "adb shell" commands.
4882d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden */
4892d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFaddenstatic FILE* prepareRawOutput(const char* fileName) {
4902d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    FILE* rawFp = NULL;
4912d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden
4922d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    if (strcmp(fileName, "-") == 0) {
4932d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        if (gVerbose) {
4942d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            fprintf(stderr, "ERROR: verbose output and '-' not compatible");
4952d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            return NULL;
4962d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        }
4972d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        rawFp = stdout;
4982d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    } else {
4992d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        rawFp = fopen(fileName, "w");
5002d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        if (rawFp == NULL) {
5012d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            fprintf(stderr, "fopen raw failed: %s\n", strerror(errno));
5022d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            return NULL;
5032d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        }
5042d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    }
5052d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden
5062d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    int fd = fileno(rawFp);
5072d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    if (isatty(fd)) {
5082d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        // best effort -- reconfigure tty for "raw"
5092d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        ALOGD("raw video output to tty (fd=%d)", fd);
5102d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        struct termios term;
5112d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        if (tcgetattr(fd, &term) == 0) {
5122d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            cfmakeraw(&term);
5132d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            if (tcsetattr(fd, TCSANOW, &term) == 0) {
5142d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden                ALOGD("tty successfully configured for raw");
5152d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            }
5162d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        }
5172d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    }
5182d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden
5192d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    return rawFp;
5202d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden}
5212d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden
5222d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden/*
52321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden * Main "do work" start point.
5241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
5251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures codec, muxer, and virtual display, then starts moving bits
5261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * around.
5271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
5281f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t recordScreen(const char* fileName) {
5291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    status_t err;
5301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure signal handler.
5321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = configureSignals();
5331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) return err;
5341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Start Binder thread pool.  MediaCodec needs to be able to receive
5361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // messages from mediaserver.
5371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<ProcessState> self = ProcessState::self();
5381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    self->startThreadPool();
5391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
5401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Get main display parameters.
5411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
5421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            ISurfaceComposer::eDisplayIdMain);
5431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    DisplayInfo mainDpyInfo;
5441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
5451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (err != NO_ERROR) {
5461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "ERROR: unable to get display characteristics\n");
5471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return err;
5481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
5491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (gVerbose) {
5501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
5511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
5521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                mainDpyInfo.orientation);
5531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
5541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
555f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    bool rotated = isDeviceRotated(mainDpyInfo.orientation);
556f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (gVideoWidth == 0) {
557f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w;
558f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
559f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    if (gVideoHeight == 0) {
560f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h;
561f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
562f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden
5631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure and start the encoder.
5641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<MediaCodec> encoder;
56521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    sp<FrameOutput> frameOutput;
566aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    sp<IGraphicBufferProducer> encoderInputSurface;
567e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby    if (gOutputFormat != FORMAT_FRAMES && gOutputFormat != FORMAT_RAW_FRAMES) {
56821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);
56921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden
57021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        if (err != NO_ERROR && !gSizeSpecified) {
57121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // fallback is defined for landscape; swap if we're in portrait
57221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            bool needSwap = gVideoWidth < gVideoHeight;
57321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            uint32_t newWidth = needSwap ? kFallbackHeight : kFallbackWidth;
57421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            uint32_t newHeight = needSwap ? kFallbackWidth : kFallbackHeight;
57521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            if (gVideoWidth != newWidth && gVideoHeight != newHeight) {
57621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                ALOGV("Retrying with 720p");
57721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                fprintf(stderr, "WARNING: failed at %dx%d, retrying at %dx%d\n",
57821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                        gVideoWidth, gVideoHeight, newWidth, newHeight);
57921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                gVideoWidth = newWidth;
58021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                gVideoHeight = newHeight;
58121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                err = prepareEncoder(mainDpyInfo.fps, &encoder,
58221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                        &encoderInputSurface);
58321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            }
584f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        }
58521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        if (err != NO_ERROR) return err;
586aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
58721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // From here on, we must explicitly release() the encoder before it goes
58821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // out of scope, or we will get an assertion failure from stagefright
58921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // later on in a different thread.
59021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    } else {
59121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // We're not using an encoder at all.  The "encoder input surface" we hand to
59221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // SurfaceFlinger will just feed directly to us.
59321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        frameOutput = new FrameOutput();
59421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        err = frameOutput->createInputSurface(gVideoWidth, gVideoHeight, &encoderInputSurface);
59521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        if (err != NO_ERROR) {
59621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            return err;
59721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        }
59821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    }
599aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
600aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    // Draw the "info" page by rendering a frame with GLES and sending
601aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    // it directly to the encoder.
602aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    // TODO: consider displaying this as a regular layer to avoid b/11697754
603aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    if (gWantInfoScreen) {
604aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        Overlay::drawInfoPage(encoderInputSurface);
605aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    }
606aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
607aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    // Configure optional overlay.
608aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    sp<IGraphicBufferProducer> bufferProducer;
6090c98f99cb8207ff5b08e33da4b7e024312c5d9c9Andy McFadden    sp<Overlay> overlay;
610aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    if (gWantFrameTime) {
611aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        // Send virtual display frames to an external texture.
6120c98f99cb8207ff5b08e33da4b7e024312c5d9c9Andy McFadden        overlay = new Overlay();
613aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        err = overlay->start(encoderInputSurface, &bufferProducer);
614aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        if (err != NO_ERROR) {
61521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            if (encoder != NULL) encoder->release();
616aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            return err;
617aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        }
618aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        if (gVerbose) {
619aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            printf("Bugreport overlay created\n");
620aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        }
621aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    } else {
622aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        // Use the encoder's input surface as the virtual display surface.
623aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        bufferProducer = encoderInputSurface;
624f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden    }
6251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
6261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Configure virtual display.
6271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    sp<IBinder> dpy;
6281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
629e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber    if (err != NO_ERROR) {
63021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        if (encoder != NULL) encoder->release();
631e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber        return err;
632e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber    }
6331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
6342d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    sp<MediaMuxer> muxer = NULL;
6352d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    FILE* rawFp = NULL;
63621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    switch (gOutputFormat) {
63721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        case FORMAT_MP4: {
63821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // Configure muxer.  We have to wait for the CSD blob from the encoder
63921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // before we can start it.
64021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            muxer = new MediaMuxer(fileName, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
64121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            if (gRotate) {
64221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                muxer->setOrientationHint(90);  // TODO: does this do anything?
64321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            }
64421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            break;
64521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        }
64621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        case FORMAT_H264:
647e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby        case FORMAT_FRAMES:
648e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby        case FORMAT_RAW_FRAMES: {
64921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            rawFp = prepareRawOutput(fileName);
65021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            if (rawFp == NULL) {
65121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                if (encoder != NULL) encoder->release();
65221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                return -1;
65321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            }
65421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            break;
65521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        }
65621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        default:
65721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            fprintf(stderr, "ERROR: unknown format %d\n", gOutputFormat);
65821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            abort();
65921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    }
66021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden
661e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby    if (gOutputFormat == FORMAT_FRAMES || gOutputFormat == FORMAT_RAW_FRAMES) {
66221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // TODO: if we want to make this a proper feature, we should output
66321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        //       an outer header with version info.  Right now we never change
66421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        //       the frame size or format, so we could conceivably just send
66521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        //       the current frame header once and then follow it with an
66621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        //       unbroken stream of data.
66721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden
66821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // Make the EGL context current again.  This gets unhooked if we're
66921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // using "--bugreport" mode.
67021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // TODO: figure out if we can eliminate this
67121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        frameOutput->prepareToCopy();
67221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden
67321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        while (!gStopRequested) {
67421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // Poll for frames, the same way we do for MediaCodec.  We do
67521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // all of the work on the main thread.
67621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            //
67721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // Ideally we'd sleep indefinitely and wake when the
67821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // stop was requested, but this will do for now.  (It almost
67921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // works because wait() wakes when a signal hits, but we
68021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // need to handle the edge cases.)
681e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby            bool rawFrames = gOutputFormat == FORMAT_RAW_FRAMES;
682e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby            err = frameOutput->copyFrame(rawFp, 250000, rawFrames);
68321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            if (err == ETIMEDOUT) {
68421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                err = NO_ERROR;
68521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            } else if (err != NO_ERROR) {
68621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                ALOGE("Got error %d from copyFrame()", err);
68721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                break;
68821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            }
6892d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        }
6902d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    } else {
69121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // Main encoder loop.
69221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        err = runEncoder(encoder, muxer, rawFp, mainDpy, dpy,
69321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                mainDpyInfo.orientation);
69421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        if (err != NO_ERROR) {
69521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            fprintf(stderr, "Encoder failed (err=%d)\n", err);
69621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            // fall through to cleanup
6972d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        }
6981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
69921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        if (gVerbose) {
70021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            printf("Stopping encoder and muxer\n");
70121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        }
7021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
7031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
7042533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden    // Shut everything down, starting with the producer side.
705aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    encoderInputSurface = NULL;
7062533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden    SurfaceComposerClient::destroyDisplay(dpy);
70721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    if (overlay != NULL) overlay->stop();
70821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    if (encoder != NULL) encoder->stop();
7092d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    if (muxer != NULL) {
7102d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        // If we don't stop muxer explicitly, i.e. let the destructor run,
7112d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        // it may hang (b/11050628).
7122d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        muxer->stop();
7132d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    } else if (rawFp != stdout) {
7142d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        fclose(rawFp);
7152d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden    }
71621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    if (encoder != NULL) encoder->release();
7171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
718aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    return err;
7191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
7201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
7211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
72248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden * Sends a broadcast to the media scanner to tell it about the new video.
723f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden *
724f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden * This is optional, but nice to have.
72548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden */
72648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFaddenstatic status_t notifyMediaScanner(const char* fileName) {
727aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    // need to do allocations before the fork()
728aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    String8 fileUrl("file://");
729aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    fileUrl.append(fileName);
730aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
731aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    const char* kCommand = "/system/bin/am";
732aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    const char* const argv[] = {
733aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            kCommand,
734aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            "broadcast",
735aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            "-a",
736aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            "android.intent.action.MEDIA_SCANNER_SCAN_FILE",
737aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            "-d",
738aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            fileUrl.string(),
739aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            NULL
740aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    };
741aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    if (gVerbose) {
742aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        printf("Executing:");
743aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        for (int i = 0; argv[i] != NULL; i++) {
744aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            printf(" %s", argv[i]);
745aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        }
746aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        putchar('\n');
747aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    }
748aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
749f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden    pid_t pid = fork();
750f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden    if (pid < 0) {
751f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        int err = errno;
752f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        ALOGW("fork() failed: %s", strerror(err));
753f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        return -err;
754f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden    } else if (pid > 0) {
755f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        // parent; wait for the child, mostly to make the verbose-mode output
756f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        // look right, but also to check for and log failures
757f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        int status;
758f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
759f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        if (actualPid != pid) {
760aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            ALOGW("waitpid(%d) returned %d (errno=%d)", pid, actualPid, errno);
761f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        } else if (status != 0) {
762f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            ALOGW("'am broadcast' exited with status=%d", status);
763f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        } else {
764f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            ALOGV("'am broadcast' exited successfully");
765f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        }
766f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden    } else {
767aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        if (!gVerbose) {
768f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            // non-verbose, suppress 'am' output
769f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            ALOGV("closing stdout/stderr in child");
770f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            int fd = open("/dev/null", O_WRONLY);
771f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            if (fd >= 0) {
772f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                dup2(fd, STDOUT_FILENO);
773f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                dup2(fd, STDERR_FILENO);
774f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden                close(fd);
775f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden            }
776f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        }
777f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        execv(kCommand, const_cast<char* const*>(argv));
778f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno));
779f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden        exit(1);
78048326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden    }
78148326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden    return NO_ERROR;
78248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden}
78348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden
78448326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden/*
7851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses a string of the form "1280x720".
7861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *
7871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Returns true on success.
7881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
7891f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth,
7901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        uint32_t* pHeight) {
7911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    long width, height;
7921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    char* end;
7931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
7941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    // Must specify base 10, or "0x0" gets parsed differently.
7951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    width = strtol(widthHeight, &end, 10);
7961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (end == widthHeight || *end != 'x' || *(end+1) == '\0') {
7971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // invalid chars in width, or missing 'x', or missing height
7981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return false;
7991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
8001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    height = strtol(end + 1, &end, 10);
8011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (*end != '\0') {
8021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        // invalid chars in height
8031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return false;
8041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
8051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
8061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pWidth = width;
8071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    *pHeight = height;
8081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return true;
8091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
8101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
8111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
812aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * Accepts a string with a bare number ("4000000") or with a single-character
813aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * unit ("4m").
814aaa3f358410701710e31f31de62f0b4521989661Andy McFadden *
815aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * Returns an error if parsing fails.
816aaa3f358410701710e31f31de62f0b4521989661Andy McFadden */
817aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic status_t parseValueWithUnit(const char* str, uint32_t* pValue) {
818aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    long value;
819aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    char* endptr;
820aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
821aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    value = strtol(str, &endptr, 10);
822aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    if (*endptr == '\0') {
823aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        // bare number
824aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        *pValue = value;
825aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        return NO_ERROR;
826aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    } else if (toupper(*endptr) == 'M' && *(endptr+1) == '\0') {
827aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        *pValue = value * 1000000;  // check for overflow?
828aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        return NO_ERROR;
829aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    } else {
830aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        fprintf(stderr, "Unrecognized value: %s\n", str);
831aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        return UNKNOWN_ERROR;
832aaa3f358410701710e31f31de62f0b4521989661Andy McFadden    }
833aaa3f358410701710e31f31de62f0b4521989661Andy McFadden}
834aaa3f358410701710e31f31de62f0b4521989661Andy McFadden
835aaa3f358410701710e31f31de62f0b4521989661Andy McFadden/*
8361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Dumps usage on stderr.
8371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
8381f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void usage() {
8391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    fprintf(stderr,
8401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "Usage: screenrecord [options] <filename>\n"
8411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "\n"
842aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        "Android screenrecord v%d.%d.  Records the device's display to a .mp4 file.\n"
843f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden        "\n"
8441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "Options:\n"
8451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--size WIDTHxHEIGHT\n"
8462c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "    Set the video size, e.g. \"1280x720\".  Default is the device's main\n"
8472c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "    display resolution (if supported), 1280x720 if not.  For best results,\n"
8482c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "    use a size supported by the AVC encoder.\n"
8491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--bit-rate RATE\n"
85096f2ead1ec99f6aaab876827a7c9985b039bf3c8Andy McFadden        "    Set the video bit rate, in bits per second.  Value may be specified as\n"
85196f2ead1ec99f6aaab876827a7c9985b039bf3c8Andy McFadden        "    bits or megabits, e.g. '4000000' is equivalent to '4M'.  Default %dMbps.\n"
852aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        "--bugreport\n"
853aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        "    Add additional information, such as a timestamp overlay, that is helpful\n"
854aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        "    in videos captured to illustrate bugs.\n"
8552c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "--time-limit TIME\n"
8562c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "    Set the maximum recording time, in seconds.  Default / maximum is %d.\n"
8571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--verbose\n"
8581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "    Display interesting information on stdout.\n"
8591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "--help\n"
8601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "    Show this message.\n"
8611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        "\n"
8622c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "Recording continues until Ctrl-C is hit or the time limit is reached.\n"
8632c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        "\n",
864aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        kVersionMajor, kVersionMinor, gBitRate / 1000000, gTimeLimitSec
8651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        );
8661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
8671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
8681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/*
8691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses args and kicks things off.
8701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */
8711f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenint main(int argc, char* const argv[]) {
8721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    static const struct option longOptions[] = {
873aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        { "help",               no_argument,        NULL, 'h' },
874aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        { "verbose",            no_argument,        NULL, 'v' },
875aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        { "size",               required_argument,  NULL, 's' },
876aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        { "bit-rate",           required_argument,  NULL, 'b' },
877aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        { "time-limit",         required_argument,  NULL, 't' },
87821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        { "bugreport",          no_argument,        NULL, 'u' },
87921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        // "unofficial" options
880aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        { "show-device-info",   no_argument,        NULL, 'i' },
881aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        { "show-frame-time",    no_argument,        NULL, 'f' },
882aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        { "rotate",             no_argument,        NULL, 'r' },
88321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        { "output-format",      required_argument,  NULL, 'o' },
884aaa3f358410701710e31f31de62f0b4521989661Andy McFadden        { NULL,                 0,                  NULL, 0 }
8851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    };
8861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
8871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    while (true) {
8881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        int optionIndex = 0;
8891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
8901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        if (ic == -1) {
8911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
8921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
8931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
8941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        switch (ic) {
8951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'h':
8961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            usage();
8971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            return 0;
8981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'v':
8991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gVerbose = true;
9001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
9011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 's':
9021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) {
9031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr, "Invalid size '%s', must be width x height\n",
9041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        optarg);
9051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return 2;
9061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
9071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (gVideoWidth == 0 || gVideoHeight == 0) {
9081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr,
9091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    "Invalid size %ux%u, width and height may not be zero\n",
9101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                    gVideoWidth, gVideoHeight);
9111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return 2;
9121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
913f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden            gSizeSpecified = true;
9141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
9151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'b':
916aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            if (parseValueWithUnit(optarg, &gBitRate) != NO_ERROR) {
917aaa3f358410701710e31f31de62f0b4521989661Andy McFadden                return 2;
918aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            }
9191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) {
9201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr,
9211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        "Bit rate %dbps outside acceptable range [%d,%d]\n",
9221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                        gBitRate, kMinBitRate, kMaxBitRate);
9231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                return 2;
9241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
9251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
9262c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden        case 't':
9272c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            gTimeLimitSec = atoi(optarg);
9282c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            if (gTimeLimitSec == 0 || gTimeLimitSec > kMaxTimeLimitSec) {
9292c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                fprintf(stderr,
9302c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                        "Time limit %ds outside acceptable range [1,%d]\n",
9312c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                        gTimeLimitSec, kMaxTimeLimitSec);
9322c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden                return 2;
9332c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            }
9342c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden            break;
93521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        case 'u':
936aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            gWantInfoScreen = true;
937aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            gWantFrameTime = true;
938aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            break;
93921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        case 'i':
940aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            gWantInfoScreen = true;
94121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            break;
94221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        case 'f':
943aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            gWantFrameTime = true;
944aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            break;
9451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        case 'r':
946aaa3f358410701710e31f31de62f0b4521989661Andy McFadden            // experimental feature
9471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            gRotate = true;
9481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            break;
94921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden        case 'o':
95021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            if (strcmp(optarg, "mp4") == 0) {
95121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                gOutputFormat = FORMAT_MP4;
95221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            } else if (strcmp(optarg, "h264") == 0) {
95321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                gOutputFormat = FORMAT_H264;
95421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            } else if (strcmp(optarg, "frames") == 0) {
95521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                gOutputFormat = FORMAT_FRAMES;
956e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby            } else if (strcmp(optarg, "raw-frames") == 0) {
957e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby                gOutputFormat = FORMAT_RAW_FRAMES;
95821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            } else {
95921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                fprintf(stderr, "Unknown format '%s'\n", optarg);
96021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden                return 2;
96121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden            }
9622d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            break;
9631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        default:
9641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            if (ic != '?') {
9651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden                fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
9661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            }
9671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden            return 2;
9681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        }
9691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
9701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
9711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    if (optind != argc - 1) {
9721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        fprintf(stderr, "Must specify output file (see --help).\n");
9731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden        return 2;
9741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    }
9751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden
97646052913f307b1561f1661bb776fa29c0775758cAndy McFadden    const char* fileName = argv[optind];
97721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden    if (gOutputFormat == FORMAT_MP4) {
9782d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        // MediaMuxer tries to create the file in the constructor, but we don't
9792d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        // learn about the failure until muxer.start(), which returns a generic
9802d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        // error code without logging anything.  We attempt to create the file
9812d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        // now for better diagnostics.
9822d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        int fd = open(fileName, O_CREAT | O_RDWR, 0644);
9832d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        if (fd < 0) {
9842d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno));
9852d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden            return 1;
9862d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        }
9872d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden        close(fd);
98846052913f307b1561f1661bb776fa29c0775758cAndy McFadden    }
98946052913f307b1561f1661bb776fa29c0775758cAndy McFadden
99046052913f307b1561f1661bb776fa29c0775758cAndy McFadden    status_t err = recordScreen(fileName);
99148326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden    if (err == NO_ERROR) {
99248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden        // Try to notify the media scanner.  Not fatal if this fails.
99348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden        notifyMediaScanner(fileName);
99448326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden    }
9951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    ALOGD(err == NO_ERROR ? "success" : "failed");
9961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden    return (int) err;
9971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden}
998