screenrecord.cpp revision 48326940f48390e79476e5ce7c2a18b8201cdafc
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 LOG_NDEBUG 0
19#include <utils/Log.h>
20
21#include <binder/IPCThreadState.h>
22#include <utils/Errors.h>
23#include <utils/Thread.h>
24
25#include <gui/Surface.h>
26#include <gui/SurfaceComposerClient.h>
27#include <gui/ISurfaceComposer.h>
28#include <ui/DisplayInfo.h>
29#include <media/openmax/OMX_IVCommon.h>
30#include <media/stagefright/foundation/ABuffer.h>
31#include <media/stagefright/foundation/ADebug.h>
32#include <media/stagefright/foundation/AMessage.h>
33#include <media/stagefright/MediaCodec.h>
34#include <media/stagefright/MediaErrors.h>
35#include <media/stagefright/MediaMuxer.h>
36#include <media/ICrypto.h>
37
38#include <stdlib.h>
39#include <string.h>
40#include <stdio.h>
41#include <fcntl.h>
42#include <signal.h>
43#include <getopt.h>
44
45using namespace android;
46
47// Command-line parameters.
48static bool gVerbose = false;               // chatty on stdout
49static bool gRotate = false;                // rotate 90 degrees
50static bool gSizeSpecified = false;         // was size explicitly requested?
51static uint32_t gVideoWidth = 0;            // default width+height
52static uint32_t gVideoHeight = 0;
53static uint32_t gBitRate = 4000000;         // 4Mbps
54
55// Set by signal handler to stop recording.
56static bool gStopRequested;
57
58// Previous signal handler state, restored after first hit.
59static struct sigaction gOrigSigactionINT;
60static struct sigaction gOrigSigactionHUP;
61
62static const uint32_t kMinBitRate = 100000;         // 0.1Mbps
63static const uint32_t kMaxBitRate = 100 * 1000000;  // 100Mbps
64
65/*
66 * Catch keyboard interrupt signals.  On receipt, the "stop requested"
67 * flag is raised, and the original handler is restored (so that, if
68 * we get stuck finishing, a second Ctrl-C will kill the process).
69 */
70static void signalCatcher(int signum)
71{
72    gStopRequested = true;
73    switch (signum) {
74    case SIGINT:
75        sigaction(SIGINT, &gOrigSigactionINT, NULL);
76        break;
77    case SIGHUP:
78        sigaction(SIGHUP, &gOrigSigactionHUP, NULL);
79        break;
80    default:
81        abort();
82        break;
83    }
84}
85
86/*
87 * Configures signal handlers.  The previous handlers are saved.
88 *
89 * If the command is run from an interactive adb shell, we get SIGINT
90 * when Ctrl-C is hit.  If we're run from the host, the local adb process
91 * gets the signal, and we get a SIGHUP when the terminal disconnects.
92 */
93static status_t configureSignals()
94{
95    struct sigaction act;
96    memset(&act, 0, sizeof(act));
97    act.sa_handler = signalCatcher;
98    if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) {
99        status_t err = -errno;
100        fprintf(stderr, "Unable to configure SIGINT handler: %s\n",
101                strerror(errno));
102        return err;
103    }
104    if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) {
105        status_t err = -errno;
106        fprintf(stderr, "Unable to configure SIGHUP handler: %s\n",
107                strerror(errno));
108        return err;
109    }
110    return NO_ERROR;
111}
112
113/*
114 * Returns "true" if the device is rotated 90 degrees.
115 */
116static bool isDeviceRotated(int orientation) {
117    return orientation != DISPLAY_ORIENTATION_0 &&
118            orientation != DISPLAY_ORIENTATION_180;
119}
120
121/*
122 * Configures and starts the MediaCodec encoder.  Obtains an input surface
123 * from the codec.
124 */
125static status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec,
126        sp<IGraphicBufferProducer>* pBufferProducer) {
127    status_t err;
128
129    if (gVerbose) {
130        printf("Configuring recorder for %dx%d video at %.2fMbps\n",
131                gVideoWidth, gVideoHeight, gBitRate / 1000000.0);
132    }
133
134    sp<AMessage> format = new AMessage;
135    format->setInt32("width", gVideoWidth);
136    format->setInt32("height", gVideoHeight);
137    format->setString("mime", "video/avc");
138    format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
139    format->setInt32("bitrate", gBitRate);
140    format->setFloat("frame-rate", displayFps);
141    format->setInt32("i-frame-interval", 10);
142
143    // MediaCodec
144    sp<ALooper> looper = new ALooper;
145    looper->setName("screenrecord_looper");
146    looper->start();
147    ALOGV("Creating codec");
148    sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true);
149    if (codec == NULL) {
150        fprintf(stderr, "ERROR: unable to create video/avc codec instance\n");
151        return UNKNOWN_ERROR;
152    }
153    err = codec->configure(format, NULL, NULL,
154            MediaCodec::CONFIGURE_FLAG_ENCODE);
155    if (err != NO_ERROR) {
156        fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err);
157        return err;
158    }
159
160    ALOGV("Creating buffer producer");
161    sp<IGraphicBufferProducer> bufferProducer;
162    err = codec->createInputSurface(&bufferProducer);
163    if (err != NO_ERROR) {
164        fprintf(stderr,
165            "ERROR: unable to create encoder input surface (err=%d)\n", err);
166        return err;
167    }
168
169    ALOGV("Starting codec");
170    err = codec->start();
171    if (err != NO_ERROR) {
172        fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err);
173        return err;
174    }
175
176    ALOGV("Codec prepared");
177    *pCodec = codec;
178    *pBufferProducer = bufferProducer;
179    return 0;
180}
181
182/*
183 * Configures the virtual display.  When this completes, virtual display
184 * frames will start being sent to the encoder's surface.
185 */
186static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
187        const sp<IGraphicBufferProducer>& bufferProducer,
188        sp<IBinder>* pDisplayHandle) {
189    status_t err;
190
191    // Set the region of the layer stack we're interested in, which in our
192    // case is "all of it".  If the app is rotated (so that the width of the
193    // app is based on the height of the display), reverse width/height.
194    bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation);
195    uint32_t sourceWidth, sourceHeight;
196    if (!deviceRotated) {
197        sourceWidth = mainDpyInfo.w;
198        sourceHeight = mainDpyInfo.h;
199    } else {
200        ALOGV("using rotated width/height");
201        sourceHeight = mainDpyInfo.w;
202        sourceWidth = mainDpyInfo.h;
203    }
204    Rect layerStackRect(sourceWidth, sourceHeight);
205
206    // We need to preserve the aspect ratio of the display.
207    float displayAspect = (float) sourceHeight / (float) sourceWidth;
208
209
210    // Set the way we map the output onto the display surface (which will
211    // be e.g. 1280x720 for a 720p video).  The rect is interpreted
212    // post-rotation, so if the display is rotated 90 degrees we need to
213    // "pre-rotate" it by flipping width/height, so that the orientation
214    // adjustment changes it back.
215    //
216    // We might want to encode a portrait display as landscape to use more
217    // of the screen real estate.  (If players respect a 90-degree rotation
218    // hint, we can essentially get a 720x1280 video instead of 1280x720.)
219    // In that case, we swap the configured video width/height and then
220    // supply a rotation value to the display projection.
221    uint32_t videoWidth, videoHeight;
222    uint32_t outWidth, outHeight;
223    if (!gRotate) {
224        videoWidth = gVideoWidth;
225        videoHeight = gVideoHeight;
226    } else {
227        videoWidth = gVideoHeight;
228        videoHeight = gVideoWidth;
229    }
230    if (videoHeight > (uint32_t)(videoWidth * displayAspect)) {
231        // limited by narrow width; reduce height
232        outWidth = videoWidth;
233        outHeight = (uint32_t)(videoWidth * displayAspect);
234    } else {
235        // limited by short height; restrict width
236        outHeight = videoHeight;
237        outWidth = (uint32_t)(videoHeight / displayAspect);
238    }
239    uint32_t offX, offY;
240    offX = (videoWidth - outWidth) / 2;
241    offY = (videoHeight - outHeight) / 2;
242    Rect displayRect(offX, offY, offX + outWidth, offY + outHeight);
243
244    if (gVerbose) {
245        if (gRotate) {
246            printf("Rotated content area is %ux%u at offset x=%d y=%d\n",
247                    outHeight, outWidth, offY, offX);
248        } else {
249            printf("Content area is %ux%u at offset x=%d y=%d\n",
250                    outWidth, outHeight, offX, offY);
251        }
252    }
253
254
255    sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
256            String8("ScreenRecorder"), false /* secure */);
257
258    SurfaceComposerClient::openGlobalTransaction();
259    SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
260    SurfaceComposerClient::setDisplayProjection(dpy,
261            gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
262            layerStackRect, displayRect);
263    SurfaceComposerClient::setDisplayLayerStack(dpy, 0);    // default stack
264    SurfaceComposerClient::closeGlobalTransaction();
265
266    *pDisplayHandle = dpy;
267
268    return NO_ERROR;
269}
270
271/*
272 * Runs the MediaCodec encoder, sending the output to the MediaMuxer.  The
273 * input frames are coming from the virtual display as fast as SurfaceFlinger
274 * wants to send them.
275 *
276 * The muxer must *not* have been started before calling.
277 */
278static status_t runEncoder(const sp<MediaCodec>& encoder,
279        const sp<MediaMuxer>& muxer) {
280    static int kTimeout = 250000;   // be responsive on signal
281    status_t err;
282    ssize_t trackIdx = -1;
283    uint32_t debugNumFrames = 0;
284    time_t debugStartWhen = time(NULL);
285
286    Vector<sp<ABuffer> > buffers;
287    err = encoder->getOutputBuffers(&buffers);
288    if (err != NO_ERROR) {
289        fprintf(stderr, "Unable to get output buffers (err=%d)\n", err);
290        return err;
291    }
292
293    // This is set by the signal handler.
294    gStopRequested = false;
295
296    // Run until we're signaled.
297    while (!gStopRequested) {
298        size_t bufIndex, offset, size;
299        int64_t ptsUsec;
300        uint32_t flags;
301        ALOGV("Calling dequeueOutputBuffer");
302        err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
303                &flags, kTimeout);
304        ALOGV("dequeueOutputBuffer returned %d", err);
305        switch (err) {
306        case NO_ERROR:
307            // got a buffer
308            if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
309                // ignore this -- we passed the CSD into MediaMuxer when
310                // we got the format change notification
311                ALOGV("Got codec config buffer (%u bytes); ignoring", size);
312                size = 0;
313            }
314            if (size != 0) {
315                ALOGV("Got data in buffer %d, size=%d, pts=%lld",
316                        bufIndex, size, ptsUsec);
317                CHECK(trackIdx != -1);
318
319                // If the virtual display isn't providing us with timestamps,
320                // use the current time.
321                if (ptsUsec == 0) {
322                    ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000;
323                }
324
325                // The MediaMuxer docs are unclear, but it appears that we
326                // need to pass either the full set of BufferInfo flags, or
327                // (flags & BUFFER_FLAG_SYNCFRAME).
328                err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
329                        ptsUsec, flags);
330                if (err != NO_ERROR) {
331                    fprintf(stderr, "Failed writing data to muxer (err=%d)\n",
332                            err);
333                    return err;
334                }
335                debugNumFrames++;
336            }
337            err = encoder->releaseOutputBuffer(bufIndex);
338            if (err != NO_ERROR) {
339                fprintf(stderr, "Unable to release output buffer (err=%d)\n",
340                        err);
341                return err;
342            }
343            if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) {
344                // Not expecting EOS from SurfaceFlinger.  Go with it.
345                ALOGD("Received end-of-stream");
346                gStopRequested = false;
347            }
348            break;
349        case -EAGAIN:                       // INFO_TRY_AGAIN_LATER
350            // not expected with infinite timeout
351            ALOGV("Got -EAGAIN, looping");
352            break;
353        case INFO_FORMAT_CHANGED:           // INFO_OUTPUT_FORMAT_CHANGED
354            {
355                // format includes CSD, which we must provide to muxer
356                ALOGV("Encoder format changed");
357                sp<AMessage> newFormat;
358                encoder->getOutputFormat(&newFormat);
359                trackIdx = muxer->addTrack(newFormat);
360                ALOGV("Starting muxer");
361                err = muxer->start();
362                if (err != NO_ERROR) {
363                    fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
364                    return err;
365                }
366            }
367            break;
368        case INFO_OUTPUT_BUFFERS_CHANGED:   // INFO_OUTPUT_BUFFERS_CHANGED
369            // not expected for an encoder; handle it anyway
370            ALOGV("Encoder buffers changed");
371            err = encoder->getOutputBuffers(&buffers);
372            if (err != NO_ERROR) {
373                fprintf(stderr,
374                        "Unable to get new output buffers (err=%d)\n", err);
375                return err;
376            }
377            break;
378        case INVALID_OPERATION:
379            fprintf(stderr, "Request for encoder buffer failed\n");
380            return err;
381        default:
382            fprintf(stderr,
383                    "Got weird result %d from dequeueOutputBuffer\n", err);
384            return err;
385        }
386    }
387
388    ALOGV("Encoder stopping (req=%d)", gStopRequested);
389    if (gVerbose) {
390        printf("Encoder stopping; recorded %u frames in %ld seconds\n",
391                debugNumFrames, time(NULL) - debugStartWhen);
392    }
393    return NO_ERROR;
394}
395
396/*
397 * Main "do work" method.
398 *
399 * Configures codec, muxer, and virtual display, then starts moving bits
400 * around.
401 */
402static status_t recordScreen(const char* fileName) {
403    status_t err;
404
405    // Configure signal handler.
406    err = configureSignals();
407    if (err != NO_ERROR) return err;
408
409    // Start Binder thread pool.  MediaCodec needs to be able to receive
410    // messages from mediaserver.
411    sp<ProcessState> self = ProcessState::self();
412    self->startThreadPool();
413
414    // Get main display parameters.
415    sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
416            ISurfaceComposer::eDisplayIdMain);
417    DisplayInfo mainDpyInfo;
418    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
419    if (err != NO_ERROR) {
420        fprintf(stderr, "ERROR: unable to get display characteristics\n");
421        return err;
422    }
423    if (gVerbose) {
424        printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
425                mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
426                mainDpyInfo.orientation);
427    }
428
429    bool rotated = isDeviceRotated(mainDpyInfo.orientation);
430    if (gVideoWidth == 0) {
431        gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w;
432    }
433    if (gVideoHeight == 0) {
434        gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h;
435    }
436
437    // Configure and start the encoder.
438    sp<MediaCodec> encoder;
439    sp<IGraphicBufferProducer> bufferProducer;
440    err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
441    if (err != NO_ERROR && !gSizeSpecified) {
442        ALOGV("Retrying with 720p");
443        if (gVideoWidth != 1280 && gVideoHeight != 720) {
444            fprintf(stderr, "WARNING: failed at %dx%d, retrying at 720p\n",
445                    gVideoWidth, gVideoHeight);
446            gVideoWidth = 1280;
447            gVideoHeight = 720;
448            err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
449        }
450    }
451    if (err != NO_ERROR) {
452        return err;
453    }
454
455    // Configure virtual display.
456    sp<IBinder> dpy;
457    err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
458    if (err != NO_ERROR) return err;
459
460    // Configure, but do not start, muxer.
461    sp<MediaMuxer> muxer = new MediaMuxer(fileName,
462            MediaMuxer::OUTPUT_FORMAT_MPEG_4);
463    if (gRotate) {
464        muxer->setOrientationHint(90);
465    }
466
467    // Main encoder loop.
468    err = runEncoder(encoder, muxer);
469    if (err != NO_ERROR) return err;
470
471    if (gVerbose) {
472        printf("Stopping encoder and muxer\n");
473    }
474
475    // Shut everything down, starting with the producer side.
476    bufferProducer = NULL;
477    SurfaceComposerClient::destroyDisplay(dpy);
478
479    encoder->stop();
480    muxer->stop();
481    encoder->release();
482
483    return 0;
484}
485
486/*
487 * Sends a broadcast to the media scanner to tell it about the new video.
488 */
489static status_t notifyMediaScanner(const char* fileName) {
490    String8 command("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
491    command.append(fileName);
492    if (gVerbose) {
493        printf("Shell: %s\n", command.string());
494    }
495
496    // TODO: for non-verbose mode we should suppress stdout
497    int status = system(command.string());
498    if (status < 0) {
499        fprintf(stderr, "Unable to fork shell for media scanner broadcast\n");
500        return UNKNOWN_ERROR;
501    } else if (status != 0) {
502        fprintf(stderr, "am command failed (status=%d): '%s'\n",
503                status, command.string());
504        return UNKNOWN_ERROR;
505    }
506    return NO_ERROR;
507}
508
509/*
510 * Parses a string of the form "1280x720".
511 *
512 * Returns true on success.
513 */
514static bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth,
515        uint32_t* pHeight) {
516    long width, height;
517    char* end;
518
519    // Must specify base 10, or "0x0" gets parsed differently.
520    width = strtol(widthHeight, &end, 10);
521    if (end == widthHeight || *end != 'x' || *(end+1) == '\0') {
522        // invalid chars in width, or missing 'x', or missing height
523        return false;
524    }
525    height = strtol(end + 1, &end, 10);
526    if (*end != '\0') {
527        // invalid chars in height
528        return false;
529    }
530
531    *pWidth = width;
532    *pHeight = height;
533    return true;
534}
535
536/*
537 * Dumps usage on stderr.
538 */
539static void usage() {
540    fprintf(stderr,
541        "Usage: screenrecord [options] <filename>\n"
542        "\n"
543        "Records the device's display to a .mp4 file.\n"
544        "\n"
545        "Options:\n"
546        "--size WIDTHxHEIGHT\n"
547        "    Set the video size, e.g. \"1280x720\".  For best results, use\n"
548        "    a size supported by the AVC encoder.\n"
549        "--bit-rate RATE\n"
550        "    Set the video bit rate, in megabits per second.  Default 4Mbps.\n"
551        "--rotate\n"
552        "    Rotate the output 90 degrees.\n"
553        "--verbose\n"
554        "    Display interesting information on stdout.\n"
555        "--help\n"
556        "    Show this message.\n"
557        "\n"
558        "Recording continues until Ctrl-C is hit.\n"
559        "\n"
560        );
561}
562
563/*
564 * Parses args and kicks things off.
565 */
566int main(int argc, char* const argv[]) {
567    static const struct option longOptions[] = {
568        { "help",       no_argument,        NULL, 'h' },
569        { "verbose",    no_argument,        NULL, 'v' },
570        { "size",       required_argument,  NULL, 's' },
571        { "bit-rate",   required_argument,  NULL, 'b' },
572        { "rotate",     no_argument,        NULL, 'r' },
573        { NULL,         0,                  NULL, 0 }
574    };
575
576    while (true) {
577        int optionIndex = 0;
578        int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
579        if (ic == -1) {
580            break;
581        }
582
583        switch (ic) {
584        case 'h':
585            usage();
586            return 0;
587        case 'v':
588            gVerbose = true;
589            break;
590        case 's':
591            if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) {
592                fprintf(stderr, "Invalid size '%s', must be width x height\n",
593                        optarg);
594                return 2;
595            }
596            if (gVideoWidth == 0 || gVideoHeight == 0) {
597                fprintf(stderr,
598                    "Invalid size %ux%u, width and height may not be zero\n",
599                    gVideoWidth, gVideoHeight);
600                return 2;
601            }
602            gSizeSpecified = true;
603            break;
604        case 'b':
605            gBitRate = atoi(optarg);
606            if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) {
607                fprintf(stderr,
608                        "Bit rate %dbps outside acceptable range [%d,%d]\n",
609                        gBitRate, kMinBitRate, kMaxBitRate);
610                return 2;
611            }
612            break;
613        case 'r':
614            gRotate = true;
615            break;
616        default:
617            if (ic != '?') {
618                fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
619            }
620            return 2;
621        }
622    }
623
624    if (optind != argc - 1) {
625        fprintf(stderr, "Must specify output file (see --help).\n");
626        return 2;
627    }
628
629    // MediaMuxer tries to create the file in the constructor, but we don't
630    // learn about the failure until muxer.start(), which returns a generic
631    // error code without logging anything.  We attempt to create the file
632    // now for better diagnostics.
633    const char* fileName = argv[optind];
634    int fd = open(fileName, O_CREAT | O_RDWR, 0644);
635    if (fd < 0) {
636        fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno));
637        return 1;
638    }
639    close(fd);
640
641    status_t err = recordScreen(fileName);
642    if (err == NO_ERROR) {
643        // Try to notify the media scanner.  Not fatal if this fails.
644        notifyMediaScanner(fileName);
645    }
646    ALOGD(err == NO_ERROR ? "success" : "failed");
647    return (int) err;
648}
649