API that allows usage of MediaCodec APIs without polling.
Change-Id: Iebccdd3aec74a2cfa9ad0bf16c0c6006a3b72999
related-to-bug: 11990118
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 221ea57..3ce483d 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -51,6 +51,10 @@
DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3,
};
+enum {
+ EVENT_NOTIFY = 1,
+};
+
struct CryptoErrorCodes {
jint cryptoErrorNoKey;
jint cryptoErrorKeyExpired;
@@ -59,6 +63,7 @@
struct fields_t {
jfieldID context;
+ jmethodID postEventFromNativeID;
jfieldID cryptoInfoNumSubSamplesID;
jfieldID cryptoInfoNumBytesOfClearDataID;
jfieldID cryptoInfoNumBytesOfEncryptedDataID;
@@ -75,7 +80,9 @@
JNIEnv *env, jobject thiz,
const char *name, bool nameIsType, bool encoder)
: mClass(NULL),
- mObject(NULL) {
+ mObject(NULL),
+ mGeneration(1),
+ mRequestedActivityNotification(false) {
jclass clazz = env->GetObjectClass(thiz);
CHECK(clazz != NULL);
@@ -87,7 +94,7 @@
mLooper->start(
false, // runOnCallingThread
- false, // canCallJava
+ true, // canCallJava
PRIORITY_FOREGROUND);
if (nameIsType) {
@@ -101,6 +108,10 @@
return mCodec != NULL ? OK : NO_INIT;
}
+void JMediaCodec::registerSelf() {
+ mLooper->registerHandler(this);
+}
+
JMediaCodec::~JMediaCodec() {
if (mCodec != NULL) {
mCodec->release();
@@ -122,7 +133,8 @@
int flags) {
sp<Surface> client;
if (bufferProducer != NULL) {
- mSurfaceTextureClient = new Surface(bufferProducer, true /* controlledByApp */);
+ mSurfaceTextureClient =
+ new Surface(bufferProducer, true /* controlledByApp */);
} else {
mSurfaceTextureClient.clear();
}
@@ -136,13 +148,32 @@
}
status_t JMediaCodec::start() {
- return mCodec->start();
+ status_t err = mCodec->start();
+
+ if (err != OK) {
+ return err;
+ }
+
+ mActivityNotification = new AMessage(kWhatActivityNotify, id());
+ mActivityNotification->setInt32("generation", mGeneration);
+
+ requestActivityNotification();
+
+ return err;
}
status_t JMediaCodec::stop() {
mSurfaceTextureClient.clear();
- return mCodec->stop();
+ status_t err = mCodec->stop();
+
+ sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, id());
+ sp<AMessage> response;
+ msg->postAndAwaitResponse(&response);
+
+ mActivityNotification.clear();
+
+ return err;
}
status_t JMediaCodec::flush() {
@@ -174,7 +205,11 @@
}
status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
- return mCodec->dequeueInputBuffer(index, timeoutUs);
+ status_t err = mCodec->dequeueInputBuffer(index, timeoutUs);
+
+ requestActivityNotification();
+
+ return err;
}
status_t JMediaCodec::dequeueOutputBuffer(
@@ -182,9 +217,12 @@
size_t size, offset;
int64_t timeUs;
uint32_t flags;
- status_t err;
- if ((err = mCodec->dequeueOutputBuffer(
- index, &offset, &size, &timeUs, &flags, timeoutUs)) != OK) {
+ status_t err = mCodec->dequeueOutputBuffer(
+ index, &offset, &size, &timeUs, &flags, timeoutUs);
+
+ requestActivityNotification();
+
+ if (err != OK) {
return err;
}
@@ -320,6 +358,67 @@
}
}
+void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatRequestActivityNotifications:
+ {
+ if (mRequestedActivityNotification) {
+ break;
+ }
+
+ mCodec->requestActivityNotification(mActivityNotification);
+ mRequestedActivityNotification = true;
+ break;
+ }
+
+ case kWhatActivityNotify:
+ {
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mGeneration) {
+ // stale
+ break;
+ }
+
+ mRequestedActivityNotification = false;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(
+ mObject,
+ gFields.postEventFromNativeID,
+ EVENT_NOTIFY,
+ 0 /* arg1 */,
+ 0 /* arg2 */,
+ NULL /* obj */);
+
+ break;
+ }
+
+ case kWhatStopActivityNotifications:
+ {
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ ++mGeneration;
+ mRequestedActivityNotification = false;
+
+ sp<AMessage> response = new AMessage;
+ response->postReply(replyID);
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
+void JMediaCodec::requestActivityNotification() {
+ (new AMessage(kWhatRequestActivityNotifications, id()))->post();
+}
+
} // namespace android
////////////////////////////////////////////////////////////////////////////////
@@ -888,6 +987,12 @@
gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
CHECK(gFields.context != NULL);
+ gFields.postEventFromNativeID =
+ env->GetMethodID(
+ clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");
+
+ CHECK(gFields.postEventFromNativeID != NULL);
+
clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
CHECK(clazz.get() != NULL);
@@ -961,6 +1066,8 @@
return;
}
+ codec->registerSelf();
+
setMediaCodec(env,thiz, codec);
}
@@ -981,7 +1088,7 @@
(void *)android_media_MediaCodec_createInputSurface },
{ "start", "()V", (void *)android_media_MediaCodec_start },
- { "stop", "()V", (void *)android_media_MediaCodec_stop },
+ { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
{ "flush", "()V", (void *)android_media_MediaCodec_flush },
{ "queueInputBuffer", "(IIIJI)V",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 2fbbd72..53254c9 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -21,8 +21,8 @@
#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandler.h>
#include <utils/Errors.h>
-#include <utils/RefBase.h>
namespace android {
@@ -34,13 +34,15 @@
struct MediaCodec;
class Surface;
-struct JMediaCodec : public RefBase {
+struct JMediaCodec : public AHandler {
JMediaCodec(
JNIEnv *env, jobject thiz,
const char *name, bool nameIsType, bool encoder);
status_t initCheck() const;
+ void registerSelf();
+
status_t configure(
const sp<AMessage> &format,
const sp<IGraphicBufferProducer> &bufferProducer,
@@ -94,7 +96,15 @@
protected:
virtual ~JMediaCodec();
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
private:
+ enum {
+ kWhatActivityNotify,
+ kWhatRequestActivityNotifications,
+ kWhatStopActivityNotifications,
+ };
+
jclass mClass;
jweak mObject;
sp<Surface> mSurfaceTextureClient;
@@ -102,6 +112,12 @@
sp<ALooper> mLooper;
sp<MediaCodec> mCodec;
+ sp<AMessage> mActivityNotification;
+ int32_t mGeneration;
+ bool mRequestedActivityNotification;
+
+ void requestActivityNotification();
+
DISALLOW_EVIL_CONSTRUCTORS(JMediaCodec);
};