Android screenrecord

来源:互联网 发布:闲鱼 淘宝介入 卖家赢 编辑:程序博客网 时间:2024/05/21 15:39

  1. /*
  2. * Copyright 2013 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #define LOG_TAG"ScreenRecord"
  17. //#define LOG_NDEBUG 0
  18. #include<utils/Log.h>
  19. #include<binder/IPCThreadState.h>
  20. #include<utils/Errors.h>
  21. #include<utils/Thread.h>
  22. #include<utils/Timers.h>
  23. #include<gui/Surface.h>
  24. #include<gui/SurfaceComposerClient.h>
  25. #include<gui/ISurfaceComposer.h>
  26. #include<ui/DisplayInfo.h>
  27. #include<media/openmax/OMX_IVCommon.h>
  28. #include<media/stagefright/foundation/ABuffer.h>
  29. #include<media/stagefright/foundation/ADebug.h>
  30. #include<media/stagefright/foundation/AMessage.h>
  31. #include<media/stagefright/MediaCodec.h>
  32. #include<media/stagefright/MediaErrors.h>
  33. #include<media/stagefright/MediaMuxer.h>
  34. #include<media/ICrypto.h>
  35. #include<stdlib.h>
  36. #include<unistd.h>
  37. #include<string.h>
  38. #include<stdio.h>
  39. #include<fcntl.h>
  40. #include<signal.h>
  41. #include<getopt.h>
  42. #include<sys/wait.h>
  43. usingnamespace android;
  44. staticconstuint32_t kMinBitRate=100000;// 0.1Mbps
  45. staticconstuint32_t kMaxBitRate=100*1000000;// 100Mbps
  46. staticconstuint32_t kMaxTimeLimitSec=180;// 3 minutes
  47. staticconstuint32_t kFallbackWidth=1280;// 720p
  48. staticconstuint32_t kFallbackHeight=720;
  49. // Command-line parameters.
  50. staticbool gVerbose=false;// chatty on stdout
  51. staticbool gRotate=false;// rotate 90 degrees
  52. staticbool gSizeSpecified=false;// was size explicitly requested?
  53. staticuint32_t gVideoWidth=0;// default width+height
  54. staticuint32_t gVideoHeight=0;
  55. staticuint32_t gBitRate=4000000;// 4Mbps
  56. staticuint32_t gTimeLimitSec= kMaxTimeLimitSec;
  57. // Set by signal handler to stop recording.
  58. staticbool gStopRequested;
  59. // Previous signal handler state, restored after first hit.
  60. staticstruct sigaction gOrigSigactionINT;
  61. staticstruct sigaction gOrigSigactionHUP;
  62. /*
  63. * Catch keyboard interrupt signals. On receipt, the "stop requested"
  64. * flag is raised, and the original handler is restored (so that, if
  65. * we get stuck finishing, a second Ctrl-C will kill the process).
  66. */
  67. staticvoid signalCatcher(int signum)
  68. {
  69. gStopRequested=true;
  70. switch(signum){
  71. case SIGINT:
  72. case SIGHUP:
  73. sigaction(SIGINT,&gOrigSigactionINT, NULL);
  74. sigaction(SIGHUP,&gOrigSigactionHUP, NULL);
  75. break;
  76. default:
  77. abort();
  78. break;
  79. }
  80. }
  81. /*
  82. * Configures signal handlers. The previous handlers are saved.
  83. *
  84. * If the command is run from an interactive adb shell, we get SIGINT
  85. * when Ctrl-C is hit. If we're run from the host, the local adb process
  86. * gets the signal, and we get a SIGHUP when the terminal disconnects.
  87. */
  88. staticstatus_t configureSignals()
  89. {
  90. struct sigaction act;
  91. memset(&act,0,sizeof(act));
  92. act.sa_handler= signalCatcher;
  93. if(sigaction(SIGINT,&act,&gOrigSigactionINT)!=0){
  94. status_t err=-errno;
  95. fprintf(stderr,"Unable to configure SIGINT handler: %s\n",
  96. strerror(errno));
  97. return err;
  98. }
  99. if(sigaction(SIGHUP,&act,&gOrigSigactionHUP)!=0){
  100. status_t err=-errno;
  101. fprintf(stderr,"Unable to configure SIGHUP handler: %s\n",
  102. strerror(errno));
  103. return err;
  104. }
  105. return NO_ERROR;
  106. }
  107. /*
  108. * Returns "true" if the device is rotated 90 degrees.
  109. */
  110. staticbool isDeviceRotated(int orientation){
  111. return orientation!= DISPLAY_ORIENTATION_0&&
  112. orientation!= DISPLAY_ORIENTATION_180;
  113. }
  114. /*
  115. * Configures and starts the MediaCodec encoder. Obtains an input surface
  116. * from the codec.
  117. */
  118. staticstatus_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec,
  119. sp<IGraphicBufferProducer>* pBufferProducer){
  120. status_t err;
  121. if(gVerbose){
  122. printf("Configuring recorder for %dx%d video at %.2fMbps\n",
  123. gVideoWidth, gVideoHeight, gBitRate /1000000.0);
  124. }
  125. sp<AMessage> format =newAMessage;
  126. format->setInt32("width", gVideoWidth);
  127. format->setInt32("height", gVideoHeight);
  128. format->setString("mime","video/avc");
  129. format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
  130. format->setInt32("bitrate", gBitRate);
  131. format->setFloat("frame-rate", displayFps);
  132. format->setInt32("i-frame-interval",10);
  133. sp<ALooper> looper =newALooper;
  134. looper->setName("screenrecord_looper");
  135. looper->start();
  136. ALOGV("Creating codec");
  137. sp<MediaCodec> codec =MediaCodec::CreateByType(looper,"video/avc",true);
  138. if(codec== NULL){
  139. fprintf(stderr,"ERROR: unable to create video/avc codec instance\n");
  140. return UNKNOWN_ERROR;
  141. }
  142. err= codec->configure(format, NULL, NULL,
  143. MediaCodec::CONFIGURE_FLAG_ENCODE);
  144. if(err!= NO_ERROR){
  145. codec->release();
  146. codec.clear();
  147. fprintf(stderr,"ERROR: unable to configure codec (err=%d)\n", err);
  148. return err;
  149. }
  150. ALOGV("Creating buffer producer");
  151. sp<IGraphicBufferProducer> bufferProducer;
  152. err= codec->createInputSurface(&bufferProducer);
  153. if(err!= NO_ERROR){
  154. codec->release();
  155. codec.clear();
  156. fprintf(stderr,
  157. "ERROR: unable to create encoder input surface (err=%d)\n", err);
  158. return err;
  159. }
  160. ALOGV("Starting codec");
  161. err= codec->start();
  162. if(err!= NO_ERROR){
  163. codec->release();
  164. codec.clear();
  165. fprintf(stderr,"ERROR: unable to start codec (err=%d)\n", err);
  166. return err;
  167. }
  168. ALOGV("Codec prepared");
  169. *pCodec= codec;
  170. *pBufferProducer= bufferProducer;
  171. return0;
  172. }
  173. /*
  174. * Configures the virtual display. When this completes, virtual display
  175. * frames will start being sent to the encoder's surface.
  176. */
  177. staticstatus_t prepareVirtualDisplay(constDisplayInfo& mainDpyInfo,
  178. const sp<IGraphicBufferProducer>& bufferProducer,
  179. sp<IBinder>* pDisplayHandle){
  180. status_t err;
  181. // Set the region of the layer stack we're interested in, which in our
  182. // case is "all of it". If the app is rotated (so that the width of the
  183. // app is based on the height of the display), reverse width/height.
  184. bool deviceRotated= isDeviceRotated(mainDpyInfo.orientation);
  185. uint32_t sourceWidth, sourceHeight;
  186. if(!deviceRotated){
  187. sourceWidth= mainDpyInfo.w;
  188. sourceHeight= mainDpyInfo.h;
  189. }else{
  190. ALOGV("using rotated width/height");
  191. sourceHeight= mainDpyInfo.w;
  192. sourceWidth= mainDpyInfo.h;
  193. }
  194. Rect layerStackRect(sourceWidth, sourceHeight);
  195. // We need to preserve the aspect ratio of the display.
  196. float displayAspect=(float) sourceHeight/(float) sourceWidth;
  197. // Set the way we map the output onto the display surface (which will
  198. // be e.g. 1280x720 for a 720p video). The rect is interpreted
  199. // post-rotation, so if the display is rotated 90 degrees we need to
  200. // "pre-rotate" it by flipping width/height, so that the orientation
  201. // adjustment changes it back.
  202. //
  203. // We might want to encode a portrait display as landscape to use more
  204. // of the screen real estate. (If players respect a 90-degree rotation
  205. // hint, we can essentially get a 720x1280 video instead of 1280x720.)
  206. // In that case, we swap the configured video width/height and then
  207. // supply a rotation value to the display projection.
  208. uint32_t videoWidth, videoHeight;
  209. uint32_t outWidth, outHeight;
  210. if(!gRotate){
  211. videoWidth= gVideoWidth;
  212. videoHeight= gVideoHeight;
  213. }else{
  214. videoWidth= gVideoHeight;
  215. videoHeight= gVideoWidth;
  216. }
  217. if(videoHeight>(uint32_t)(videoWidth* displayAspect)){
  218. // limited by narrow width; reduce height
  219. outWidth= videoWidth;
  220. outHeight=(uint32_t)(videoWidth* displayAspect);
  221. }else{
  222. // limited by short height; restrict width
  223. outHeight= videoHeight;
  224. outWidth=(uint32_t)(videoHeight/ displayAspect);
  225. }
  226. uint32_t offX, offY;
  227. offX=(videoWidth- outWidth)/2;
  228. offY=(videoHeight- outHeight)/2;
  229. Rect displayRect(offX, offY, offX+ outWidth, offY+ outHeight);
  230. if(gVerbose){
  231. if(gRotate){
  232. printf("Rotated content area is %ux%u at offset x=%d y=%d\n",
  233. outHeight, outWidth, offY, offX);
  234. }else{
  235. printf("Content area is %ux%u at offset x=%d y=%d\n",
  236. outWidth, outHeight, offX, offY);
  237. }
  238. }
  239. sp<IBinder> dpy =SurfaceComposerClient::createDisplay(
  240. String8("ScreenRecorder"),false/* secure */);
  241. SurfaceComposerClient::openGlobalTransaction();
  242. SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
  243. SurfaceComposerClient::setDisplayProjection(dpy,
  244. gRotate? DISPLAY_ORIENTATION_90: DISPLAY_ORIENTATION_0,
  245. layerStackRect, displayRect);
  246. SurfaceComposerClient::setDisplayLayerStack(dpy,0);// default stack
  247. SurfaceComposerClient::closeGlobalTransaction();
  248. *pDisplayHandle= dpy;
  249. return NO_ERROR;
  250. }
  251. /*
  252. * Runs the MediaCodec encoder, sending the output to the MediaMuxer. The
  253. * input frames are coming from the virtual display as fast as SurfaceFlinger
  254. * wants to send them.
  255. *
  256. * The muxer must *not* have been started before calling.
  257. */
  258. staticstatus_t runEncoder(const sp<MediaCodec>& encoder,
  259. const sp<MediaMuxer>& muxer){
  260. staticint kTimeout=250000;// be responsive on signal
  261. status_t err;
  262. ssize_t trackIdx=-1;
  263. uint32_t debugNumFrames=0;
  264. int64_t startWhenNsec= systemTime(CLOCK_MONOTONIC);
  265. int64_t endWhenNsec= startWhenNsec+ seconds_to_nanoseconds(gTimeLimitSec);
  266. Vector<sp<ABuffer>> buffers;
  267. err= encoder->getOutputBuffers(&buffers);
  268. if(err!= NO_ERROR){
  269. fprintf(stderr,"Unable to get output buffers (err=%d)\n", err);
  270. return err;
  271. }
  272. // This is set by the signal handler.
  273. gStopRequested=false;
  274. // Run until we're signaled.
  275. while(!gStopRequested){
  276. size_t bufIndex, offset, size;
  277. int64_t ptsUsec;
  278. uint32_t flags;
  279. if(systemTime(CLOCK_MONOTONIC)> endWhenNsec){
  280. if(gVerbose){
  281. printf("Time limit reached\n");
  282. }
  283. break;
  284. }
  285. ALOGV("Calling dequeueOutputBuffer");
  286. err= encoder->dequeueOutputBuffer(&bufIndex,&offset,&size,&ptsUsec,
  287. &flags, kTimeout);
  288. ALOGV("dequeueOutputBuffer returned %d", err);
  289. switch(err){
  290. case NO_ERROR:
  291. // got a buffer
  292. if((flags&MediaCodec::BUFFER_FLAG_CODECCONFIG)!=0){
  293. // ignore this -- we passed the CSD into MediaMuxer when
  294. // we got the format change notification
  295. ALOGV("Got codec config buffer (%u bytes); ignoring", size);
  296. size=0;
  297. }
  298. if(size!=0){
  299. ALOGV("Got data in buffer %d, size=%d, pts=%lld",
  300. bufIndex, size, ptsUsec);
  301. CHECK(trackIdx!=-1);
  302. // If the virtual display isn't providing us with timestamps,
  303. // use the current time.
  304. if(ptsUsec==0){
  305. ptsUsec= systemTime(SYSTEM_TIME_MONOTONIC)/1000;
  306. }
  307. // The MediaMuxer docs are unclear, but it appears that we
  308. // need to pass either the full set of BufferInfo flags, or
  309. // (flags & BUFFER_FLAG_SYNCFRAME).
  310. err= muxer->writeSampleData(buffers[bufIndex], trackIdx,
  311. ptsUsec, flags);
  312. if(err!= NO_ERROR){
  313. fprintf(stderr,"Failed writing data to muxer (err=%d)\n",
  314. err);
  315. return err;
  316. }
  317. debugNumFrames++;
  318. }
  319. err= encoder->releaseOutputBuffer(bufIndex);
  320. if(err!= NO_ERROR){
  321. fprintf(stderr,"Unable to release output buffer (err=%d)\n",
  322. err);
  323. return err;
  324. }
  325. if((flags&MediaCodec::BUFFER_FLAG_EOS)!=0){
  326. // Not expecting EOS from SurfaceFlinger. Go with it.
  327. ALOGD("Received end-of-stream");
  328. gStopRequested=false;
  329. }
  330. break;
  331. case-EAGAIN:// INFO_TRY_AGAIN_LATER
  332. ALOGV("Got -EAGAIN, looping");
  333. break;
  334. case INFO_FORMAT_CHANGED:// INFO_OUTPUT_FORMAT_CHANGED
  335. {
  336. // format includes CSD, which we must provide to muxer
  337. ALOGV("Encoder format changed");
  338. sp<AMessage> newFormat;
  339. encoder->getOutputFormat(&newFormat);
  340. trackIdx= muxer->addTrack(newFormat);
  341. ALOGV("Starting muxer");
  342. err= muxer->start();
  343. if(err!= NO_ERROR){
  344. fprintf(stderr,"Unable to start muxer (err=%d)\n", err);
  345. return err;
  346. }
  347. }
  348. break;
  349. case INFO_OUTPUT_BUFFERS_CHANGED:// INFO_OUTPUT_BUFFERS_CHANGED
  350. // not expected for an encoder; handle it anyway
  351. ALOGV("Encoder buffers changed");
  352. err= encoder->getOutputBuffers(&buffers);
  353. if(err!= NO_ERROR){
  354. fprintf(stderr,
  355. "Unable to get new output buffers (err=%d)\n", err);
  356. return err;
  357. }
  358. break;
  359. case INVALID_OPERATION:
  360. fprintf(stderr,"Request for encoder buffer failed\n");
  361. return err;
  362. default:
  363. fprintf(stderr,
  364. "Got weird result %d from dequeueOutputBuffer\n", err);
  365. return err;
  366. }
  367. }
  368. ALOGV("Encoder stopping (req=%d)", gStopRequested);
  369. if(gVerbose){
  370. printf("Encoder stopping; recorded %u frames in %lld seconds\n",
  371. debugNumFrames,
  372. nanoseconds_to_seconds(systemTime(CLOCK_MONOTONIC)- startWhenNsec));
  373. }
  374. return NO_ERROR;
  375. }
  376. /*
  377. * Main "do work" method.
  378. *
  379. * Configures codec, muxer, and virtual display, then starts moving bits
  380. * around.
  381. */
  382. staticstatus_t recordScreen(constchar* fileName){
  383. status_t err;
  384. // Configure signal handler.
  385. err= configureSignals();
  386. if(err!= NO_ERROR)return err;
  387. // Start Binder thread pool. MediaCodec needs to be able to receive
  388. // messages from mediaserver.
  389. sp<ProcessState> self =ProcessState::self();
  390. self->startThreadPool();
  391. // Get main display parameters.
  392. sp<IBinder> mainDpy =SurfaceComposerClient::getBuiltInDisplay(
  393. ISurfaceComposer::eDisplayIdMain);
  394. DisplayInfo mainDpyInfo;
  395. err=SurfaceComposerClient::getDisplayInfo(mainDpy,&mainDpyInfo);
  396. if(err!= NO_ERROR){
  397. fprintf(stderr,"ERROR: unable to get display characteristics\n");
  398. return err;
  399. }
  400. if(gVerbose){
  401. printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
  402. mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
  403. mainDpyInfo.orientation);
  404. }
  405. bool rotated= isDeviceRotated(mainDpyInfo.orientation);
  406. if(gVideoWidth==0){
  407. gVideoWidth= rotated? mainDpyInfo.h: mainDpyInfo.w;
  408. }
  409. if(gVideoHeight==0){
  410. gVideoHeight= rotated? mainDpyInfo.w: mainDpyInfo.h;
  411. }
  412. // Configure and start the encoder.
  413. sp<MediaCodec> encoder;
  414. sp<IGraphicBufferProducer> bufferProducer;
  415. err= prepareEncoder(mainDpyInfo.fps,&encoder,&bufferProducer);
  416. if(err!= NO_ERROR&&!gSizeSpecified){
  417. // fallback is defined for landscape; swap if we're in portrait
  418. bool needSwap= gVideoWidth< gVideoHeight;
  419. uint32_t newWidth= needSwap? kFallbackHeight: kFallbackWidth;
  420. uint32_t newHeight= needSwap? kFallbackWidth: kFallbackHeight;
  421. if(gVideoWidth!= newWidth&& gVideoHeight!= newHeight){
  422. ALOGV("Retrying with 720p");
  423. fprintf(stderr,"WARNING: failed at %dx%d, retrying at %dx%d\n",
  424. gVideoWidth, gVideoHeight, newWidth, newHeight);
  425. gVideoWidth= newWidth;
  426. gVideoHeight= newHeight;
  427. err= prepareEncoder(mainDpyInfo.fps,&encoder,&bufferProducer);
  428. }
  429. }
  430. if(err!= NO_ERROR){
  431. return err;
  432. }
  433. // Configure virtual display.
  434. sp<IBinder> dpy;
  435. err= prepareVirtualDisplay(mainDpyInfo, bufferProducer,&dpy);
  436. if(err!= NO_ERROR){
  437. encoder->release();
  438. encoder.clear();
  439. return err;
  440. }
  441. // Configure, but do not start, muxer.
  442. sp<MediaMuxer> muxer =newMediaMuxer(fileName,
  443. MediaMuxer::OUTPUT_FORMAT_MPEG_4);
  444. if(gRotate){
  445. muxer->setOrientationHint(90);
  446. }
  447. // Main encoder loop.
  448. err= runEncoder(encoder, muxer);
  449. if(err!= NO_ERROR){
  450. encoder->release();
  451. encoder.clear();
  452. return err;
  453. }
  454. if(gVerbose){
  455. printf("Stopping encoder and muxer\n");
  456. }
  457. // Shut everything down, starting with the producer side.
  458. bufferProducer= NULL;
  459. SurfaceComposerClient::destroyDisplay(dpy);
  460. encoder->stop();
  461. muxer->stop();
  462. encoder->release();
  463. return0;
  464. }
  465. /*
  466. * Sends a broadcast to the media scanner to tell it about the new video.
  467. *
  468. * This is optional, but nice to have.
  469. */
  470. staticstatus_t notifyMediaScanner(constchar* fileName){
  471. pid_t pid= fork();
  472. if(pid<0){
  473. int err= errno;
  474. ALOGW("fork() failed: %s", strerror(err));
  475. return-err;
  476. }elseif(pid>0){
  477. // parent; wait for the child, mostly to make the verbose-mode output
  478. // look right, but also to check for and log failures
  479. int status;
  480. pid_t actualPid= TEMP_FAILURE_RETRY(waitpid(pid,&status,0));
  481. if(actualPid!= pid){
  482. ALOGW("waitpid() returned %d (errno=%d)", actualPid, errno);
  483. }elseif(status!=0){
  484. ALOGW("'am broadcast' exited with status=%d", status);
  485. }else{
  486. ALOGV("'am broadcast' exited successfully");
  487. }
  488. }else{
  489. constchar* kCommand="/system/bin/am";
  490. // child; we're single-threaded, so okay to alloc
  491. String8 fileUrl("file://");
  492. fileUrl.append(fileName);
  493. constchar*const argv[]={
  494. kCommand,
  495. "broadcast",
  496. "-a",
  497. "android.intent.action.MEDIA_SCANNER_SCAN_FILE",
  498. "-d",
  499. fileUrl.string(),
  500. NULL
  501. };
  502. if(gVerbose){
  503. printf("Executing:");
  504. for(int i=0; argv[i]!= NULL; i++){
  505. printf(" %s", argv[i]);
  506. }
  507. putchar('\n');
  508. }else{
  509. // non-verbose, suppress 'am' output
  510. ALOGV("closing stdout/stderr in child");
  511. int fd= open("/dev/null", O_WRONLY);
  512. if(fd>=0){
  513. dup2(fd, STDOUT_FILENO);
  514. dup2(fd, STDERR_FILENO);
  515. close(fd);
  516. }
  517. }
  518. execv(kCommand,const_cast<char*const*>(argv));
  519. ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno));
  520. exit(1);
  521. }
  522. return NO_ERROR;
  523. }
  524. /*
  525. * Parses a string of the form "1280x720".
  526. *
  527. * Returns true on success.
  528. */
  529. staticbool parseWidthHeight(constchar* widthHeight,uint32_t* pWidth,
  530. uint32_t* pHeight){
  531. long width, height;
  532. char* end;
  533. // Must specify base 10, or "0x0" gets parsed differently.
  534. width= strtol(widthHeight,&end,10);
  535. if(end== widthHeight||*end!='x'||*(end+1)=='\0'){
  536. // invalid chars in width, or missing 'x', or missing height
  537. returnfalse;
  538. }
  539. height= strtol(end+1,&end,10);
  540. if(*end!='\0'){
  541. // invalid chars in height
  542. returnfalse;
  543. }
  544. *pWidth= width;
  545. *pHeight= height;
  546. returntrue;
  547. }
  548. /*
  549. * Dumps usage on stderr.
  550. */
  551. staticvoid usage(){
  552. fprintf(stderr,
  553. "Usage: screenrecord [options] <filename>\n"
  554. "\n"
  555. "Records the device's display to a .mp4 file.\n"
  556. "\n"
  557. "Options:\n"
  558. "--size WIDTHxHEIGHT\n"
  559. " Set the video size, e.g. \"1280x720\". Default is the device's main\n"
  560. " display resolution (if supported), 1280x720 if not. For best results,\n"
  561. " use a size supported by the AVC encoder.\n"
  562. "--bit-rate RATE\n"
  563. " Set the video bit rate, in megabits per second. Default %dMbps.\n"
  564. "--time-limit TIME\n"
  565. " Set the maximum recording time, in seconds. Default / maximum is %d.\n"
  566. "--rotate\n"
  567. " Rotate the output 90 degrees.\n"
  568. "--verbose\n"
  569. " Display interesting information on stdout.\n"
  570. "--help\n"
  571. " Show this message.\n"
  572. "\n"
  573. "Recording continues until Ctrl-C is hit or the time limit is reached.\n"
  574. "\n",
  575. gBitRate/1000000, gTimeLimitSec
  576. );
  577. }
  578. /*
  579. * Parses args and kicks things off.
  580. */
  581. int main(int argc,char*const argv[]){
  582. staticconststruct option longOptions[]={
  583. {"help", no_argument, NULL,'h'},
  584. {"verbose", no_argument, NULL,'v'},
  585. {"size", required_argument, NULL,'s'},
  586. {"bit-rate", required_argument, NULL,'b'},
  587. {"time-limit", required_argument, NULL,'t'},
  588. {"rotate", no_argument, NULL,'r'},
  589. { NULL,0, NULL,0}
  590. };
  591. while(true){
  592. int optionIndex=0;
  593. int ic= getopt_long(argc, argv,"", longOptions,&optionIndex);
  594. if(ic==-1){
  595. break;
  596. }
  597. switch(ic){
  598. case'h':
  599. usage();
  600. return0;
  601. case'v':
  602. gVerbose=true;
  603. break;
  604. case's':
  605. if(!parseWidthHeight(optarg,&gVideoWidth,&gVideoHeight)){
  606. fprintf(stderr,"Invalid size '%s', must be width x height\n",
  607. optarg);
  608. return2;
  609. }
  610. if(gVideoWidth==0|| gVideoHeight==0){
  611. fprintf(stderr,
  612. "Invalid size %ux%u, width and height may not be zero\n",
  613. gVideoWidth, gVideoHeight);
  614. return2;
  615. }
  616. gSizeSpecified=true;
  617. break;
  618. case'b':
  619. gBitRate= atoi(optarg);
  620. if(gBitRate< kMinBitRate|| gBitRate> kMaxBitRate){
  621. fprintf(stderr,
  622. "Bit rate %dbps outside acceptable range [%d,%d]\n",
  623. gBitRate, kMinBitRate, kMaxBitRate);
  624. return2;
  625. }
  626. break;
  627. case't':
  628. gTimeLimitSec= atoi(optarg);
  629. if(gTimeLimitSec==0|| gTimeLimitSec> kMaxTimeLimitSec){
  630. fprintf(stderr,
  631. "Time limit %ds outside acceptable range [1,%d]\n",
  632. gTimeLimitSec, kMaxTimeLimitSec);
  633. return2;
  634. }
  635. break;
  636. case'r':
  637. gRotate=true;
  638. break;
  639. default:
  640. if(ic!='?'){
  641. fprintf(stderr,"getopt_long returned unexpected value 0x%x\n", ic);
  642. }
  643. return2;
  644. }
  645. }
  646. if(optind!= argc-1){
  647. fprintf(stderr,"Must specify output file (see --help).\n");
  648. return2;
  649. }
  650. // MediaMuxer tries to create the file in the constructor, but we don't
  651. // learn about the failure until muxer.start(), which returns a generic
  652. // error code without logging anything. We attempt to create the file
  653. // now for better diagnostics.
  654. constchar* fileName= argv[optind];
  655. int fd= open(fileName, O_CREAT| O_RDWR,0644);
  656. if(fd<0){
  657. fprintf(stderr,"Unable to open '%s': %s\n", fileName, strerror(errno));
  658. return1;
  659. }
  660. close(fd);
  661. status_t err= recordScreen(fileName);
  662. if(err== NO_ERROR){
  663. // Try to notify the media scanner. Not fatal if this fails.
  664. notifyMediaScanner(fileName);
  665. }
  666. ALOGD(err== NO_ERROR?"success":"failed");
  667. return(int) err;
  668. }


  1. # Copyright 2013 The Android Open Source Project
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. LOCAL_PATH:= $(call my-dir)
  15. include $(CLEAR_VARS)
  16. LOCAL_SRC_FILES:= \
  17. screenrecord.cpp \
  18. LOCAL_SHARED_LIBRARIES:= \
  19. libstagefright libmedia libutils libbinder libstagefright_foundation \
  20. libjpeg libgui libcutils liblog
  21. LOCAL_C_INCLUDES:= \
  22. frameworks/av/media/libstagefright \
  23. frameworks/av/media/libstagefright/include \
  24. $(TOP)/frameworks/native/include/media/openmax \
  25. external/jpeg
  26. LOCAL_CFLAGS+=-Wno-multichar
  27. LOCAL_MODULE_TAGS:= optional
  28. LOCAL_MODULE:= screenrecord
  29. include $(BUILD_EXECUTABLE)


https://android.googlesource.com/platform/frameworks/av/+/kitkat-release/cmds/screenrecord/
0 0