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