Loading media/java/android/media/MediaCodec.java +12 −35 Original line number Diff line number Diff line Loading @@ -1455,15 +1455,6 @@ final public class MediaCodec { @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; Loading Loading @@ -1503,10 +1494,16 @@ final public class MediaCodec { } 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; } Loading Loading @@ -2362,26 +2359,9 @@ final public class MediaCodec { 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 Loading Loading @@ -2440,12 +2420,6 @@ final public class MediaCodec { 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); } Loading Loading @@ -3049,9 +3023,12 @@ final public class MediaCodec { } 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) { Loading media/jni/android_media_MediaCodec.cpp +58 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ enum { enum { EVENT_CALLBACK = 1, EVENT_SET_CALLBACK = 2, EVENT_FRAME_RENDERED = 3, }; static struct CryptoErrorCodes { Loading Loading @@ -226,6 +227,18 @@ void JMediaCodec::deleteJavaObjects(JNIEnv *env) { 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) { Loading Loading @@ -728,6 +741,27 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) { 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: Loading @@ -735,6 +769,11 @@ void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) { handleCallback(msg); break; } case kWhatFrameRendered: { handleFrameRenderedNotification(msg); break; } default: TRESPASS(); } Loading Loading @@ -848,6 +887,22 @@ static jint throwExceptionAsNecessary( } } 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, Loading Loading @@ -1744,6 +1799,9 @@ static JNINativeMethod gMethods[] = { { "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 }, Loading media/jni/android_media_MediaCodec.h +6 −1 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ struct JMediaCodec : public AHandler { void registerSelf(); void release(); status_t enableOnFrameRenderedListener(jboolean enable); status_t setCallback(jobject cb); status_t configure( Loading Loading @@ -116,11 +118,11 @@ protected: virtual ~JMediaCodec(); virtual void onMessageReceived(const sp<AMessage> &msg); void handleCallback(const sp<AMessage> &msg); private: enum { kWhatCallbackNotify, kWhatFrameRendered, }; jclass mClass; Loading @@ -139,6 +141,7 @@ private: sp<MediaCodec> mCodec; sp<AMessage> mCallbackNotification; sp<AMessage> mOnFrameRenderedNotification; status_t mInitStatus; Loading @@ -148,6 +151,8 @@ private: void cacheJavaObjects(JNIEnv *env); void deleteJavaObjects(JNIEnv *env); void handleCallback(const sp<AMessage> &msg); void handleFrameRenderedNotification(const sp<AMessage> &msg); DISALLOW_EVIL_CONSTRUCTORS(JMediaCodec); }; Loading Loading
media/java/android/media/MediaCodec.java +12 −35 Original line number Diff line number Diff line Loading @@ -1455,15 +1455,6 @@ final public class MediaCodec { @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; Loading Loading @@ -1503,10 +1494,16 @@ final public class MediaCodec { } 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; } Loading Loading @@ -2362,26 +2359,9 @@ final public class MediaCodec { 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 Loading Loading @@ -2440,12 +2420,6 @@ final public class MediaCodec { 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); } Loading Loading @@ -3049,9 +3023,12 @@ final public class MediaCodec { } 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) { Loading
media/jni/android_media_MediaCodec.cpp +58 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ enum { enum { EVENT_CALLBACK = 1, EVENT_SET_CALLBACK = 2, EVENT_FRAME_RENDERED = 3, }; static struct CryptoErrorCodes { Loading Loading @@ -226,6 +227,18 @@ void JMediaCodec::deleteJavaObjects(JNIEnv *env) { 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) { Loading Loading @@ -728,6 +741,27 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) { 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: Loading @@ -735,6 +769,11 @@ void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) { handleCallback(msg); break; } case kWhatFrameRendered: { handleFrameRenderedNotification(msg); break; } default: TRESPASS(); } Loading Loading @@ -848,6 +887,22 @@ static jint throwExceptionAsNecessary( } } 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, Loading Loading @@ -1744,6 +1799,9 @@ static JNINativeMethod gMethods[] = { { "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 }, Loading
media/jni/android_media_MediaCodec.h +6 −1 Original line number Diff line number Diff line Loading @@ -46,6 +46,8 @@ struct JMediaCodec : public AHandler { void registerSelf(); void release(); status_t enableOnFrameRenderedListener(jboolean enable); status_t setCallback(jobject cb); status_t configure( Loading Loading @@ -116,11 +118,11 @@ protected: virtual ~JMediaCodec(); virtual void onMessageReceived(const sp<AMessage> &msg); void handleCallback(const sp<AMessage> &msg); private: enum { kWhatCallbackNotify, kWhatFrameRendered, }; jclass mClass; Loading @@ -139,6 +141,7 @@ private: sp<MediaCodec> mCodec; sp<AMessage> mCallbackNotification; sp<AMessage> mOnFrameRenderedNotification; status_t mInitStatus; Loading @@ -148,6 +151,8 @@ private: void cacheJavaObjects(JNIEnv *env); void deleteJavaObjects(JNIEnv *env); void handleCallback(const sp<AMessage> &msg); void handleFrameRenderedNotification(const sp<AMessage> &msg); DISALLOW_EVIL_CONSTRUCTORS(JMediaCodec); }; Loading