MediaCodec: implement persistent input surface APIs
Bug: 19127604 Bug: 19489395 Change-Id: If0d723c9ecd6fe81d9df210bd2fd026b8603ea4a
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user