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 17884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <assert.h> 18884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <ctype.h> 19884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <fcntl.h> 20884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <inttypes.h> 21884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <getopt.h> 22884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <signal.h> 23884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <stdio.h> 24884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <stdlib.h> 25884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <string.h> 26884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <sys/wait.h> 27884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <termios.h> 28884989c67081190ff864419328e9e81506db67caMark Salyzyn#include <unistd.h> 29884989c67081190ff864419328e9e81506db67caMark Salyzyn 301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#define LOG_TAG "ScreenRecord" 31aaa3f358410701710e31f31de62f0b4521989661Andy McFadden#define ATRACE_TAG ATRACE_TAG_GRAPHICS 321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden//#define LOG_NDEBUG 0 331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Log.h> 341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <binder/IPCThreadState.h> 361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <utils/Errors.h> 372c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden#include <utils/Timers.h> 38aaa3f358410701710e31f31de62f0b4521989661Andy McFadden#include <utils/Trace.h> 391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/Surface.h> 411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/SurfaceComposerClient.h> 421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <gui/ISurfaceComposer.h> 431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <ui/DisplayInfo.h> 441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/openmax/OMX_IVCommon.h> 451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/ABuffer.h> 461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/foundation/AMessage.h> 471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaCodec.h> 481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaErrors.h> 491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/stagefright/MediaMuxer.h> 501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden#include <media/ICrypto.h> 511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 52aaa3f358410701710e31f31de62f0b4521989661Andy McFadden#include "screenrecord.h" 53aaa3f358410701710e31f31de62f0b4521989661Andy McFadden#include "Overlay.h" 5421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden#include "FrameOutput.h" 55aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 561f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenusing namespace android; 571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 582c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMinBitRate = 100000; // 0.1Mbps 59aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic const uint32_t kMaxBitRate = 200 * 1000000; // 200Mbps 602c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kMaxTimeLimitSec = 180; // 3 minutes 612c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kFallbackWidth = 1280; // 720p 622c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic const uint32_t kFallbackHeight = 720; 6321bde57f0099fed5cca78d9357571dc015a63227Andy McFaddenstatic const char* kMimeTypeAvc = "video/avc"; 642c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden 651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Command-line parameters. 66aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gVerbose = false; // chatty on stdout 67aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gRotate = false; // rotate 90 degrees 6821bde57f0099fed5cca78d9357571dc015a63227Andy McFaddenstatic enum { 69e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES, FORMAT_RAW_FRAMES 7021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden} gOutputFormat = FORMAT_MP4; // data format for output 71aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gSizeSpecified = false; // was size explicitly requested? 72aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gWantInfoScreen = false; // do we want initial info screen? 73aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic bool gWantFrameTime = false; // do we want times on each frame? 74aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic uint32_t gVideoWidth = 0; // default width+height 75f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic uint32_t gVideoHeight = 0; 76aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic uint32_t gBitRate = 4000000; // 4Mbps 772c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFaddenstatic uint32_t gTimeLimitSec = kMaxTimeLimitSec; 781f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 791f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Set by signal handler to stop recording. 80aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic volatile bool gStopRequested; 811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden// Previous signal handler state, restored after first hit. 831f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionINT; 841f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic struct sigaction gOrigSigactionHUP; 851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Catch keyboard interrupt signals. On receipt, the "stop requested" 891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * flag is raised, and the original handler is restored (so that, if 901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * we get stuck finishing, a second Ctrl-C will kill the process). 911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 921f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void signalCatcher(int signum) 931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden{ 941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gStopRequested = true; 951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden switch (signum) { 961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case SIGINT: 971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case SIGHUP: 982c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden sigaction(SIGINT, &gOrigSigactionINT, NULL); 991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sigaction(SIGHUP, &gOrigSigactionHUP, NULL); 1001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 1011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden default: 1021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden abort(); 1031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 1041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 1061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 1081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures signal handlers. The previous handlers are saved. 1091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 1101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * If the command is run from an interactive adb shell, we get SIGINT 1111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * when Ctrl-C is hit. If we're run from the host, the local adb process 1121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * gets the signal, and we get a SIGHUP when the terminal disconnects. 1131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 114aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic status_t configureSignals() { 1151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden struct sigaction act; 1161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden memset(&act, 0, sizeof(act)); 1171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden act.sa_handler = signalCatcher; 1181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) { 1191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err = -errno; 1201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to configure SIGINT handler: %s\n", 1211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden strerror(errno)); 1221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) { 1251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err = -errno; 1261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to configure SIGHUP handler: %s\n", 1271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden strerror(errno)); 1281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return NO_ERROR; 1311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 1321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 134f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden * Returns "true" if the device is rotated 90 degrees. 135f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden */ 136f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFaddenstatic bool isDeviceRotated(int orientation) { 137f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden return orientation != DISPLAY_ORIENTATION_0 && 138f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden orientation != DISPLAY_ORIENTATION_180; 139f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden} 140f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 141f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden/* 1421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures and starts the MediaCodec encoder. Obtains an input surface 1431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * from the codec. 1441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 1451f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec, 1461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IGraphicBufferProducer>* pBufferProducer) { 1471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 1481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 149f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVerbose) { 15021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden printf("Configuring recorder for %dx%d %s at %.2fMbps\n", 15121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden gVideoWidth, gVideoHeight, kMimeTypeAvc, gBitRate / 1000000.0); 152f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 153f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 1541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<AMessage> format = new AMessage; 1551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("width", gVideoWidth); 1561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("height", gVideoHeight); 15721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden format->setString("mime", kMimeTypeAvc); 1581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque); 1591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("bitrate", gBitRate); 1601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setFloat("frame-rate", displayFps); 1611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden format->setInt32("i-frame-interval", 10); 1621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<ALooper> looper = new ALooper; 1641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden looper->setName("screenrecord_looper"); 1651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden looper->start(); 1661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Creating codec"); 16721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden sp<MediaCodec> codec = MediaCodec::CreateByType(looper, kMimeTypeAvc, true); 168a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden if (codec == NULL) { 16921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden fprintf(stderr, "ERROR: unable to create %s codec instance\n", 17021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden kMimeTypeAvc); 171a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden return UNKNOWN_ERROR; 172a2081368e2068a86f2db9b0dd562d9e18f69ea37Andy McFadden } 173aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 1741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = codec->configure(format, NULL, NULL, 1751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden MediaCodec::CONFIGURE_FLAG_ENCODE); 1761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 17721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden fprintf(stderr, "ERROR: unable to configure %s codec at %dx%d (err=%d)\n", 17821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden kMimeTypeAvc, gVideoWidth, gVideoHeight, err); 179aaa3f358410701710e31f31de62f0b4521989661Andy McFadden codec->release(); 1801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 183aaa3f358410701710e31f31de62f0b4521989661Andy McFadden ALOGV("Creating encoder input surface"); 1841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IGraphicBufferProducer> bufferProducer; 1851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = codec->createInputSurface(&bufferProducer); 1861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 1871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 1881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "ERROR: unable to create encoder input surface (err=%d)\n", err); 189aaa3f358410701710e31f31de62f0b4521989661Andy McFadden codec->release(); 1901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 1921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 1931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Starting codec"); 1941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = codec->start(); 1951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 1961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err); 197aaa3f358410701710e31f31de62f0b4521989661Andy McFadden codec->release(); 1981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 1991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 201f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden ALOGV("Codec prepared"); 2021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pCodec = codec; 2031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pBufferProducer = bufferProducer; 2041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 0; 2051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 2061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 208aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * Sets the display projection, based on the display dimensions, video size, 209aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * and device orientation. 2101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 211aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic status_t setDisplayProjection(const sp<IBinder>& dpy, 212aaa3f358410701710e31f31de62f0b4521989661Andy McFadden const DisplayInfo& mainDpyInfo) { 2131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 2141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Set the region of the layer stack we're interested in, which in our 2161f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // case is "all of it". If the app is rotated (so that the width of the 2171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // app is based on the height of the display), reverse width/height. 218f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation); 2191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t sourceWidth, sourceHeight; 2201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (!deviceRotated) { 2211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceWidth = mainDpyInfo.w; 2221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceHeight = mainDpyInfo.h; 2231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("using rotated width/height"); 2251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceHeight = mainDpyInfo.w; 2261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sourceWidth = mainDpyInfo.h; 2271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden Rect layerStackRect(sourceWidth, sourceHeight); 2291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // We need to preserve the aspect ratio of the display. 2311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden float displayAspect = (float) sourceHeight / (float) sourceWidth; 2321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Set the way we map the output onto the display surface (which will 2351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // be e.g. 1280x720 for a 720p video). The rect is interpreted 2361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // post-rotation, so if the display is rotated 90 degrees we need to 2371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // "pre-rotate" it by flipping width/height, so that the orientation 2381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // adjustment changes it back. 2391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // 2401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // We might want to encode a portrait display as landscape to use more 2411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // of the screen real estate. (If players respect a 90-degree rotation 2421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // hint, we can essentially get a 720x1280 video instead of 1280x720.) 2431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // In that case, we swap the configured video width/height and then 2441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // supply a rotation value to the display projection. 2451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t videoWidth, videoHeight; 2461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t outWidth, outHeight; 2471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (!gRotate) { 2481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoWidth = gVideoWidth; 2491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoHeight = gVideoHeight; 2501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoWidth = gVideoHeight; 2521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden videoHeight = gVideoWidth; 2531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (videoHeight > (uint32_t)(videoWidth * displayAspect)) { 2551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // limited by narrow width; reduce height 2561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outWidth = videoWidth; 2571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outHeight = (uint32_t)(videoWidth * displayAspect); 2581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // limited by short height; restrict width 2601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outHeight = videoHeight; 2611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outWidth = (uint32_t)(videoHeight / displayAspect); 2621f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t offX, offY; 2641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden offX = (videoWidth - outWidth) / 2; 2651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden offY = (videoHeight - outHeight) / 2; 2661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden Rect displayRect(offX, offY, offX + outWidth, offY + outHeight); 2671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 2691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gRotate) { 2701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Rotated content area is %ux%u at offset x=%d y=%d\n", 2711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outHeight, outWidth, offY, offX); 2721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } else { 2731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Content area is %ux%u at offset x=%d y=%d\n", 2741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden outWidth, outHeight, offX, offY); 2751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 2771f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 278aaa3f358410701710e31f31de62f0b4521989661Andy McFadden SurfaceComposerClient::setDisplayProjection(dpy, 279aaa3f358410701710e31f31de62f0b4521989661Andy McFadden gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0, 280aaa3f358410701710e31f31de62f0b4521989661Andy McFadden layerStackRect, displayRect); 281aaa3f358410701710e31f31de62f0b4521989661Andy McFadden return NO_ERROR; 282aaa3f358410701710e31f31de62f0b4521989661Andy McFadden} 2831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 284aaa3f358410701710e31f31de62f0b4521989661Andy McFadden/* 285aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * Configures the virtual display. When this completes, virtual display 286aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * frames will start arriving from the buffer producer. 287aaa3f358410701710e31f31de62f0b4521989661Andy McFadden */ 288aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo, 289aaa3f358410701710e31f31de62f0b4521989661Andy McFadden const sp<IGraphicBufferProducer>& bufferProducer, 290aaa3f358410701710e31f31de62f0b4521989661Andy McFadden sp<IBinder>* pDisplayHandle) { 2911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder> dpy = SurfaceComposerClient::createDisplay( 292aaa3f358410701710e31f31de62f0b4521989661Andy McFadden String8("ScreenRecorder"), false /*secure*/); 2931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 2941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::openGlobalTransaction(); 2951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer); 296aaa3f358410701710e31f31de62f0b4521989661Andy McFadden setDisplayProjection(dpy, mainDpyInfo); 2971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::setDisplayLayerStack(dpy, 0); // default stack 2981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden SurfaceComposerClient::closeGlobalTransaction(); 2991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pDisplayHandle = dpy; 3011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return NO_ERROR; 3031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 3041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 3061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Runs the MediaCodec encoder, sending the output to the MediaMuxer. The 3071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * input frames are coming from the virtual display as fast as SurfaceFlinger 3081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * wants to send them. 3091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 3102d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden * Exactly one of muxer or rawFp must be non-null. 3112d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden * 3121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * The muxer must *not* have been started before calling. 3131f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 3141f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t runEncoder(const sp<MediaCodec>& encoder, 3152d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& mainDpy, 316aaa3f358410701710e31f31de62f0b4521989661Andy McFadden const sp<IBinder>& virtualDpy, uint8_t orientation) { 3171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden static int kTimeout = 250000; // be responsive on signal 3181f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 3191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ssize_t trackIdx = -1; 3201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t debugNumFrames = 0; 3212c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC); 3222c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec); 323aaa3f358410701710e31f31de62f0b4521989661Andy McFadden DisplayInfo mainDpyInfo; 3241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3252d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden assert((rawFp == NULL && muxer != NULL) || (rawFp != NULL && muxer == NULL)); 3262d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden 3271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden Vector<sp<ABuffer> > buffers; 3281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->getOutputBuffers(&buffers); 3291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 3301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to get output buffers (err=%d)\n", err); 3311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 3321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // This is set by the signal handler. 3351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gStopRequested = false; 3361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 3371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Run until we're signaled. 3381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden while (!gStopRequested) { 3391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden size_t bufIndex, offset, size; 3401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden int64_t ptsUsec; 3411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t flags; 3422c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden 3432c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) { 3442c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden if (gVerbose) { 3452c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden printf("Time limit reached\n"); 3462c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden } 3472c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden break; 3482c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden } 3492c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden 3501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Calling dequeueOutputBuffer"); 3511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec, 3521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden &flags, kTimeout); 3531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("dequeueOutputBuffer returned %d", err); 3541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden switch (err) { 3551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case NO_ERROR: 3561f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // got a buffer 3571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) { 358884989c67081190ff864419328e9e81506db67caMark Salyzyn ALOGV("Got codec config buffer (%zu bytes)", size); 3592d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (muxer != NULL) { 3602d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // ignore this -- we passed the CSD into MediaMuxer when 3612d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // we got the format change notification 3622d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden size = 0; 3632d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 3641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 3651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (size != 0) { 366884989c67081190ff864419328e9e81506db67caMark Salyzyn ALOGV("Got data in buffer %zu, size=%zu, pts=%" PRId64, 3671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden bufIndex, size, ptsUsec); 368aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 369aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { // scope 370aaa3f358410701710e31f31de62f0b4521989661Andy McFadden ATRACE_NAME("orientation"); 371aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // Check orientation, update if it has changed. 372aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // 373aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // Polling for changes is inefficient and wrong, but the 374aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // useful stuff is hard to get at without a Dalvik VM. 375aaa3f358410701710e31f31de62f0b4521989661Andy McFadden err = SurfaceComposerClient::getDisplayInfo(mainDpy, 376aaa3f358410701710e31f31de62f0b4521989661Andy McFadden &mainDpyInfo); 377aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (err != NO_ERROR) { 378aaa3f358410701710e31f31de62f0b4521989661Andy McFadden ALOGW("getDisplayInfo(main) failed: %d", err); 379aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } else if (orientation != mainDpyInfo.orientation) { 380aaa3f358410701710e31f31de62f0b4521989661Andy McFadden ALOGD("orientation changed, now %d", mainDpyInfo.orientation); 381aaa3f358410701710e31f31de62f0b4521989661Andy McFadden SurfaceComposerClient::openGlobalTransaction(); 382aaa3f358410701710e31f31de62f0b4521989661Andy McFadden setDisplayProjection(virtualDpy, mainDpyInfo); 383aaa3f358410701710e31f31de62f0b4521989661Andy McFadden SurfaceComposerClient::closeGlobalTransaction(); 384aaa3f358410701710e31f31de62f0b4521989661Andy McFadden orientation = mainDpyInfo.orientation; 385aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 386aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 3871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 388f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden // If the virtual display isn't providing us with timestamps, 389aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // use the current time. This isn't great -- we could get 390aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // decoded data in clusters -- but we're not expecting 391aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // to hit this anyway. 392f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (ptsUsec == 0) { 393f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000; 394f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 395f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 3962d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (muxer == NULL) { 3972d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden fwrite(buffers[bufIndex]->data(), 1, size, rawFp); 3982d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // Flush the data immediately in case we're streaming. 3992d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // We don't want to do this if all we've written is 4002d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // the SPS/PPS data because mplayer gets confused. 4012d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) == 0) { 4022d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden fflush(rawFp); 4032d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 4042d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } else { 4052d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // The MediaMuxer docs are unclear, but it appears that we 4062d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // need to pass either the full set of BufferInfo flags, or 4072d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // (flags & BUFFER_FLAG_SYNCFRAME). 4082d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // 4092d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // If this blocks for too long we could drop frames. We may 4102d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // want to queue these up and do them on a different thread. 411aaa3f358410701710e31f31de62f0b4521989661Andy McFadden ATRACE_NAME("write sample"); 4122d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden assert(trackIdx != -1); 413aaa3f358410701710e31f31de62f0b4521989661Andy McFadden err = muxer->writeSampleData(buffers[bufIndex], trackIdx, 414aaa3f358410701710e31f31de62f0b4521989661Andy McFadden ptsUsec, flags); 415aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (err != NO_ERROR) { 416aaa3f358410701710e31f31de62f0b4521989661Andy McFadden fprintf(stderr, 417aaa3f358410701710e31f31de62f0b4521989661Andy McFadden "Failed writing data to muxer (err=%d)\n", err); 418aaa3f358410701710e31f31de62f0b4521989661Andy McFadden return err; 419aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 4201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden debugNumFrames++; 4221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->releaseOutputBuffer(bufIndex); 4241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 4251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Unable to release output buffer (err=%d)\n", 4261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err); 4271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 4281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) { 4301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Not expecting EOS from SurfaceFlinger. Go with it. 431aaa3f358410701710e31f31de62f0b4521989661Andy McFadden ALOGI("Received end-of-stream"); 432aaa3f358410701710e31f31de62f0b4521989661Andy McFadden gStopRequested = true; 4331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 4351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case -EAGAIN: // INFO_TRY_AGAIN_LATER 4361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Got -EAGAIN, looping"); 4371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 4381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case INFO_FORMAT_CHANGED: // INFO_OUTPUT_FORMAT_CHANGED 4391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden { 440aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // Format includes CSD, which we must provide to muxer. 4411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Encoder format changed"); 4421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<AMessage> newFormat; 4431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden encoder->getOutputFormat(&newFormat); 4442d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (muxer != NULL) { 4452d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden trackIdx = muxer->addTrack(newFormat); 4462d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden ALOGV("Starting muxer"); 4472d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden err = muxer->start(); 4482d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (err != NO_ERROR) { 4492d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden fprintf(stderr, "Unable to start muxer (err=%d)\n", err); 4502d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden return err; 4512d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 4521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 4551f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case INFO_OUTPUT_BUFFERS_CHANGED: // INFO_OUTPUT_BUFFERS_CHANGED 456aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // Not expected for an encoder; handle it anyway. 4571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Encoder buffers changed"); 4581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = encoder->getOutputBuffers(&buffers); 4591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 4601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 4611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Unable to get new output buffers (err=%d)\n", err); 46248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden return err; 4631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 46548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden case INVALID_OPERATION: 466aaa3f358410701710e31f31de62f0b4521989661Andy McFadden ALOGW("dequeueOutputBuffer returned INVALID_OPERATION"); 46748326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden return err; 4681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden default: 46948326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden fprintf(stderr, 47048326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden "Got weird result %d from dequeueOutputBuffer\n", err); 4711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 4721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGV("Encoder stopping (req=%d)", gStopRequested); 4761f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 477884989c67081190ff864419328e9e81506db67caMark Salyzyn printf("Encoder stopping; recorded %u frames in %" PRId64 " seconds\n", 478aaa3f358410701710e31f31de62f0b4521989661Andy McFadden debugNumFrames, nanoseconds_to_seconds( 479aaa3f358410701710e31f31de62f0b4521989661Andy McFadden systemTime(CLOCK_MONOTONIC) - startWhenNsec)); 4801f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 4811f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return NO_ERROR; 4821f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 4831f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 4841f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 4852d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden * Raw H.264 byte stream output requested. Send the output to stdout 4862d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden * if desired. If the output is a tty, reconfigure it to avoid the 4872d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden * CRLF line termination that we see with "adb shell" commands. 4882d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden */ 4892d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFaddenstatic FILE* prepareRawOutput(const char* fileName) { 4902d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden FILE* rawFp = NULL; 4912d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden 4922d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (strcmp(fileName, "-") == 0) { 4932d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (gVerbose) { 4942d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden fprintf(stderr, "ERROR: verbose output and '-' not compatible"); 4952d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden return NULL; 4962d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 4972d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden rawFp = stdout; 4982d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } else { 4992d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden rawFp = fopen(fileName, "w"); 5002d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (rawFp == NULL) { 5012d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden fprintf(stderr, "fopen raw failed: %s\n", strerror(errno)); 5022d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden return NULL; 5032d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 5042d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 5052d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden 5062d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden int fd = fileno(rawFp); 5072d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (isatty(fd)) { 5082d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // best effort -- reconfigure tty for "raw" 5092d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden ALOGD("raw video output to tty (fd=%d)", fd); 5102d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden struct termios term; 5112d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (tcgetattr(fd, &term) == 0) { 5122d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden cfmakeraw(&term); 5132d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (tcsetattr(fd, TCSANOW, &term) == 0) { 5142d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden ALOGD("tty successfully configured for raw"); 5152d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 5162d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 5172d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 5182d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden 5192d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden return rawFp; 5202d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden} 5212d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden 5222d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden/* 52321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden * Main "do work" start point. 5241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 5251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Configures codec, muxer, and virtual display, then starts moving bits 5261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * around. 5271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 5281f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic status_t recordScreen(const char* fileName) { 5291f5a90bc795475896044fcb1f74816c102851f06Andy McFadden status_t err; 5301f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5311f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure signal handler. 5321f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = configureSignals(); 5331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) return err; 5341f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5351f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Start Binder thread pool. MediaCodec needs to be able to receive 5361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // messages from mediaserver. 5371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<ProcessState> self = ProcessState::self(); 5381f5a90bc795475896044fcb1f74816c102851f06Andy McFadden self->startThreadPool(); 5391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 5401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Get main display parameters. 5411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay( 5421f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ISurfaceComposer::eDisplayIdMain); 5431f5a90bc795475896044fcb1f74816c102851f06Andy McFadden DisplayInfo mainDpyInfo; 5441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo); 5451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (err != NO_ERROR) { 5461f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "ERROR: unable to get display characteristics\n"); 5471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return err; 5481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVerbose) { 5501f5a90bc795475896044fcb1f74816c102851f06Andy McFadden printf("Main display is %dx%d @%.2ffps (orientation=%u)\n", 5511f5a90bc795475896044fcb1f74816c102851f06Andy McFadden mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps, 5521f5a90bc795475896044fcb1f74816c102851f06Andy McFadden mainDpyInfo.orientation); 5531f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 5541f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 555f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden bool rotated = isDeviceRotated(mainDpyInfo.orientation); 556f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVideoWidth == 0) { 557f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w; 558f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 559f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden if (gVideoHeight == 0) { 560f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h; 561f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 562f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden 5631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure and start the encoder. 5641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<MediaCodec> encoder; 56521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden sp<FrameOutput> frameOutput; 566aaa3f358410701710e31f31de62f0b4521989661Andy McFadden sp<IGraphicBufferProducer> encoderInputSurface; 567e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby if (gOutputFormat != FORMAT_FRAMES && gOutputFormat != FORMAT_RAW_FRAMES) { 56821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface); 56921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden 57021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (err != NO_ERROR && !gSizeSpecified) { 57121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // fallback is defined for landscape; swap if we're in portrait 57221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden bool needSwap = gVideoWidth < gVideoHeight; 57321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden uint32_t newWidth = needSwap ? kFallbackHeight : kFallbackWidth; 57421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden uint32_t newHeight = needSwap ? kFallbackWidth : kFallbackHeight; 57521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (gVideoWidth != newWidth && gVideoHeight != newHeight) { 57621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden ALOGV("Retrying with 720p"); 57721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden fprintf(stderr, "WARNING: failed at %dx%d, retrying at %dx%d\n", 57821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden gVideoWidth, gVideoHeight, newWidth, newHeight); 57921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden gVideoWidth = newWidth; 58021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden gVideoHeight = newHeight; 58121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden err = prepareEncoder(mainDpyInfo.fps, &encoder, 58221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden &encoderInputSurface); 58321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 584f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 58521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (err != NO_ERROR) return err; 586aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 58721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // From here on, we must explicitly release() the encoder before it goes 58821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // out of scope, or we will get an assertion failure from stagefright 58921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // later on in a different thread. 59021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } else { 59121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // We're not using an encoder at all. The "encoder input surface" we hand to 59221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // SurfaceFlinger will just feed directly to us. 59321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden frameOutput = new FrameOutput(); 59421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden err = frameOutput->createInputSurface(gVideoWidth, gVideoHeight, &encoderInputSurface); 59521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (err != NO_ERROR) { 59621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden return err; 59721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 59821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 599aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 600aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // Draw the "info" page by rendering a frame with GLES and sending 601aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // it directly to the encoder. 602aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // TODO: consider displaying this as a regular layer to avoid b/11697754 603aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (gWantInfoScreen) { 604aaa3f358410701710e31f31de62f0b4521989661Andy McFadden Overlay::drawInfoPage(encoderInputSurface); 605aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 606aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 607aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // Configure optional overlay. 608aaa3f358410701710e31f31de62f0b4521989661Andy McFadden sp<IGraphicBufferProducer> bufferProducer; 6090c98f99cb8207ff5b08e33da4b7e024312c5d9c9Andy McFadden sp<Overlay> overlay; 610aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (gWantFrameTime) { 611aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // Send virtual display frames to an external texture. 6120c98f99cb8207ff5b08e33da4b7e024312c5d9c9Andy McFadden overlay = new Overlay(); 613aaa3f358410701710e31f31de62f0b4521989661Andy McFadden err = overlay->start(encoderInputSurface, &bufferProducer); 614aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (err != NO_ERROR) { 61521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (encoder != NULL) encoder->release(); 616aaa3f358410701710e31f31de62f0b4521989661Andy McFadden return err; 617aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 618aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (gVerbose) { 619aaa3f358410701710e31f31de62f0b4521989661Andy McFadden printf("Bugreport overlay created\n"); 620aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 621aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } else { 622aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // Use the encoder's input surface as the virtual display surface. 623aaa3f358410701710e31f31de62f0b4521989661Andy McFadden bufferProducer = encoderInputSurface; 624f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden } 6251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 6261f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Configure virtual display. 6271f5a90bc795475896044fcb1f74816c102851f06Andy McFadden sp<IBinder> dpy; 6281f5a90bc795475896044fcb1f74816c102851f06Andy McFadden err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy); 629e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber if (err != NO_ERROR) { 63021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (encoder != NULL) encoder->release(); 631e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber return err; 632e6d5794b2173ffe4e7509203a91778b19eafcebfAndreas Huber } 6331f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 6342d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden sp<MediaMuxer> muxer = NULL; 6352d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden FILE* rawFp = NULL; 63621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden switch (gOutputFormat) { 63721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden case FORMAT_MP4: { 63821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // Configure muxer. We have to wait for the CSD blob from the encoder 63921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // before we can start it. 64021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden muxer = new MediaMuxer(fileName, MediaMuxer::OUTPUT_FORMAT_MPEG_4); 64121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (gRotate) { 64221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden muxer->setOrientationHint(90); // TODO: does this do anything? 64321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 64421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden break; 64521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 64621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden case FORMAT_H264: 647e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby case FORMAT_FRAMES: 648e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby case FORMAT_RAW_FRAMES: { 64921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden rawFp = prepareRawOutput(fileName); 65021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (rawFp == NULL) { 65121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (encoder != NULL) encoder->release(); 65221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden return -1; 65321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 65421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden break; 65521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 65621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden default: 65721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden fprintf(stderr, "ERROR: unknown format %d\n", gOutputFormat); 65821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden abort(); 65921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 66021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden 661e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby if (gOutputFormat == FORMAT_FRAMES || gOutputFormat == FORMAT_RAW_FRAMES) { 66221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // TODO: if we want to make this a proper feature, we should output 66321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // an outer header with version info. Right now we never change 66421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // the frame size or format, so we could conceivably just send 66521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // the current frame header once and then follow it with an 66621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // unbroken stream of data. 66721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden 66821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // Make the EGL context current again. This gets unhooked if we're 66921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // using "--bugreport" mode. 67021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // TODO: figure out if we can eliminate this 67121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden frameOutput->prepareToCopy(); 67221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden 67321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden while (!gStopRequested) { 67421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // Poll for frames, the same way we do for MediaCodec. We do 67521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // all of the work on the main thread. 67621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // 67721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // Ideally we'd sleep indefinitely and wake when the 67821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // stop was requested, but this will do for now. (It almost 67921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // works because wait() wakes when a signal hits, but we 68021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // need to handle the edge cases.) 681e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby bool rawFrames = gOutputFormat == FORMAT_RAW_FRAMES; 682e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby err = frameOutput->copyFrame(rawFp, 250000, rawFrames); 68321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (err == ETIMEDOUT) { 68421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden err = NO_ERROR; 68521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } else if (err != NO_ERROR) { 68621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden ALOGE("Got error %d from copyFrame()", err); 68721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden break; 68821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 6892d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 6902d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } else { 69121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // Main encoder loop. 69221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden err = runEncoder(encoder, muxer, rawFp, mainDpy, dpy, 69321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden mainDpyInfo.orientation); 69421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (err != NO_ERROR) { 69521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden fprintf(stderr, "Encoder failed (err=%d)\n", err); 69621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // fall through to cleanup 6972d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 6981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 69921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (gVerbose) { 70021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden printf("Stopping encoder and muxer\n"); 70121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 7021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 7031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 7042533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden // Shut everything down, starting with the producer side. 705aaa3f358410701710e31f31de62f0b4521989661Andy McFadden encoderInputSurface = NULL; 7062533c83b4ed8e1ca5b259d59373f941c8f0e9635Andy McFadden SurfaceComposerClient::destroyDisplay(dpy); 70721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (overlay != NULL) overlay->stop(); 70821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (encoder != NULL) encoder->stop(); 7092d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (muxer != NULL) { 7102d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // If we don't stop muxer explicitly, i.e. let the destructor run, 7112d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // it may hang (b/11050628). 7122d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden muxer->stop(); 7132d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } else if (rawFp != stdout) { 7142d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden fclose(rawFp); 7152d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 71621bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (encoder != NULL) encoder->release(); 7171f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 718aaa3f358410701710e31f31de62f0b4521989661Andy McFadden return err; 7191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 7201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 7211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 72248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden * Sends a broadcast to the media scanner to tell it about the new video. 723f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden * 724f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden * This is optional, but nice to have. 72548326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden */ 72648326940f48390e79476e5ce7c2a18b8201cdafcAndy McFaddenstatic status_t notifyMediaScanner(const char* fileName) { 727aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // need to do allocations before the fork() 728aaa3f358410701710e31f31de62f0b4521989661Andy McFadden String8 fileUrl("file://"); 729aaa3f358410701710e31f31de62f0b4521989661Andy McFadden fileUrl.append(fileName); 730aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 731aaa3f358410701710e31f31de62f0b4521989661Andy McFadden const char* kCommand = "/system/bin/am"; 732aaa3f358410701710e31f31de62f0b4521989661Andy McFadden const char* const argv[] = { 733aaa3f358410701710e31f31de62f0b4521989661Andy McFadden kCommand, 734aaa3f358410701710e31f31de62f0b4521989661Andy McFadden "broadcast", 735aaa3f358410701710e31f31de62f0b4521989661Andy McFadden "-a", 736aaa3f358410701710e31f31de62f0b4521989661Andy McFadden "android.intent.action.MEDIA_SCANNER_SCAN_FILE", 737aaa3f358410701710e31f31de62f0b4521989661Andy McFadden "-d", 738aaa3f358410701710e31f31de62f0b4521989661Andy McFadden fileUrl.string(), 739aaa3f358410701710e31f31de62f0b4521989661Andy McFadden NULL 740aaa3f358410701710e31f31de62f0b4521989661Andy McFadden }; 741aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (gVerbose) { 742aaa3f358410701710e31f31de62f0b4521989661Andy McFadden printf("Executing:"); 743aaa3f358410701710e31f31de62f0b4521989661Andy McFadden for (int i = 0; argv[i] != NULL; i++) { 744aaa3f358410701710e31f31de62f0b4521989661Andy McFadden printf(" %s", argv[i]); 745aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 746aaa3f358410701710e31f31de62f0b4521989661Andy McFadden putchar('\n'); 747aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 748aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 749f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden pid_t pid = fork(); 750f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden if (pid < 0) { 751f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden int err = errno; 752f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGW("fork() failed: %s", strerror(err)); 753f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden return -err; 754f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } else if (pid > 0) { 755f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden // parent; wait for the child, mostly to make the verbose-mode output 756f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden // look right, but also to check for and log failures 757f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden int status; 758f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); 759f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden if (actualPid != pid) { 760aaa3f358410701710e31f31de62f0b4521989661Andy McFadden ALOGW("waitpid(%d) returned %d (errno=%d)", pid, actualPid, errno); 761f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } else if (status != 0) { 762f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGW("'am broadcast' exited with status=%d", status); 763f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } else { 764f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGV("'am broadcast' exited successfully"); 765f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } 766f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } else { 767aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (!gVerbose) { 768f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden // non-verbose, suppress 'am' output 769f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGV("closing stdout/stderr in child"); 770f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden int fd = open("/dev/null", O_WRONLY); 771f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden if (fd >= 0) { 772f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden dup2(fd, STDOUT_FILENO); 773f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden dup2(fd, STDERR_FILENO); 774f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden close(fd); 775f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } 776f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden } 777f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden execv(kCommand, const_cast<char* const*>(argv)); 778f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno)); 779f74ccdb61627421bccfdbc479ffdc06ced717db4Andy McFadden exit(1); 78048326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden } 78148326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden return NO_ERROR; 78248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden} 78348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden 78448326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden/* 7851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses a string of the form "1280x720". 7861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * 7871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Returns true on success. 7881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 7891f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth, 7901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden uint32_t* pHeight) { 7911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden long width, height; 7921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden char* end; 7931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 7941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // Must specify base 10, or "0x0" gets parsed differently. 7951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden width = strtol(widthHeight, &end, 10); 7961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (end == widthHeight || *end != 'x' || *(end+1) == '\0') { 7971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // invalid chars in width, or missing 'x', or missing height 7981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return false; 7991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 8001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden height = strtol(end + 1, &end, 10); 8011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (*end != '\0') { 8021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden // invalid chars in height 8031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return false; 8041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 8051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 8061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pWidth = width; 8071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden *pHeight = height; 8081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return true; 8091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 8101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 8111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 812aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * Accepts a string with a bare number ("4000000") or with a single-character 813aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * unit ("4m"). 814aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * 815aaa3f358410701710e31f31de62f0b4521989661Andy McFadden * Returns an error if parsing fails. 816aaa3f358410701710e31f31de62f0b4521989661Andy McFadden */ 817aaa3f358410701710e31f31de62f0b4521989661Andy McFaddenstatic status_t parseValueWithUnit(const char* str, uint32_t* pValue) { 818aaa3f358410701710e31f31de62f0b4521989661Andy McFadden long value; 819aaa3f358410701710e31f31de62f0b4521989661Andy McFadden char* endptr; 820aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 821aaa3f358410701710e31f31de62f0b4521989661Andy McFadden value = strtol(str, &endptr, 10); 822aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (*endptr == '\0') { 823aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // bare number 824aaa3f358410701710e31f31de62f0b4521989661Andy McFadden *pValue = value; 825aaa3f358410701710e31f31de62f0b4521989661Andy McFadden return NO_ERROR; 826aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } else if (toupper(*endptr) == 'M' && *(endptr+1) == '\0') { 827aaa3f358410701710e31f31de62f0b4521989661Andy McFadden *pValue = value * 1000000; // check for overflow? 828aaa3f358410701710e31f31de62f0b4521989661Andy McFadden return NO_ERROR; 829aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } else { 830aaa3f358410701710e31f31de62f0b4521989661Andy McFadden fprintf(stderr, "Unrecognized value: %s\n", str); 831aaa3f358410701710e31f31de62f0b4521989661Andy McFadden return UNKNOWN_ERROR; 832aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 833aaa3f358410701710e31f31de62f0b4521989661Andy McFadden} 834aaa3f358410701710e31f31de62f0b4521989661Andy McFadden 835aaa3f358410701710e31f31de62f0b4521989661Andy McFadden/* 8361f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Dumps usage on stderr. 8371f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 8381f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenstatic void usage() { 8391f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 8401f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Usage: screenrecord [options] <filename>\n" 8411f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "\n" 842aaa3f358410701710e31f31de62f0b4521989661Andy McFadden "Android screenrecord v%d.%d. Records the device's display to a .mp4 file.\n" 843f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden "\n" 8441f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Options:\n" 8451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--size WIDTHxHEIGHT\n" 8462c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden " Set the video size, e.g. \"1280x720\". Default is the device's main\n" 8472c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden " display resolution (if supported), 1280x720 if not. For best results,\n" 8482c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden " use a size supported by the AVC encoder.\n" 8491f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--bit-rate RATE\n" 85096f2ead1ec99f6aaab876827a7c9985b039bf3c8Andy McFadden " Set the video bit rate, in bits per second. Value may be specified as\n" 85196f2ead1ec99f6aaab876827a7c9985b039bf3c8Andy McFadden " bits or megabits, e.g. '4000000' is equivalent to '4M'. Default %dMbps.\n" 852aaa3f358410701710e31f31de62f0b4521989661Andy McFadden "--bugreport\n" 853aaa3f358410701710e31f31de62f0b4521989661Andy McFadden " Add additional information, such as a timestamp overlay, that is helpful\n" 854aaa3f358410701710e31f31de62f0b4521989661Andy McFadden " in videos captured to illustrate bugs.\n" 8552c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden "--time-limit TIME\n" 8562c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden " Set the maximum recording time, in seconds. Default / maximum is %d.\n" 8571f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--verbose\n" 8581f5a90bc795475896044fcb1f74816c102851f06Andy McFadden " Display interesting information on stdout.\n" 8591f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "--help\n" 8601f5a90bc795475896044fcb1f74816c102851f06Andy McFadden " Show this message.\n" 8611f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "\n" 8622c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden "Recording continues until Ctrl-C is hit or the time limit is reached.\n" 8632c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden "\n", 864aaa3f358410701710e31f31de62f0b4521989661Andy McFadden kVersionMajor, kVersionMinor, gBitRate / 1000000, gTimeLimitSec 8651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ); 8661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 8671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 8681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden/* 8691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden * Parses args and kicks things off. 8701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden */ 8711f5a90bc795475896044fcb1f74816c102851f06Andy McFaddenint main(int argc, char* const argv[]) { 8721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden static const struct option longOptions[] = { 873aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { "help", no_argument, NULL, 'h' }, 874aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { "verbose", no_argument, NULL, 'v' }, 875aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { "size", required_argument, NULL, 's' }, 876aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { "bit-rate", required_argument, NULL, 'b' }, 877aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { "time-limit", required_argument, NULL, 't' }, 87821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden { "bugreport", no_argument, NULL, 'u' }, 87921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden // "unofficial" options 880aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { "show-device-info", no_argument, NULL, 'i' }, 881aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { "show-frame-time", no_argument, NULL, 'f' }, 882aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { "rotate", no_argument, NULL, 'r' }, 88321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden { "output-format", required_argument, NULL, 'o' }, 884aaa3f358410701710e31f31de62f0b4521989661Andy McFadden { NULL, 0, NULL, 0 } 8851f5a90bc795475896044fcb1f74816c102851f06Andy McFadden }; 8861f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 8871f5a90bc795475896044fcb1f74816c102851f06Andy McFadden while (true) { 8881f5a90bc795475896044fcb1f74816c102851f06Andy McFadden int optionIndex = 0; 8891f5a90bc795475896044fcb1f74816c102851f06Andy McFadden int ic = getopt_long(argc, argv, "", longOptions, &optionIndex); 8901f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (ic == -1) { 8911f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 8921f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 8931f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 8941f5a90bc795475896044fcb1f74816c102851f06Andy McFadden switch (ic) { 8951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'h': 8961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden usage(); 8971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 0; 8981f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'v': 8991f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gVerbose = true; 9001f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 9011f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 's': 9021f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) { 9031f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Invalid size '%s', must be width x height\n", 9041f5a90bc795475896044fcb1f74816c102851f06Andy McFadden optarg); 9051f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 9061f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 9071f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gVideoWidth == 0 || gVideoHeight == 0) { 9081f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 9091f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Invalid size %ux%u, width and height may not be zero\n", 9101f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gVideoWidth, gVideoHeight); 9111f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 9121f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 913f560001b5d60225dc7e101b2481477a3c39b66a4Andy McFadden gSizeSpecified = true; 9141f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 9151f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'b': 916aaa3f358410701710e31f31de62f0b4521989661Andy McFadden if (parseValueWithUnit(optarg, &gBitRate) != NO_ERROR) { 917aaa3f358410701710e31f31de62f0b4521989661Andy McFadden return 2; 918aaa3f358410701710e31f31de62f0b4521989661Andy McFadden } 9191f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) { 9201f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, 9211f5a90bc795475896044fcb1f74816c102851f06Andy McFadden "Bit rate %dbps outside acceptable range [%d,%d]\n", 9221f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gBitRate, kMinBitRate, kMaxBitRate); 9231f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 9241f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 9251f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 9262c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden case 't': 9272c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden gTimeLimitSec = atoi(optarg); 9282c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden if (gTimeLimitSec == 0 || gTimeLimitSec > kMaxTimeLimitSec) { 9292c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden fprintf(stderr, 9302c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden "Time limit %ds outside acceptable range [1,%d]\n", 9312c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden gTimeLimitSec, kMaxTimeLimitSec); 9322c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden return 2; 9332c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden } 9342c041c1c927fdbf60f53f1a1960e5155a79007b7Andy McFadden break; 93521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden case 'u': 936aaa3f358410701710e31f31de62f0b4521989661Andy McFadden gWantInfoScreen = true; 937aaa3f358410701710e31f31de62f0b4521989661Andy McFadden gWantFrameTime = true; 938aaa3f358410701710e31f31de62f0b4521989661Andy McFadden break; 93921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden case 'i': 940aaa3f358410701710e31f31de62f0b4521989661Andy McFadden gWantInfoScreen = true; 94121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden break; 94221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden case 'f': 943aaa3f358410701710e31f31de62f0b4521989661Andy McFadden gWantFrameTime = true; 944aaa3f358410701710e31f31de62f0b4521989661Andy McFadden break; 9451f5a90bc795475896044fcb1f74816c102851f06Andy McFadden case 'r': 946aaa3f358410701710e31f31de62f0b4521989661Andy McFadden // experimental feature 9471f5a90bc795475896044fcb1f74816c102851f06Andy McFadden gRotate = true; 9481f5a90bc795475896044fcb1f74816c102851f06Andy McFadden break; 94921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden case 'o': 95021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (strcmp(optarg, "mp4") == 0) { 95121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden gOutputFormat = FORMAT_MP4; 95221bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } else if (strcmp(optarg, "h264") == 0) { 95321bde57f0099fed5cca78d9357571dc015a63227Andy McFadden gOutputFormat = FORMAT_H264; 95421bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } else if (strcmp(optarg, "frames") == 0) { 95521bde57f0099fed5cca78d9357571dc015a63227Andy McFadden gOutputFormat = FORMAT_FRAMES; 956e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby } else if (strcmp(optarg, "raw-frames") == 0) { 957e32106fd5175afdf939ae397aece9caf378a4912Benoit Goby gOutputFormat = FORMAT_RAW_FRAMES; 95821bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } else { 95921bde57f0099fed5cca78d9357571dc015a63227Andy McFadden fprintf(stderr, "Unknown format '%s'\n", optarg); 96021bde57f0099fed5cca78d9357571dc015a63227Andy McFadden return 2; 96121bde57f0099fed5cca78d9357571dc015a63227Andy McFadden } 9622d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden break; 9631f5a90bc795475896044fcb1f74816c102851f06Andy McFadden default: 9641f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (ic != '?') { 9651f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic); 9661f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 9671f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 9681f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 9691f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 9701f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 9711f5a90bc795475896044fcb1f74816c102851f06Andy McFadden if (optind != argc - 1) { 9721f5a90bc795475896044fcb1f74816c102851f06Andy McFadden fprintf(stderr, "Must specify output file (see --help).\n"); 9731f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return 2; 9741f5a90bc795475896044fcb1f74816c102851f06Andy McFadden } 9751f5a90bc795475896044fcb1f74816c102851f06Andy McFadden 97646052913f307b1561f1661bb776fa29c0775758cAndy McFadden const char* fileName = argv[optind]; 97721bde57f0099fed5cca78d9357571dc015a63227Andy McFadden if (gOutputFormat == FORMAT_MP4) { 9782d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // MediaMuxer tries to create the file in the constructor, but we don't 9792d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // learn about the failure until muxer.start(), which returns a generic 9802d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // error code without logging anything. We attempt to create the file 9812d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden // now for better diagnostics. 9822d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden int fd = open(fileName, O_CREAT | O_RDWR, 0644); 9832d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden if (fd < 0) { 9842d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno)); 9852d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden return 1; 9862d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden } 9872d11a2031b99db9b503a7ad7efd1f18606af4012Andy McFadden close(fd); 98846052913f307b1561f1661bb776fa29c0775758cAndy McFadden } 98946052913f307b1561f1661bb776fa29c0775758cAndy McFadden 99046052913f307b1561f1661bb776fa29c0775758cAndy McFadden status_t err = recordScreen(fileName); 99148326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden if (err == NO_ERROR) { 99248326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden // Try to notify the media scanner. Not fatal if this fails. 99348326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden notifyMediaScanner(fileName); 99448326940f48390e79476e5ce7c2a18b8201cdafcAndy McFadden } 9951f5a90bc795475896044fcb1f74816c102851f06Andy McFadden ALOGD(err == NO_ERROR ? "success" : "failed"); 9961f5a90bc795475896044fcb1f74816c102851f06Andy McFadden return (int) err; 9971f5a90bc795475896044fcb1f74816c102851f06Andy McFadden} 998