API access to mediametrics
provide SDK/API access to media metrics for user apps. This lets the
apps metrics data for their instances of player and codecs. Others
to come.
Bug: 34715803
Test: booted, invoked new APIs to verify desired results
Change-Id: Iaae6406aadef30adc893952961ac154a7c4c761d
diff --git a/api/current.txt b/api/current.txt
index e2616a6..28a2c7a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21320,6 +21320,7 @@
method public deprecated java.nio.ByteBuffer[] getInputBuffers();
method public final android.media.MediaFormat getInputFormat();
method public android.media.Image getInputImage(int);
+ method public android.os.Bundle getMetrics();
method public final java.lang.String getName();
method public java.nio.ByteBuffer getOutputBuffer(int);
method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
@@ -22145,6 +22146,7 @@
method public int getCurrentPosition();
method public android.media.BufferingParams getDefaultBufferingParams();
method public int getDuration();
+ method public android.os.Bundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
diff --git a/api/system-current.txt b/api/system-current.txt
index 21f15f2..ce316d9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -22924,6 +22924,7 @@
method public deprecated java.nio.ByteBuffer[] getInputBuffers();
method public final android.media.MediaFormat getInputFormat();
method public android.media.Image getInputImage(int);
+ method public android.os.Bundle getMetrics();
method public final java.lang.String getName();
method public java.nio.ByteBuffer getOutputBuffer(int);
method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
@@ -23749,6 +23750,7 @@
method public int getCurrentPosition();
method public android.media.BufferingParams getDefaultBufferingParams();
method public int getDuration();
+ method public android.os.Bundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
diff --git a/api/test-current.txt b/api/test-current.txt
index 940f68b..f4a52ea 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -21412,6 +21412,7 @@
method public deprecated java.nio.ByteBuffer[] getInputBuffers();
method public final android.media.MediaFormat getInputFormat();
method public android.media.Image getInputImage(int);
+ method public android.os.Bundle getMetrics();
method public final java.lang.String getName();
method public java.nio.ByteBuffer getOutputBuffer(int);
method public deprecated java.nio.ByteBuffer[] getOutputBuffers();
@@ -22237,6 +22238,7 @@
method public int getCurrentPosition();
method public android.media.BufferingParams getDefaultBufferingParams();
method public int getDuration();
+ method public android.os.Bundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 264944f..75ccffe 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3134,6 +3134,15 @@
public native final String getName();
/**
+ * Returns Analytics/Metrics data about the current content being
+ *
+ * @return a Bundle containint the set of attributes and values available
+ * for the media being handled by this instance of MediaCodec
+ *
+ */
+ public native Bundle getMetrics();
+
+ /**
* Change a video encoder's target bitrate on the fly. The value is an
* Integer object containing the new bitrate in bps.
*/
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 4023400..88dde53 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -1387,6 +1388,14 @@
public native int getVideoHeight();
/**
+ * Returns Analytics/Metrics data about the current video in this player.
+ *
+ * @return the a map of attributes and values available for this video
+ * player or null if no metrics are available.
+ */
+ public native Bundle getMetrics();
+
+ /**
* Checks whether the MediaPlayer is playing.
*
* @return true if currently playing, false otherwise
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 8d4271f..f69313c 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -11,6 +11,7 @@
android_media_MediaDrm.cpp \
android_media_MediaExtractor.cpp \
android_media_MediaHTTPConnection.cpp \
+ android_media_MediaMetricsJNI.cpp \
android_media_MediaMetadataRetriever.cpp \
android_media_MediaMuxer.cpp \
android_media_MediaPlayer.cpp \
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index c2c66fd..6f9883c 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -21,6 +21,7 @@
#include "android_media_MediaCodec.h"
#include "android_media_MediaCrypto.h"
+#include "android_media_MediaMetricsJNI.h"
#include "android_media_Utils.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
@@ -618,6 +619,12 @@
return OK;
}
+status_t JMediaCodec::getMetrics(JNIEnv *, Parcel *reply) const {
+
+ status_t status = mCodec->getMetrics(reply);
+ return status;
+}
+
status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
return mCodec->setParameters(msg);
}
@@ -1646,6 +1653,37 @@
return NULL;
}
+static jobject
+android_media_MediaCodec_getMetrics(JNIEnv *env, jobject thiz)
+{
+ ALOGV("android_media_MediaCodec_getMetrics");
+
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+ if (codec == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return 0;
+ }
+
+ // get what we have for the metrics from the codec
+ Parcel reply;
+ status_t err = codec->getMetrics(env, &reply);
+ if (err != OK) {
+ ALOGE("getMetrics failed");
+ return (jobject) NULL;
+ }
+
+ // build and return the Bundle
+ MediaAnalyticsItem *item = new MediaAnalyticsItem;
+ item->readFromParcel(reply);
+ jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
+
+ // housekeeping
+ delete item;
+ item = NULL;
+
+ return mybundle;
+}
+
static void android_media_MediaCodec_setParameters(
JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
ALOGV("android_media_MediaCodec_setParameters");
@@ -1954,6 +1992,9 @@
{ "getName", "()Ljava/lang/String;",
(void *)android_media_MediaCodec_getName },
+ { "getMetrics", "()Landroid/os/Bundle;",
+ (void *)android_media_MediaCodec_getMetrics},
+
{ "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
(void *)android_media_MediaCodec_setParameters },
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 5f0d3df..b3b1b3a 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -111,6 +111,8 @@
status_t getName(JNIEnv *env, jstring *name) const;
+ status_t getMetrics(JNIEnv *env, Parcel *reply) const;
+
status_t setParameters(const sp<AMessage> ¶ms);
void setVideoScalingMode(int mode);
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
new file mode 100644
index 0000000..fb606ba
--- /dev/null
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+#include <JNIHelp.h>
+
+#include "android_media_MediaMetricsJNI.h"
+#include <media/MediaAnalyticsItem.h>
+
+
+namespace android {
+
+// place the attributes into a java Bundle object
+// decide whether this is appropriately scoped here.
+// if we do it somewhere else, we have to figure a "give me all the attrs"
+// access to the inside of MediaAnalyticsItem
+jobject MediaMetricsJNI::writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle) {
+
+ jclass clazzBundle = env->FindClass("android/os/Bundle");
+ if (clazzBundle==NULL) {
+ ALOGD("can't find android/os/Bundle");
+ return NULL;
+ }
+ // sometimes the caller provides one for us to fill
+ if (mybundle == NULL) {
+ // create the bundle
+ jmethodID constructID = env->GetMethodID(clazzBundle, "<init>", "()V");
+ mybundle = env->NewObject(clazzBundle, constructID);
+ if (mybundle == NULL) {
+ return NULL;
+ }
+ }
+
+ // grab methods that we can invoke
+ jmethodID setIntID = env->GetMethodID(clazzBundle, "putInt", "(Ljava/lang/String;I)V");
+ jmethodID setLongID = env->GetMethodID(clazzBundle, "putLong", "(Ljava/lang/String;J)V");
+ jmethodID setDoubleID = env->GetMethodID(clazzBundle, "putDouble", "(Ljava/lang/String;D)V");
+ jmethodID setStringID = env->GetMethodID(clazzBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V");
+
+ // env, class, method, {parms}
+ //env->CallVoidMethod(env, mybundle, setIntID, jstr, jint);
+
+ // iterate through my attributes
+ // -- get name, get type, get value
+ // -- insert appropriately into the bundle
+ for (size_t i = 0 ; i < item->mPropCount; i++ ) {
+ MediaAnalyticsItem::Prop *prop = &item->mProps[i];
+ // build the key parameter from prop->mName
+ jstring keyName = env->NewStringUTF(prop->mName);
+ // invoke the appropriate method to insert
+ switch (prop->mType) {
+ case MediaAnalyticsItem::kTypeInt32:
+ env->CallVoidMethod(mybundle, setIntID,
+ keyName, (jint) prop->u.int32Value);
+ break;
+ case MediaAnalyticsItem::kTypeInt64:
+ env->CallVoidMethod(mybundle, setLongID,
+ keyName, (jlong) prop->u.int64Value);
+ break;
+ case MediaAnalyticsItem::kTypeDouble:
+ env->CallVoidMethod(mybundle, setDoubleID,
+ keyName, (jdouble) prop->u.doubleValue);
+ break;
+ case MediaAnalyticsItem::kTypeCString:
+ env->CallVoidMethod(mybundle, setStringID, keyName,
+ env->NewStringUTF(prop->u.CStringValue));
+ break;
+ default:
+ ALOGE("to_String bad item type: %d for %s",
+ prop->mType, prop->mName);
+ break;
+ }
+ }
+
+ return mybundle;
+}
+
+}; // namespace android
+
diff --git a/media/jni/android_media_MediaMetricsJNI.h b/media/jni/android_media_MediaMetricsJNI.h
new file mode 100644
index 0000000..d174212
--- /dev/null
+++ b/media/jni/android_media_MediaMetricsJNI.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_MEDIA_MEDIAMETRICSJNI_H_
+#define _ANDROID_MEDIA_MEDIAMETRICSJNI_H_
+
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+#include <JNIHelp.h>
+#include <media/MediaAnalyticsItem.h>
+
+namespace android {
+
+class MediaMetricsJNI {
+public:
+ static jobject writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle);
+};
+
+}; // namespace android
+
+#endif // _ANDROID_MEDIA_MEDIAMETRICSJNI_H_
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 8225052..af59d81 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -23,6 +23,8 @@
#include <media/AudioResamplerPublic.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaPlayerInterface.h>
+#include <media/MediaAnalyticsItem.h>
+#include <media/stagefright/Utils.h> // for FOURCC definition
#include <stdio.h>
#include <assert.h>
#include <limits.h>
@@ -39,6 +41,7 @@
#include "utils/String8.h"
#include "android_media_BufferingParams.h"
#include "android_media_MediaDataSource.h"
+#include "android_media_MediaMetricsJNI.h"
#include "android_media_PlaybackParams.h"
#include "android_media_SyncParams.h"
#include "android_media_Utils.h"
@@ -684,6 +687,33 @@
return (jint) h;
}
+static jobject
+android_media_MediaPlayer_getMetrics(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return 0;
+ }
+
+ Parcel p;
+ int key = FOURCC('m','t','r','X');
+ status_t status = mp->getParameter(key, &p);
+ if (status != OK) {
+ ALOGD("getMetrics() failed: %d", status);
+ return (jobject) NULL;
+ }
+
+ MediaAnalyticsItem *item = new MediaAnalyticsItem;
+ item->readFromParcel(p);
+ jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
+
+ // housekeeping
+ delete item;
+ item = NULL;
+
+ return mybundle;
+}
static jint
android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
@@ -1118,6 +1148,7 @@
{"_stop", "()V", (void *)android_media_MediaPlayer_stop},
{"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
{"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
+ {"getMetrics", "()Landroid/os/Bundle;", (void *)android_media_MediaPlayer_getMetrics},
{"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams},
{"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
{"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer_setSyncParams},