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