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