Media metrics for android.media.MediaRecorder
underlying collection of MediaRecorder metrics for getMetrics() API
and for media metrics cloud analysis.
Bug: 35150984
Test: hacked CTS, observation of 'dumpsys media.metrics'
Change-Id: Ife2ab06158b0015549ed17d52d7f4c35781f5e0f
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index d5aec3f..9d0341a 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -53,6 +53,7 @@
virtual status_t setClientName(const String16& clientName) = 0;
virtual status_t prepare() = 0;
virtual status_t getMaxAmplitude(int* max) = 0;
+ virtual status_t getMetrics(Parcel *reply) = 0;
virtual status_t start() = 0;
virtual status_t stop() = 0;
virtual status_t reset() = 0;
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index c273da7..0b0f916 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -58,6 +58,7 @@
virtual status_t close() = 0;
virtual status_t reset() = 0;
virtual status_t getMaxAmplitude(int *max) = 0;
+ virtual status_t getMetrics(Parcel *reply) = 0;
virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
virtual status_t setInputSurface(const sp<PersistentSurface>& surface) = 0;
virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() const = 0;
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index c2916be..071e7a1 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -249,6 +249,7 @@
void notify(int msg, int ext1, int ext2);
status_t setInputSurface(const sp<PersistentSurface>& surface);
sp<IGraphicBufferProducer> querySurfaceMediaSourceFromMediaServer();
+ status_t getMetrics(Parcel *reply);
private:
void doCleanUp();
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 5730c76..5282352 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -59,7 +59,9 @@
SET_LISTENER,
SET_CLIENT_NAME,
PAUSE,
- RESUME
+ RESUME,
+ GET_METRICS,
+
};
class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -261,6 +263,18 @@
return reply.readInt32();
}
+ status_t getMetrics(Parcel* reply)
+ {
+ ALOGV("getMetrics");
+ Parcel data;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ status_t ret = remote()->transact(GET_METRICS, data, reply);
+ if (ret == NO_ERROR) {
+ return OK;
+ }
+ return UNKNOWN_ERROR;
+ }
+
status_t start()
{
ALOGV("start");
@@ -397,6 +411,11 @@
reply->writeInt32(ret);
return NO_ERROR;
} break;
+ case GET_METRICS: {
+ ALOGV("GET_METRICS");
+ status_t ret = getMetrics(reply);
+ return ret;
+ } break;
case SET_VIDEO_SOURCE: {
ALOGV("SET_VIDEO_SOURCE");
CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index dbe4b3b..4405930 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -513,6 +513,17 @@
return ret;
}
+status_t MediaRecorder::getMetrics(Parcel *reply) {
+
+ ALOGV("getMetrics");
+
+ status_t ret = mMediaRecorder->getMetrics(reply);
+ if (OK != ret) {
+ ALOGE("getMetrics failed: %d", ret);
+ }
+ return ret;
+}
+
status_t MediaRecorder::start()
{
ALOGV("start");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index bb2d28b..2a3b732 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -238,6 +238,17 @@
return mRecorder->getMaxAmplitude(max);
}
+status_t MediaRecorderClient::getMetrics(Parcel* reply)
+{
+ ALOGV("MediaRecorderClient::getMetrics");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ ALOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->getMetrics(reply);
+}
+
status_t MediaRecorderClient::start()
{
ALOGV("start");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 8ddd680..4b6ee56 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -63,6 +63,7 @@
virtual status_t setClientName(const String16& clientName);
virtual status_t prepare();
virtual status_t getMaxAmplitude(int* max);
+ virtual status_t getMetrics(Parcel* reply);
virtual status_t start();
virtual status_t stop();
virtual status_t reset();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index d00e377..ba4324e 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -30,6 +30,7 @@
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
+#include <media/MediaAnalyticsItem.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -65,6 +66,10 @@
static const float kMinTypicalDisplayRefreshingRate = kTypicalDisplayRefreshingRate / 2;
static const int kMaxNumVideoTemporalLayers = 8;
+// key for media statistics
+static const char *kKeyRecorder = "recorder";
+// attrs for media statistics
+//
// To collect the encoder usage for the battery app
static void addBatteryData(uint32_t params) {
sp<IBinder> binder =
@@ -85,6 +90,8 @@
mStarted(false) {
ALOGV("Constructor");
+
+ mAnalyticsDirty = false;
reset();
}
@@ -95,6 +102,80 @@
if (mLooper != NULL) {
mLooper->stop();
}
+
+ // log the current record, provided it has some information worth recording
+ if (mAnalyticsDirty && mAnalyticsItem != NULL) {
+ updateMetrics();
+ if (mAnalyticsItem->count() > 0) {
+ mAnalyticsItem->setFinalized(true);
+ mAnalyticsItem->selfrecord();
+ }
+ delete mAnalyticsItem;
+ mAnalyticsItem = NULL;
+ }
+}
+
+void StagefrightRecorder::updateMetrics() {
+ ALOGV("updateMetrics");
+
+ // we'll populate the values from the raw fields.
+ // (NOT going to populate as we go through the various set* ops)
+
+ // TBD mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
+ // TBD mAudioEncoder = AUDIO_ENCODER_AMR_NB;
+ // TBD mVideoEncoder = VIDEO_ENCODER_DEFAULT;
+ mAnalyticsItem->setInt32("ht", mVideoHeight);
+ mAnalyticsItem->setInt32("wid", mVideoWidth);
+ mAnalyticsItem->setInt32("frame-rate", mFrameRate);
+ mAnalyticsItem->setInt32("video-bitrate", mVideoBitRate);
+ mAnalyticsItem->setInt32("audio-samplerate", mSampleRate);
+ mAnalyticsItem->setInt32("audio-channels", mAudioChannels);
+ mAnalyticsItem->setInt32("audio-bitrate", mAudioBitRate);
+ // TBD mInterleaveDurationUs = 0;
+ mAnalyticsItem->setInt32("video-iframe-interval", mIFramesIntervalSec);
+ // TBD mAudioSourceNode = 0;
+ // TBD mUse64BitFileOffset = false;
+ mAnalyticsItem->setInt32("movie-timescale", mMovieTimeScale);
+ mAnalyticsItem->setInt32("audio-timescale", mAudioTimeScale);
+ mAnalyticsItem->setInt32("video-timescale", mVideoTimeScale);
+ // TBD mCameraId = 0;
+ // TBD mStartTimeOffsetMs = -1;
+ mAnalyticsItem->setInt32("video-encoder-profile", mVideoEncoderProfile);
+ mAnalyticsItem->setInt32("video-encoder-level", mVideoEncoderLevel);
+ // TBD mMaxFileDurationUs = 0;
+ // TBD mMaxFileSizeBytes = 0;
+ // TBD mTrackEveryTimeDurationUs = 0;
+ mAnalyticsItem->setInt32("capture-fpsenable", mCaptureFpsEnable);
+ mAnalyticsItem->setInt32("capture-fps", mCaptureFps);
+ // TBD mTimeBetweenCaptureUs = -1;
+ // TBD mCameraSourceTimeLapse = NULL;
+ // TBD mMetaDataStoredInVideoBuffers = kMetadataBufferTypeInvalid;
+ // TBD mEncoderProfiles = MediaProfiles::getInstance();
+ mAnalyticsItem->setInt32("rotation", mRotationDegrees);
+ // PII mLatitudex10000 = -3600000;
+ // PII mLongitudex10000 = -3600000;
+ // TBD mTotalBitRate = 0;
+
+ // TBD: some duration information (capture, paused)
+ //
+
+}
+
+void StagefrightRecorder::resetMetrics() {
+ ALOGV("resetMetrics");
+ // flush anything we have, restart the record
+ if (mAnalyticsDirty && mAnalyticsItem != NULL) {
+ updateMetrics();
+ if (mAnalyticsItem->count() > 0) {
+ mAnalyticsItem->setFinalized(true);
+ mAnalyticsItem->selfrecord();
+ }
+ delete mAnalyticsItem;
+ mAnalyticsItem = NULL;
+ }
+ mAnalyticsItem = new MediaAnalyticsItem(kKeyRecorder);
+ (void) mAnalyticsItem->generateSessionID();
+ mAnalyticsDirty = false;
}
status_t StagefrightRecorder::init() {
@@ -387,6 +468,7 @@
// Additional check on the sample rate will be performed later.
mSampleRate = sampleRate;
+
return OK;
}
@@ -399,6 +481,7 @@
// Additional check on the number of channels will be performed later.
mAudioChannels = channels;
+
return OK;
}
@@ -930,6 +1013,7 @@
}
if ((status == OK) && (!mStarted)) {
+ mAnalyticsDirty = true;
mStarted = true;
uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted;
@@ -1887,6 +1971,9 @@
err = mWriter->stop();
mWriter.clear();
}
+
+ resetMetrics();
+
mTotalPausedDurationUs = 0;
mPauseStartTimeUs = 0;
@@ -1990,6 +2077,23 @@
return OK;
}
+status_t StagefrightRecorder::getMetrics(Parcel *reply) {
+ ALOGD("StagefrightRecorder::getMetrics");
+
+ if (reply == NULL) {
+ ALOGE("Null pointer argument");
+ return BAD_VALUE;
+ }
+
+ if (mAnalyticsItem == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ updateMetrics();
+ mAnalyticsItem->writeToParcel(reply);
+ return OK;
+}
+
status_t StagefrightRecorder::dump(
int fd, const Vector<String16>& args) const {
ALOGV("dump");
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index b7d0b0e..38377d2 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -18,6 +18,7 @@
#define STAGEFRIGHT_RECORDER_H_
+#include <media/MediaAnalyticsItem.h>
#include <media/MediaRecorderBase.h>
#include <camera/CameraParameters.h>
#include <utils/String8.h>
@@ -67,6 +68,7 @@
virtual status_t close();
virtual status_t reset();
virtual status_t getMaxAmplitude(int *max);
+ virtual status_t getMetrics(Parcel *reply);
virtual status_t dump(int fd, const Vector<String16> &args) const;
// Querying a SurfaceMediaSourcer
virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() const;
@@ -85,6 +87,11 @@
int mOutputFd;
sp<AudioSource> mAudioSourceNode;
+ MediaAnalyticsItem *mAnalyticsItem;
+ bool mAnalyticsDirty;
+ void resetMetrics();
+ void updateMetrics();
+
audio_source_t mAudioSource;
video_source mVideoSource;
output_format mOutputFormat;