blob: 2437a511238cf0a8291c60d99ec7ed4aad16376e [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "Camera-SurfaceUtils-JNI"
// #define LOG_NDEBUG 0
#include <camera/CameraUtils.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <nativehelper/JNIHelp.h>
#include "android_runtime/android_graphics_SurfaceTexture.h"
#include "android_runtime/android_view_Surface.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
#include <gui/Surface.h>
#include <system/window.h>
#include <ui/GraphicBuffer.h>
#include <inttypes.h>
#include <stdint.h>
using namespace android;
// fully-qualified class name
#define CAMERA_UTILS_CLASS_NAME "android/hardware/camera2/utils/SurfaceUtils"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
#define OVERRIDE_SURFACE_ERROR(err) \
do { \
if (err == -ENODEV) { \
err = BAD_VALUE; \
} \
} while (0)
static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
sp<ANativeWindow> anw;
if (surface) {
anw = android_view_Surface_getNativeWindow(env, surface);
if (env->ExceptionCheck()) {
return NULL;
}
} else {
jniThrowNullPointerException(env, "surface");
return NULL;
}
if (anw == NULL) {
ALOGE("%s: Surface had no valid native window.", __FUNCTION__);
return NULL;
}
return anw;
}
static sp<Surface> getSurface(JNIEnv* env, jobject surface) {
sp<Surface> s;
if (surface) {
s = android_view_Surface_getSurface(env, surface);
if (env->ExceptionCheck()) {
return NULL;
}
} else {
jniThrowNullPointerException(env, "surface");
return NULL;
}
if (s == NULL) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
"Surface had no valid native Surface.");
return NULL;
}
return s;
}
extern "C" {
static jint SurfaceUtils_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) {
ALOGV("nativeDetectSurfaceType");
sp<ANativeWindow> anw;
if ((anw = getNativeWindow(env, surface)) == NULL) {
ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
return BAD_VALUE;
}
int32_t fmt = 0;
status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt);
if (err != NO_ERROR) {
ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__,
strerror(-err), err);
OVERRIDE_SURFACE_ERROR(err);
return err;
}
return fmt;
}
static jint SurfaceUtils_nativeDetectSurfaceDataspace(JNIEnv* env, jobject thiz, jobject surface) {
ALOGV("nativeDetectSurfaceDataspace");
sp<ANativeWindow> anw;
if ((anw = getNativeWindow(env, surface)) == NULL) {
ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
return BAD_VALUE;
}
int32_t fmt = 0;
status_t err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, &fmt);
if (err != NO_ERROR) {
ALOGE("%s: Error while querying surface dataspace %s (%d).", __FUNCTION__, strerror(-err),
err);
OVERRIDE_SURFACE_ERROR(err);
return err;
}
return fmt;
}
static jint SurfaceUtils_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface,
jintArray dimens) {
ALOGV("nativeGetSurfaceDimens");
if (dimens == NULL) {
ALOGE("%s: Null dimens argument passed to nativeDetectSurfaceDimens", __FUNCTION__);
return BAD_VALUE;
}
if (env->GetArrayLength(dimens) < 2) {
ALOGE("%s: Invalid length of dimens argument in nativeDetectSurfaceDimens", __FUNCTION__);
return BAD_VALUE;
}
sp<ANativeWindow> anw;
if ((anw = getNativeWindow(env, surface)) == NULL) {
ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
return BAD_VALUE;
}
int32_t dimenBuf[2];
status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
if (err != NO_ERROR) {
ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err), err);
OVERRIDE_SURFACE_ERROR(err);
return err;
}
err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
if (err != NO_ERROR) {
ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
err);
OVERRIDE_SURFACE_ERROR(err);
return err;
}
env->SetIntArrayRegion(dimens, /*start*/ 0, /*length*/ ARRAY_SIZE(dimenBuf), dimenBuf);
return NO_ERROR;
}
static jlong SurfaceUtils_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobject thiz,
jobject surface) {
ALOGV("nativeDetectSurfaceUsageFlags");
sp<ANativeWindow> anw;
if ((anw = getNativeWindow(env, surface)) == NULL) {
jniThrowException(env, "java/lang/UnsupportedOperationException",
"Could not retrieve native window from surface.");
return BAD_VALUE;
}
uint64_t usage = 0;
status_t err = native_window_get_consumer_usage(anw.get(), &usage);
if (err != NO_ERROR) {
jniThrowException(env, "java/lang/UnsupportedOperationException",
"Error while querying surface usage bits");
OVERRIDE_SURFACE_ERROR(err);
return err;
}
return usage;
}
static jlong SurfaceUtils_nativeGetSurfaceId(JNIEnv* env, jobject thiz, jobject surface) {
ALOGV("nativeGetSurfaceId");
sp<Surface> s;
if ((s = getSurface(env, surface)) == NULL) {
ALOGE("%s: Could not retrieve native Surface from surface.", __FUNCTION__);
return 0;
}
sp<IGraphicBufferProducer> gbp = s->getIGraphicBufferProducer();
if (gbp == NULL) {
ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__);
return 0;
}
sp<IBinder> b = IInterface::asBinder(gbp);
if (b == NULL) {
ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__);
return 0;
}
/*
* FIXME: Use better unique ID for surfaces than native IBinder pointer. Fix also in the camera
* service (CameraDeviceClient.h).
*/
return reinterpret_cast<jlong>(b.get());
}
} // extern "C"
static const JNINativeMethod gCameraSurfaceUtilsMethods[] = {
{"nativeDetectSurfaceType", "(Landroid/view/Surface;)I",
(void*)SurfaceUtils_nativeDetectSurfaceType},
{"nativeDetectSurfaceDataspace", "(Landroid/view/Surface;)I",
(void*)SurfaceUtils_nativeDetectSurfaceDataspace},
{"nativeDetectSurfaceDimens", "(Landroid/view/Surface;[I)I",
(void*)SurfaceUtils_nativeDetectSurfaceDimens},
{"nativeDetectSurfaceUsageFlags", "(Landroid/view/Surface;)J",
(void*)SurfaceUtils_nativeDetectSurfaceUsageFlags},
{"nativeGetSurfaceId", "(Landroid/view/Surface;)J", (void*)SurfaceUtils_nativeGetSurfaceId},
};
// Get all the required offsets in java class and register native functions
int register_android_hardware_camera2_utils_SurfaceUtils(JNIEnv* env) {
// Register native functions
return RegisterMethodsOrDie(env, CAMERA_UTILS_CLASS_NAME, gCameraSurfaceUtilsMethods,
NELEM(gCameraSurfaceUtilsMethods));
}