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