summaryrefslogtreecommitdiffstats
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/screenrecord/screenrecord.cpp153
-rw-r--r--cmds/screenrecord/screenrecord.h2
-rw-r--r--cmds/stagefright/SimplePlayer.cpp4
-rw-r--r--cmds/stagefright/codec.cpp3
-rw-r--r--cmds/stagefright/muxer.cpp3
-rw-r--r--cmds/stagefright/sf2.cpp65
-rw-r--r--cmds/stagefright/stagefright.cpp4
-rw-r--r--cmds/stagefright/stream.cpp5
8 files changed, 178 insertions, 61 deletions
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 61f83e3..b6f150c 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -45,6 +45,7 @@
#include <signal.h>
#include <getopt.h>
#include <sys/wait.h>
+#include <termios.h>
#include <assert.h>
#include "screenrecord.h"
@@ -61,6 +62,7 @@ static const uint32_t kFallbackHeight = 720;
// Command-line parameters.
static bool gVerbose = false; // chatty on stdout
static bool gRotate = false; // rotate 90 degrees
+static bool gRawOutput = false; // generate raw H.264 byte stream output
static bool gSizeSpecified = false; // was size explicitly requested?
static bool gWantInfoScreen = false; // do we want initial info screen?
static bool gWantFrameTime = false; // do we want times on each frame?
@@ -298,10 +300,12 @@ static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
* input frames are coming from the virtual display as fast as SurfaceFlinger
* wants to send them.
*
+ * Exactly one of muxer or rawFp must be non-null.
+ *
* The muxer must *not* have been started before calling.
*/
static status_t runEncoder(const sp<MediaCodec>& encoder,
- const sp<MediaMuxer>& muxer, const sp<IBinder>& mainDpy,
+ const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& mainDpy,
const sp<IBinder>& virtualDpy, uint8_t orientation) {
static int kTimeout = 250000; // be responsive on signal
status_t err;
@@ -311,6 +315,8 @@ static status_t runEncoder(const sp<MediaCodec>& encoder,
int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
DisplayInfo mainDpyInfo;
+ assert((rawFp == NULL && muxer != NULL) || (rawFp != NULL && muxer == NULL));
+
Vector<sp<ABuffer> > buffers;
err = encoder->getOutputBuffers(&buffers);
if (err != NO_ERROR) {
@@ -342,15 +348,16 @@ static status_t runEncoder(const sp<MediaCodec>& encoder,
case NO_ERROR:
// got a buffer
if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
- // ignore this -- we passed the CSD into MediaMuxer when
- // we got the format change notification
- ALOGV("Got codec config buffer (%u bytes); ignoring", size);
- size = 0;
+ ALOGV("Got codec config buffer (%u bytes)", size);
+ if (muxer != NULL) {
+ // ignore this -- we passed the CSD into MediaMuxer when
+ // we got the format change notification
+ size = 0;
+ }
}
if (size != 0) {
ALOGV("Got data in buffer %d, size=%d, pts=%lld",
bufIndex, size, ptsUsec);
- assert(trackIdx != -1);
{ // scope
ATRACE_NAME("orientation");
@@ -379,14 +386,23 @@ static status_t runEncoder(const sp<MediaCodec>& encoder,
ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000;
}
- // The MediaMuxer docs are unclear, but it appears that we
- // need to pass either the full set of BufferInfo flags, or
- // (flags & BUFFER_FLAG_SYNCFRAME).
- //
- // If this blocks for too long we could drop frames. We may
- // want to queue these up and do them on a different thread.
- { // scope
+ if (muxer == NULL) {
+ fwrite(buffers[bufIndex]->data(), 1, size, rawFp);
+ // Flush the data immediately in case we're streaming.
+ // We don't want to do this if all we've written is
+ // the SPS/PPS data because mplayer gets confused.
+ if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) == 0) {
+ fflush(rawFp);
+ }
+ } else {
+ // The MediaMuxer docs are unclear, but it appears that we
+ // need to pass either the full set of BufferInfo flags, or
+ // (flags & BUFFER_FLAG_SYNCFRAME).
+ //
+ // If this blocks for too long we could drop frames. We may
+ // want to queue these up and do them on a different thread.
ATRACE_NAME("write sample");
+ assert(trackIdx != -1);
err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
ptsUsec, flags);
if (err != NO_ERROR) {
@@ -418,12 +434,14 @@ static status_t runEncoder(const sp<MediaCodec>& encoder,
ALOGV("Encoder format changed");
sp<AMessage> newFormat;
encoder->getOutputFormat(&newFormat);
- trackIdx = muxer->addTrack(newFormat);
- ALOGV("Starting muxer");
- err = muxer->start();
- if (err != NO_ERROR) {
- fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
- return err;
+ if (muxer != NULL) {
+ trackIdx = muxer->addTrack(newFormat);
+ ALOGV("Starting muxer");
+ err = muxer->start();
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
+ return err;
+ }
}
}
break;
@@ -457,6 +475,44 @@ static status_t runEncoder(const sp<MediaCodec>& encoder,
}
/*
+ * Raw H.264 byte stream output requested. Send the output to stdout
+ * if desired. If the output is a tty, reconfigure it to avoid the
+ * CRLF line termination that we see with "adb shell" commands.
+ */
+static FILE* prepareRawOutput(const char* fileName) {
+ FILE* rawFp = NULL;
+
+ if (strcmp(fileName, "-") == 0) {
+ if (gVerbose) {
+ fprintf(stderr, "ERROR: verbose output and '-' not compatible");
+ return NULL;
+ }
+ rawFp = stdout;
+ } else {
+ rawFp = fopen(fileName, "w");
+ if (rawFp == NULL) {
+ fprintf(stderr, "fopen raw failed: %s\n", strerror(errno));
+ return NULL;
+ }
+ }
+
+ int fd = fileno(rawFp);
+ if (isatty(fd)) {
+ // best effort -- reconfigure tty for "raw"
+ ALOGD("raw video output to tty (fd=%d)", fd);
+ struct termios term;
+ if (tcgetattr(fd, &term) == 0) {
+ cfmakeraw(&term);
+ if (tcsetattr(fd, TCSANOW, &term) == 0) {
+ ALOGD("tty successfully configured for raw");
+ }
+ }
+ }
+
+ return rawFp;
+}
+
+/*
* Main "do work" method.
*
* Configures codec, muxer, and virtual display, then starts moving bits
@@ -558,16 +614,26 @@ static status_t recordScreen(const char* fileName) {
return err;
}
- // Configure muxer. We have to wait for the CSD blob from the encoder
- // before we can start it.
- sp<MediaMuxer> muxer = new MediaMuxer(fileName,
- MediaMuxer::OUTPUT_FORMAT_MPEG_4);
- if (gRotate) {
- muxer->setOrientationHint(90); // TODO: does this do anything?
+ sp<MediaMuxer> muxer = NULL;
+ FILE* rawFp = NULL;
+ if (gRawOutput) {
+ rawFp = prepareRawOutput(fileName);
+ if (rawFp == NULL) {
+ encoder->release();
+ return -1;
+ }
+ } else {
+ // Configure muxer. We have to wait for the CSD blob from the encoder
+ // before we can start it.
+ muxer = new MediaMuxer(fileName, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+ if (gRotate) {
+ muxer->setOrientationHint(90); // TODO: does this do anything?
+ }
}
// Main encoder loop.
- err = runEncoder(encoder, muxer, mainDpy, dpy, mainDpyInfo.orientation);
+ err = runEncoder(encoder, muxer, rawFp, mainDpy, dpy,
+ mainDpyInfo.orientation);
if (err != NO_ERROR) {
fprintf(stderr, "Encoder failed (err=%d)\n", err);
// fall through to cleanup
@@ -584,9 +650,13 @@ static status_t recordScreen(const char* fileName) {
overlay->stop();
}
encoder->stop();
- // If we don't stop muxer explicitly, i.e. let the destructor run,
- // it may hang (b/11050628).
- muxer->stop();
+ if (muxer != NULL) {
+ // If we don't stop muxer explicitly, i.e. let the destructor run,
+ // it may hang (b/11050628).
+ muxer->stop();
+ } else if (rawFp != stdout) {
+ fclose(rawFp);
+ }
encoder->release();
return err;
@@ -753,6 +823,7 @@ int main(int argc, char* const argv[]) {
{ "show-frame-time", no_argument, NULL, 'f' },
{ "bugreport", no_argument, NULL, 'u' },
{ "rotate", no_argument, NULL, 'r' },
+ { "raw", no_argument, NULL, 'w' },
{ NULL, 0, NULL, 0 }
};
@@ -818,6 +889,10 @@ int main(int argc, char* const argv[]) {
// experimental feature
gRotate = true;
break;
+ case 'w':
+ // experimental feature
+ gRawOutput = true;
+ break;
default:
if (ic != '?') {
fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
@@ -831,17 +906,19 @@ int main(int argc, char* const argv[]) {
return 2;
}
- // MediaMuxer tries to create the file in the constructor, but we don't
- // learn about the failure until muxer.start(), which returns a generic
- // error code without logging anything. We attempt to create the file
- // now for better diagnostics.
const char* fileName = argv[optind];
- int fd = open(fileName, O_CREAT | O_RDWR, 0644);
- if (fd < 0) {
- fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno));
- return 1;
+ if (!gRawOutput) {
+ // MediaMuxer tries to create the file in the constructor, but we don't
+ // learn about the failure until muxer.start(), which returns a generic
+ // error code without logging anything. We attempt to create the file
+ // now for better diagnostics.
+ int fd = open(fileName, O_CREAT | O_RDWR, 0644);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno));
+ return 1;
+ }
+ close(fd);
}
- close(fd);
status_t err = recordScreen(fileName);
if (err == NO_ERROR) {
diff --git a/cmds/screenrecord/screenrecord.h b/cmds/screenrecord/screenrecord.h
index 95e8a68..9b058c2 100644
--- a/cmds/screenrecord/screenrecord.h
+++ b/cmds/screenrecord/screenrecord.h
@@ -18,6 +18,6 @@
#define SCREENRECORD_SCREENRECORD_H
#define kVersionMajor 1
-#define kVersionMinor 1
+#define kVersionMinor 2
#endif /*SCREENRECORD_SCREENRECORD_H*/
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index 5d2d721..1b2f792 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -23,6 +23,7 @@
#include <gui/Surface.h>
#include <media/AudioTrack.h>
#include <media/ICrypto.h>
+#include <media/IMediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -275,7 +276,8 @@ status_t SimplePlayer::onPrepare() {
mExtractor = new NuMediaExtractor;
- status_t err = mExtractor->setDataSource(mPath.c_str());
+ status_t err = mExtractor->setDataSource(
+ NULL /* httpService */, mPath.c_str());
if (err != OK) {
mExtractor.clear();
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index d125ad1..fd02bcc 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -24,6 +24,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/ICrypto.h>
+#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -76,7 +77,7 @@ static int decode(
static int64_t kTimeout = 500ll;
sp<NuMediaExtractor> extractor = new NuMediaExtractor;
- if (extractor->setDataSource(path) != OK) {
+ if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
fprintf(stderr, "unable to instantiate extractor.\n");
return 1;
}
diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp
index 90daea2..f4a33e8 100644
--- a/cmds/stagefright/muxer.cpp
+++ b/cmds/stagefright/muxer.cpp
@@ -20,6 +20,7 @@
#include <utils/Log.h>
#include <binder/ProcessState.h>
+#include <media/IMediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
@@ -59,7 +60,7 @@ static int muxing(
int trimEndTimeMs,
int rotationDegrees) {
sp<NuMediaExtractor> extractor = new NuMediaExtractor;
- if (extractor->setDataSource(path) != OK) {
+ if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
fprintf(stderr, "unable to instantiate extractor. %s\n", path);
return 1;
}
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index b2b9ce5..3c0c7ec 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -19,8 +19,12 @@
#include <inttypes.h>
#include <utils/Log.h>
+#include <signal.h>
+
#include <binder/ProcessState.h>
+#include <media/IMediaHTTPService.h>
+
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -43,6 +47,18 @@
using namespace android;
+volatile static bool ctrlc = false;
+
+static sighandler_t oldhandler = NULL;
+
+static void mysighandler(int signum) {
+ if (signum == SIGINT) {
+ ctrlc = true;
+ return;
+ }
+ oldhandler(signum);
+}
+
struct Controller : public AHandler {
Controller(const char *uri, bool decodeAudio,
const sp<Surface> &surface, bool renderToSurface)
@@ -63,7 +79,30 @@ protected:
virtual ~Controller() {
}
+ virtual void printStatistics() {
+ int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
+
+ if (mDecodeAudio) {
+ printf("%" PRId64 " bytes received. %.2f KB/sec\n",
+ mTotalBytesReceived,
+ mTotalBytesReceived * 1E6 / 1024 / delayUs);
+ } else {
+ printf("%d frames decoded, %.2f fps. %" PRId64 " bytes "
+ "received. %.2f KB/sec\n",
+ mNumOutputBuffersReceived,
+ mNumOutputBuffersReceived * 1E6 / delayUs,
+ mTotalBytesReceived,
+ mTotalBytesReceived * 1E6 / 1024 / delayUs);
+ }
+ }
+
virtual void onMessageReceived(const sp<AMessage> &msg) {
+ if (ctrlc) {
+ printf("\n");
+ printStatistics();
+ (new AMessage(kWhatStop, id()))->post();
+ ctrlc = false;
+ }
switch (msg->what()) {
case kWhatStart:
{
@@ -76,7 +115,8 @@ protected:
#endif
sp<DataSource> dataSource =
- DataSource::CreateFromURI(mURI.c_str());
+ DataSource::CreateFromURI(
+ NULL /* httpService */, mURI.c_str());
sp<MediaExtractor> extractor =
MediaExtractor::Create(dataSource);
@@ -99,7 +139,10 @@ protected:
break;
}
}
- CHECK(mSource != NULL);
+ if (mSource == NULL) {
+ printf("no %s track found\n", mDecodeAudio ? "audio" : "video");
+ exit (1);
+ }
CHECK_EQ(mSource->start(), (status_t)OK);
@@ -181,21 +224,7 @@ protected:
|| what == ACodec::kWhatError) {
printf((what == ACodec::kWhatEOS) ? "$\n" : "E\n");
- int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
-
- if (mDecodeAudio) {
- printf("%" PRId64 " bytes received. %.2f KB/sec\n",
- mTotalBytesReceived,
- mTotalBytesReceived * 1E6 / 1024 / delayUs);
- } else {
- printf("%d frames decoded, %.2f fps. %" PRId64 " bytes "
- "received. %.2f KB/sec\n",
- mNumOutputBuffersReceived,
- mNumOutputBuffersReceived * 1E6 / delayUs,
- mTotalBytesReceived,
- mTotalBytesReceived * 1E6 / 1024 / delayUs);
- }
-
+ printStatistics();
(new AMessage(kWhatStop, id()))->post();
} else if (what == ACodec::kWhatFlushCompleted) {
mSeekState = SEEK_FLUSH_COMPLETED;
@@ -639,6 +668,8 @@ int main(int argc, char **argv) {
looper->registerHandler(controller);
+ signal(SIGINT, mysighandler);
+
controller->startAsync();
CHECK_EQ(looper->start(true /* runOnCallingThread */), (status_t)OK);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 8efb39e..daaea27 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -29,6 +29,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ALooper.h>
#include "include/NuCachedSource2.h"
@@ -960,7 +961,8 @@ int main(int argc, char **argv) {
const char *filename = argv[k];
- sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
+ sp<DataSource> dataSource =
+ DataSource::CreateFromURI(NULL /* httpService */, filename);
if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
fprintf(stderr, "Unable to create data source.\n");
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index dba67a9..b2abc0f 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -21,6 +21,7 @@
#include <binder/ProcessState.h>
#include <cutils/properties.h> // for property_get
+#include <media/IMediaHTTPService.h>
#include <media/IStreamSource.h>
#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -159,7 +160,9 @@ private:
MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
: mCurrentBufferIndex(-1),
mCurrentBufferOffset(0) {
- sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
+ sp<DataSource> dataSource =
+ DataSource::CreateFromURI(NULL /* httpService */, filename);
+
CHECK(dataSource != NULL);
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);