From e32106fd5175afdf939ae397aece9caf378a4912 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Mon, 12 May 2014 15:59:50 -0700 Subject: screenrecord: Add raw frames output format This works like the frames output format but without a header so that the output can be piped directly to mplayer: adb shell screenrecord --output-format=raw-frames - | mplayer -demuxer rawvideo -rawvideo w=320:h=240:format=rgb24 - Change-Id: Ib5ed508fdca3a5d63e973c5189b3677c2d92b43f --- cmds/screenrecord/FrameOutput.cpp | 25 ++++++++++++++----------- cmds/screenrecord/FrameOutput.h | 2 +- cmds/screenrecord/screenrecord.cpp | 14 +++++++++----- 3 files changed, 24 insertions(+), 17 deletions(-) (limited to 'cmds') diff --git a/cmds/screenrecord/FrameOutput.cpp b/cmds/screenrecord/FrameOutput.cpp index b5cf2f9..6c37501 100644 --- a/cmds/screenrecord/FrameOutput.cpp +++ b/cmds/screenrecord/FrameOutput.cpp @@ -85,7 +85,7 @@ status_t FrameOutput::createInputSurface(int width, int height, return NO_ERROR; } -status_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec) { +status_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec, bool rawFrames) { Mutex::Autolock _l(mMutex); ALOGV("copyFrame %ld\n", timeoutUsec); @@ -150,16 +150,20 @@ status_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec) { (endWhenNsec - pixWhenNsec) / 1000000.0); } - // Fill out the header. - size_t headerLen = sizeof(uint32_t) * 5; size_t rgbDataLen = width * height * kOutBytesPerPixel; - size_t packetLen = headerLen - sizeof(uint32_t) + rgbDataLen; - uint8_t header[headerLen]; - setValueLE(&header[0], packetLen); - setValueLE(&header[4], width); - setValueLE(&header[8], height); - setValueLE(&header[12], width * kOutBytesPerPixel); - setValueLE(&header[16], HAL_PIXEL_FORMAT_RGB_888); + + if (!rawFrames) { + // Fill out the header. + size_t headerLen = sizeof(uint32_t) * 5; + size_t packetLen = headerLen - sizeof(uint32_t) + rgbDataLen; + uint8_t header[headerLen]; + setValueLE(&header[0], packetLen); + setValueLE(&header[4], width); + setValueLE(&header[8], height); + setValueLE(&header[12], width * kOutBytesPerPixel); + setValueLE(&header[16], HAL_PIXEL_FORMAT_RGB_888); + fwrite(header, 1, headerLen, fp); + } // Currently using buffered I/O rather than writev(). Not expecting it // to make much of a difference, but it might be worth a test for larger @@ -167,7 +171,6 @@ status_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec) { if (kShowTiming) { startWhenNsec = systemTime(CLOCK_MONOTONIC); } - fwrite(header, 1, headerLen, fp); fwrite(mPixelBuf, 1, rgbDataLen, fp); fflush(fp); if (kShowTiming) { diff --git a/cmds/screenrecord/FrameOutput.h b/cmds/screenrecord/FrameOutput.h index b8e9e68..4ac3e8a 100644 --- a/cmds/screenrecord/FrameOutput.h +++ b/cmds/screenrecord/FrameOutput.h @@ -48,7 +48,7 @@ public: // specified number of microseconds. // // Returns ETIMEDOUT if the timeout expired before we found a frame. - status_t copyFrame(FILE* fp, long timeoutUsec); + status_t copyFrame(FILE* fp, long timeoutUsec, bool rawFrames); // Prepare to copy frames. Makes the EGL context used by this object current. void prepareToCopy() { diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp index a17fc51..02ed53a 100644 --- a/cmds/screenrecord/screenrecord.cpp +++ b/cmds/screenrecord/screenrecord.cpp @@ -65,7 +65,7 @@ static const char* kMimeTypeAvc = "video/avc"; static bool gVerbose = false; // chatty on stdout static bool gRotate = false; // rotate 90 degrees static enum { - FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES + FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES, FORMAT_RAW_FRAMES } gOutputFormat = FORMAT_MP4; // data format for output static bool gSizeSpecified = false; // was size explicitly requested? static bool gWantInfoScreen = false; // do we want initial info screen? @@ -563,7 +563,7 @@ static status_t recordScreen(const char* fileName) { sp encoder; sp frameOutput; sp encoderInputSurface; - if (gOutputFormat != FORMAT_FRAMES) { + if (gOutputFormat != FORMAT_FRAMES && gOutputFormat != FORMAT_RAW_FRAMES) { err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface); if (err != NO_ERROR && !gSizeSpecified) { @@ -643,7 +643,8 @@ static status_t recordScreen(const char* fileName) { break; } case FORMAT_H264: - case FORMAT_FRAMES: { + case FORMAT_FRAMES: + case FORMAT_RAW_FRAMES: { rawFp = prepareRawOutput(fileName); if (rawFp == NULL) { if (encoder != NULL) encoder->release(); @@ -656,7 +657,7 @@ static status_t recordScreen(const char* fileName) { abort(); } - if (gOutputFormat == FORMAT_FRAMES) { + if (gOutputFormat == FORMAT_FRAMES || gOutputFormat == FORMAT_RAW_FRAMES) { // TODO: if we want to make this a proper feature, we should output // an outer header with version info. Right now we never change // the frame size or format, so we could conceivably just send @@ -676,7 +677,8 @@ static status_t recordScreen(const char* fileName) { // stop was requested, but this will do for now. (It almost // works because wait() wakes when a signal hits, but we // need to handle the edge cases.) - err = frameOutput->copyFrame(rawFp, 250000); + bool rawFrames = gOutputFormat == FORMAT_RAW_FRAMES; + err = frameOutput->copyFrame(rawFp, 250000, rawFrames); if (err == ETIMEDOUT) { err = NO_ERROR; } else if (err != NO_ERROR) { @@ -950,6 +952,8 @@ int main(int argc, char* const argv[]) { gOutputFormat = FORMAT_H264; } else if (strcmp(optarg, "frames") == 0) { gOutputFormat = FORMAT_FRAMES; + } else if (strcmp(optarg, "raw-frames") == 0) { + gOutputFormat = FORMAT_RAW_FRAMES; } else { fprintf(stderr, "Unknown format '%s'\n", optarg); return 2; -- cgit v1.1