screenrecord.cpp revision c475546b6df3b8febc0191e5895f4546a0abd52f
11ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni/* 21ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni * Copyright 2013 The Android Open Source Project 3da0f069871343119251d6b0586be356dc2146a62Yang Ni * 4433558f0f9abbf07770db288183a15fd261cace2Yabin Cui * Licensed under the Apache License, Version 2.0 (the "License"); 5433558f0f9abbf07770db288183a15fd261cace2Yabin Cui * you may not use this file except in compliance with the License. 6433558f0f9abbf07770db288183a15fd261cace2Yabin Cui * You may obtain a copy of the License at 7da0f069871343119251d6b0586be356dc2146a62Yang Ni * 8062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * http://www.apache.org/licenses/LICENSE-2.0 9062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * 10da0f069871343119251d6b0586be356dc2146a62Yang Ni * Unless required by applicable law or agreed to in writing, software 11da0f069871343119251d6b0586be356dc2146a62Yang Ni * distributed under the License is distributed on an "AS IS" BASIS, 12da0f069871343119251d6b0586be356dc2146a62Yang Ni * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13da0f069871343119251d6b0586be356dc2146a62Yang Ni * See the License for the specific language governing permissions and 14da0f069871343119251d6b0586be356dc2146a62Yang Ni * limitations under the License. 15da0f069871343119251d6b0586be356dc2146a62Yang Ni */ 16da0f069871343119251d6b0586be356dc2146a62Yang Ni 17da0f069871343119251d6b0586be356dc2146a62Yang Ni#define LOG_TAG "ScreenRecord" 181ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#define ATRACE_TAG ATRACE_TAG_GRAPHICS 191ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni//#define LOG_NDEBUG 0 201ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <utils/Log.h> 211ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni 222abfcc6d129fe3defddef4540aa95cc445c03a7aYang Ni#include <binder/IPCThreadState.h> 231ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <utils/Errors.h> 241ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <utils/Timers.h> 251ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <utils/Trace.h> 26da0f069871343119251d6b0586be356dc2146a62Yang Ni 27da0f069871343119251d6b0586be356dc2146a62Yang Ni#include <gui/Surface.h> 28da0f069871343119251d6b0586be356dc2146a62Yang Ni#include <gui/SurfaceComposerClient.h> 29da0f069871343119251d6b0586be356dc2146a62Yang Ni#include <gui/ISurfaceComposer.h> 301ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <ui/DisplayInfo.h> 311ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <media/openmax/OMX_IVCommon.h> 321ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <media/stagefright/foundation/ABuffer.h> 331ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <media/stagefright/foundation/AMessage.h> 341ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <media/stagefright/MediaCodec.h> 351ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <media/stagefright/MediaErrors.h> 36da0f069871343119251d6b0586be356dc2146a62Yang Ni#include <media/stagefright/MediaMuxer.h> 371ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <media/ICrypto.h> 381ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni 391ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <stdlib.h> 40ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni#include <unistd.h> 41eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include <string.h> 42eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include <stdio.h> 43eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include <ctype.h> 44eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include <fcntl.h> 45eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include <signal.h> 46eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include <getopt.h> 47eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include <sys/wait.h> 48eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include <termios.h> 49eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include <assert.h> 50eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 51eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include "screenrecord.h" 52eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#include "Overlay.h" 53eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 54ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Niusing namespace android; 55ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni 56eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic const uint32_t kMinBitRate = 100000; // 0.1Mbps 57eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic const uint32_t kMaxBitRate = 200 * 1000000; // 200Mbps 58eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic const uint32_t kMaxTimeLimitSec = 180; // 3 minutes 59eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic const uint32_t kFallbackWidth = 1280; // 720p 60eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic const uint32_t kFallbackHeight = 720; 61eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 62eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni// Command-line parameters. 63eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic bool gVerbose = false; // chatty on stdout 64eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic bool gRotate = false; // rotate 90 degrees 65eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic bool gRawOutput = false; // generate raw H.264 byte stream output 661ffd86b448d78366190c540f98f8b6d641cdb6cfYang Nistatic bool gSizeSpecified = false; // was size explicitly requested? 67eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic bool gWantInfoScreen = false; // do we want initial info screen? 68eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic bool gWantFrameTime = false; // do we want times on each frame? 691ffd86b448d78366190c540f98f8b6d641cdb6cfYang Nistatic uint32_t gVideoWidth = 0; // default width+height 70eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic uint32_t gVideoHeight = 0; 71eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic uint32_t gBitRate = 4000000; // 4Mbps 72eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic uint32_t gTimeLimitSec = kMaxTimeLimitSec; 73eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 74eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni// Set by signal handler to stop recording. 75eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic volatile bool gStopRequested; 76eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 771ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni// Previous signal handler state, restored after first hit. 78eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic struct sigaction gOrigSigactionINT; 791ffd86b448d78366190c540f98f8b6d641cdb6cfYang Nistatic struct sigaction gOrigSigactionHUP; 80eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 811ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni 821ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni/* 83eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * Catch keyboard interrupt signals. On receipt, the "stop requested" 84eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * flag is raised, and the original handler is restored (so that, if 851ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni * we get stuck finishing, a second Ctrl-C will kill the process). 861ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni */ 87da0f069871343119251d6b0586be356dc2146a62Yang Nistatic void signalCatcher(int signum) 88da0f069871343119251d6b0586be356dc2146a62Yang Ni{ 89062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni gStopRequested = true; 90062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni switch (signum) { 91062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni case SIGINT: 92062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni case SIGHUP: 93062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni sigaction(SIGINT, &gOrigSigactionINT, NULL); 94da0f069871343119251d6b0586be356dc2146a62Yang Ni sigaction(SIGHUP, &gOrigSigactionHUP, NULL); 95eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni break; 96eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni default: 97eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni abort(); 98062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni break; 99da0f069871343119251d6b0586be356dc2146a62Yang Ni } 100da0f069871343119251d6b0586be356dc2146a62Yang Ni} 101ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni 102eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni/* 103eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * Configures signal handlers. The previous handlers are saved. 104eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * 105da0f069871343119251d6b0586be356dc2146a62Yang Ni * If the command is run from an interactive adb shell, we get SIGINT 106ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni * when Ctrl-C is hit. If we're run from the host, the local adb process 107ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni * gets the signal, and we get a SIGHUP when the terminal disconnects. 108062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni */ 109eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic status_t configureSignals() { 110eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni struct sigaction act; 1111ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni memset(&act, 0, sizeof(act)); 1121ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni act.sa_handler = signalCatcher; 113eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) { 114ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni status_t err = -errno; 115ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni fprintf(stderr, "Unable to configure SIGINT handler: %s\n", 116ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni strerror(errno)); 117ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni return err; 118ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni } 119ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) { 120ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni status_t err = -errno; 121eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni fprintf(stderr, "Unable to configure SIGHUP handler: %s\n", 122ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni strerror(errno)); 123ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni return err; 124ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni } 125ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni return NO_ERROR; 126ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni} 127ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni 128eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni/* 129eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * Returns "true" if the device is rotated 90 degrees. 1301ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni */ 1311ffd86b448d78366190c540f98f8b6d641cdb6cfYang Nistatic bool isDeviceRotated(int orientation) { 132ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni return orientation != DISPLAY_ORIENTATION_0 && 133eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni orientation != DISPLAY_ORIENTATION_180; 1341ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni} 1351ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni 1361ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni/* 1371ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni * Configures and starts the MediaCodec encoder. Obtains an input surface 138062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * from the codec. 139062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni */ 140eb9aa675754c49f613c6ad71d41472b30f38b007Yang Nistatic status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec, 141eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni sp<IGraphicBufferProducer>* pBufferProducer) { 142062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni status_t err; 143062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 144eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (gVerbose) { 145eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni printf("Configuring recorder for %dx%d video at %.2fMbps\n", 146062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni gVideoWidth, gVideoHeight, gBitRate / 1000000.0); 147062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 148062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 149062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni sp<AMessage> format = new AMessage; 150eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni format->setInt32("width", gVideoWidth); 151062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni format->setInt32("height", gVideoHeight); 152062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni format->setString("mime", "video/avc"); 153eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque); 154eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni format->setInt32("bitrate", gBitRate); 155eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni format->setFloat("frame-rate", displayFps); 1561ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni format->setInt32("i-frame-interval", 10); 157eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 158eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni sp<ALooper> looper = new ALooper; 159062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni looper->setName("screenrecord_looper"); 160062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni looper->start(); 161062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGV("Creating codec"); 162eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true); 163da0f069871343119251d6b0586be356dc2146a62Yang Ni if (codec == NULL) { 164eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni fprintf(stderr, "ERROR: unable to create video/avc codec instance\n"); 165eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni return UNKNOWN_ERROR; 166da0f069871343119251d6b0586be356dc2146a62Yang Ni } 167eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 168eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni err = codec->configure(format, NULL, NULL, 169da0f069871343119251d6b0586be356dc2146a62Yang Ni MediaCodec::CONFIGURE_FLAG_ENCODE); 170da0f069871343119251d6b0586be356dc2146a62Yang Ni if (err != NO_ERROR) { 171062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err); 172062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni codec->release(); 173062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return err; 174062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 175062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 176eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni ALOGV("Creating encoder input surface"); 177062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni sp<IGraphicBufferProducer> bufferProducer; 178062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni err = codec->createInputSurface(&bufferProducer); 179062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (err != NO_ERROR) { 180062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni fprintf(stderr, 181062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni "ERROR: unable to create encoder input surface (err=%d)\n", err); 182062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni codec->release(); 183062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return err; 184062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 185062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 186062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGV("Starting codec"); 1871ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni err = codec->start(); 1881ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni if (err != NO_ERROR) { 1891ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err); 190eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni codec->release(); 191eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni return err; 192eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 193062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 194062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGV("Codec prepared"); 195062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni *pCodec = codec; 196062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni *pBufferProducer = bufferProducer; 197062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return 0; 198da0f069871343119251d6b0586be356dc2146a62Yang Ni} 199da0f069871343119251d6b0586be356dc2146a62Yang Ni 200da0f069871343119251d6b0586be356dc2146a62Yang Ni/* 201da0f069871343119251d6b0586be356dc2146a62Yang Ni * Sets the display projection, based on the display dimensions, video size, 202da0f069871343119251d6b0586be356dc2146a62Yang Ni * and device orientation. 203da0f069871343119251d6b0586be356dc2146a62Yang Ni */ 204edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Nistatic status_t setDisplayProjection(const sp<IBinder>& dpy, 205edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni const DisplayInfo& mainDpyInfo) { 206edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni status_t err; 207edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni 208edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni // Set the region of the layer stack we're interested in, which in our 209edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni // case is "all of it". If the app is rotated (so that the width of the 210edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni // app is based on the height of the display), reverse width/height. 211edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation); 212edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni uint32_t sourceWidth, sourceHeight; 213edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni if (!deviceRotated) { 214edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni sourceWidth = mainDpyInfo.w; 215edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni sourceHeight = mainDpyInfo.h; 216edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni } else { 217edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni ALOGV("using rotated width/height"); 218edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni sourceHeight = mainDpyInfo.w; 219edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni sourceWidth = mainDpyInfo.h; 220edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni } 221edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni Rect layerStackRect(sourceWidth, sourceHeight); 222edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni 223edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni // We need to preserve the aspect ratio of the display. 224edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni float displayAspect = (float) sourceHeight / (float) sourceWidth; 225edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni 226edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni 227edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni // Set the way we map the output onto the display surface (which will 228edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni // be e.g. 1280x720 for a 720p video). The rect is interpreted 229edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni // post-rotation, so if the display is rotated 90 degrees we need to 230da0f069871343119251d6b0586be356dc2146a62Yang Ni // "pre-rotate" it by flipping width/height, so that the orientation 231eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // adjustment changes it back. 232eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // 233da0f069871343119251d6b0586be356dc2146a62Yang Ni // We might want to encode a portrait display as landscape to use more 234da0f069871343119251d6b0586be356dc2146a62Yang Ni // of the screen real estate. (If players respect a 90-degree rotation 235da0f069871343119251d6b0586be356dc2146a62Yang Ni // hint, we can essentially get a 720x1280 video instead of 1280x720.) 236062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // In that case, we swap the configured video width/height and then 237062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // supply a rotation value to the display projection. 238eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni uint32_t videoWidth, videoHeight; 239edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni uint32_t outWidth, outHeight; 240edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni if (!gRotate) { 241eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni videoWidth = gVideoWidth; 242eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni videoHeight = gVideoHeight; 243eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } else { 244eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni videoWidth = gVideoHeight; 245eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni videoHeight = gVideoWidth; 246eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 247edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni if (videoHeight > (uint32_t)(videoWidth * displayAspect)) { 248edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni // limited by narrow width; reduce height 249edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni outWidth = videoWidth; 250eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni outHeight = (uint32_t)(videoWidth * displayAspect); 251eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } else { 252eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // limited by short height; restrict width 253062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni outHeight = videoHeight; 254062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni outWidth = (uint32_t)(videoHeight / displayAspect); 255062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 256062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni uint32_t offX, offY; 257062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni offX = (videoWidth - outWidth) / 2; 258062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni offY = (videoHeight - outHeight) / 2; 259062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni Rect displayRect(offX, offY, offX + outWidth, offY + outHeight); 260eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 261eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (gVerbose) { 262eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (gRotate) { 263eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni printf("Rotated content area is %ux%u at offset x=%d y=%d\n", 264eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni outHeight, outWidth, offY, offX); 265eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } else { 266da0f069871343119251d6b0586be356dc2146a62Yang Ni printf("Content area is %ux%u at offset x=%d y=%d\n", 267da0f069871343119251d6b0586be356dc2146a62Yang Ni outWidth, outHeight, offX, offY); 268da0f069871343119251d6b0586be356dc2146a62Yang Ni } 269da0f069871343119251d6b0586be356dc2146a62Yang Ni } 270eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 271da0f069871343119251d6b0586be356dc2146a62Yang Ni SurfaceComposerClient::setDisplayProjection(dpy, 272eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0, 273eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni layerStackRect, displayRect); 274eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni return NO_ERROR; 275eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni} 276da0f069871343119251d6b0586be356dc2146a62Yang Ni 277eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni/* 278eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * Configures the virtual display. When this completes, virtual display 279eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * frames will start arriving from the buffer producer. 280eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni */ 281da0f069871343119251d6b0586be356dc2146a62Yang Nistatic status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo, 282eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni const sp<IGraphicBufferProducer>& bufferProducer, 283eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni sp<IBinder>* pDisplayHandle) { 284eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni sp<IBinder> dpy = SurfaceComposerClient::createDisplay( 285eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni String8("ScreenRecorder"), false /*secure*/); 286da0f069871343119251d6b0586be356dc2146a62Yang Ni 287eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni SurfaceComposerClient::openGlobalTransaction(); 288eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer); 289eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni setDisplayProjection(dpy, mainDpyInfo); 290eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni SurfaceComposerClient::setDisplayLayerStack(dpy, 0); // default stack 291eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni SurfaceComposerClient::closeGlobalTransaction(); 292eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 293da0f069871343119251d6b0586be356dc2146a62Yang Ni *pDisplayHandle = dpy; 294eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 295eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni return NO_ERROR; 296eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni} 297eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 298da0f069871343119251d6b0586be356dc2146a62Yang Ni/* 299eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * Runs the MediaCodec encoder, sending the output to the MediaMuxer. The 300da0f069871343119251d6b0586be356dc2146a62Yang Ni * input frames are coming from the virtual display as fast as SurfaceFlinger 301062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * wants to send them. 302062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * 303062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * Exactly one of muxer or rawFp must be non-null. 304062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * 305062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * The muxer must *not* have been started before calling. 306062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni */ 307062c287f573ecc06c38ee4295e5627e12c52ac3dYang Nistatic status_t runEncoder(const sp<MediaCodec>& encoder, 308062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& mainDpy, 309062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni const sp<IBinder>& virtualDpy, uint8_t orientation) { 310062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni static int kTimeout = 250000; // be responsive on signal 311062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni status_t err; 312062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ssize_t trackIdx = -1; 313062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni uint32_t debugNumFrames = 0; 314062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC); 315062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec); 316062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni DisplayInfo mainDpyInfo; 317062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 318062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni assert((rawFp == NULL && muxer != NULL) || (rawFp != NULL && muxer == NULL)); 319062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 320062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni Vector<sp<ABuffer> > buffers; 321da0f069871343119251d6b0586be356dc2146a62Yang Ni err = encoder->getOutputBuffers(&buffers); 322da0f069871343119251d6b0586be356dc2146a62Yang Ni if (err != NO_ERROR) { 323da0f069871343119251d6b0586be356dc2146a62Yang Ni fprintf(stderr, "Unable to get output buffers (err=%d)\n", err); 324062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return err; 325da0f069871343119251d6b0586be356dc2146a62Yang Ni } 326062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 327eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // This is set by the signal handler. 328eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni gStopRequested = false; 329da0f069871343119251d6b0586be356dc2146a62Yang Ni 330eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // Run until we're signaled. 331eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni while (!gStopRequested) { 332eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni size_t bufIndex, offset, size; 333da0f069871343119251d6b0586be356dc2146a62Yang Ni int64_t ptsUsec; 334062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni uint32_t flags; 335062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 336062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) { 337da0f069871343119251d6b0586be356dc2146a62Yang Ni if (gVerbose) { 338062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni printf("Time limit reached\n"); 339eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 340eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni break; 341eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 342da0f069871343119251d6b0586be356dc2146a62Yang Ni 343eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni ALOGV("Calling dequeueOutputBuffer"); 344eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec, 345eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni &flags, kTimeout); 346062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGV("dequeueOutputBuffer returned %d", err); 347062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni switch (err) { 348062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni case NO_ERROR: 349062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // got a buffer 350062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) { 351062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGV("Got codec config buffer (%u bytes)", size); 352062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (muxer != NULL) { 353062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // ignore this -- we passed the CSD into MediaMuxer when 354062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // we got the format change notification 355062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni size = 0; 356062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 357da0f069871343119251d6b0586be356dc2146a62Yang Ni } 358062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (size != 0) { 359062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGV("Got data in buffer %d, size=%d, pts=%lld", 360062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni bufIndex, size, ptsUsec); 361062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 362062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni { // scope 363062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ATRACE_NAME("orientation"); 364062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // Check orientation, update if it has changed. 365062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // 366062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // Polling for changes is inefficient and wrong, but the 367062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // useful stuff is hard to get at without a Dalvik VM. 368062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni err = SurfaceComposerClient::getDisplayInfo(mainDpy, 369062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni &mainDpyInfo); 370062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (err != NO_ERROR) { 371eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni ALOGW("getDisplayInfo(main) failed: %d", err); 372da0f069871343119251d6b0586be356dc2146a62Yang Ni } else if (orientation != mainDpyInfo.orientation) { 373433558f0f9abbf07770db288183a15fd261cace2Yabin Cui ALOGD("orientation changed, now %d", mainDpyInfo.orientation); 374433558f0f9abbf07770db288183a15fd261cace2Yabin Cui SurfaceComposerClient::openGlobalTransaction(); 375433558f0f9abbf07770db288183a15fd261cace2Yabin Cui setDisplayProjection(virtualDpy, mainDpyInfo); 376433558f0f9abbf07770db288183a15fd261cace2Yabin Cui SurfaceComposerClient::closeGlobalTransaction(); 377433558f0f9abbf07770db288183a15fd261cace2Yabin Cui orientation = mainDpyInfo.orientation; 378433558f0f9abbf07770db288183a15fd261cace2Yabin Cui } 379433558f0f9abbf07770db288183a15fd261cace2Yabin Cui } 380433558f0f9abbf07770db288183a15fd261cace2Yabin Cui 381433558f0f9abbf07770db288183a15fd261cace2Yabin Cui // If the virtual display isn't providing us with timestamps, 382433558f0f9abbf07770db288183a15fd261cace2Yabin Cui // use the current time. This isn't great -- we could get 383433558f0f9abbf07770db288183a15fd261cace2Yabin Cui // decoded data in clusters -- but we're not expecting 384edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni // to hit this anyway. 385edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni if (ptsUsec == 0) { 386edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000; 387eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 388062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 389edf4ea312cc3f7dd4373f8db5aaf9325ff054c8eYang Ni if (muxer == NULL) { 3902abfcc6d129fe3defddef4540aa95cc445c03a7aYang Ni fwrite(buffers[bufIndex]->data(), 1, size, rawFp); 3912abfcc6d129fe3defddef4540aa95cc445c03a7aYang Ni // Flush the data immediately in case we're streaming. 3922abfcc6d129fe3defddef4540aa95cc445c03a7aYang Ni // We don't want to do this if all we've written is 393eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // the SPS/PPS data because mplayer gets confused. 394eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) == 0) { 395433558f0f9abbf07770db288183a15fd261cace2Yabin Cui fflush(rawFp); 396eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 397eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } else { 398da0f069871343119251d6b0586be356dc2146a62Yang Ni // The MediaMuxer docs are unclear, but it appears that we 399eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // need to pass either the full set of BufferInfo flags, or 400eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // (flags & BUFFER_FLAG_SYNCFRAME). 401eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // 402da0f069871343119251d6b0586be356dc2146a62Yang Ni // If this blocks for too long we could drop frames. We may 403eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // want to queue these up and do them on a different thread. 404da0f069871343119251d6b0586be356dc2146a62Yang Ni ATRACE_NAME("write sample"); 405eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni assert(trackIdx != -1); 406eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni err = muxer->writeSampleData(buffers[bufIndex], trackIdx, 407eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni ptsUsec, flags); 408eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (err != NO_ERROR) { 409da0f069871343119251d6b0586be356dc2146a62Yang Ni fprintf(stderr, 410062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni "Failed writing data to muxer (err=%d)\n", err); 411062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return err; 412eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 413eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 414eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni debugNumFrames++; 415da0f069871343119251d6b0586be356dc2146a62Yang Ni } 416eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni err = encoder->releaseOutputBuffer(bufIndex); 417062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (err != NO_ERROR) { 418062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni fprintf(stderr, "Unable to release output buffer (err=%d)\n", 419da0f069871343119251d6b0586be356dc2146a62Yang Ni err); 420da0f069871343119251d6b0586be356dc2146a62Yang Ni return err; 4211ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni } 4221ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) { 4231ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni // Not expecting EOS from SurfaceFlinger. Go with it. 424eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni ALOGI("Received end-of-stream"); 425eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni gStopRequested = true; 426eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 427eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni break; 4281ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni case -EAGAIN: // INFO_TRY_AGAIN_LATER 4291ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni ALOGV("Got -EAGAIN, looping"); 430da0f069871343119251d6b0586be356dc2146a62Yang Ni break; 431eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni case INFO_FORMAT_CHANGED: // INFO_OUTPUT_FORMAT_CHANGED 432eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni { 433062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // Format includes CSD, which we must provide to muxer. 434062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGV("Encoder format changed"); 435eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni sp<AMessage> newFormat; 436eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni encoder->getOutputFormat(&newFormat); 437eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (muxer != NULL) { 438eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni trackIdx = muxer->addTrack(newFormat); 439eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni ALOGV("Starting muxer"); 440eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni err = muxer->start(); 441eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (err != NO_ERROR) { 442eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni fprintf(stderr, "Unable to start muxer (err=%d)\n", err); 443eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni return err; 444eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 445ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni } 446ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni } 447ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni break; 448062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni case INFO_OUTPUT_BUFFERS_CHANGED: // INFO_OUTPUT_BUFFERS_CHANGED 449062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni // Not expected for an encoder; handle it anyway. 450062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGV("Encoder buffers changed"); 451062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni err = encoder->getOutputBuffers(&buffers); 452062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (err != NO_ERROR) { 453062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni fprintf(stderr, 454062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni "Unable to get new output buffers (err=%d)\n", err); 455062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return err; 456062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 457062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni break; 458062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni case INVALID_OPERATION: 459062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGW("dequeueOutputBuffer returned INVALID_OPERATION"); 460062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return err; 461062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni default: 462eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni fprintf(stderr, 463062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni "Got weird result %d from dequeueOutputBuffer\n", err); 464062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return err; 465062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 466062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 467062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 468062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni ALOGV("Encoder stopping (req=%d)", gStopRequested); 469eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (gVerbose) { 470eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni printf("Encoder stopping; recorded %u frames in %lld seconds\n", 4711ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni debugNumFrames, nanoseconds_to_seconds( 4721ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni systemTime(CLOCK_MONOTONIC) - startWhenNsec)); 4731ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni } 474da0f069871343119251d6b0586be356dc2146a62Yang Ni return NO_ERROR; 475062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni} 476062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 477062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni/* 478062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * Raw H.264 byte stream output requested. Send the output to stdout 479062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * if desired. If the output is a tty, reconfigure it to avoid the 480062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni * CRLF line termination that we see with "adb shell" commands. 481062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni */ 482062c287f573ecc06c38ee4295e5627e12c52ac3dYang Nistatic FILE* prepareRawOutput(const char* fileName) { 483062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni FILE* rawFp = NULL; 484062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 485062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (strcmp(fileName, "-") == 0) { 486062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (gVerbose) { 487062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni fprintf(stderr, "ERROR: verbose output and '-' not compatible"); 488062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return NULL; 489062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 490062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni rawFp = stdout; 491062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } else { 492062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni rawFp = fopen(fileName, "w"); 493062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (rawFp == NULL) { 494062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni fprintf(stderr, "fopen raw failed: %s\n", strerror(errno)); 495062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni return NULL; 496eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 497eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 498eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 499eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni int fd = fileno(rawFp); 500eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (isatty(fd)) { 501ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni // best effort -- reconfigure tty for "raw" 502ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni ALOGD("raw video output to tty (fd=%d)", fd); 503eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni struct termios term; 504eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (tcgetattr(fd, &term) == 0) { 505eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni cfmakeraw(&term); 506eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (tcsetattr(fd, TCSANOW, &term) == 0) { 507eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni ALOGD("tty successfully configured for raw"); 508062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni } 509eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 510eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 511ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni 512ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni return rawFp; 513eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni} 514eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 515eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni/* 516eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * Main "do work" method. 517eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * 518eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * Configures codec, muxer, and virtual display, then starts moving bits 519eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni * around. 520eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni */ 521062c287f573ecc06c38ee4295e5627e12c52ac3dYang Nistatic status_t recordScreen(const char* fileName) { 522062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni status_t err; 523eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 524ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni // Configure signal handler. 525ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni err = configureSignals(); 526062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni if (err != NO_ERROR) return err; 527eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni 528da0f069871343119251d6b0586be356dc2146a62Yang Ni // Start Binder thread pool. MediaCodec needs to be able to receive 529eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni // messages from mediaserver. 530eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni sp<ProcessState> self = ProcessState::self(); 531eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni self->startThreadPool(); 532da0f069871343119251d6b0586be356dc2146a62Yang Ni 533ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni // Get main display parameters. 534ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay( 535eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni ISurfaceComposer::eDisplayIdMain); 536eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni DisplayInfo mainDpyInfo; 537da0f069871343119251d6b0586be356dc2146a62Yang Ni err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo); 538eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (err != NO_ERROR) { 539eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni fprintf(stderr, "ERROR: unable to get display characteristics\n"); 540eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni return err; 541da0f069871343119251d6b0586be356dc2146a62Yang Ni } 542eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (gVerbose) { 543eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni printf("Main display is %dx%d @%.2ffps (orientation=%u)\n", 544eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps, 545eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni mainDpyInfo.orientation); 546eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni } 547062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni 548062c287f573ecc06c38ee4295e5627e12c52ac3dYang Ni bool rotated = isDeviceRotated(mainDpyInfo.orientation); 549eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (gVideoWidth == 0) { 550ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w; 551ff2bb54ebf593b1d19d3a2e4cfa70a8ea4432c0dYang Ni } 552eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni if (gVideoHeight == 0) { 553eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h; 5541ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni } 5551ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni 5561ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni // Configure and start the encoder. 5571ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni sp<MediaCodec> encoder; 558 sp<IGraphicBufferProducer> encoderInputSurface; 559 err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface); 560 561 if (err != NO_ERROR && !gSizeSpecified) { 562 // fallback is defined for landscape; swap if we're in portrait 563 bool needSwap = gVideoWidth < gVideoHeight; 564 uint32_t newWidth = needSwap ? kFallbackHeight : kFallbackWidth; 565 uint32_t newHeight = needSwap ? kFallbackWidth : kFallbackHeight; 566 if (gVideoWidth != newWidth && gVideoHeight != newHeight) { 567 ALOGV("Retrying with 720p"); 568 fprintf(stderr, "WARNING: failed at %dx%d, retrying at %dx%d\n", 569 gVideoWidth, gVideoHeight, newWidth, newHeight); 570 gVideoWidth = newWidth; 571 gVideoHeight = newHeight; 572 err = prepareEncoder(mainDpyInfo.fps, &encoder, 573 &encoderInputSurface); 574 } 575 } 576 if (err != NO_ERROR) return err; 577 578 // From here on, we must explicitly release() the encoder before it goes 579 // out of scope, or we will get an assertion failure from stagefright 580 // later on in a different thread. 581 582 583 // Draw the "info" page by rendering a frame with GLES and sending 584 // it directly to the encoder. 585 // TODO: consider displaying this as a regular layer to avoid b/11697754 586 if (gWantInfoScreen) { 587 Overlay::drawInfoPage(encoderInputSurface); 588 } 589 590 // Configure optional overlay. 591 sp<IGraphicBufferProducer> bufferProducer; 592 sp<Overlay> overlay; 593 if (gWantFrameTime) { 594 // Send virtual display frames to an external texture. 595 overlay = new Overlay(); 596 err = overlay->start(encoderInputSurface, &bufferProducer); 597 if (err != NO_ERROR) { 598 encoder->release(); 599 return err; 600 } 601 if (gVerbose) { 602 printf("Bugreport overlay created\n"); 603 } 604 } else { 605 // Use the encoder's input surface as the virtual display surface. 606 bufferProducer = encoderInputSurface; 607 } 608 609 // Configure virtual display. 610 sp<IBinder> dpy; 611 err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy); 612 if (err != NO_ERROR) { 613 encoder->release(); 614 return err; 615 } 616 617 sp<MediaMuxer> muxer = NULL; 618 FILE* rawFp = NULL; 619 if (gRawOutput) { 620 rawFp = prepareRawOutput(fileName); 621 if (rawFp == NULL) { 622 encoder->release(); 623 return -1; 624 } 625 } else { 626 // Configure muxer. We have to wait for the CSD blob from the encoder 627 // before we can start it. 628 muxer = new MediaMuxer(fileName, MediaMuxer::OUTPUT_FORMAT_MPEG_4); 629 if (gRotate) { 630 muxer->setOrientationHint(90); // TODO: does this do anything? 631 } 632 } 633 634 // Main encoder loop. 635 err = runEncoder(encoder, muxer, rawFp, mainDpy, dpy, 636 mainDpyInfo.orientation); 637 if (err != NO_ERROR) { 638 fprintf(stderr, "Encoder failed (err=%d)\n", err); 639 // fall through to cleanup 640 } 641 642 if (gVerbose) { 643 printf("Stopping encoder and muxer\n"); 644 } 645 646 // Shut everything down, starting with the producer side. 647 encoderInputSurface = NULL; 648 SurfaceComposerClient::destroyDisplay(dpy); 649 if (overlay != NULL) { 650 overlay->stop(); 651 } 652 encoder->stop(); 653 if (muxer != NULL) { 654 // If we don't stop muxer explicitly, i.e. let the destructor run, 655 // it may hang (b/11050628). 656 muxer->stop(); 657 } else if (rawFp != stdout) { 658 fclose(rawFp); 659 } 660 encoder->release(); 661 662 return err; 663} 664 665/* 666 * Sends a broadcast to the media scanner to tell it about the new video. 667 * 668 * This is optional, but nice to have. 669 */ 670static status_t notifyMediaScanner(const char* fileName) { 671 // need to do allocations before the fork() 672 String8 fileUrl("file://"); 673 fileUrl.append(fileName); 674 675 const char* kCommand = "/system/bin/am"; 676 const char* const argv[] = { 677 kCommand, 678 "broadcast", 679 "-a", 680 "android.intent.action.MEDIA_SCANNER_SCAN_FILE", 681 "-d", 682 fileUrl.string(), 683 NULL 684 }; 685 if (gVerbose) { 686 printf("Executing:"); 687 for (int i = 0; argv[i] != NULL; i++) { 688 printf(" %s", argv[i]); 689 } 690 putchar('\n'); 691 } 692 693 pid_t pid = fork(); 694 if (pid < 0) { 695 int err = errno; 696 ALOGW("fork() failed: %s", strerror(err)); 697 return -err; 698 } else if (pid > 0) { 699 // parent; wait for the child, mostly to make the verbose-mode output 700 // look right, but also to check for and log failures 701 int status; 702 pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); 703 if (actualPid != pid) { 704 ALOGW("waitpid(%d) returned %d (errno=%d)", pid, actualPid, errno); 705 } else if (status != 0) { 706 ALOGW("'am broadcast' exited with status=%d", status); 707 } else { 708 ALOGV("'am broadcast' exited successfully"); 709 } 710 } else { 711 if (!gVerbose) { 712 // non-verbose, suppress 'am' output 713 ALOGV("closing stdout/stderr in child"); 714 int fd = open("/dev/null", O_WRONLY); 715 if (fd >= 0) { 716 dup2(fd, STDOUT_FILENO); 717 dup2(fd, STDERR_FILENO); 718 close(fd); 719 } 720 } 721 execv(kCommand, const_cast<char* const*>(argv)); 722 ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno)); 723 exit(1); 724 } 725 return NO_ERROR; 726} 727 728/* 729 * Parses a string of the form "1280x720". 730 * 731 * Returns true on success. 732 */ 733static bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth, 734 uint32_t* pHeight) { 735 long width, height; 736 char* end; 737 738 // Must specify base 10, or "0x0" gets parsed differently. 739 width = strtol(widthHeight, &end, 10); 740 if (end == widthHeight || *end != 'x' || *(end+1) == '\0') { 741 // invalid chars in width, or missing 'x', or missing height 742 return false; 743 } 744 height = strtol(end + 1, &end, 10); 745 if (*end != '\0') { 746 // invalid chars in height 747 return false; 748 } 749 750 *pWidth = width; 751 *pHeight = height; 752 return true; 753} 754 755/* 756 * Accepts a string with a bare number ("4000000") or with a single-character 757 * unit ("4m"). 758 * 759 * Returns an error if parsing fails. 760 */ 761static status_t parseValueWithUnit(const char* str, uint32_t* pValue) { 762 long value; 763 char* endptr; 764 765 value = strtol(str, &endptr, 10); 766 if (*endptr == '\0') { 767 // bare number 768 *pValue = value; 769 return NO_ERROR; 770 } else if (toupper(*endptr) == 'M' && *(endptr+1) == '\0') { 771 *pValue = value * 1000000; // check for overflow? 772 return NO_ERROR; 773 } else { 774 fprintf(stderr, "Unrecognized value: %s\n", str); 775 return UNKNOWN_ERROR; 776 } 777} 778 779/* 780 * Dumps usage on stderr. 781 */ 782static void usage() { 783 fprintf(stderr, 784 "Usage: screenrecord [options] <filename>\n" 785 "\n" 786 "Android screenrecord v%d.%d. Records the device's display to a .mp4 file.\n" 787 "\n" 788 "Options:\n" 789 "--size WIDTHxHEIGHT\n" 790 " Set the video size, e.g. \"1280x720\". Default is the device's main\n" 791 " display resolution (if supported), 1280x720 if not. For best results,\n" 792 " use a size supported by the AVC encoder.\n" 793 "--bit-rate RATE\n" 794 " Set the video bit rate, in bits per second. Value may be specified as\n" 795 " bits or megabits, e.g. '4000000' is equivalent to '4M'. Default %dMbps.\n" 796 "--bugreport\n" 797 " Add additional information, such as a timestamp overlay, that is helpful\n" 798 " in videos captured to illustrate bugs.\n" 799 "--time-limit TIME\n" 800 " Set the maximum recording time, in seconds. Default / maximum is %d.\n" 801 "--verbose\n" 802 " Display interesting information on stdout.\n" 803 "--help\n" 804 " Show this message.\n" 805 "\n" 806 "Recording continues until Ctrl-C is hit or the time limit is reached.\n" 807 "\n", 808 kVersionMajor, kVersionMinor, gBitRate / 1000000, gTimeLimitSec 809 ); 810} 811 812/* 813 * Parses args and kicks things off. 814 */ 815int main(int argc, char* const argv[]) { 816 static const struct option longOptions[] = { 817 { "help", no_argument, NULL, 'h' }, 818 { "verbose", no_argument, NULL, 'v' }, 819 { "size", required_argument, NULL, 's' }, 820 { "bit-rate", required_argument, NULL, 'b' }, 821 { "time-limit", required_argument, NULL, 't' }, 822 { "show-device-info", no_argument, NULL, 'i' }, 823 { "show-frame-time", no_argument, NULL, 'f' }, 824 { "bugreport", no_argument, NULL, 'u' }, 825 { "rotate", no_argument, NULL, 'r' }, 826 { "raw", no_argument, NULL, 'w' }, 827 { NULL, 0, NULL, 0 } 828 }; 829 830 while (true) { 831 int optionIndex = 0; 832 int ic = getopt_long(argc, argv, "", longOptions, &optionIndex); 833 if (ic == -1) { 834 break; 835 } 836 837 switch (ic) { 838 case 'h': 839 usage(); 840 return 0; 841 case 'v': 842 gVerbose = true; 843 break; 844 case 's': 845 if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) { 846 fprintf(stderr, "Invalid size '%s', must be width x height\n", 847 optarg); 848 return 2; 849 } 850 if (gVideoWidth == 0 || gVideoHeight == 0) { 851 fprintf(stderr, 852 "Invalid size %ux%u, width and height may not be zero\n", 853 gVideoWidth, gVideoHeight); 854 return 2; 855 } 856 gSizeSpecified = true; 857 break; 858 case 'b': 859 if (parseValueWithUnit(optarg, &gBitRate) != NO_ERROR) { 860 return 2; 861 } 862 if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) { 863 fprintf(stderr, 864 "Bit rate %dbps outside acceptable range [%d,%d]\n", 865 gBitRate, kMinBitRate, kMaxBitRate); 866 return 2; 867 } 868 break; 869 case 't': 870 gTimeLimitSec = atoi(optarg); 871 if (gTimeLimitSec == 0 || gTimeLimitSec > kMaxTimeLimitSec) { 872 fprintf(stderr, 873 "Time limit %ds outside acceptable range [1,%d]\n", 874 gTimeLimitSec, kMaxTimeLimitSec); 875 return 2; 876 } 877 break; 878 case 'i': 879 gWantInfoScreen = true; 880 break; 881 case 'f': 882 gWantFrameTime = true; 883 break; 884 case 'u': 885 gWantInfoScreen = true; 886 gWantFrameTime = true; 887 break; 888 case 'r': 889 // experimental feature 890 gRotate = true; 891 break; 892 case 'w': 893 // experimental feature 894 gRawOutput = true; 895 break; 896 default: 897 if (ic != '?') { 898 fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic); 899 } 900 return 2; 901 } 902 } 903 904 if (optind != argc - 1) { 905 fprintf(stderr, "Must specify output file (see --help).\n"); 906 return 2; 907 } 908 909 const char* fileName = argv[optind]; 910 if (!gRawOutput) { 911 // MediaMuxer tries to create the file in the constructor, but we don't 912 // learn about the failure until muxer.start(), which returns a generic 913 // error code without logging anything. We attempt to create the file 914 // now for better diagnostics. 915 int fd = open(fileName, O_CREAT | O_RDWR, 0644); 916 if (fd < 0) { 917 fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno)); 918 return 1; 919 } 920 close(fd); 921 } 922 923 status_t err = recordScreen(fileName); 924 if (err == NO_ERROR) { 925 // Try to notify the media scanner. Not fatal if this fails. 926 notifyMediaScanner(fileName); 927 } 928 ALOGD(err == NO_ERROR ? "success" : "failed"); 929 return (int) err; 930} 931