Merge "AudioTrack: fix write retries for compressed audio" into klp-dev
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 3f8567c..d027ba9 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -21,6 +21,7 @@
#include <binder/IPCThreadState.h>
#include <utils/Errors.h>
#include <utils/Thread.h>
+#include <utils/Timers.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -35,6 +36,8 @@
#include <media/stagefright/MediaMuxer.h>
#include <media/ICrypto.h>
+#include <stdlib.h>
+#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
@@ -42,6 +45,12 @@
using namespace android;
+static const uint32_t kMinBitRate = 100000; // 0.1Mbps
+static const uint32_t kMaxBitRate = 100 * 1000000; // 100Mbps
+static const uint32_t kMaxTimeLimitSec = 180; // 3 minutes
+static const uint32_t kFallbackWidth = 1280; // 720p
+static const uint32_t kFallbackHeight = 720;
+
// Command-line parameters.
static bool gVerbose = false; // chatty on stdout
static bool gRotate = false; // rotate 90 degrees
@@ -49,6 +58,7 @@
static uint32_t gVideoWidth = 0; // default width+height
static uint32_t gVideoHeight = 0;
static uint32_t gBitRate = 4000000; // 4Mbps
+static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
// Set by signal handler to stop recording.
static bool gStopRequested;
@@ -57,8 +67,6 @@
static struct sigaction gOrigSigactionINT;
static struct sigaction gOrigSigactionHUP;
-static const uint32_t kMinBitRate = 100000; // 0.1Mbps
-static const uint32_t kMaxBitRate = 100 * 1000000; // 100Mbps
/*
* Catch keyboard interrupt signals. On receipt, the "stop requested"
@@ -70,9 +78,8 @@
gStopRequested = true;
switch (signum) {
case SIGINT:
- sigaction(SIGINT, &gOrigSigactionINT, NULL);
- break;
case SIGHUP:
+ sigaction(SIGINT, &gOrigSigactionINT, NULL);
sigaction(SIGHUP, &gOrigSigactionHUP, NULL);
break;
default:
@@ -138,7 +145,6 @@
format->setFloat("frame-rate", displayFps);
format->setInt32("i-frame-interval", 10);
- /// MediaCodec
sp<ALooper> looper = new ALooper;
looper->setName("screenrecord_looper");
looper->start();
@@ -279,7 +285,8 @@
status_t err;
ssize_t trackIdx = -1;
uint32_t debugNumFrames = 0;
- time_t debugStartWhen = time(NULL);
+ int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC);
+ int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
Vector<sp<ABuffer> > buffers;
err = encoder->getOutputBuffers(&buffers);
@@ -296,6 +303,14 @@
size_t bufIndex, offset, size;
int64_t ptsUsec;
uint32_t flags;
+
+ if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) {
+ if (gVerbose) {
+ printf("Time limit reached\n");
+ }
+ break;
+ }
+
ALOGV("Calling dequeueOutputBuffer");
err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
&flags, kTimeout);
@@ -345,7 +360,6 @@
}
break;
case -EAGAIN: // INFO_TRY_AGAIN_LATER
- // not expected with infinite timeout
ALOGV("Got -EAGAIN, looping");
break;
case INFO_FORMAT_CHANGED: // INFO_OUTPUT_FORMAT_CHANGED
@@ -370,18 +384,24 @@
if (err != NO_ERROR) {
fprintf(stderr,
"Unable to get new output buffers (err=%d)\n", err);
+ return err;
}
break;
+ case INVALID_OPERATION:
+ fprintf(stderr, "Request for encoder buffer failed\n");
+ return err;
default:
- ALOGW("Got weird result %d from dequeueOutputBuffer", err);
+ fprintf(stderr,
+ "Got weird result %d from dequeueOutputBuffer\n", err);
return err;
}
}
ALOGV("Encoder stopping (req=%d)", gStopRequested);
if (gVerbose) {
- printf("Encoder stopping; recorded %u frames in %ld seconds\n",
- debugNumFrames, time(NULL) - debugStartWhen);
+ printf("Encoder stopping; recorded %u frames in %lld seconds\n",
+ debugNumFrames,
+ nanoseconds_to_seconds(systemTime(CLOCK_MONOTONIC) - startWhenNsec));
}
return NO_ERROR;
}
@@ -432,12 +452,12 @@
sp<IGraphicBufferProducer> bufferProducer;
err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
if (err != NO_ERROR && !gSizeSpecified) {
- ALOGV("Retrying with 720p");
- if (gVideoWidth != 1280 && gVideoHeight != 720) {
+ if (gVideoWidth != kFallbackWidth && gVideoHeight != kFallbackHeight) {
+ ALOGV("Retrying with 720p");
fprintf(stderr, "WARNING: failed at %dx%d, retrying at 720p\n",
gVideoWidth, gVideoHeight);
- gVideoWidth = 1280;
- gVideoHeight = 720;
+ gVideoWidth = kFallbackWidth;
+ gVideoHeight = kFallbackHeight;
err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
}
}
@@ -477,6 +497,29 @@
}
/*
+ * Sends a broadcast to the media scanner to tell it about the new video.
+ */
+static status_t notifyMediaScanner(const char* fileName) {
+ String8 command("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
+ command.append(fileName);
+ if (gVerbose) {
+ printf("Shell: %s\n", command.string());
+ }
+
+ // TODO: for non-verbose mode we should suppress stdout
+ int status = system(command.string());
+ if (status < 0) {
+ fprintf(stderr, "Unable to fork shell for media scanner broadcast\n");
+ return UNKNOWN_ERROR;
+ } else if (status != 0) {
+ fprintf(stderr, "am command failed (status=%d): '%s'\n",
+ status, command.string());
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+/*
* Parses a string of the form "1280x720".
*
* Returns true on success.
@@ -514,10 +557,13 @@
"\n"
"Options:\n"
"--size WIDTHxHEIGHT\n"
- " Set the video size, e.g. \"1280x720\". For best results, use\n"
- " a size supported by the AVC encoder.\n"
+ " Set the video size, e.g. \"1280x720\". Default is the device's main\n"
+ " display resolution (if supported), 1280x720 if not. For best results,\n"
+ " use a size supported by the AVC encoder.\n"
"--bit-rate RATE\n"
- " Set the video bit rate, in megabits per second. Default 4Mbps.\n"
+ " Set the video bit rate, in megabits per second. Default %dMbps.\n"
+ "--time-limit TIME\n"
+ " Set the maximum recording time, in seconds. Default / maximum is %d.\n"
"--rotate\n"
" Rotate the output 90 degrees.\n"
"--verbose\n"
@@ -525,8 +571,9 @@
"--help\n"
" Show this message.\n"
"\n"
- "Recording continues until Ctrl-C is hit.\n"
- "\n"
+ "Recording continues until Ctrl-C is hit or the time limit is reached.\n"
+ "\n",
+ gBitRate / 1000000, gTimeLimitSec
);
}
@@ -539,6 +586,7 @@
{ "verbose", no_argument, NULL, 'v' },
{ "size", required_argument, NULL, 's' },
{ "bit-rate", required_argument, NULL, 'b' },
+ { "time-limit", required_argument, NULL, 't' },
{ "rotate", no_argument, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
@@ -580,6 +628,15 @@
return 2;
}
break;
+ case 't':
+ gTimeLimitSec = atoi(optarg);
+ if (gTimeLimitSec == 0 || gTimeLimitSec > kMaxTimeLimitSec) {
+ fprintf(stderr,
+ "Time limit %ds outside acceptable range [1,%d]\n",
+ gTimeLimitSec, kMaxTimeLimitSec);
+ return 2;
+ }
+ break;
case 'r':
gRotate = true;
break;
@@ -609,6 +666,10 @@
close(fd);
status_t err = recordScreen(fileName);
+ if (err == NO_ERROR) {
+ // Try to notify the media scanner. Not fatal if this fails.
+ notifyMediaScanner(fileName);
+ }
ALOGD(err == NO_ERROR ? "success" : "failed");
return (int) err;
}