screenrecord.cpp revision 2533c83b4ed8e1ca5b259d59373f941c8f0e9635
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> 241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/Surface.h> 261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/SurfaceComposerClient.h> 271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/ISurfaceComposer.h> 281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <ui/DisplayInfo.h> 291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/openmax/OMX_IVCommon.h> 301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ABuffer.h> 311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ADebug.h> 321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/AMessage.h> 331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaCodec.h> 341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaErrors.h> 351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaMuxer.h> 361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/ICrypto.h> 371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <stdio.h> 391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <signal.h> 401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <getopt.h> 411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 421f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenusing namespace android; 431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Command-line parameters. 451f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gVerbose = false; // chatty on stdout 461f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gRotate = false; // rotate 90 degrees 47f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool gSizeSpecified = false; // was size explicitly requested? 48f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoWidth = 0; // default width+height 49f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoHeight = 0; 501f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic uint32_t gBitRate = 4000000; // 4Mbps 511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Set by signal handler to stop recording. 531f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool gStopRequested; 541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Previous signal handler state, restored after first hit. 561f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionINT; 571f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionHUP; 581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 591f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic const uint32_t kMinBitRate = 100000; // 0.1Mbps 601f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic const uint32_t kMaxBitRate = 100 * 1000000; // 100Mbps 611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Catch keyboard interrupt signals. On receipt, the "stop requested" 641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * flag is raised, and the original handler is restored (so that, if 651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * we get stuck finishing, a second Ctrl-C will kill the process). 661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 671f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void signalCatcher(int signum) 681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{ 691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gStopRequested = true; 701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden switch (signum) { 711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case SIGINT: 721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sigaction(SIGINT, &gOrigSigactionINT, NULL); 731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case SIGHUP: 751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sigaction(SIGHUP, &gOrigSigactionHUP, NULL); 761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden default: 781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden abort(); 791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures signal handlers. The previous handlers are saved. 851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * If the command is run from an interactive adb shell, we get SIGINT 871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * when Ctrl-C is hit. If we're run from the host, the local adb process 881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * gets the signal, and we get a SIGHUP when the terminal disconnects. 891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 901f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t configureSignals() 911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{ 921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden struct sigaction act; 931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden memset(&act, 0, sizeof(act)); 941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden act.sa_handler = signalCatcher; 951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) { 961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err = -errno; 971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to configure SIGINT handler: %s\n", 981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden strerror(errno)); 991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) { 1021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err = -errno; 1031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to configure SIGHUP handler: %s\n", 1041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden strerror(errno)); 1051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return NO_ERROR; 1081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 1091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 111f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden * Returns "true" if the device is rotated 90 degrees. 112f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden */ 113f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool isDeviceRotated(int orientation) { 114f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden return orientation != DISPLAY_ORIENTATION_0 && 115f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden orientation != DISPLAY_ORIENTATION_180; 116f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden} 117f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 118f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden/* 1191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures and starts the MediaCodec encoder. Obtains an input surface 1201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * from the codec. 1211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 1221f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec, 1231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IGraphicBufferProducer>* pBufferProducer) { 1241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 1251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 126f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVerbose) { 127f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden printf("Configuring recorder for %dx%d video at %.2fMbps\n", 128f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoWidth, gVideoHeight, gBitRate / 1000000.0); 129f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 130f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 1311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<AMessage> format = new AMessage; 1321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("width", gVideoWidth); 1331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("height", gVideoHeight); 1341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setString("mime", "video/avc"); 1351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque); 1361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("bitrate", gBitRate); 1371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setFloat("frame-rate", displayFps); 1381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("i-frame-interval", 10); 1391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden /// MediaCodec 1411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<ALooper> looper = new ALooper; 1421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden looper->setName("screenrecord_looper"); 1431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden looper->start(); 1441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Creating codec"); 1451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true); 1461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = codec->configure(format, NULL, NULL, 1471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden MediaCodec::CONFIGURE_FLAG_ENCODE); 1481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 1491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err); 1501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Creating buffer producer"); 1541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IGraphicBufferProducer> bufferProducer; 1551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = codec->createInputSurface(&bufferProducer); 1561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 1571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 1581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "ERROR: unable to create encoder input surface (err=%d)\n", err); 1591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Starting codec"); 1631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = codec->start(); 1641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 1651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err); 1661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 169f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden ALOGV("Codec prepared"); 1701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pCodec = codec; 1711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pBufferProducer = bufferProducer; 1721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 0; 1731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 1741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 1761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures the virtual display. When this completes, virtual display 1771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * frames will start being sent to the encoder's surface. 1781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 1791f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo, 1801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden const sp<IGraphicBufferProducer>& bufferProducer, 1811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder>* pDisplayHandle) { 1821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 1831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Set the region of the layer stack we're interested in, which in our 1851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // case is "all of it". If the app is rotated (so that the width of the 1861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // app is based on the height of the display), reverse width/height. 187f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation); 1881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t sourceWidth, sourceHeight; 1891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (!deviceRotated) { 1901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceWidth = mainDpyInfo.w; 1911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceHeight = mainDpyInfo.h; 1921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 1931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("using rotated width/height"); 1941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceHeight = mainDpyInfo.w; 1951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceWidth = mainDpyInfo.h; 1961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden Rect layerStackRect(sourceWidth, sourceHeight); 1981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // We need to preserve the aspect ratio of the display. 2001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden float displayAspect = (float) sourceHeight / (float) sourceWidth; 2011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Set the way we map the output onto the display surface (which will 2041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // be e.g. 1280x720 for a 720p video). The rect is interpreted 2051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // post-rotation, so if the display is rotated 90 degrees we need to 2061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // "pre-rotate" it by flipping width/height, so that the orientation 2071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // adjustment changes it back. 2081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // 2091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // We might want to encode a portrait display as landscape to use more 2101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // of the screen real estate. (If players respect a 90-degree rotation 2111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // hint, we can essentially get a 720x1280 video instead of 1280x720.) 2121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // In that case, we swap the configured video width/height and then 2131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // supply a rotation value to the display projection. 2141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t videoWidth, videoHeight; 2151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t outWidth, outHeight; 2161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (!gRotate) { 2171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoWidth = gVideoWidth; 2181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoHeight = gVideoHeight; 2191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoWidth = gVideoHeight; 2211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoHeight = gVideoWidth; 2221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (videoHeight > (uint32_t)(videoWidth * displayAspect)) { 2241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // limited by narrow width; reduce height 2251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outWidth = videoWidth; 2261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outHeight = (uint32_t)(videoWidth * displayAspect); 2271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // limited by short height; restrict width 2291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outHeight = videoHeight; 2301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outWidth = (uint32_t)(videoHeight / displayAspect); 2311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t offX, offY; 2331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden offX = (videoWidth - outWidth) / 2; 2341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden offY = (videoHeight - outHeight) / 2; 2351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden Rect displayRect(offX, offY, offX + outWidth, offY + outHeight); 2361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 2381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gRotate) { 2391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Rotated content area is %ux%u at offset x=%d y=%d\n", 2401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outHeight, outWidth, offY, offX); 2411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Content area is %ux%u at offset x=%d y=%d\n", 2431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outWidth, outHeight, offX, offY); 2441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder> dpy = SurfaceComposerClient::createDisplay( 2491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden String8("ScreenRecorder"), false /* secure */); 2501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::openGlobalTransaction(); 2521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer); 2531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::setDisplayProjection(dpy, 2541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0, 2551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden layerStackRect, displayRect); 2561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::setDisplayLayerStack(dpy, 0); // default stack 2571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::closeGlobalTransaction(); 2581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pDisplayHandle = dpy; 2601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return NO_ERROR; 2621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 2631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 2651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Runs the MediaCodec encoder, sending the output to the MediaMuxer. The 2661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * input frames are coming from the virtual display as fast as SurfaceFlinger 2671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * wants to send them. 2681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 2691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * The muxer must *not* have been started before calling. 2701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 2711f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t runEncoder(const sp<MediaCodec>& encoder, 2721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden const sp<MediaMuxer>& muxer) { 2731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden static int kTimeout = 250000; // be responsive on signal 2741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 2751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ssize_t trackIdx = -1; 2761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t debugNumFrames = 0; 2771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden time_t debugStartWhen = time(NULL); 2781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden Vector<sp<ABuffer> > buffers; 2801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->getOutputBuffers(&buffers); 2811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 2821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to get output buffers (err=%d)\n", err); 2831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 2841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // This is set by the signal handler. 2871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gStopRequested = false; 2881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Run until we're signaled. 2901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden while (!gStopRequested) { 2911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden size_t bufIndex, offset, size; 2921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden int64_t ptsUsec; 2931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t flags; 2941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Calling dequeueOutputBuffer"); 2951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec, 2961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden &flags, kTimeout); 2971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("dequeueOutputBuffer returned %d", err); 2981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden switch (err) { 2991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case NO_ERROR: 3001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // got a buffer 3011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) { 3021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // ignore this -- we passed the CSD into MediaMuxer when 3031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // we got the format change notification 3041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Got codec config buffer (%u bytes); ignoring", size); 3051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden size = 0; 3061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (size != 0) { 3081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Got data in buffer %d, size=%d, pts=%lld", 3091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden bufIndex, size, ptsUsec); 3101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden CHECK(trackIdx != -1); 3111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 312f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden // If the virtual display isn't providing us with timestamps, 313f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden // use the current time. 314f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (ptsUsec == 0) { 315f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000; 316f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 317f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 3181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // The MediaMuxer docs are unclear, but it appears that we 3191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // need to pass either the full set of BufferInfo flags, or 3201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // (flags & BUFFER_FLAG_SYNCFRAME). 3211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = muxer->writeSampleData(buffers[bufIndex], trackIdx, 3221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ptsUsec, flags); 3231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Failed writing data to muxer (err=%d)\n", 3251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err); 3261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 3271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden debugNumFrames++; 3291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->releaseOutputBuffer(bufIndex); 3311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to release output buffer (err=%d)\n", 3331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err); 3341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 3351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) { 3371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Not expecting EOS from SurfaceFlinger. Go with it. 3381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGD("Received end-of-stream"); 3391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gStopRequested = false; 3401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 3421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case -EAGAIN: // INFO_TRY_AGAIN_LATER 3431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // not expected with infinite timeout 3441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Got -EAGAIN, looping"); 3451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 3461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case INFO_FORMAT_CHANGED: // INFO_OUTPUT_FORMAT_CHANGED 3471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { 3481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // format includes CSD, which we must provide to muxer 3491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Encoder format changed"); 3501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<AMessage> newFormat; 3511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden encoder->getOutputFormat(&newFormat); 3521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden trackIdx = muxer->addTrack(newFormat); 3531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Starting muxer"); 3541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = muxer->start(); 3551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to start muxer (err=%d)\n", err); 3571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 3581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 3611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case INFO_OUTPUT_BUFFERS_CHANGED: // INFO_OUTPUT_BUFFERS_CHANGED 3621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // not expected for an encoder; handle it anyway 3631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Encoder buffers changed"); 3641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->getOutputBuffers(&buffers); 3651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 3671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Unable to get new output buffers (err=%d)\n", err); 3681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 3701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden default: 3711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGW("Got weird result %d from dequeueOutputBuffer", err); 3721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 3731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Encoder stopping (req=%d)", gStopRequested); 3771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 3781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Encoder stopping; recorded %u frames in %ld seconds\n", 3791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden debugNumFrames, time(NULL) - debugStartWhen); 3801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return NO_ERROR; 3821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 3831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 3851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Main "do work" method. 3861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 3871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures codec, muxer, and virtual display, then starts moving bits 3881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * around. 3891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 3901f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t recordScreen(const char* fileName) { 3911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 3921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure signal handler. 3941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = configureSignals(); 3951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) return err; 3961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Start Binder thread pool. MediaCodec needs to be able to receive 3981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // messages from mediaserver. 3991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<ProcessState> self = ProcessState::self(); 4001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden self->startThreadPool(); 4011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Get main display parameters. 4031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay( 4041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ISurfaceComposer::eDisplayIdMain); 4051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden DisplayInfo mainDpyInfo; 4061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo); 4071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 4081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "ERROR: unable to get display characteristics\n"); 4091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 4101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 4121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Main display is %dx%d @%.2ffps (orientation=%u)\n", 4131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps, 4141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden mainDpyInfo.orientation); 4151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 417f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden bool rotated = isDeviceRotated(mainDpyInfo.orientation); 418f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVideoWidth == 0) { 419f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w; 420f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 421f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVideoHeight == 0) { 422f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h; 423f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 424f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 4251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure and start the encoder. 4261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<MediaCodec> encoder; 4271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IGraphicBufferProducer> bufferProducer; 4281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer); 429f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (err != NO_ERROR && !gSizeSpecified) { 430f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden ALOGV("Retrying with 720p"); 431f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVideoWidth != 1280 && gVideoHeight != 720) { 432f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden fprintf(stderr, "WARNING: failed at %dx%d, retrying at 720p\n", 433f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoWidth, gVideoHeight); 434f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoWidth = 1280; 435f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoHeight = 720; 436f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer); 437f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 438f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 439f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (err != NO_ERROR) { 440f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden return err; 441f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 4421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure virtual display. 4441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder> dpy; 4451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy); 4461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) return err; 4471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure, but do not start, muxer. 4491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<MediaMuxer> muxer = new MediaMuxer(fileName, 4501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden MediaMuxer::OUTPUT_FORMAT_MPEG_4); 4511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gRotate) { 4521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden muxer->setOrientationHint(90); 4531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Main encoder loop. 4561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = runEncoder(encoder, muxer); 4571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) return err; 4581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 4601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Stopping encoder and muxer\n"); 4611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4632533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden // Shut everything down, starting with the producer side. 4641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden bufferProducer = NULL; 4652533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden SurfaceComposerClient::destroyDisplay(dpy); 4661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden encoder->stop(); 4681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden muxer->stop(); 4691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden encoder->release(); 4701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 0; 4721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 4731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 4751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses a string of the form "1280x720". 4761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 4771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Returns true on success. 4781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 4791f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth, 4801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t* pHeight) { 4811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden long width, height; 4821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden char* end; 4831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Must specify base 10, or "0x0" gets parsed differently. 4851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden width = strtol(widthHeight, &end, 10); 4861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (end == widthHeight || *end != 'x' || *(end+1) == '\0') { 4871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // invalid chars in width, or missing 'x', or missing height 4881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return false; 4891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden height = strtol(end + 1, &end, 10); 4911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (*end != '\0') { 4921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // invalid chars in height 4931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return false; 4941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pWidth = width; 4971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pHeight = height; 4981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return true; 4991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 5001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 5021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Dumps usage on stderr. 5031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 5041f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void usage() { 5051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 5061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Usage: screenrecord [options] <filename>\n" 5071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "\n" 508f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden "Records the device's display to a .mp4 file.\n" 509f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden "\n" 5101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Options:\n" 5111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--size WIDTHxHEIGHT\n" 5121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden " Set the video size, e.g. \"1280x720\". For best results, use\n" 5131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden " a size supported by the AVC encoder.\n" 5141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--bit-rate RATE\n" 5151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden " Set the video bit rate, in megabits per second. Default 4Mbps.\n" 5161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--rotate\n" 517f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden " Rotate the output 90 degrees.\n" 5181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--verbose\n" 5191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden " Display interesting information on stdout.\n" 5201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--help\n" 5211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden " Show this message.\n" 5221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "\n" 5231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Recording continues until Ctrl-C is hit.\n" 5241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "\n" 5251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ); 5261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 5271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 5291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses args and kicks things off. 5301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 5311f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenint main(int argc, char* const argv[]) { 5321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden static const struct option longOptions[] = { 5331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "help", no_argument, NULL, 'h' }, 5341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "verbose", no_argument, NULL, 'v' }, 5351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "size", required_argument, NULL, 's' }, 5361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "bit-rate", required_argument, NULL, 'b' }, 5371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { "rotate", no_argument, NULL, 'r' }, 5381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { NULL, 0, NULL, 0 } 5391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden }; 5401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden while (true) { 5421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden int optionIndex = 0; 5431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden int ic = getopt_long(argc, argv, "", longOptions, &optionIndex); 5441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (ic == -1) { 5451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 5461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden switch (ic) { 5491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'h': 5501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden usage(); 5511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 0; 5521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'v': 5531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gVerbose = true; 5541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 5551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 's': 5561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) { 5571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Invalid size '%s', must be width x height\n", 5581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden optarg); 5591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 5601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVideoWidth == 0 || gVideoHeight == 0) { 5621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 5631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Invalid size %ux%u, width and height may not be zero\n", 5641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gVideoWidth, gVideoHeight); 5651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 5661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 567f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gSizeSpecified = true; 5681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 5691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'b': 5701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gBitRate = atoi(optarg); 5711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) { 5721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 5731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Bit rate %dbps outside acceptable range [%d,%d]\n", 5741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gBitRate, kMinBitRate, kMaxBitRate); 5751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 5761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 5781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'r': 5791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gRotate = true; 5801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 5811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden default: 5821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (ic != '?') { 5831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic); 5841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 5861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (optind != argc - 1) { 5901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Must specify output file (see --help).\n"); 5911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 5921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err = recordScreen(argv[optind]); 5951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGD(err == NO_ERROR ? "success" : "failed"); 5961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return (int) err; 5971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 598