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

Commit dae9fd31 authored by James Dong's avatar James Dong
Browse files

Initial check-in for collecting stats from authoring engine at runtime

Change-Id: I93a9d8bd260efc5e7fc135b726e3f1307c6df794
parent 31b19758
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -51,6 +51,12 @@ private:
    AudioRecord *mRecord;
    status_t mInitCheck;
    bool mStarted;

    bool mCollectStats;
    int64_t mTotalReadTimeUs;
    int64_t mTotalReadBytes;
    int64_t mTotalReads;

    MediaBufferGroup *mGroup;

    AudioSource(const AudioSource &);
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ private:
    int32_t mNumFramesReceived;
    int32_t mNumFramesEncoded;
    int32_t mNumFramesDropped;
    bool mCollectStats;
    bool mStarted;

    CameraSource(const sp<Camera> &camera);
+34 −1
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <cutils/properties.h>
#include <sys/time.h>
#include <time.h>

namespace android {

@@ -34,6 +37,10 @@ AudioSource::AudioSource(
                inputSource, sampleRate, AudioSystem::PCM_16_BIT, channels)),
      mInitCheck(mRecord->initCheck()),
      mStarted(false),
      mCollectStats(false),
      mTotalReadTimeUs(0),
      mTotalReadBytes(0),
      mTotalReads(0),
      mGroup(NULL) {
}

@@ -55,6 +62,11 @@ status_t AudioSource::start(MetaData *params) {
        return UNKNOWN_ERROR;
    }

    char value[PROPERTY_VALUE_MAX];
    if (property_get("media.stagefright.record-stats", value, NULL)
        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
        mCollectStats = true;
    }
    status_t err = mRecord->start();

    if (err == OK) {
@@ -79,6 +91,13 @@ status_t AudioSource::stop() {

    mStarted = false;

    if (mCollectStats) {
        LOGI("%lld reads: %.2f bps in %lld us",
                mTotalReads,
                (mTotalReadBytes * 8000000.0) / mTotalReadTimeUs,
                mTotalReadTimeUs);
    }

    return OK;
}

@@ -95,6 +114,7 @@ sp<MetaData> AudioSource::getFormat() {
status_t AudioSource::read(
        MediaBuffer **out, const ReadOptions *options) {
    *out = NULL;
    ++mTotalReads;

    MediaBuffer *buffer;
    CHECK_EQ(mGroup->acquire_buffer(&buffer), OK);
@@ -107,7 +127,20 @@ status_t AudioSource::read(
            (1000000ll * numFramesRecorded) / mRecord->getSampleRate()
            - mRecord->latency() * 1000);

    ssize_t n = mRecord->read(buffer->data(), buffer->size());
    ssize_t n = 0;
    if (mCollectStats) {
        struct timeval tv_start, tv_end;
        gettimeofday(&tv_start, NULL);
        n = mRecord->read(buffer->data(), buffer->size());
        gettimeofday(&tv_end, NULL);
        mTotalReadTimeUs += ((1000000LL * (tv_end.tv_sec - tv_start.tv_sec))
                + (tv_end.tv_usec - tv_start.tv_usec));
        if (n >= 0) {
            mTotalReadBytes += n;
        }
    } else {
        n = mRecord->read(buffer->data(), buffer->size());
    }

    if (n < 0) {
        buffer->release();
+16 −5
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
#include <utils/String8.h>
#include <cutils/properties.h>

namespace android {

@@ -122,6 +123,7 @@ CameraSource::CameraSource(const sp<Camera> &camera)
      mNumFramesReceived(0),
      mNumFramesEncoded(0),
      mNumFramesDropped(0),
      mCollectStats(false),
      mStarted(false) {
    String8 s = mCamera->getParameters();
    printf("params: \"%s\"\n", s.string());
@@ -151,6 +153,11 @@ status_t CameraSource::start(MetaData *) {
    LOGV("start");
    CHECK(!mStarted);

    char value[PROPERTY_VALUE_MAX];
    if (property_get("media.stagefright.record-stats", value, NULL)
        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
        mCollectStats = true;
    }
    mCamera->setListener(new CameraSourceListener(this));
    CHECK_EQ(OK, mCamera->startRecording());

@@ -163,19 +170,23 @@ status_t CameraSource::stop() {
    Mutex::Autolock autoLock(mLock);
    mStarted = false;
    mFrameAvailableCondition.signal();

    mCamera->setListener(NULL);
    mCamera->stopRecording();

    releaseQueuedFrames();

    while (!mFramesBeingEncoded.empty()) {
        LOGI("Number of outstanding frames is being encoded: %d", mFramesBeingEncoded.size());
        LOGI("Waiting for outstanding frames being encoded: %d",
                mFramesBeingEncoded.size());
        mFrameCompleteCondition.wait(mLock);
    }

    LOGI("Frames received/encoded/dropped: %d/%d/%d, timestamp (us) last/first: %lld/%lld",
    if (mCollectStats) {
        LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
                mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
            mLastFrameTimestampUs, mFirstFrameTimeUs);
                mLastFrameTimestampUs - mFirstFrameTimeUs);
    }

    CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
    return OK;
@@ -252,7 +263,6 @@ status_t CameraSource::read(
void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
        int32_t msgType, const sp<IMemory> &data) {
    LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
    mLastFrameTimestampUs = timestampUs;
    Mutex::Autolock autoLock(mLock);
    if (!mStarted) {
        mCamera->releaseRecordingFrame(data);
@@ -261,6 +271,7 @@ void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
        return;
    }

    mLastFrameTimestampUs = timestampUs;
    if (mNumFramesReceived == 0) {
        mFirstFrameTimeUs = timestampUs;
    }
+88 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/Utils.h>
#include <media/mediarecorder.h>
#include <cutils/properties.h>

namespace android {

@@ -82,6 +83,7 @@ private:
    List<StscTableEntry> mStscTableEntries;

    List<int32_t> mStssTableEntries;
    List<int64_t> mChunkDurations;

    struct SttsTableEntry {

@@ -106,6 +108,9 @@ private:
    status_t makeAVCCodecSpecificData(
            const uint8_t *data, size_t size);
    void writeOneChunk(bool isAvc);
    void logStatisticalData(bool isAudio);
    void findMinMaxFrameRates(float *minFps, float *maxFps);
    void findMinMaxChunkDurations(int64_t *min, int64_t *max);

    Track(const Track &);
    Track &operator=(const Track &);
@@ -912,6 +917,7 @@ void MPEG4Writer::Track::threadEntry() {
            } else {
                if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
                    ++nChunks;
                    mChunkDurations.push_back(timestampUs - chunkTimestampUs);
                    if (nChunks == 1 ||  // First chunk
                        (--(mStscTableEntries.end()))->samplesPerChunk !=
                         mChunkSamples.size()) {
@@ -952,6 +958,88 @@ void MPEG4Writer::Track::threadEntry() {
    mReachedEOS = true;
    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s",
            count, nZeroLengthFrames, mSampleInfos.size(), is_audio? "audio": "video");

    logStatisticalData(is_audio);
}

void MPEG4Writer::Track::findMinMaxFrameRates(float *minFps, float *maxFps) {
    int32_t minSampleDuration = 0x7FFFFFFF;
    int32_t maxSampleDuration = 0;
    for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
        it != mSttsTableEntries.end(); ++it) {
        int32_t sampleDuration = static_cast<int32_t>(it->sampleDuration);
        if (sampleDuration > maxSampleDuration) {
            maxSampleDuration = sampleDuration;
        } else if (sampleDuration < minSampleDuration) {
            minSampleDuration = sampleDuration;
        }
    }
    CHECK(minSampleDuration != 0 && maxSampleDuration != 0);
    *minFps = 1000.0 / maxSampleDuration;
    *maxFps = 1000.0 / minSampleDuration;
}

// Don't count the last duration
void MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) {
    int64_t duration = mOwner->interleaveDuration();
    int64_t minChunkDuration = duration;
    int64_t maxChunkDuration = duration;
    if (mChunkDurations.size() > 1) {
        for (List<int64_t>::iterator it = mChunkDurations.begin();
            it != --mChunkDurations.end(); ++it) {
            if (minChunkDuration > (*it)) {
                minChunkDuration = (*it);
            } else if (maxChunkDuration < (*it)) {
                maxChunkDuration = (*it);
            }
        }
    }
    *min = minChunkDuration;
    *max = maxChunkDuration;
}

void MPEG4Writer::Track::logStatisticalData(bool isAudio) {
    if (mMaxTimeStampUs <= 0 || mSampleInfos.empty()) {
        LOGI("nothing is recorded");
        return;
    }

    bool collectStats = false;
    char value[PROPERTY_VALUE_MAX];
    if (property_get("media.stagefright.record-stats", value, NULL)
        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
        collectStats = true;
    }

    if (collectStats) {
        if (isAudio) {
            LOGI("audio track - duration %lld us", mMaxTimeStampUs);
        } else {
            float fps = (mSampleInfos.size() * 1000000.0) / mMaxTimeStampUs;
            float minFps;
            float maxFps;
            findMinMaxFrameRates(&minFps, &maxFps);
            LOGI("video track - duration %lld us", mMaxTimeStampUs);
            LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f",
                minFps, fps, maxFps);
        }

        int64_t totalBytes = 0;
        for (List<SampleInfo>::iterator it = mSampleInfos.begin();
            it != mSampleInfos.end(); ++it) {
            totalBytes += it->size;
        }
        float bitRate = (totalBytes * 8000000.0) / mMaxTimeStampUs;
        LOGI("avg bit rate (bps): %.2f", bitRate);

        int64_t duration = mOwner->interleaveDuration();
        if (duration != 0) {  // If interleaving is enabled
            int64_t minChunk, maxChunk;
            findMinMaxChunkDurations(&minChunk, &maxChunk);
            LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld",
                minChunk, duration, maxChunk);
        }
    }
}

void MPEG4Writer::Track::writeOneChunk(bool isAvc) {