MediaCodec: implement persistent input surface APIs

Bug: 19127604
Bug: 19489395

Change-Id: If0d723c9ecd6fe81d9df210bd2fd026b8603ea4a
This commit is contained in:
Chong Zhang
2015-04-28 13:38:48 -07:00
parent 574f53793d
commit 8034d60f6e
3 changed files with 185 additions and 5 deletions

View File

@@ -681,12 +681,20 @@ final public class MediaCodec {
*/
@NonNull
public static Surface createPersistentInputSurface() {
// TODO implement this
return new PersistentSurface();
return native_createPersistentInputSurface();
}
static class PersistentSurface extends Surface {
PersistentSurface() {}
@SuppressWarnings("unused")
PersistentSurface() {} // used by native
@Override
public void release() {
native_releasePersistentInputSurface(this);
super.release();
}
private long mPersistentObject;
};
/**
@@ -700,9 +708,17 @@ final public class MediaCodec {
* {@link #createPersistentInputSurface}.
*/
public void usePersistentInputSurface(@NonNull Surface surface) {
throw new IllegalArgumentException("not implemented");
if (!(surface instanceof PersistentSurface)) {
throw new IllegalArgumentException("not a PersistentSurface");
}
native_usePersistentInputSurface(surface);
}
@NonNull
private static native final PersistentSurface native_createPersistentInputSurface();
private static native final void native_releasePersistentInputSurface(@NonNull Surface surface);
private native final void native_usePersistentInputSurface(@NonNull Surface surface);
private native final void native_setCallback(@Nullable Callback cb);
private native final void native_configure(

View File

@@ -39,7 +39,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/PersistentSurface.h>
#include <nativehelper/ScopedLocalRef.h>
#include <system/window.h>
@@ -75,6 +75,14 @@ static struct ExceptionReason {
jint reasonReclaimed;
} gExceptionReason;
static struct {
jclass clazz;
jfieldID mLock;
jfieldID mPersistentObject;
jmethodID ctor;
jmethodID setNativeObjectLocked;
} gPersistentSurfaceClassInfo;
struct fields_t {
jfieldID context;
jmethodID postEventFromNativeID;
@@ -87,6 +95,7 @@ struct fields_t {
};
static fields_t gFields;
static const void *sRefBaseOwner;
////////////////////////////////////////////////////////////////////////////////
@@ -250,6 +259,11 @@ status_t JMediaCodec::createInputSurface(
return mCodec->createInputSurface(bufferProducer);
}
status_t JMediaCodec::usePersistentInputSurface(
const sp<PersistentSurface> &surface) {
return mCodec->usePersistentInputSurface(surface);
}
status_t JMediaCodec::start() {
return mCodec->start();
}
@@ -869,6 +883,120 @@ static void android_media_MediaCodec_native_configure(
throwExceptionAsNecessary(env, err);
}
sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
JNIEnv* env, jobject object) {
sp<PersistentSurface> persistentSurface;
jobject lock = env->GetObjectField(
object, gPersistentSurfaceClassInfo.mLock);
if (env->MonitorEnter(lock) == JNI_OK) {
persistentSurface = reinterpret_cast<PersistentSurface *>(
env->GetLongField(object,
gPersistentSurfaceClassInfo.mPersistentObject));
env->MonitorExit(lock);
}
env->DeleteLocalRef(lock);
return persistentSurface;
}
static jobject android_media_MediaCodec_createPersistentInputSurface(
JNIEnv* env, jclass /* clazz */) {
ALOGV("android_media_MediaCodec_createPersistentInputSurface");
sp<PersistentSurface> persistentSurface =
MediaCodec::CreatePersistentInputSurface();
if (persistentSurface == NULL) {
return NULL;
}
sp<Surface> surface = new Surface(
persistentSurface->getBufferProducer(), true);
if (surface == NULL) {
return NULL;
}
jobject object = env->NewObject(
gPersistentSurfaceClassInfo.clazz,
gPersistentSurfaceClassInfo.ctor);
if (object == NULL) {
if (env->ExceptionCheck()) {
ALOGE("Could not create PersistentSurface.");
env->ExceptionClear();
}
return NULL;
}
jobject lock = env->GetObjectField(
object, gPersistentSurfaceClassInfo.mLock);
if (env->MonitorEnter(lock) == JNI_OK) {
env->CallVoidMethod(
object,
gPersistentSurfaceClassInfo.setNativeObjectLocked,
(jlong)surface.get());
env->SetLongField(
object,
gPersistentSurfaceClassInfo.mPersistentObject,
(jlong)persistentSurface.get());
env->MonitorExit(lock);
} else {
env->DeleteLocalRef(object);
object = NULL;
}
env->DeleteLocalRef(lock);
if (object != NULL) {
surface->incStrong(&sRefBaseOwner);
persistentSurface->incStrong(&sRefBaseOwner);
}
return object;
}
static void android_media_MediaCodec_releasePersistentInputSurface(
JNIEnv* env, jclass /* clazz */, jobject object) {
sp<PersistentSurface> persistentSurface;
jobject lock = env->GetObjectField(
object, gPersistentSurfaceClassInfo.mLock);
if (env->MonitorEnter(lock) == JNI_OK) {
persistentSurface = reinterpret_cast<PersistentSurface *>(
env->GetLongField(
object, gPersistentSurfaceClassInfo.mPersistentObject));
env->SetLongField(
object,
gPersistentSurfaceClassInfo.mPersistentObject,
(jlong)0);
env->MonitorExit(lock);
}
env->DeleteLocalRef(lock);
if (persistentSurface != NULL) {
persistentSurface->decStrong(&sRefBaseOwner);
}
// no need to release surface as it will be released by Surface's jni
}
static void android_media_MediaCodec_usePersistentInputSurface(
JNIEnv* env, jobject thiz, jobject object) {
ALOGV("android_media_MediaCodec_usePersistentInputSurface");
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
sp<PersistentSurface> persistentSurface =
android_media_MediaCodec_getPersistentInputSurface(env, object);
status_t err = codec->usePersistentInputSurface(persistentSurface);
if (err != NO_ERROR) {
throwExceptionAsNecessary(env, err);
}
}
static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
jobject thiz) {
ALOGV("android_media_MediaCodec_createInputSurface");
@@ -1471,6 +1599,29 @@ static void android_media_MediaCodec_native_init(JNIEnv *env) {
CHECK(field != NULL);
gExceptionReason.reasonReclaimed =
env->GetStaticIntField(clazz.get(), field);
clazz.reset(env->FindClass("android/view/Surface"));
CHECK(clazz.get() != NULL);
field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
CHECK(field != NULL);
gPersistentSurfaceClassInfo.mLock = field;
jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V");
CHECK(method != NULL);
gPersistentSurfaceClassInfo.setNativeObjectLocked = method;
clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface"));
CHECK(clazz.get() != NULL);
gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
method = env->GetMethodID(clazz.get(), "<init>", "()V");
CHECK(method != NULL);
gPersistentSurfaceClassInfo.ctor = method;
field = env->GetFieldID(clazz.get(), "mPersistentObject", "J");
CHECK(field != NULL);
gPersistentSurfaceClassInfo.mPersistentObject = field;
}
static void android_media_MediaCodec_native_setup(
@@ -1521,6 +1672,17 @@ static JNINativeMethod gMethods[] = {
{ "native_reset", "()V", (void *)android_media_MediaCodec_reset },
{ "native_releasePersistentInputSurface",
"(Landroid/view/Surface;)V",
(void *)android_media_MediaCodec_releasePersistentInputSurface},
{ "native_createPersistentInputSurface",
"()Landroid/media/MediaCodec$PersistentSurface;",
(void *)android_media_MediaCodec_createPersistentInputSurface },
{ "native_usePersistentInputSurface", "(Landroid/view/Surface;)V",
(void *)android_media_MediaCodec_usePersistentInputSurface },
{ "native_setCallback",
"(Landroid/media/MediaCodec$Callback;)V",
(void *)android_media_MediaCodec_native_setCallback },

View File

@@ -33,6 +33,7 @@ struct AString;
struct ICrypto;
struct IGraphicBufferProducer;
struct MediaCodec;
struct PersistentSurface;
class Surface;
struct JMediaCodec : public AHandler {
@@ -54,6 +55,7 @@ struct JMediaCodec : public AHandler {
int flags);
status_t createInputSurface(sp<IGraphicBufferProducer>* bufferProducer);
status_t usePersistentInputSurface(const sp<PersistentSurface> &surface);
status_t start();
status_t stop();