media: hook up OnFrameRenderedListener events to framework events
Bug: 20503131
Change-Id: Ife6d4862d14daf5b9659307af57417bd3532e8fe
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index eec4960..a79dd04 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1455,15 +1455,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface BufferFlag {}
- private static class FrameRenderedInfo {
- public long mPresentationTimeUs;
- public long mNanoTime;
- public FrameRenderedInfo(long presentationTimeUs, long nanoTime) {
- mPresentationTimeUs = presentationTimeUs;
- mNanoTime = nanoTime;
- }
- }
-
private EventHandler mEventHandler;
private EventHandler mOnFrameRenderedHandler;
private EventHandler mCallbackHandler;
@@ -1503,10 +1494,16 @@
}
case EVENT_FRAME_RENDERED:
synchronized (mListenerLock) {
- FrameRenderedInfo info = (FrameRenderedInfo)msg.obj;
- if (mOnFrameRenderedListener != null) {
+ Map<String, Object> map = (Map<String, Object>)msg.obj;
+ for (int i = 0; ; ++i) {
+ Object mediaTimeUs = map.get(i + "-media-time-us");
+ Object systemNano = map.get(i + "-system-nano");
+ if (mediaTimeUs == null || systemNano == null
+ || mOnFrameRenderedListener == null) {
+ break;
+ }
mOnFrameRenderedListener.onFrameRendered(
- mCodec, info.mPresentationTimeUs, info.mNanoTime);
+ mCodec, (long)mediaTimeUs, (long)systemNano);
}
break;
}
@@ -2362,26 +2359,9 @@
info = mDequeuedOutputInfos.remove(index);
}
}
- // TODO
- // until codec and libgui supports callback, assume frame is rendered within 50 ms
- postRenderedCallback(render, info, 50 /* delayMs */);
releaseOutputBuffer(index, render, false /* updatePTS */, 0 /* dummy */);
}
- private void postRenderedCallback(boolean render, @Nullable BufferInfo info, long delayMs) {
- if (render && info != null) {
- synchronized (mListenerLock) {
- if (mOnFrameRenderedListener != null) {
- FrameRenderedInfo obj = new FrameRenderedInfo(
- info.presentationTimeUs, System.nanoTime() + delayMs * 1000000);
- Message msg = mOnFrameRenderedHandler.obtainMessage(
- EVENT_FRAME_RENDERED, obj);
- mOnFrameRenderedHandler.sendMessageDelayed(msg, delayMs);
- }
- }
- }
- }
-
/**
* If you are done with a buffer, use this call to update its surface timestamp
* and return it to the codec to render it on the output surface. If you
@@ -2440,12 +2420,6 @@
info = mDequeuedOutputInfos.remove(index);
}
}
- // TODO
- // until codec and libgui supports callback, assume frame is rendered at the
- // render time or 16 ms from now, whichever is later.
- postRenderedCallback(
- true /* render */, info,
- Math.max(renderTimestampNs - System.nanoTime(), 16666666) / 1000000);
releaseOutputBuffer(
index, true /* render */, true /* updatePTS */, renderTimestampNs);
}
@@ -3049,9 +3023,12 @@
} else if (mOnFrameRenderedHandler != null) {
mOnFrameRenderedHandler.removeMessages(EVENT_FRAME_RENDERED);
}
+ native_enableOnFrameRenderedListener(listener != null);
}
}
+ private native void native_enableOnFrameRenderedListener(boolean enable);
+
private EventHandler getEventHandlerOn(
@Nullable Handler handler, @NonNull EventHandler lastHandler) {
if (handler == null) {
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 93b8ec7..ce7f7e5 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -56,6 +56,7 @@
enum {
EVENT_CALLBACK = 1,
EVENT_SET_CALLBACK = 2,
+ EVENT_FRAME_RENDERED = 3,
};
static struct CryptoErrorCodes {
@@ -226,6 +227,18 @@
mByteBufferLimitMethodID = NULL;
}
+status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
+ if (enable) {
+ if (mOnFrameRenderedNotification == NULL) {
+ mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this);
+ }
+ } else {
+ mOnFrameRenderedNotification.clear();
+ }
+
+ return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification);
+}
+
status_t JMediaCodec::setCallback(jobject cb) {
if (cb != NULL) {
if (mCallbackNotification == NULL) {
@@ -728,6 +741,27 @@
env->DeleteLocalRef(obj);
}
+void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
+ int32_t arg1 = 0, arg2 = 0;
+ jobject obj = NULL;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ sp<AMessage> data;
+ CHECK(msg->findMessage("data", &data));
+
+ status_t err = ConvertMessageToMap(env, data, &obj);
+ if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ env->CallVoidMethod(
+ mObject, gFields.postEventFromNativeID,
+ EVENT_FRAME_RENDERED, arg1, arg2, obj);
+
+ env->DeleteLocalRef(obj);
+}
+
void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatCallbackNotify:
@@ -735,6 +769,11 @@
handleCallback(msg);
break;
}
+ case kWhatFrameRendered:
+ {
+ handleFrameRenderedNotification(msg);
+ break;
+ }
default:
TRESPASS();
}
@@ -848,6 +887,22 @@
}
}
+static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
+ JNIEnv *env,
+ jobject thiz,
+ jboolean enabled) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ status_t err = codec->enableOnFrameRenderedListener(enabled);
+
+ throwExceptionAsNecessary(env, err);
+}
+
static void android_media_MediaCodec_native_setCallback(
JNIEnv *env,
jobject thiz,
@@ -1744,6 +1799,9 @@
{ "native_setInputSurface", "(Landroid/view/Surface;)V",
(void *)android_media_MediaCodec_setInputSurface },
+ { "native_enableOnFrameRenderedListener", "(Z)V",
+ (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },
+
{ "native_setCallback",
"(Landroid/media/MediaCodec$Callback;)V",
(void *)android_media_MediaCodec_native_setCallback },
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index a4ed67b..6650cf9 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -46,6 +46,8 @@
void registerSelf();
void release();
+ status_t enableOnFrameRenderedListener(jboolean enable);
+
status_t setCallback(jobject cb);
status_t configure(
@@ -116,11 +118,11 @@
virtual ~JMediaCodec();
virtual void onMessageReceived(const sp<AMessage> &msg);
- void handleCallback(const sp<AMessage> &msg);
private:
enum {
kWhatCallbackNotify,
+ kWhatFrameRendered,
};
jclass mClass;
@@ -139,6 +141,7 @@
sp<MediaCodec> mCodec;
sp<AMessage> mCallbackNotification;
+ sp<AMessage> mOnFrameRenderedNotification;
status_t mInitStatus;
@@ -148,6 +151,8 @@
void cacheJavaObjects(JNIEnv *env);
void deleteJavaObjects(JNIEnv *env);
+ void handleCallback(const sp<AMessage> &msg);
+ void handleFrameRenderedNotification(const sp<AMessage> &msg);
DISALLOW_EVIL_CONSTRUCTORS(JMediaCodec);
};