Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e32106fd authored by Benoit Goby's avatar Benoit Goby
Browse files

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
parent 21bde57f
Loading
Loading
Loading
Loading
+14 −11
Original line number Original line Diff line number Diff line
@@ -85,7 +85,7 @@ status_t FrameOutput::createInputSurface(int width, int height,
    return NO_ERROR;
    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);
    Mutex::Autolock _l(mMutex);
    ALOGV("copyFrame %ld\n", timeoutUsec);
    ALOGV("copyFrame %ld\n", timeoutUsec);


@@ -150,9 +150,11 @@ status_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec) {
                (endWhenNsec - pixWhenNsec) / 1000000.0);
                (endWhenNsec - pixWhenNsec) / 1000000.0);
    }
    }


    size_t rgbDataLen = width * height * kOutBytesPerPixel;

    if (!rawFrames) {
        // Fill out the header.
        // Fill out the header.
        size_t headerLen = sizeof(uint32_t) * 5;
        size_t headerLen = sizeof(uint32_t) * 5;
    size_t rgbDataLen = width * height * kOutBytesPerPixel;
        size_t packetLen = headerLen - sizeof(uint32_t) + rgbDataLen;
        size_t packetLen = headerLen - sizeof(uint32_t) + rgbDataLen;
        uint8_t header[headerLen];
        uint8_t header[headerLen];
        setValueLE(&header[0], packetLen);
        setValueLE(&header[0], packetLen);
@@ -160,6 +162,8 @@ status_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec) {
        setValueLE(&header[8], height);
        setValueLE(&header[8], height);
        setValueLE(&header[12], width * kOutBytesPerPixel);
        setValueLE(&header[12], width * kOutBytesPerPixel);
        setValueLE(&header[16], HAL_PIXEL_FORMAT_RGB_888);
        setValueLE(&header[16], HAL_PIXEL_FORMAT_RGB_888);
        fwrite(header, 1, headerLen, fp);
    }


    // Currently using buffered I/O rather than writev().  Not expecting it
    // 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
    // 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) {
    if (kShowTiming) {
        startWhenNsec = systemTime(CLOCK_MONOTONIC);
        startWhenNsec = systemTime(CLOCK_MONOTONIC);
    }
    }
    fwrite(header, 1, headerLen, fp);
    fwrite(mPixelBuf, 1, rgbDataLen, fp);
    fwrite(mPixelBuf, 1, rgbDataLen, fp);
    fflush(fp);
    fflush(fp);
    if (kShowTiming) {
    if (kShowTiming) {
+1 −1
Original line number Original line Diff line number Diff line
@@ -48,7 +48,7 @@ public:
    // specified number of microseconds.
    // specified number of microseconds.
    //
    //
    // Returns ETIMEDOUT if the timeout expired before we found a frame.
    // 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.
    // Prepare to copy frames.  Makes the EGL context used by this object current.
    void prepareToCopy() {
    void prepareToCopy() {
+9 −5
Original line number Original line Diff line number Diff line
@@ -65,7 +65,7 @@ static const char* kMimeTypeAvc = "video/avc";
static bool gVerbose = false;           // chatty on stdout
static bool gVerbose = false;           // chatty on stdout
static bool gRotate = false;            // rotate 90 degrees
static bool gRotate = false;            // rotate 90 degrees
static enum {
static enum {
    FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES
    FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES, FORMAT_RAW_FRAMES
} gOutputFormat = FORMAT_MP4;           // data format for output
} gOutputFormat = FORMAT_MP4;           // data format for output
static bool gSizeSpecified = false;     // was size explicitly requested?
static bool gSizeSpecified = false;     // was size explicitly requested?
static bool gWantInfoScreen = false;    // do we want initial info screen?
static bool gWantInfoScreen = false;    // do we want initial info screen?
@@ -563,7 +563,7 @@ static status_t recordScreen(const char* fileName) {
    sp<MediaCodec> encoder;
    sp<MediaCodec> encoder;
    sp<FrameOutput> frameOutput;
    sp<FrameOutput> frameOutput;
    sp<IGraphicBufferProducer> encoderInputSurface;
    sp<IGraphicBufferProducer> encoderInputSurface;
    if (gOutputFormat != FORMAT_FRAMES) {
    if (gOutputFormat != FORMAT_FRAMES && gOutputFormat != FORMAT_RAW_FRAMES) {
        err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);
        err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);


        if (err != NO_ERROR && !gSizeSpecified) {
        if (err != NO_ERROR && !gSizeSpecified) {
@@ -643,7 +643,8 @@ static status_t recordScreen(const char* fileName) {
            break;
            break;
        }
        }
        case FORMAT_H264:
        case FORMAT_H264:
        case FORMAT_FRAMES: {
        case FORMAT_FRAMES:
        case FORMAT_RAW_FRAMES: {
            rawFp = prepareRawOutput(fileName);
            rawFp = prepareRawOutput(fileName);
            if (rawFp == NULL) {
            if (rawFp == NULL) {
                if (encoder != NULL) encoder->release();
                if (encoder != NULL) encoder->release();
@@ -656,7 +657,7 @@ static status_t recordScreen(const char* fileName) {
            abort();
            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
        // TODO: if we want to make this a proper feature, we should output
        //       an outer header with version info.  Right now we never change
        //       an outer header with version info.  Right now we never change
        //       the frame size or format, so we could conceivably just send
        //       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
            // stop was requested, but this will do for now.  (It almost
            // works because wait() wakes when a signal hits, but we
            // works because wait() wakes when a signal hits, but we
            // need to handle the edge cases.)
            // 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) {
            if (err == ETIMEDOUT) {
                err = NO_ERROR;
                err = NO_ERROR;
            } else if (err != NO_ERROR) {
            } else if (err != NO_ERROR) {
@@ -950,6 +952,8 @@ int main(int argc, char* const argv[]) {
                gOutputFormat = FORMAT_H264;
                gOutputFormat = FORMAT_H264;
            } else if (strcmp(optarg, "frames") == 0) {
            } else if (strcmp(optarg, "frames") == 0) {
                gOutputFormat = FORMAT_FRAMES;
                gOutputFormat = FORMAT_FRAMES;
            } else if (strcmp(optarg, "raw-frames") == 0) {
                gOutputFormat = FORMAT_RAW_FRAMES;
            } else {
            } else {
                fprintf(stderr, "Unknown format '%s'\n", optarg);
                fprintf(stderr, "Unknown format '%s'\n", optarg);
                return 2;
                return 2;