screenrecord.cpp revision 441e847feb0e055ecb004802802cea07782ab228
1/*
2 * Copyright 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "ScreenRecord"
18#define ATRACE_TAG ATRACE_TAG_GRAPHICS
19//#define LOG_NDEBUG 0
20#include <utils/Log.h>
21
22#include <binder/IPCThreadState.h>
23#include <utils/Errors.h>
24#include <utils/Timers.h>
25#include <utils/Trace.h>
26
27#include <gui/Surface.h>
28#include <gui/SurfaceComposerClient.h>
29#include <gui/ISurfaceComposer.h>
30#include <ui/DisplayInfo.h>
31#include <media/openmax/OMX_IVCommon.h>
32#include <media/stagefright/foundation/ABuffer.h>
33#include <media/stagefright/foundation/AMessage.h>
34#include <media/stagefright/MediaCodec.h>
35#include <media/stagefright/MediaErrors.h>
36#include <media/stagefright/MediaMuxer.h>
37#include <media/ICrypto.h>
38
39#include <stdlib.h>
40#include <unistd.h>
41#include <string.h>
42#include <stdio.h>
43#include <ctype.h>
44#include <fcntl.h>
45#include <signal.h>
46#include <getopt.h>
47#include <sys/wait.h>
48
49#include "screenrecord.h"
50#include "Overlay.h"
51
52using namespace android;
53
54static const uint32_t kMinBitRate = 100000;         // 0.1Mbps
55static const uint32_t kMaxBitRate = 200 * 1000000;  // 200Mbps
56static const uint32_t kMaxTimeLimitSec = 180;       // 3 minutes
57static const uint32_t kFallbackWidth = 1280;        // 720p
58static const uint32_t kFallbackHeight = 720;
59
60// Command-line parameters.
61static bool gVerbose = false;           // chatty on stdout
62static bool gRotate = false;            // rotate 90 degrees
63static bool gSizeSpecified = false;     // was size explicitly requested?
64static bool gWantInfoScreen = false;    // do we want initial info screen?
65static bool gWantFrameTime = false;     // do we want times on each frame?
66static uint32_t gVideoWidth = 0;        // default width+height
67static uint32_t gVideoHeight = 0;
68static uint32_t gBitRate = 4000000;     // 4Mbps
69static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
70
71// Set by signal handler to stop recording.
72static volatile bool gStopRequested;
73
74// Previous signal handler state, restored after first hit.
75static struct sigaction gOrigSigactionINT;
76static struct sigaction gOrigSigactionHUP;
77
78
79/*
80 * Catch keyboard interrupt signals.  On receipt, the "stop requested"
81 * flag is raised, and the original handler is restored (so that, if
82 * we get stuck finishing, a second Ctrl-C will kill the process).
83 */
84static void signalCatcher(int signum)
85{
86    gStopRequested = true;
87    switch (signum) {
88    case SIGINT:
89    case SIGHUP:
90        sigaction(SIGINT, &gOrigSigactionINT, NULL);
91        sigaction(SIGHUP, &gOrigSigactionHUP, NULL);
92        break;
93    default:
94        abort();
95        break;
96    }
97}
98
99/*
100 * Configures signal handlers.  The previous handlers are saved.
101 *
102 * If the command is run from an interactive adb shell, we get SIGINT
103 * when Ctrl-C is hit.  If we're run from the host, the local adb process
104 * gets the signal, and we get a SIGHUP when the terminal disconnects.
105 */
106static status_t configureSignals() {
107    struct sigaction act;
108    memset(&act, 0, sizeof(act));
109    act.sa_handler = signalCatcher;
110    if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) {
111        status_t err = -errno;
112        fprintf(stderr, "Unable to configure SIGINT handler: %s\n",
113                strerror(errno));
114        return err;
115    }
116    if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) {
117        status_t err = -errno;
118        fprintf(stderr, "Unable to configure SIGHUP handler: %s\n",
119                strerror(errno));
120        return err;
121    }
122    return NO_ERROR;
123}
124
125/*
126 * Returns "true" if the device is rotated 90 degrees.
127 */
128static bool isDeviceRotated(int orientation) {
129    return orientation != DISPLAY_ORIENTATION_0 &&
130            orientation != DISPLAY_ORIENTATION_180;
131}
132
133/*
134 * Configures and starts the MediaCodec encoder.  Obtains an input surface
135 * from the codec.
136 */
137static status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec,
138        sp<IGraphicBufferProducer>* pBufferProducer) {
139    status_t err;
140
141    if (gVerbose) {
142        printf("Configuring recorder for %dx%d video at %.2fMbps\n",
143                gVideoWidth, gVideoHeight, gBitRate / 1000000.0);
144    }
145
146    sp<AMessage> format = new AMessage;
147    format->setInt32("width", gVideoWidth);
148    format->setInt32("height", gVideoHeight);
149    format->setString("mime", "video/avc");
150    format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
151    format->setInt32("bitrate", gBitRate);
152    format->setFloat("frame-rate", displayFps);
153    format->setInt32("i-frame-interval", 10);
154
155    sp<ALooper> looper = new ALooper;
156    looper->setName("screenrecord_looper");
157    looper->start();
158    ALOGV("Creating codec");
159    sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true);
160    if (codec == NULL) {
161        fprintf(stderr, "ERROR: unable to create video/avc codec instance\n");
162        return UNKNOWN_ERROR;
163    }
164
165    err = codec->configure(format, NULL, NULL,
166            MediaCodec::CONFIGURE_FLAG_ENCODE);
167    if (err != NO_ERROR) {
168        fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err);
169        codec->release();
170        return err;
171    }
172
173    ALOGV("Creating encoder input surface");
174    sp<IGraphicBufferProducer> bufferProducer;
175    err = codec->createInputSurface(&bufferProducer);
176    if (err != NO_ERROR) {
177        fprintf(stderr,
178            "ERROR: unable to create encoder input surface (err=%d)\n", err);
179        codec->release();
180        return err;
181    }
182
183    ALOGV("Starting codec");
184    err = codec->start();
185    if (err != NO_ERROR) {
186        fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err);
187        codec->release();
188        return err;
189    }
190
191    ALOGV("Codec prepared");
192    *pCodec = codec;
193    *pBufferProducer = bufferProducer;
194    return 0;
195}
196
197/*
198 * Sets the display projection, based on the display dimensions, video size,
199 * and device orientation.
200 */
201static status_t setDisplayProjection(const sp<IBinder>& dpy,
202        const DisplayInfo& mainDpyInfo) {
203    status_t err;
204
205    // Set the region of the layer stack we're interested in, which in our
206    // case is "all of it".  If the app is rotated (so that the width of the
207    // app is based on the height of the display), reverse width/height.
208    bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation);
209    uint32_t sourceWidth, sourceHeight;
210    if (!deviceRotated) {
211        sourceWidth = mainDpyInfo.w;
212        sourceHeight = mainDpyInfo.h;
213    } else {
214        ALOGV("using rotated width/height");
215        sourceHeight = mainDpyInfo.w;
216        sourceWidth = mainDpyInfo.h;
217    }
218    Rect layerStackRect(sourceWidth, sourceHeight);
219
220    // We need to preserve the aspect ratio of the display.
221    float displayAspect = (float) sourceHeight / (float) sourceWidth;
222
223
224    // Set the way we map the output onto the display surface (which will
225    // be e.g. 1280x720 for a 720p video).  The rect is interpreted
226    // post-rotation, so if the display is rotated 90 degrees we need to
227    // "pre-rotate" it by flipping width/height, so that the orientation
228    // adjustment changes it back.
229    //
230    // We might want to encode a portrait display as landscape to use more
231    // of the screen real estate.  (If players respect a 90-degree rotation
232    // hint, we can essentially get a 720x1280 video instead of 1280x720.)
233    // In that case, we swap the configured video width/height and then
234    // supply a rotation value to the display projection.
235    uint32_t videoWidth, videoHeight;
236    uint32_t outWidth, outHeight;
237    if (!gRotate) {
238        videoWidth = gVideoWidth;
239        videoHeight = gVideoHeight;
240    } else {
241        videoWidth = gVideoHeight;
242        videoHeight = gVideoWidth;
243    }
244    if (videoHeight > (uint32_t)(videoWidth * displayAspect)) {
245        // limited by narrow width; reduce height
246        outWidth = videoWidth;
247        outHeight = (uint32_t)(videoWidth * displayAspect);
248    } else {
249        // limited by short height; restrict width
250        outHeight = videoHeight;
251        outWidth = (uint32_t)(videoHeight / displayAspect);
252    }
253    uint32_t offX, offY;
254    offX = (videoWidth - outWidth) / 2;
255    offY = (videoHeight - outHeight) / 2;
256    Rect displayRect(offX, offY, offX + outWidth, offY + outHeight);
257
258    if (gVerbose) {
259        if (gRotate) {
260            printf("Rotated content area is %ux%u at offset x=%d y=%d\n",
261                    outHeight, outWidth, offY, offX);
262        } else {
263            printf("Content area is %ux%u at offset x=%d y=%d\n",
264                    outWidth, outHeight, offX, offY);
265        }
266    }
267
268    SurfaceComposerClient::setDisplayProjection(dpy,
269            gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
270            layerStackRect, displayRect);
271    return NO_ERROR;
272}
273
274/*
275 * Configures the virtual display.  When this completes, virtual display
276 * frames will start arriving from the buffer producer.
277 */
278static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
279        const sp<IGraphicBufferProducer>& bufferProducer,
280        sp<IBinder>* pDisplayHandle) {
281    sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
282            String8("ScreenRecorder"), false /*secure*/);
283
284    SurfaceComposerClient::openGlobalTransaction();
285    SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
286    setDisplayProjection(dpy, mainDpyInfo);
287    SurfaceComposerClient::setDisplayLayerStack(dpy, 0);    // default stack
288    SurfaceComposerClient::closeGlobalTransaction();
289
290    *pDisplayHandle = dpy;
291
292    return NO_ERROR;
293}
294
295/*
296 * Runs the MediaCodec encoder, sending the output to the MediaMuxer.  The
297 * input frames are coming from the virtual display as fast as SurfaceFlinger
298 * wants to send them.
299 *
300 * The muxer must *not* have been started before calling.
301 */
302static status_t runEncoder(const sp<MediaCodec>& encoder,
303        const sp<MediaMuxer>& muxer, const sp<IBinder>& mainDpy,
304        const sp<IBinder>& virtualDpy, uint8_t orientation) {
305    static int kTimeout = 250000;   // be responsive on signal
306    status_t err;
307    ssize_t trackIdx = -1;
308    uint32_t debugNumFrames = 0;
309    int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC);
310    int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
311    DisplayInfo mainDpyInfo;
312
313    Vector<sp<ABuffer> > buffers;
314    err = encoder->getOutputBuffers(&buffers);
315    if (err != NO_ERROR) {
316        fprintf(stderr, "Unable to get output buffers (err=%d)\n", err);
317        return err;
318    }
319
320    // This is set by the signal handler.
321    gStopRequested = false;
322
323    // Run until we're signaled.
324    while (!gStopRequested) {
325        size_t bufIndex, offset, size;
326        int64_t ptsUsec;
327        uint32_t flags;
328
329        if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) {
330            if (gVerbose) {
331                printf("Time limit reached\n");
332            }
333            break;
334        }
335
336        ALOGV("Calling dequeueOutputBuffer");
337        err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
338                &flags, kTimeout);
339        ALOGV("dequeueOutputBuffer returned %d", err);
340        switch (err) {
341        case NO_ERROR:
342            // got a buffer
343            if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
344                // ignore this -- we passed the CSD into MediaMuxer when
345                // we got the format change notification
346                ALOGV("Got codec config buffer (%u bytes); ignoring", size);
347                size = 0;
348            }
349            if (size != 0) {
350                ALOGV("Got data in buffer %d, size=%d, pts=%lld",
351                        bufIndex, size, ptsUsec);
352                assert(trackIdx != -1);
353
354                { // scope
355                    ATRACE_NAME("orientation");
356                    // Check orientation, update if it has changed.
357                    //
358                    // Polling for changes is inefficient and wrong, but the
359                    // useful stuff is hard to get at without a Dalvik VM.
360                    err = SurfaceComposerClient::getDisplayInfo(mainDpy,
361                            &mainDpyInfo);
362                    if (err != NO_ERROR) {
363                        ALOGW("getDisplayInfo(main) failed: %d", err);
364                    } else if (orientation != mainDpyInfo.orientation) {
365                        ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
366                        SurfaceComposerClient::openGlobalTransaction();
367                        setDisplayProjection(virtualDpy, mainDpyInfo);
368                        SurfaceComposerClient::closeGlobalTransaction();
369                        orientation = mainDpyInfo.orientation;
370                    }
371                }
372
373                // If the virtual display isn't providing us with timestamps,
374                // use the current time.  This isn't great -- we could get
375                // decoded data in clusters -- but we're not expecting
376                // to hit this anyway.
377                if (ptsUsec == 0) {
378                    ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000;
379                }
380
381                // The MediaMuxer docs are unclear, but it appears that we
382                // need to pass either the full set of BufferInfo flags, or
383                // (flags & BUFFER_FLAG_SYNCFRAME).
384                //
385                // If this blocks for too long we could drop frames.  We may
386                // want to queue these up and do them on a different thread.
387                { // scope
388                    ATRACE_NAME("write sample");
389                    err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
390                            ptsUsec, flags);
391                    if (err != NO_ERROR) {
392                        fprintf(stderr,
393                            "Failed writing data to muxer (err=%d)\n", err);
394                        return err;
395                    }
396                }
397                debugNumFrames++;
398            }
399            err = encoder->releaseOutputBuffer(bufIndex);
400            if (err != NO_ERROR) {
401                fprintf(stderr, "Unable to release output buffer (err=%d)\n",
402                        err);
403                return err;
404            }
405            if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) {
406                // Not expecting EOS from SurfaceFlinger.  Go with it.
407                ALOGI("Received end-of-stream");
408                gStopRequested = true;
409            }
410            break;
411        case -EAGAIN:                       // INFO_TRY_AGAIN_LATER
412            ALOGV("Got -EAGAIN, looping");
413            break;
414        case INFO_FORMAT_CHANGED:           // INFO_OUTPUT_FORMAT_CHANGED
415            {
416                // Format includes CSD, which we must provide to muxer.
417                ALOGV("Encoder format changed");
418                sp<AMessage> newFormat;
419                encoder->getOutputFormat(&newFormat);
420                trackIdx = muxer->addTrack(newFormat);
421                ALOGV("Starting muxer");
422                err = muxer->start();
423                if (err != NO_ERROR) {
424                    fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
425                    return err;
426                }
427            }
428            break;
429        case INFO_OUTPUT_BUFFERS_CHANGED:   // INFO_OUTPUT_BUFFERS_CHANGED
430            // Not expected for an encoder; handle it anyway.
431            ALOGV("Encoder buffers changed");
432            err = encoder->getOutputBuffers(&buffers);
433            if (err != NO_ERROR) {
434                fprintf(stderr,
435                        "Unable to get new output buffers (err=%d)\n", err);
436                return err;
437            }
438            break;
439        case INVALID_OPERATION:
440            ALOGW("dequeueOutputBuffer returned INVALID_OPERATION");
441            return err;
442        default:
443            fprintf(stderr,
444                    "Got weird result %d from dequeueOutputBuffer\n", err);
445            return err;
446        }
447    }
448
449    ALOGV("Encoder stopping (req=%d)", gStopRequested);
450    if (gVerbose) {
451        printf("Encoder stopping; recorded %u frames in %lld seconds\n",
452                debugNumFrames, nanoseconds_to_seconds(
453                        systemTime(CLOCK_MONOTONIC) - startWhenNsec));
454    }
455    return NO_ERROR;
456}
457
458/*
459 * Main "do work" method.
460 *
461 * Configures codec, muxer, and virtual display, then starts moving bits
462 * around.
463 */
464static status_t recordScreen(const char* fileName) {
465    status_t err;
466
467    // Configure signal handler.
468    err = configureSignals();
469    if (err != NO_ERROR) return err;
470
471    // Start Binder thread pool.  MediaCodec needs to be able to receive
472    // messages from mediaserver.
473    sp<ProcessState> self = ProcessState::self();
474    self->startThreadPool();
475
476    // Get main display parameters.
477    sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
478            ISurfaceComposer::eDisplayIdMain);
479    DisplayInfo mainDpyInfo;
480    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
481    if (err != NO_ERROR) {
482        fprintf(stderr, "ERROR: unable to get display characteristics\n");
483        return err;
484    }
485    if (gVerbose) {
486        printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
487                mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
488                mainDpyInfo.orientation);
489    }
490
491    bool rotated = isDeviceRotated(mainDpyInfo.orientation);
492    if (gVideoWidth == 0) {
493        gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w;
494    }
495    if (gVideoHeight == 0) {
496        gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h;
497    }
498
499    // Configure and start the encoder.
500    sp<MediaCodec> encoder;
501    sp<IGraphicBufferProducer> encoderInputSurface;
502    err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);
503
504    if (err != NO_ERROR && !gSizeSpecified) {
505        // fallback is defined for landscape; swap if we're in portrait
506        bool needSwap = gVideoWidth < gVideoHeight;
507        uint32_t newWidth = needSwap ? kFallbackHeight : kFallbackWidth;
508        uint32_t newHeight = needSwap ? kFallbackWidth : kFallbackHeight;
509        if (gVideoWidth != newWidth && gVideoHeight != newHeight) {
510            ALOGV("Retrying with 720p");
511            fprintf(stderr, "WARNING: failed at %dx%d, retrying at %dx%d\n",
512                    gVideoWidth, gVideoHeight, newWidth, newHeight);
513            gVideoWidth = newWidth;
514            gVideoHeight = newHeight;
515            err = prepareEncoder(mainDpyInfo.fps, &encoder,
516                    &encoderInputSurface);
517        }
518    }
519    if (err != NO_ERROR) return err;
520
521    // From here on, we must explicitly release() the encoder before it goes
522    // out of scope, or we will get an assertion failure from stagefright
523    // later on in a different thread.
524
525
526    // Draw the "info" page by rendering a frame with GLES and sending
527    // it directly to the encoder.
528    // TODO: consider displaying this as a regular layer to avoid b/11697754
529    if (gWantInfoScreen) {
530        Overlay::drawInfoPage(encoderInputSurface);
531    }
532
533    // Configure optional overlay.
534    sp<IGraphicBufferProducer> bufferProducer;
535    sp<Overlay> overlay = new Overlay();
536    if (gWantFrameTime) {
537        // Send virtual display frames to an external texture.
538        err = overlay->start(encoderInputSurface, &bufferProducer);
539        if (err != NO_ERROR) {
540            encoder->release();
541            return err;
542        }
543        if (gVerbose) {
544            printf("Bugreport overlay created\n");
545        }
546    } else {
547        // Use the encoder's input surface as the virtual display surface.
548        bufferProducer = encoderInputSurface;
549    }
550
551    // Configure virtual display.
552    sp<IBinder> dpy;
553    err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
554    if (err != NO_ERROR) {
555        encoder->release();
556        return err;
557    }
558
559    // Configure muxer.  We have to wait for the CSD blob from the encoder
560    // before we can start it.
561    sp<MediaMuxer> muxer = new MediaMuxer(fileName,
562            MediaMuxer::OUTPUT_FORMAT_MPEG_4);
563    if (gRotate) {
564        muxer->setOrientationHint(90);  // TODO: does this do anything?
565    }
566
567    // Main encoder loop.
568    err = runEncoder(encoder, muxer, mainDpy, dpy, mainDpyInfo.orientation);
569    if (err != NO_ERROR) {
570        fprintf(stderr, "Encoder failed (err=%d)\n", err);
571        // fall through to cleanup
572    }
573
574    if (gVerbose) {
575        printf("Stopping encoder and muxer\n");
576    }
577
578    // Shut everything down, starting with the producer side.
579    encoderInputSurface = NULL;
580    SurfaceComposerClient::destroyDisplay(dpy);
581    overlay->stop();
582    encoder->stop();
583    // If we don't stop muxer explicitly, i.e. let the destructor run,
584    // it may hang (b/11050628).
585    muxer->stop();
586    encoder->release();
587
588    return err;
589}
590
591/*
592 * Sends a broadcast to the media scanner to tell it about the new video.
593 *
594 * This is optional, but nice to have.
595 */
596static status_t notifyMediaScanner(const char* fileName) {
597    // need to do allocations before the fork()
598    String8 fileUrl("file://");
599    fileUrl.append(fileName);
600
601    const char* kCommand = "/system/bin/am";
602    const char* const argv[] = {
603            kCommand,
604            "broadcast",
605            "-a",
606            "android.intent.action.MEDIA_SCANNER_SCAN_FILE",
607            "-d",
608            fileUrl.string(),
609            NULL
610    };
611    if (gVerbose) {
612        printf("Executing:");
613        for (int i = 0; argv[i] != NULL; i++) {
614            printf(" %s", argv[i]);
615        }
616        putchar('\n');
617    }
618
619    pid_t pid = fork();
620    if (pid < 0) {
621        int err = errno;
622        ALOGW("fork() failed: %s", strerror(err));
623        return -err;
624    } else if (pid > 0) {
625        // parent; wait for the child, mostly to make the verbose-mode output
626        // look right, but also to check for and log failures
627        int status;
628        pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
629        if (actualPid != pid) {
630            ALOGW("waitpid(%d) returned %d (errno=%d)", pid, actualPid, errno);
631        } else if (status != 0) {
632            ALOGW("'am broadcast' exited with status=%d", status);
633        } else {
634            ALOGV("'am broadcast' exited successfully");
635        }
636    } else {
637        if (!gVerbose) {
638            // non-verbose, suppress 'am' output
639            ALOGV("closing stdout/stderr in child");
640            int fd = open("/dev/null", O_WRONLY);
641            if (fd >= 0) {
642                dup2(fd, STDOUT_FILENO);
643                dup2(fd, STDERR_FILENO);
644                close(fd);
645            }
646        }
647        execv(kCommand, const_cast<char* const*>(argv));
648        ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno));
649        exit(1);
650    }
651    return NO_ERROR;
652}
653
654/*
655 * Parses a string of the form "1280x720".
656 *
657 * Returns true on success.
658 */
659static bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth,
660        uint32_t* pHeight) {
661    long width, height;
662    char* end;
663
664    // Must specify base 10, or "0x0" gets parsed differently.
665    width = strtol(widthHeight, &end, 10);
666    if (end == widthHeight || *end != 'x' || *(end+1) == '\0') {
667        // invalid chars in width, or missing 'x', or missing height
668        return false;
669    }
670    height = strtol(end + 1, &end, 10);
671    if (*end != '\0') {
672        // invalid chars in height
673        return false;
674    }
675
676    *pWidth = width;
677    *pHeight = height;
678    return true;
679}
680
681/*
682 * Accepts a string with a bare number ("4000000") or with a single-character
683 * unit ("4m").
684 *
685 * Returns an error if parsing fails.
686 */
687static status_t parseValueWithUnit(const char* str, uint32_t* pValue) {
688    long value;
689    char* endptr;
690
691    value = strtol(str, &endptr, 10);
692    if (*endptr == '\0') {
693        // bare number
694        *pValue = value;
695        return NO_ERROR;
696    } else if (toupper(*endptr) == 'M' && *(endptr+1) == '\0') {
697        *pValue = value * 1000000;  // check for overflow?
698        return NO_ERROR;
699    } else {
700        fprintf(stderr, "Unrecognized value: %s\n", str);
701        return UNKNOWN_ERROR;
702    }
703}
704
705/*
706 * Dumps usage on stderr.
707 */
708static void usage() {
709    fprintf(stderr,
710        "Usage: screenrecord [options] <filename>\n"
711        "\n"
712        "Android screenrecord v%d.%d.  Records the device's display to a .mp4 file.\n"
713        "\n"
714        "Options:\n"
715        "--size WIDTHxHEIGHT\n"
716        "    Set the video size, e.g. \"1280x720\".  Default is the device's main\n"
717        "    display resolution (if supported), 1280x720 if not.  For best results,\n"
718        "    use a size supported by the AVC encoder.\n"
719        "--bit-rate RATE\n"
720        "    Set the video bit rate, in megabits per second.  Value may be specified\n"
721        "    in bits or megabits, e.g. '4000000' is equivalent to '4M'.  Default %dMbps.\n"
722        "--bugreport\n"
723        "    Add additional information, such as a timestamp overlay, that is helpful\n"
724        "    in videos captured to illustrate bugs.\n"
725        "--time-limit TIME\n"
726        "    Set the maximum recording time, in seconds.  Default / maximum is %d.\n"
727        "--verbose\n"
728        "    Display interesting information on stdout.\n"
729        "--help\n"
730        "    Show this message.\n"
731        "\n"
732        "Recording continues until Ctrl-C is hit or the time limit is reached.\n"
733        "\n",
734        kVersionMajor, kVersionMinor, gBitRate / 1000000, gTimeLimitSec
735        );
736}
737
738/*
739 * Parses args and kicks things off.
740 */
741int main(int argc, char* const argv[]) {
742    static const struct option longOptions[] = {
743        { "help",               no_argument,        NULL, 'h' },
744        { "verbose",            no_argument,        NULL, 'v' },
745        { "size",               required_argument,  NULL, 's' },
746        { "bit-rate",           required_argument,  NULL, 'b' },
747        { "time-limit",         required_argument,  NULL, 't' },
748        { "show-device-info",   no_argument,        NULL, 'i' },
749        { "show-frame-time",    no_argument,        NULL, 'f' },
750        { "bugreport",          no_argument,        NULL, 'u' },
751        { "rotate",             no_argument,        NULL, 'r' },
752        { NULL,                 0,                  NULL, 0 }
753    };
754
755    while (true) {
756        int optionIndex = 0;
757        int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
758        if (ic == -1) {
759            break;
760        }
761
762        switch (ic) {
763        case 'h':
764            usage();
765            return 0;
766        case 'v':
767            gVerbose = true;
768            break;
769        case 's':
770            if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) {
771                fprintf(stderr, "Invalid size '%s', must be width x height\n",
772                        optarg);
773                return 2;
774            }
775            if (gVideoWidth == 0 || gVideoHeight == 0) {
776                fprintf(stderr,
777                    "Invalid size %ux%u, width and height may not be zero\n",
778                    gVideoWidth, gVideoHeight);
779                return 2;
780            }
781            gSizeSpecified = true;
782            break;
783        case 'b':
784            if (parseValueWithUnit(optarg, &gBitRate) != NO_ERROR) {
785                return 2;
786            }
787            if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) {
788                fprintf(stderr,
789                        "Bit rate %dbps outside acceptable range [%d,%d]\n",
790                        gBitRate, kMinBitRate, kMaxBitRate);
791                return 2;
792            }
793            break;
794        case 't':
795            gTimeLimitSec = atoi(optarg);
796            if (gTimeLimitSec == 0 || gTimeLimitSec > kMaxTimeLimitSec) {
797                fprintf(stderr,
798                        "Time limit %ds outside acceptable range [1,%d]\n",
799                        gTimeLimitSec, kMaxTimeLimitSec);
800                return 2;
801            }
802            break;
803        case 'i':
804            gWantInfoScreen = true;
805            break;
806        case 'f':
807            gWantFrameTime = true;
808            break;
809        case 'u':
810            gWantInfoScreen = true;
811            gWantFrameTime = true;
812            break;
813        case 'r':
814            // experimental feature
815            gRotate = true;
816            break;
817        default:
818            if (ic != '?') {
819                fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
820            }
821            return 2;
822        }
823    }
824
825    if (optind != argc - 1) {
826        fprintf(stderr, "Must specify output file (see --help).\n");
827        return 2;
828    }
829
830    // MediaMuxer tries to create the file in the constructor, but we don't
831    // learn about the failure until muxer.start(), which returns a generic
832    // error code without logging anything.  We attempt to create the file
833    // now for better diagnostics.
834    const char* fileName = argv[optind];
835    int fd = open(fileName, O_CREAT | O_RDWR, 0644);
836    if (fd < 0) {
837        fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno));
838        return 1;
839    }
840    close(fd);
841
842    status_t err = recordScreen(fileName);
843    if (err == NO_ERROR) {
844        // Try to notify the media scanner.  Not fatal if this fails.
845        notifyMediaScanner(fileName);
846    }
847    ALOGD(err == NO_ERROR ? "success" : "failed");
848    return (int) err;
849}
850