11f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 21f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Copyright 2013 The Android Open Source Project 31f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 41f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Licensed under the Apache License, Version 2.0 (the "License"); 51f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * you may not use this file except in compliance with the License. 61f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * You may obtain a copy of the License at 71f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 81f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * http://www.apache.org/licenses/LICENSE-2.0 91f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Unless required by applicable law or agreed to in writing, software 111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * distributed under the License is distributed on an "AS IS" BASIS, 121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * See the License for the specific language governing permissions and 141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * limitations under the License. 151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#define LOG_TAG "ScreenRecord" 181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden//#define LOG_NDEBUG 0 191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Log.h> 201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <binder/IPCThreadState.h> 221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Errors.h> 231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Thread.h> 242c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden#include <utils/Timers.h> 251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/Surface.h> 271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/SurfaceComposerClient.h> 281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/ISurfaceComposer.h> 291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <ui/DisplayInfo.h> 301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/openmax/OMX_IVCommon.h> 311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ABuffer.h> 321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ADebug.h> 331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/AMessage.h> 341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaCodec.h> 351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaErrors.h> 361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaMuxer.h> 371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/ICrypto.h> 381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3948326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden#include <stdlib.h> 40f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden#include <unistd.h> 4148326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden#include <string.h> 421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <stdio.h> 4346052913f307b1561f1661bb776fa29c0775758cAndy McFadden#include <fcntl.h> 441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <signal.h> 451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <getopt.h> 46f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden#include <sys/wait.h> 471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 481f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenusing namespace android; 491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 502c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMinBitRate = 100000; // 0.1Mbps 512c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMaxBitRate = 100 * 1000000; // 100Mbps 522c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMaxTimeLimitSec = 180; // 3 minutes 532c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kFallbackWidth = 1280; // 720p 542c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kFallbackHeight = 720; 552c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden 561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Command-line parameters. 571f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gVerbose = false; // chatty on stdout 581f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gRotate = false; // rotate 90 degrees 59f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool gSizeSpecified = false; // was size explicitly requested? 60f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoWidth = 0; // default width+height 61f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoHeight = 0; 621f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic uint32_t gBitRate = 4000000; // 4Mbps 632c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic uint32_t gTimeLimitSec = kMaxTimeLimitSec; 641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Set by signal handler to stop recording. 661f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gStopRequested; 671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Previous signal handler state, restored after first hit. 691f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionINT; 701f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionHUP; 711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Catch keyboard interrupt signals. On receipt, the "stop requested" 751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * flag is raised, and the original handler is restored (so that, if 761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * we get stuck finishing, a second Ctrl-C will kill the process). 771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 781f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void signalCatcher(int signum) 791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{ 801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gStopRequested = true; 811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden switch (signum) { 821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case SIGINT: 831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case SIGHUP: 842c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden sigaction(SIGINT, &gOrigSigactionINT, NULL); 851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sigaction(SIGHUP, &gOrigSigactionHUP, NULL); 861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden default: 881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden abort(); 891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures signal handlers. The previous handlers are saved. 951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * If the command is run from an interactive adb shell, we get SIGINT 971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * when Ctrl-C is hit. If we're run from the host, the local adb process 981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * gets the signal, and we get a SIGHUP when the terminal disconnects. 991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 1001f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t configureSignals() 1011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{ 1021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden struct sigaction act; 1031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden memset(&act, 0, sizeof(act)); 1041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden act.sa_handler = signalCatcher; 1051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) { 1061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err = -errno; 1071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to configure SIGINT handler: %s\n", 1081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden strerror(errno)); 1091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) { 1121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err = -errno; 1131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to configure SIGHUP handler: %s\n", 1141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden strerror(errno)); 1151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return NO_ERROR; 1181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 1191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 121f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden * Returns "true" if the device is rotated 90 degrees. 122f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden */ 123f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool isDeviceRotated(int orientation) { 124f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden return orientation != DISPLAY_ORIENTATION_0 && 125f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden orientation != DISPLAY_ORIENTATION_180; 126f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden} 127f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 128f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden/* 1291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures and starts the MediaCodec encoder. Obtains an input surface 1301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * from the codec. 1311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 1321f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec, 1331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IGraphicBufferProducer>* pBufferProducer) { 1341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 1351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 136f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVerbose) { 137f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden printf("Configuring recorder for %dx%d video at %.2fMbps\n", 138f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoWidth, gVideoHeight, gBitRate / 1000000.0); 139f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 140f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 1411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<AMessage> format = new AMessage; 1421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("width", gVideoWidth); 1431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("height", gVideoHeight); 1441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setString("mime", "video/avc"); 1451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque); 1461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("bitrate", gBitRate); 1471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setFloat("frame-rate", displayFps); 1481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("i-frame-interval", 10); 1491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<ALooper> looper = new ALooper; 1511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden looper->setName("screenrecord_looper"); 1521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden looper->start(); 1531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Creating codec"); 1541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true); 155a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden if (codec == NULL) { 156a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden fprintf(stderr, "ERROR: unable to create video/avc codec instance\n"); 157a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden return UNKNOWN_ERROR; 158a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden } 1591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = codec->configure(format, NULL, NULL, 1601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden MediaCodec::CONFIGURE_FLAG_ENCODE); 1611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 162e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber codec->release(); 163e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber codec.clear(); 164e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber 1651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err); 1661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Creating buffer producer"); 1701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IGraphicBufferProducer> bufferProducer; 1711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = codec->createInputSurface(&bufferProducer); 1721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 173e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber codec->release(); 174e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber codec.clear(); 175e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber 1761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 1771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "ERROR: unable to create encoder input surface (err=%d)\n", err); 1781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Starting codec"); 1821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = codec->start(); 1831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 184e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber codec->release(); 185e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber codec.clear(); 186e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber 1871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err); 1881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 191f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden ALOGV("Codec prepared"); 1921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pCodec = codec; 1931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pBufferProducer = bufferProducer; 1941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 0; 1951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 1961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 1981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures the virtual display. When this completes, virtual display 1991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * frames will start being sent to the encoder's surface. 2001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 2011f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo, 2021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden const sp<IGraphicBufferProducer>& bufferProducer, 2031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder>* pDisplayHandle) { 2041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 2051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Set the region of the layer stack we're interested in, which in our 2071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // case is "all of it". If the app is rotated (so that the width of the 2081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // app is based on the height of the display), reverse width/height. 209f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation); 2101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t sourceWidth, sourceHeight; 2111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (!deviceRotated) { 2121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceWidth = mainDpyInfo.w; 2131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceHeight = mainDpyInfo.h; 2141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("using rotated width/height"); 2161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceHeight = mainDpyInfo.w; 2171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceWidth = mainDpyInfo.h; 2181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden Rect layerStackRect(sourceWidth, sourceHeight); 2201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // We need to preserve the aspect ratio of the display. 2221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden float displayAspect = (float) sourceHeight / (float) sourceWidth; 2231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Set the way we map the output onto the display surface (which will 2261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // be e.g. 1280x720 for a 720p video). The rect is interpreted 2271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // post-rotation, so if the display is rotated 90 degrees we need to 2281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // "pre-rotate" it by flipping width/height, so that the orientation 2291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // adjustment changes it back. 2301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // 2311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // We might want to encode a portrait display as landscape to use more 2321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // of the screen real estate. (If players respect a 90-degree rotation 2331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // hint, we can essentially get a 720x1280 video instead of 1280x720.) 2341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // In that case, we swap the configured video width/height and then 2351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // supply a rotation value to the display projection. 2361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t videoWidth, videoHeight; 2371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t outWidth, outHeight; 2381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (!gRotate) { 2391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoWidth = gVideoWidth; 2401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoHeight = gVideoHeight; 2411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoWidth = gVideoHeight; 2431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoHeight = gVideoWidth; 2441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (videoHeight > (uint32_t)(videoWidth * displayAspect)) { 2461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // limited by narrow width; reduce height 2471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outWidth = videoWidth; 2481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outHeight = (uint32_t)(videoWidth * displayAspect); 2491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // limited by short height; restrict width 2511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outHeight = videoHeight; 2521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outWidth = (uint32_t)(videoHeight / displayAspect); 2531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t offX, offY; 2551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden offX = (videoWidth - outWidth) / 2; 2561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden offY = (videoHeight - outHeight) / 2; 2571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden Rect displayRect(offX, offY, offX + outWidth, offY + outHeight); 2581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 2601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gRotate) { 2611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Rotated content area is %ux%u at offset x=%d y=%d\n", 2621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outHeight, outWidth, offY, offX); 2631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Content area is %ux%u at offset x=%d y=%d\n", 2651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outWidth, outHeight, offX, offY); 2661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder> dpy = SurfaceComposerClient::createDisplay( 2711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden String8("ScreenRecorder"), false /* secure */); 2721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::openGlobalTransaction(); 2741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer); 2751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::setDisplayProjection(dpy, 2761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0, 2771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden layerStackRect, displayRect); 2781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::setDisplayLayerStack(dpy, 0); // default stack 2791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::closeGlobalTransaction(); 2801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pDisplayHandle = dpy; 2821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return NO_ERROR; 2841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 2851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 2871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Runs the MediaCodec encoder, sending the output to the MediaMuxer. The 2881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * input frames are coming from the virtual display as fast as SurfaceFlinger 2891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * wants to send them. 2901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 2911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * The muxer must *not* have been started before calling. 2921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 2931f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t runEncoder(const sp<MediaCodec>& encoder, 2941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden const sp<MediaMuxer>& muxer) { 2951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden static int kTimeout = 250000; // be responsive on signal 2961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 2971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ssize_t trackIdx = -1; 2981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t debugNumFrames = 0; 2992c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC); 3002c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec); 3011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden Vector<sp<ABuffer> > buffers; 3031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->getOutputBuffers(&buffers); 3041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to get output buffers (err=%d)\n", err); 3061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 3071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // This is set by the signal handler. 3101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gStopRequested = false; 3111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Run until we're signaled. 3131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden while (!gStopRequested) { 3141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden size_t bufIndex, offset, size; 3151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden int64_t ptsUsec; 3161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t flags; 3172c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden 3182c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) { 3192c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden if (gVerbose) { 3202c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden printf("Time limit reached\n"); 3212c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden } 3222c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden break; 3232c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden } 3242c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden 3251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Calling dequeueOutputBuffer"); 3261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec, 3271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden &flags, kTimeout); 3281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("dequeueOutputBuffer returned %d", err); 3291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden switch (err) { 3301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case NO_ERROR: 3311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // got a buffer 3321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) { 3331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // ignore this -- we passed the CSD into MediaMuxer when 3341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // we got the format change notification 3351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Got codec config buffer (%u bytes); ignoring", size); 3361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden size = 0; 3371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (size != 0) { 3391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Got data in buffer %d, size=%d, pts=%lld", 3401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden bufIndex, size, ptsUsec); 3411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden CHECK(trackIdx != -1); 3421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 343f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden // If the virtual display isn't providing us with timestamps, 344f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden // use the current time. 345f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (ptsUsec == 0) { 346f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000; 347f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 348f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 3491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // The MediaMuxer docs are unclear, but it appears that we 3501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // need to pass either the full set of BufferInfo flags, or 3511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // (flags & BUFFER_FLAG_SYNCFRAME). 3521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = muxer->writeSampleData(buffers[bufIndex], trackIdx, 3531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ptsUsec, flags); 3541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Failed writing data to muxer (err=%d)\n", 3561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err); 3571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 3581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden debugNumFrames++; 3601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->releaseOutputBuffer(bufIndex); 3621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to release output buffer (err=%d)\n", 3641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err); 3651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 3661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) { 3681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Not expecting EOS from SurfaceFlinger. Go with it. 3691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGD("Received end-of-stream"); 3701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gStopRequested = false; 3711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 3731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case -EAGAIN: // INFO_TRY_AGAIN_LATER 3741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Got -EAGAIN, looping"); 3751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 3761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case INFO_FORMAT_CHANGED: // INFO_OUTPUT_FORMAT_CHANGED 3771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { 3781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // format includes CSD, which we must provide to muxer 3791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Encoder format changed"); 3801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<AMessage> newFormat; 3811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden encoder->getOutputFormat(&newFormat); 3821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden trackIdx = muxer->addTrack(newFormat); 3831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Starting muxer"); 3841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = muxer->start(); 3851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to start muxer (err=%d)\n", err); 3871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 3881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 3911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case INFO_OUTPUT_BUFFERS_CHANGED: // INFO_OUTPUT_BUFFERS_CHANGED 3921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // not expected for an encoder; handle it anyway 3931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Encoder buffers changed"); 3941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->getOutputBuffers(&buffers); 3951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 3971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Unable to get new output buffers (err=%d)\n", err); 39848326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden return err; 3991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 40148326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden case INVALID_OPERATION: 40248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden fprintf(stderr, "Request for encoder buffer failed\n"); 40348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden return err; 4041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden default: 40548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden fprintf(stderr, 40648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden "Got weird result %d from dequeueOutputBuffer\n", err); 4071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 4081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Encoder stopping (req=%d)", gStopRequested); 4121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 4132c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden printf("Encoder stopping; recorded %u frames in %lld seconds\n", 4142c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden debugNumFrames, 4152c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden nanoseconds_to_seconds(systemTime(CLOCK_MONOTONIC) - startWhenNsec)); 4161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return NO_ERROR; 4181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 4191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 4211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Main "do work" method. 4221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 4231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures codec, muxer, and virtual display, then starts moving bits 4241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * around. 4251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 4261f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t recordScreen(const char* fileName) { 4271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 4281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure signal handler. 4301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = configureSignals(); 4311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) return err; 4321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Start Binder thread pool. MediaCodec needs to be able to receive 4341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // messages from mediaserver. 4351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<ProcessState> self = ProcessState::self(); 4361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden self->startThreadPool(); 4371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Get main display parameters. 4391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay( 4401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ISurfaceComposer::eDisplayIdMain); 4411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden DisplayInfo mainDpyInfo; 4421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo); 4431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 4441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "ERROR: unable to get display characteristics\n"); 4451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 4461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 4481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Main display is %dx%d @%.2ffps (orientation=%u)\n", 4491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps, 4501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden mainDpyInfo.orientation); 4511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 453f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden bool rotated = isDeviceRotated(mainDpyInfo.orientation); 454f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVideoWidth == 0) { 455f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w; 456f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 457f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVideoHeight == 0) { 458f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h; 459f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 460f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 4611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure and start the encoder. 4621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<MediaCodec> encoder; 4631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IGraphicBufferProducer> bufferProducer; 4641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer); 465e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber 466f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (err != NO_ERROR && !gSizeSpecified) { 467253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden // fallback is defined for landscape; swap if we're in portrait 468253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden bool needSwap = gVideoWidth < gVideoHeight; 469253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden uint32_t newWidth = needSwap ? kFallbackHeight : kFallbackWidth; 470253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden uint32_t newHeight = needSwap ? kFallbackWidth : kFallbackHeight; 471253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden if (gVideoWidth != newWidth && gVideoHeight != newHeight) { 4722c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden ALOGV("Retrying with 720p"); 473253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden fprintf(stderr, "WARNING: failed at %dx%d, retrying at %dx%d\n", 474253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden gVideoWidth, gVideoHeight, newWidth, newHeight); 475253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden gVideoWidth = newWidth; 476253dfdb983611b8375c9e0b0483eda03fa146028Andy McFadden gVideoHeight = newHeight; 477f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer); 478f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 479f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 480f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (err != NO_ERROR) { 481f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden return err; 482f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 4831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure virtual display. 4851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder> dpy; 4861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy); 487e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber if (err != NO_ERROR) { 488e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber encoder->release(); 489e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber encoder.clear(); 490e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber 491e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber return err; 492e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber } 4931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure, but do not start, muxer. 4951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<MediaMuxer> muxer = new MediaMuxer(fileName, 4961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden MediaMuxer::OUTPUT_FORMAT_MPEG_4); 4971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gRotate) { 4981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden muxer->setOrientationHint(90); 4991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Main encoder loop. 5021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = runEncoder(encoder, muxer); 503e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber if (err != NO_ERROR) { 504e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber encoder->release(); 505e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber encoder.clear(); 506e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber 507e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber return err; 508e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber } 5091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 5111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Stopping encoder and muxer\n"); 5121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5142533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden // Shut everything down, starting with the producer side. 5151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden bufferProducer = NULL; 5162533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden SurfaceComposerClient::destroyDisplay(dpy); 5171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden encoder->stop(); 5191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden muxer->stop(); 5201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden encoder->release(); 5211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 0; 5231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 5241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 52648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden * Sends a broadcast to the media scanner to tell it about the new video. 527f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden * 528f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden * This is optional, but nice to have. 52948326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden */ 53048326940f48390e79476e5ce7c2a18b8201cdafcAndy McFaddenstatic status_t notifyMediaScanner(const char* fileName) { 531f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden pid_t pid = fork(); 532f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden if (pid < 0) { 533f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden int err = errno; 534f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGW("fork() failed: %s", strerror(err)); 535f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden return -err; 536f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } else if (pid > 0) { 537f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden // parent; wait for the child, mostly to make the verbose-mode output 538f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden // look right, but also to check for and log failures 539f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden int status; 540f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); 541f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden if (actualPid != pid) { 542f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGW("waitpid() returned %d (errno=%d)", actualPid, errno); 543f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } else if (status != 0) { 544f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGW("'am broadcast' exited with status=%d", status); 545f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } else { 546f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGV("'am broadcast' exited successfully"); 547f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } 548f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } else { 549f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden const char* kCommand = "/system/bin/am"; 550f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden 551f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden // child; we're single-threaded, so okay to alloc 552f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden String8 fileUrl("file://"); 553f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden fileUrl.append(fileName); 554f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden const char* const argv[] = { 555f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden kCommand, 556f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden "broadcast", 557f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden "-a", 558f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden "android.intent.action.MEDIA_SCANNER_SCAN_FILE", 559f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden "-d", 560f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden fileUrl.string(), 561f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden NULL 562f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden }; 563f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden if (gVerbose) { 564f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden printf("Executing:"); 565f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden for (int i = 0; argv[i] != NULL; i++) { 566f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden printf(" %s", argv[i]); 567f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } 568f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden putchar('\n'); 569f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } else { 570f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden // non-verbose, suppress 'am' output 571f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGV("closing stdout/stderr in child"); 572f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden int fd = open("/dev/null", O_WRONLY); 573f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden if (fd >= 0) { 574f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden dup2(fd, STDOUT_FILENO); 575f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden dup2(fd, STDERR_FILENO); 576f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden close(fd); 577f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } 578f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } 579f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden execv(kCommand, const_cast<char* const*>(argv)); 580f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno)); 581f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden exit(1); 58248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden } 58348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden return NO_ERROR; 58448326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden} 58548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden 58648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden/* 5871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses a string of the form "1280x720". 5881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 5891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Returns true on success. 5901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 5911f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth, 5921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t* pHeight) { 5931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden long width, height; 5941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden char* end; 5951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Must specify base 10, or "0x0" gets parsed differently. 5971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden width = strtol(widthHeight, &end, 10); 5981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (end == widthHeight || *end != 'x' || *(end+1) == '\0') { 5991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // invalid chars in width, or missing 'x', or missing height 6001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return false; 6011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 6021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden height = strtol(end + 1, &end, 10); 6031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (*end != '\0') { 6041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // invalid chars in height 6051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return false; 6061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 6071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 6081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pWidth = width; 6091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pHeight = height; 6101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return true; 6111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 6121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 6131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 6141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Dumps usage on stderr. 6151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 6161f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void usage() { 6171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 6181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Usage: screenrecord [options] <filename>\n" 6191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "\n" 620f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden "Records the device's display to a .mp4 file.\n" 621f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden "\n" 6221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Options:\n" 6231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--size WIDTHxHEIGHT\n" 6242c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden " Set the video size, e.g. \"1280x720\". Default is the device's main\n" 6252c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden " display resolution (if supported), 1280x720 if not. For best results,\n" 6262c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden " use a size supported by the AVC encoder.\n" 6271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--bit-rate RATE\n" 6282c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden " Set the video bit rate, in megabits per second. Default %dMbps.\n" 6292c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden "--time-limit TIME\n" 6302c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden " Set the maximum recording time, in seconds. Default / maximum is %d.\n" 6311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--rotate\n" 632f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden " Rotate the output 90 degrees.\n" 6331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--verbose\n" 6341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden " Display interesting information on stdout.\n" 6351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--help\n" 6361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden " Show this message.\n" 6371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "\n" 6382c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden "Recording continues until Ctrl-C is hit or the time limit is reached.\n" 6392c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden "\n", 6402c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden gBitRate / 1000000, gTimeLimitSec 6411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ); 6421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 6431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 6441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 6451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses args and kicks things off. 6461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 6471f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenint main(int argc, char* const argv[]) { 6481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden static const struct option longOptions[] = { 6491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "help", no_argument, NULL, 'h' }, 6501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "verbose", no_argument, NULL, 'v' }, 6511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "size", required_argument, NULL, 's' }, 6521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "bit-rate", required_argument, NULL, 'b' }, 6532c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden { "time-limit", required_argument, NULL, 't' }, 6541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "rotate", no_argument, NULL, 'r' }, 6551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { NULL, 0, NULL, 0 } 6561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden }; 6571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 6581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden while (true) { 6591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden int optionIndex = 0; 6601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden int ic = getopt_long(argc, argv, "", longOptions, &optionIndex); 6611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (ic == -1) { 6621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 6631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 6641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 6651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden switch (ic) { 6661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'h': 6671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden usage(); 6681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 0; 6691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'v': 6701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gVerbose = true; 6711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 6721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 's': 6731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) { 6741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Invalid size '%s', must be width x height\n", 6751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden optarg); 6761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 6771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 6781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVideoWidth == 0 || gVideoHeight == 0) { 6791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 6801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Invalid size %ux%u, width and height may not be zero\n", 6811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gVideoWidth, gVideoHeight); 6821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 6831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 684f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gSizeSpecified = true; 6851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 6861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'b': 6871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gBitRate = atoi(optarg); 6881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) { 6891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 6901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Bit rate %dbps outside acceptable range [%d,%d]\n", 6911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gBitRate, kMinBitRate, kMaxBitRate); 6921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 6931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 6941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 6952c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden case 't': 6962c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden gTimeLimitSec = atoi(optarg); 6972c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden if (gTimeLimitSec == 0 || gTimeLimitSec > kMaxTimeLimitSec) { 6982c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden fprintf(stderr, 6992c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden "Time limit %ds outside acceptable range [1,%d]\n", 7002c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden gTimeLimitSec, kMaxTimeLimitSec); 7012c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden return 2; 7022c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden } 7032c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden break; 7041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'r': 7051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gRotate = true; 7061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 7071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden default: 7081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (ic != '?') { 7091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic); 7101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 7111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 7121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 7131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 7141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 7151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (optind != argc - 1) { 7161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Must specify output file (see --help).\n"); 7171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 7181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 7191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 72046052913f307b1561f1661bb776fa29c0775758cAndy McFadden // MediaMuxer tries to create the file in the constructor, but we don't 72146052913f307b1561f1661bb776fa29c0775758cAndy McFadden // learn about the failure until muxer.start(), which returns a generic 72246052913f307b1561f1661bb776fa29c0775758cAndy McFadden // error code without logging anything. We attempt to create the file 72346052913f307b1561f1661bb776fa29c0775758cAndy McFadden // now for better diagnostics. 72446052913f307b1561f1661bb776fa29c0775758cAndy McFadden const char* fileName = argv[optind]; 72546052913f307b1561f1661bb776fa29c0775758cAndy McFadden int fd = open(fileName, O_CREAT | O_RDWR, 0644); 72646052913f307b1561f1661bb776fa29c0775758cAndy McFadden if (fd < 0) { 72746052913f307b1561f1661bb776fa29c0775758cAndy McFadden fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno)); 72846052913f307b1561f1661bb776fa29c0775758cAndy McFadden return 1; 72946052913f307b1561f1661bb776fa29c0775758cAndy McFadden } 73046052913f307b1561f1661bb776fa29c0775758cAndy McFadden close(fd); 73146052913f307b1561f1661bb776fa29c0775758cAndy McFadden 73246052913f307b1561f1661bb776fa29c0775758cAndy McFadden status_t err = recordScreen(fileName); 73348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden if (err == NO_ERROR) { 73448326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden // Try to notify the media scanner. Not fatal if this fails. 73548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden notifyMediaScanner(fileName); 73648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden } 7371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGD(err == NO_ERROR ? "success" : "failed"); 7381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return (int) err; 7391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 740