Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion libavcodec/mediacodec_surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@
#include "ffjni.h"
#include "mediacodec_surface.h"

static int is_surface_valid(JNIEnv *env, void *surface, void *log_ctx)
{
if (!env)
return 0;
jclass surface_class = (*env)->FindClass(env, "android/view/Surface");
if (!surface_class) {
ff_jni_exception_check(env, 1, log_ctx);
av_log(log_ctx, AV_LOG_WARNING, "Could not find android/view/Surface class\n");
return 1; /* assume valid if we cannot check */
}
jmethodID is_valid_id = (*env)->GetMethodID(env, surface_class, "isValid", "()Z");
if (!is_valid_id) {
(*env)->DeleteLocalRef(env, surface_class);
av_log(log_ctx, AV_LOG_WARNING, "Could not find Surface.isValid() method\n");
return 1; /* assume valid if we cannot check */
}
jboolean valid = (*env)->CallBooleanMethod(env, (jobject)surface, is_valid_id);
(*env)->DeleteLocalRef(env, surface_class);
ff_jni_exception_check(env, 1, log_ctx);
return valid;
}

FFANativeWindow *ff_mediacodec_surface_ref(void *surface, void *native_window, void *log_ctx)
{
FFANativeWindow *ret;
Expand All @@ -39,8 +61,15 @@ FFANativeWindow *ff_mediacodec_surface_ref(void *surface, void *native_window, v
JNIEnv *env = NULL;

env = ff_jni_get_env(log_ctx);
if (env)
if (env) {
if (!is_surface_valid(env, surface, log_ctx)) {
av_log(log_ctx, AV_LOG_ERROR,
"Surface %p is not valid (native peer released?)\n", surface);
av_freep(&ret);
return NULL;
}
ret->surface = (*env)->NewGlobalRef(env, surface);
}
}

if (native_window) {
Expand Down
37 changes: 37 additions & 0 deletions libavcodec/mediacodec_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,26 @@ static int mediacodec_jni_configure(FFAMediaCodec *ctx,

JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL);

/* Validate the Surface before passing to MediaCodec.configure(),
* which will crash if the Surface's native peer has been released */
if (surface) {
jclass surface_class = (*env)->FindClass(env, "android/view/Surface");
if (surface_class) {
jmethodID is_valid_id = (*env)->GetMethodID(env, surface_class, "isValid", "()Z");
if (is_valid_id) {
jboolean valid = (*env)->CallBooleanMethod(env, (jobject)surface, is_valid_id);
if (!valid) {
av_log(ctx, AV_LOG_ERROR, "Surface is not valid, cannot configure codec\n");
(*env)->DeleteLocalRef(env, surface_class);
ff_jni_exception_check(env, 0, 0);
return AVERROR_EXTERNAL;
}
}
(*env)->DeleteLocalRef(env, surface_class);
}
ff_jni_exception_check(env, 0, 0);
}

if (flags & codec->CONFIGURE_FLAG_ENCODE) {
if (surface && !codec->jfields.set_input_surface_id) {
av_log(ctx, AV_LOG_ERROR, "System doesn't support setInputSurface\n");
Expand Down Expand Up @@ -2390,6 +2410,23 @@ static int mediacodec_ndk_configure(FFAMediaCodec* ctx,
if (window->surface) {
JNIEnv *env = NULL;
JNI_GET_ENV_OR_RETURN(env, ctx, -1);
/* Validate the Surface before calling ANativeWindow_fromSurface,
* which will crash if the Surface's native peer has been released */
jclass surface_class = (*env)->FindClass(env, "android/view/Surface");
if (surface_class) {
jmethodID is_valid_id = (*env)->GetMethodID(env, surface_class, "isValid", "()Z");
if (is_valid_id) {
jboolean valid = (*env)->CallBooleanMethod(env, window->surface, is_valid_id);
if (!valid) {
av_log(ctx, AV_LOG_ERROR, "Surface is not valid, cannot configure codec\n");
(*env)->DeleteLocalRef(env, surface_class);
ff_jni_exception_check(env, 0, 0);
return AVERROR_EXTERNAL;
}
}
(*env)->DeleteLocalRef(env, surface_class);
}
ff_jni_exception_check(env, 0, 0);
native_window = ANativeWindow_fromSurface(env, window->surface);
// Save for release
codec->window = native_window;
Expand Down