Media Metrics for NuPlayer, Codec, Extractor
Collect metrics for nuplayer/mediaplayer, codec, extractor.
publishes them to media.metrics service
provides hooks that local APIs use to connect to retrieve metrics
from the above when running on their behalf.
Separate set of changes does the final hop to the local APIs.
Bug: 34715803
Test: build & run, observed code/extractor/player metrics in logs
Change-Id: Ic5a0a7b3b93a5a41af93d81050ba038f0f7a4329
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 2e367bf..699ae48 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -25,6 +25,7 @@
#include <media/hardware/CryptoAPI.h>
#include <media/MediaCodecInfo.h>
#include <media/MediaResource.h>
+#include <media/MediaAnalyticsItem.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/FrameRenderTracker.h>
#include <utils/Vector.h>
@@ -172,6 +173,8 @@
status_t getName(AString *componentName) const;
+ status_t getMetrics(Parcel *reply);
+
status_t setParameters(const sp<AMessage> ¶ms);
// Create a MediaCodec notification message from a list of rendered or dropped render infos
@@ -298,6 +301,8 @@
sp<Surface> mSurface;
SoftwareRenderer *mSoftRenderer;
+ MediaAnalyticsItem *mAnalyticsItem;
+
sp<AMessage> mOutputFormat;
sp<AMessage> mInputFormat;
sp<AMessage> mCallback;
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index b460ef7..211f794 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -20,6 +20,7 @@
#include <media/IMediaExtractor.h>
#include <media/IMediaSource.h>
+#include <media/MediaAnalyticsItem.h>
namespace android {
@@ -69,7 +70,9 @@
protected:
MediaExtractor();
- virtual ~MediaExtractor() {}
+ virtual ~MediaExtractor();
+
+ MediaAnalyticsItem *mAnalyticsItem;
private:
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 40af8de..745d61b 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -36,6 +36,7 @@
#include <media/AudioSystem.h>
#include <media/AVSyncSettings.h>
#include <media/IDataSource.h>
+#include <media/MediaAnalyticsItem.h>
#include <binder/MemoryBase.h>
@@ -810,7 +811,11 @@
ALOGV("MediaPlayer::getParameter(%d)", key);
Mutex::Autolock _l(mLock);
if (mPlayer != NULL) {
- return mPlayer->getParameter(key, reply);
+ status_t status = mPlayer->getParameter(key, reply);
+ if (status != OK) {
+ ALOGD("getParameter returns %d", status);
+ }
+ return status;
}
ALOGV("getParameter: no active player");
return INVALID_OPERATION;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index b8bb8fe..0ddbd63 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -706,7 +706,16 @@
return INVALID_OPERATION;
}
-status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) {
+status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
+
+ if (key == FOURCC('m','t','r','X')) {
+ // mtrX -- a play on 'metrics' (not matrix)
+ // gather current info all together, parcel it, and send it back
+ finalizeMetrics("api");
+ mAnalyticsItem->writeToParcel(reply);
+ return OK;
+ }
+
return INVALID_OPERATION;
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 9eca982..5dc9ffa 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -33,6 +33,7 @@
#include <media/IOMX.h>
#include <media/IResourceManagerService.h>
#include <media/MediaCodecBuffer.h>
+#include <media/MediaAnalyticsItem.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -57,6 +58,13 @@
namespace android {
+// key for media statistics
+static const char *CodecKeyName = "codec";
+// attrs for media statistics
+static const char *CodecMime = "mime";
+static const char *CodecCodec = "codec";
+
+
static int64_t getId(const sp<IResourceManagerClient> &client) {
return (int64_t) client.get();
}
@@ -476,11 +484,27 @@
} else {
mUid = uid;
}
+ // set up our new record, get a sessionID, put it into the in-progress list
+ mAnalyticsItem = new MediaAnalyticsItem(CodecKeyName);
+ if (mAnalyticsItem != NULL) {
+ (void) mAnalyticsItem->generateSessionID();
+ // don't record it yet; only at the end, when we have decided that we have
+ // data worth writing (e.g. .count() > 0)
+ }
}
MediaCodec::~MediaCodec() {
CHECK_EQ(mState, UNINITIALIZED);
mResourceManagerService->removeResource(getId(mResourceManagerClient));
+
+ if (mAnalyticsItem != NULL ) {
+ if (mAnalyticsItem->count() > 0) {
+ mAnalyticsItem->setFinalized(true);
+ mAnalyticsItem->selfrecord();
+ }
+ delete mAnalyticsItem;
+ mAnalyticsItem = NULL;
+ }
}
// static
@@ -600,6 +624,19 @@
msg->setInt32("encoder", encoder);
}
+ if (mAnalyticsItem != NULL) {
+ if (nameIsType) {
+ // name is the mime type
+ mAnalyticsItem->setCString(CodecMime, name.c_str());
+ } else {
+ mAnalyticsItem->setCString(CodecCodec, name.c_str());
+ }
+ mAnalyticsItem->setCString("mode", mIsVideo ? "video" : "audio");
+ //mAnalyticsItem->setInt32("type", nameIsType);
+ if (nameIsType)
+ mAnalyticsItem->setInt32("encoder", encoder);
+ }
+
status_t err;
Vector<MediaResource> resources;
MediaResource::Type type =
@@ -652,6 +689,12 @@
mRotationDegrees = 0;
}
+ if (mAnalyticsItem != NULL) {
+ mAnalyticsItem->setInt32("width", mVideoWidth);
+ mAnalyticsItem->setInt32("height", mVideoHeight);
+ mAnalyticsItem->setInt32("rotation", mRotationDegrees);
+ }
+
// Prevent possible integer overflow in downstream code.
if (mInitIsEncoder
&& (uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
@@ -666,6 +709,10 @@
if (crypto != NULL) {
msg->setPointer("crypto", crypto.get());
+ if (mAnalyticsItem != NULL) {
+ // XXX: save indication that it's crypto in some way...
+ mAnalyticsItem->setInt32("crypto", 1);
+ }
}
// save msg for reset
@@ -1058,6 +1105,21 @@
return OK;
}
+status_t MediaCodec::getMetrics(Parcel *reply) {
+
+ // shouldn't happen, but be safe
+ if (mAnalyticsItem == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ // XXX: go get current values for whatever in-flight data we want
+
+ // send it back to the caller.
+ mAnalyticsItem->writeToParcel(reply);
+
+ return OK;
+}
+
status_t MediaCodec::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
msg->setInt32("portIndex", kPortIndexInput);
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index df4d9bf..677d43e 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -36,6 +36,7 @@
#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
+#include <media/MediaAnalyticsItem.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
@@ -47,9 +48,16 @@
#include <utils/String8.h>
#include <private/android_filesystem_config.h>
+// still doing some on/off toggling here.
+#define MEDIA_LOG 1
+
namespace android {
+// key for media statistics
+static const char *KeyName_Extractor = "extractor";
+// attrs for media statistics
+
MediaExtractor::MediaExtractor() {
if (!LOG_NDEBUG) {
uid_t uid = getuid();
@@ -57,8 +65,29 @@
ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
}
+ mAnalyticsItem = NULL;
+ if (MEDIA_LOG) {
+ mAnalyticsItem = new MediaAnalyticsItem(KeyName_Extractor);
+ (void) mAnalyticsItem->generateSessionID();
+ }
}
+MediaExtractor::~MediaExtractor() {
+
+ // log the current record, provided it has some information worth recording
+ if (MEDIA_LOG) {
+ if (mAnalyticsItem != NULL) {
+ if (mAnalyticsItem->count() > 0) {
+ mAnalyticsItem->setFinalized(true);
+ mAnalyticsItem->selfrecord();
+ }
+ }
+ }
+ if (mAnalyticsItem != NULL) {
+ delete mAnalyticsItem;
+ mAnalyticsItem = NULL;
+ }
+}
sp<MetaData> MediaExtractor::getMetaData() {
return new MetaData;
@@ -214,6 +243,31 @@
ret = new MidiExtractor(source);
}
+ if (ret != NULL) {
+ // track the container format (mpeg, aac, wvm, etc)
+ if (MEDIA_LOG) {
+ if (ret->mAnalyticsItem != NULL) {
+ ret->mAnalyticsItem->setCString("fmt", ret->name());
+ // tracks (size_t)
+ ret->mAnalyticsItem->setInt32("ntrk", ret->countTracks());
+ // metadata
+ sp<MetaData> pMetaData = ret->getMetaData();
+ if (pMetaData != NULL) {
+ String8 xx = pMetaData->toString();
+ ALOGD("metadata says: %s", xx.string());
+ // can grab various fields like:
+ // 'titl' -- but this verges into PII
+ // 'mime'
+ const char *mime = NULL;
+ if (pMetaData->findCString(kKeyMIMEType, &mime)) {
+ ret->mAnalyticsItem->setCString("mime", mime);
+ }
+ // what else is interesting here?
+ }
+ }
+ }
+ }
+
return ret;
}