am dae9fd31: Initial check-in for collecting stats from authoring engine at runtime
This commit is contained in:
@@ -51,6 +51,12 @@ private:
|
|||||||
AudioRecord *mRecord;
|
AudioRecord *mRecord;
|
||||||
status_t mInitCheck;
|
status_t mInitCheck;
|
||||||
bool mStarted;
|
bool mStarted;
|
||||||
|
|
||||||
|
bool mCollectStats;
|
||||||
|
int64_t mTotalReadTimeUs;
|
||||||
|
int64_t mTotalReadBytes;
|
||||||
|
int64_t mTotalReads;
|
||||||
|
|
||||||
MediaBufferGroup *mGroup;
|
MediaBufferGroup *mGroup;
|
||||||
|
|
||||||
AudioSource(const AudioSource &);
|
AudioSource(const AudioSource &);
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ private:
|
|||||||
int32_t mNumFramesReceived;
|
int32_t mNumFramesReceived;
|
||||||
int32_t mNumFramesEncoded;
|
int32_t mNumFramesEncoded;
|
||||||
int32_t mNumFramesDropped;
|
int32_t mNumFramesDropped;
|
||||||
|
bool mCollectStats;
|
||||||
bool mStarted;
|
bool mStarted;
|
||||||
|
|
||||||
CameraSource(const sp<Camera> &camera);
|
CameraSource(const sp<Camera> &camera);
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
#include <media/stagefright/MediaDebug.h>
|
#include <media/stagefright/MediaDebug.h>
|
||||||
#include <media/stagefright/MediaDefs.h>
|
#include <media/stagefright/MediaDefs.h>
|
||||||
#include <media/stagefright/MetaData.h>
|
#include <media/stagefright/MetaData.h>
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@@ -34,6 +37,10 @@ AudioSource::AudioSource(
|
|||||||
inputSource, sampleRate, AudioSystem::PCM_16_BIT, channels)),
|
inputSource, sampleRate, AudioSystem::PCM_16_BIT, channels)),
|
||||||
mInitCheck(mRecord->initCheck()),
|
mInitCheck(mRecord->initCheck()),
|
||||||
mStarted(false),
|
mStarted(false),
|
||||||
|
mCollectStats(false),
|
||||||
|
mTotalReadTimeUs(0),
|
||||||
|
mTotalReadBytes(0),
|
||||||
|
mTotalReads(0),
|
||||||
mGroup(NULL) {
|
mGroup(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +62,11 @@ status_t AudioSource::start(MetaData *params) {
|
|||||||
return UNKNOWN_ERROR;
|
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();
|
status_t err = mRecord->start();
|
||||||
|
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
@@ -79,6 +91,13 @@ status_t AudioSource::stop() {
|
|||||||
|
|
||||||
mStarted = false;
|
mStarted = false;
|
||||||
|
|
||||||
|
if (mCollectStats) {
|
||||||
|
LOGI("%lld reads: %.2f bps in %lld us",
|
||||||
|
mTotalReads,
|
||||||
|
(mTotalReadBytes * 8000000.0) / mTotalReadTimeUs,
|
||||||
|
mTotalReadTimeUs);
|
||||||
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +114,7 @@ sp<MetaData> AudioSource::getFormat() {
|
|||||||
status_t AudioSource::read(
|
status_t AudioSource::read(
|
||||||
MediaBuffer **out, const ReadOptions *options) {
|
MediaBuffer **out, const ReadOptions *options) {
|
||||||
*out = NULL;
|
*out = NULL;
|
||||||
|
++mTotalReads;
|
||||||
|
|
||||||
MediaBuffer *buffer;
|
MediaBuffer *buffer;
|
||||||
CHECK_EQ(mGroup->acquire_buffer(&buffer), OK);
|
CHECK_EQ(mGroup->acquire_buffer(&buffer), OK);
|
||||||
@@ -107,7 +127,20 @@ status_t AudioSource::read(
|
|||||||
(1000000ll * numFramesRecorded) / mRecord->getSampleRate()
|
(1000000ll * numFramesRecorded) / mRecord->getSampleRate()
|
||||||
- mRecord->latency() * 1000);
|
- 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) {
|
if (n < 0) {
|
||||||
buffer->release();
|
buffer->release();
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <camera/Camera.h>
|
#include <camera/Camera.h>
|
||||||
#include <camera/CameraParameters.h>
|
#include <camera/CameraParameters.h>
|
||||||
#include <utils/String8.h>
|
#include <utils/String8.h>
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@@ -122,6 +123,7 @@ CameraSource::CameraSource(const sp<Camera> &camera)
|
|||||||
mNumFramesReceived(0),
|
mNumFramesReceived(0),
|
||||||
mNumFramesEncoded(0),
|
mNumFramesEncoded(0),
|
||||||
mNumFramesDropped(0),
|
mNumFramesDropped(0),
|
||||||
|
mCollectStats(false),
|
||||||
mStarted(false) {
|
mStarted(false) {
|
||||||
String8 s = mCamera->getParameters();
|
String8 s = mCamera->getParameters();
|
||||||
printf("params: \"%s\"\n", s.string());
|
printf("params: \"%s\"\n", s.string());
|
||||||
@@ -151,6 +153,11 @@ status_t CameraSource::start(MetaData *) {
|
|||||||
LOGV("start");
|
LOGV("start");
|
||||||
CHECK(!mStarted);
|
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));
|
mCamera->setListener(new CameraSourceListener(this));
|
||||||
CHECK_EQ(OK, mCamera->startRecording());
|
CHECK_EQ(OK, mCamera->startRecording());
|
||||||
|
|
||||||
@@ -163,19 +170,23 @@ status_t CameraSource::stop() {
|
|||||||
Mutex::Autolock autoLock(mLock);
|
Mutex::Autolock autoLock(mLock);
|
||||||
mStarted = false;
|
mStarted = false;
|
||||||
mFrameAvailableCondition.signal();
|
mFrameAvailableCondition.signal();
|
||||||
|
|
||||||
mCamera->setListener(NULL);
|
mCamera->setListener(NULL);
|
||||||
mCamera->stopRecording();
|
mCamera->stopRecording();
|
||||||
|
|
||||||
releaseQueuedFrames();
|
releaseQueuedFrames();
|
||||||
|
|
||||||
while (!mFramesBeingEncoded.empty()) {
|
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);
|
mFrameCompleteCondition.wait(mLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("Frames received/encoded/dropped: %d/%d/%d, timestamp (us) last/first: %lld/%lld",
|
if (mCollectStats) {
|
||||||
mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
|
LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
|
||||||
mLastFrameTimestampUs, mFirstFrameTimeUs);
|
mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
|
||||||
|
mLastFrameTimestampUs - mFirstFrameTimeUs);
|
||||||
|
}
|
||||||
|
|
||||||
CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
|
CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
|
||||||
return OK;
|
return OK;
|
||||||
@@ -252,7 +263,6 @@ status_t CameraSource::read(
|
|||||||
void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
|
void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
|
||||||
int32_t msgType, const sp<IMemory> &data) {
|
int32_t msgType, const sp<IMemory> &data) {
|
||||||
LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
|
LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
|
||||||
mLastFrameTimestampUs = timestampUs;
|
|
||||||
Mutex::Autolock autoLock(mLock);
|
Mutex::Autolock autoLock(mLock);
|
||||||
if (!mStarted) {
|
if (!mStarted) {
|
||||||
mCamera->releaseRecordingFrame(data);
|
mCamera->releaseRecordingFrame(data);
|
||||||
@@ -261,6 +271,7 @@ void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mLastFrameTimestampUs = timestampUs;
|
||||||
if (mNumFramesReceived == 0) {
|
if (mNumFramesReceived == 0) {
|
||||||
mFirstFrameTimeUs = timestampUs;
|
mFirstFrameTimeUs = timestampUs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <media/stagefright/MediaSource.h>
|
#include <media/stagefright/MediaSource.h>
|
||||||
#include <media/stagefright/Utils.h>
|
#include <media/stagefright/Utils.h>
|
||||||
#include <media/mediarecorder.h>
|
#include <media/mediarecorder.h>
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@@ -82,6 +83,7 @@ private:
|
|||||||
List<StscTableEntry> mStscTableEntries;
|
List<StscTableEntry> mStscTableEntries;
|
||||||
|
|
||||||
List<int32_t> mStssTableEntries;
|
List<int32_t> mStssTableEntries;
|
||||||
|
List<int64_t> mChunkDurations;
|
||||||
|
|
||||||
struct SttsTableEntry {
|
struct SttsTableEntry {
|
||||||
|
|
||||||
@@ -106,6 +108,9 @@ private:
|
|||||||
status_t makeAVCCodecSpecificData(
|
status_t makeAVCCodecSpecificData(
|
||||||
const uint8_t *data, size_t size);
|
const uint8_t *data, size_t size);
|
||||||
void writeOneChunk(bool isAvc);
|
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(const Track &);
|
||||||
Track &operator=(const Track &);
|
Track &operator=(const Track &);
|
||||||
@@ -912,6 +917,7 @@ void MPEG4Writer::Track::threadEntry() {
|
|||||||
} else {
|
} else {
|
||||||
if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
|
if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
|
||||||
++nChunks;
|
++nChunks;
|
||||||
|
mChunkDurations.push_back(timestampUs - chunkTimestampUs);
|
||||||
if (nChunks == 1 || // First chunk
|
if (nChunks == 1 || // First chunk
|
||||||
(--(mStscTableEntries.end()))->samplesPerChunk !=
|
(--(mStscTableEntries.end()))->samplesPerChunk !=
|
||||||
mChunkSamples.size()) {
|
mChunkSamples.size()) {
|
||||||
@@ -952,6 +958,88 @@ void MPEG4Writer::Track::threadEntry() {
|
|||||||
mReachedEOS = true;
|
mReachedEOS = true;
|
||||||
LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s",
|
LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s",
|
||||||
count, nZeroLengthFrames, mSampleInfos.size(), is_audio? "audio": "video");
|
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) {
|
void MPEG4Writer::Track::writeOneChunk(bool isAvc) {
|
||||||
|
|||||||
Reference in New Issue
Block a user