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