| /* |
| * Copyright 2024 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. |
| */ |
| |
| #include <cstring> |
| #include <string> |
| |
| #include "com_google_media_codecs_ultrahdr_UltraHDRCommon.h" |
| #include "com_google_media_codecs_ultrahdr_UltraHDRDecoder.h" |
| #include "com_google_media_codecs_ultrahdr_UltraHDREncoder.h" |
| #include "ultrahdr_api.h" |
| |
| static_assert(sizeof(void *) <= sizeof(jlong), |
| "unsupported architecture, size of pointer address exceeds jlong storage"); |
| |
| #define RET_IF_TRUE(cond, exception_class, msg) \ |
| { \ |
| if ((cond) || env->ExceptionCheck()) { \ |
| env->ExceptionClear(); \ |
| auto _clazz = env->FindClass(exception_class); \ |
| if (!_clazz || env->ExceptionCheck()) { \ |
| return; \ |
| } \ |
| env->ThrowNew(_clazz, msg); \ |
| return; \ |
| } \ |
| } |
| |
| #define GET_HANDLE() \ |
| jclass clazz = env->GetObjectClass(thiz); \ |
| RET_IF_TRUE(clazz == nullptr, "java/io/IOException", "GetObjectClass returned with error") \ |
| jfieldID fid = env->GetFieldID(clazz, "handle", "J"); \ |
| RET_IF_TRUE(fid == nullptr, "java/io/IOException", \ |
| "GetFieldID for field 'handle' returned with error") \ |
| jlong handle = env->GetLongField(thiz, fid); |
| |
| #define RET_VAL_IF_TRUE(cond, exception_class, msg, val) \ |
| { \ |
| if ((cond) || env->ExceptionCheck()) { \ |
| env->ExceptionClear(); \ |
| auto _clazz = env->FindClass(exception_class); \ |
| if (!_clazz || env->ExceptionCheck()) { \ |
| return (val); \ |
| } \ |
| env->ThrowNew(_clazz, msg); \ |
| return (val); \ |
| } \ |
| } |
| |
| #define GET_HANDLE_VAL(val) \ |
| jclass clazz = env->GetObjectClass(thiz); \ |
| RET_VAL_IF_TRUE(clazz == nullptr, "java/io/IOException", "GetObjectClass returned with error", \ |
| (val)) \ |
| jfieldID fid = env->GetFieldID(clazz, "handle", "J"); \ |
| RET_VAL_IF_TRUE(fid == nullptr, "java/io/IOException", \ |
| "GetFieldID for field 'handle' returned with error", (val)) \ |
| jlong handle = env->GetLongField(thiz, fid); |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_init(JNIEnv *env, jobject thiz) { |
| jclass clazz = env->GetObjectClass(thiz); |
| RET_IF_TRUE(clazz == nullptr, "java/io/IOException", "GetObjectClass returned with error") |
| jfieldID fid = env->GetFieldID(clazz, "handle", "J"); |
| RET_IF_TRUE(fid == nullptr, "java/io/IOException", |
| "GetFieldID for field 'handle' returned with error") |
| uhdr_codec_private_t *handle = uhdr_create_encoder(); |
| RET_IF_TRUE(handle == nullptr, "java/lang/OutOfMemoryError", |
| "Unable to allocate encoder instance") |
| env->SetLongField(thiz, fid, (jlong)handle); |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_destroy(JNIEnv *env, jobject thiz) { |
| GET_HANDLE() |
| if (!handle) { |
| uhdr_release_encoder((uhdr_codec_private_t *)handle); |
| env->SetLongField(thiz, fid, (jlong)0); |
| } |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setRawImageNative___3IIIIIIIII( |
| JNIEnv *env, jobject thiz, jintArray rgb_buff, jint width, jint height, jint rgb_stride, |
| jint color_gamut, jint color_transfer, jint color_range, jint color_format, jint intent) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| jsize length = env->GetArrayLength(rgb_buff); |
| RET_IF_TRUE(length < height * rgb_stride, "java/io/IOException", |
| "raw image rgba byteArray size is less than required size") |
| jint *rgbBody = env->GetIntArrayElements(rgb_buff, nullptr); |
| uhdr_raw_image_t img{(uhdr_img_fmt_t)color_format, |
| (uhdr_color_gamut_t)color_gamut, |
| (uhdr_color_transfer_t)color_transfer, |
| (uhdr_color_range_t)color_range, |
| (unsigned int)width, |
| (unsigned int)height, |
| {rgbBody, nullptr, nullptr}, |
| {(unsigned int)rgb_stride, 0u, 0u}}; |
| auto status = |
| uhdr_enc_set_raw_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent); |
| env->ReleaseIntArrayElements(rgb_buff, rgbBody, 0); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_raw_image() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setRawImageNative___3JIIIIIIII( |
| JNIEnv *env, jobject thiz, jlongArray rgb_buff, jint width, jint height, jint rgb_stride, |
| jint color_gamut, jint color_transfer, jint color_range, jint color_format, jint intent) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| jsize length = env->GetArrayLength(rgb_buff); |
| RET_IF_TRUE(length < height * rgb_stride, "java/io/IOException", |
| "raw image rgba byteArray size is less than required size") |
| jlong *rgbBody = env->GetLongArrayElements(rgb_buff, nullptr); |
| uhdr_raw_image_t img{(uhdr_img_fmt_t)color_format, |
| (uhdr_color_gamut_t)color_gamut, |
| (uhdr_color_transfer_t)color_transfer, |
| (uhdr_color_range_t)color_range, |
| (unsigned int)width, |
| (unsigned int)height, |
| {rgbBody, nullptr, nullptr}, |
| {(unsigned int)rgb_stride, 0u, 0u}}; |
| auto status = |
| uhdr_enc_set_raw_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent); |
| env->ReleaseLongArrayElements(rgb_buff, rgbBody, 0); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_raw_image() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setRawImageNative___3S_3SIIIIIIIII( |
| JNIEnv *env, jobject thiz, jshortArray y_buff, jshortArray uv_buff, jint width, jint height, |
| jint y_stride, jint uv_stride, jint color_gamut, jint color_transfer, jint color_range, |
| jint color_format, jint intent) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| jsize length = env->GetArrayLength(y_buff); |
| RET_IF_TRUE(length < height * y_stride, "java/io/IOException", |
| "raw image luma byteArray size is less than required size") |
| length = env->GetArrayLength(uv_buff); |
| RET_IF_TRUE(length < height * uv_stride / 2, "java/io/IOException", |
| "raw image chroma byteArray size is less than required size") |
| jshort *lumaBody = env->GetShortArrayElements(y_buff, nullptr); |
| jshort *chromaBody = env->GetShortArrayElements(uv_buff, nullptr); |
| uhdr_raw_image_t img{(uhdr_img_fmt_t)color_format, |
| (uhdr_color_gamut_t)color_gamut, |
| (uhdr_color_transfer_t)color_transfer, |
| (uhdr_color_range_t)color_range, |
| (unsigned int)width, |
| (unsigned int)height, |
| {lumaBody, chromaBody, nullptr}, |
| {(unsigned int)y_stride, (unsigned int)uv_stride, 0u}}; |
| auto status = |
| uhdr_enc_set_raw_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent); |
| env->ReleaseShortArrayElements(y_buff, lumaBody, 0); |
| env->ReleaseShortArrayElements(uv_buff, chromaBody, 0); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_raw_image() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setRawImageNative___3B_3B_3BIIIIIIIIII( |
| JNIEnv *env, jobject thiz, jbyteArray y_buff, jbyteArray u_buff, jbyteArray v_buff, jint width, |
| jint height, jint y_stride, jint u_stride, jint v_stride, jint color_gamut, jint color_transfer, |
| jint color_range, jint color_format, jint intent) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| jsize length = env->GetArrayLength(y_buff); |
| RET_IF_TRUE(length < height * y_stride, "java/io/IOException", |
| "raw image luma byteArray size is less than required size") |
| length = env->GetArrayLength(u_buff); |
| RET_IF_TRUE(length < height * u_stride / 4, "java/io/IOException", |
| "raw image cb byteArray size is less than required size") |
| length = env->GetArrayLength(v_buff); |
| RET_IF_TRUE(length < height * v_stride / 4, "java/io/IOException", |
| "raw image cb byteArray size is less than required size") |
| jbyte *lumaBody = env->GetByteArrayElements(y_buff, nullptr); |
| jbyte *cbBody = env->GetByteArrayElements(u_buff, nullptr); |
| jbyte *crBody = env->GetByteArrayElements(v_buff, nullptr); |
| uhdr_raw_image_t img{(uhdr_img_fmt_t)color_format, |
| (uhdr_color_gamut_t)color_gamut, |
| (uhdr_color_transfer_t)color_transfer, |
| (uhdr_color_range_t)color_range, |
| (unsigned int)width, |
| (unsigned int)height, |
| {lumaBody, cbBody, crBody}, |
| {(unsigned int)y_stride, (unsigned int)u_stride, (unsigned int)v_stride}}; |
| auto status = |
| uhdr_enc_set_raw_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent); |
| env->ReleaseByteArrayElements(y_buff, lumaBody, 0); |
| env->ReleaseByteArrayElements(u_buff, cbBody, 0); |
| env->ReleaseByteArrayElements(v_buff, crBody, 0); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_raw_image() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setCompressedImageNative( |
| JNIEnv *env, jobject thiz, jbyteArray data, jint size, jint color_gamut, jint color_transfer, |
| jint range, jint intent) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| jsize length = env->GetArrayLength(data); |
| RET_IF_TRUE(length < size, "java/io/IOException", |
| "compressed image byteArray size is less than configured size") |
| jbyte *body = env->GetByteArrayElements(data, nullptr); |
| uhdr_compressed_image_t img{body, |
| (unsigned int)size, |
| (unsigned int)length, |
| (uhdr_color_gamut_t)color_gamut, |
| (uhdr_color_transfer_t)color_transfer, |
| (uhdr_color_range_t)range}; |
| auto status = |
| uhdr_enc_set_compressed_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent); |
| env->ReleaseByteArrayElements(data, body, 0); |
| RET_IF_TRUE( |
| status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_compressed_image() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapImageInfoNative( |
| JNIEnv *env, jobject thiz, jbyteArray data, jint size, jfloat max_content_boost, |
| jfloat min_content_boost, jfloat gainmap_gamma, jfloat offset_sdr, jfloat offset_hdr, |
| jfloat hdr_capacity_min, jfloat hdr_capacity_max) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| jsize length = env->GetArrayLength(data); |
| RET_IF_TRUE(length < size, "java/io/IOException", |
| "compressed image byteArray size is less than configured size") |
| jbyte *body = env->GetByteArrayElements(data, nullptr); |
| uhdr_compressed_image_t img{body, |
| (unsigned int)size, |
| (unsigned int)length, |
| UHDR_CG_UNSPECIFIED, |
| UHDR_CT_UNSPECIFIED, |
| UHDR_CR_UNSPECIFIED}; |
| uhdr_gainmap_metadata_t metadata{max_content_boost, min_content_boost, gainmap_gamma, |
| offset_sdr, offset_hdr, hdr_capacity_min, |
| hdr_capacity_max}; |
| auto status = uhdr_enc_set_gainmap_image((uhdr_codec_private_t *)handle, &img, &metadata); |
| env->ReleaseByteArrayElements(data, body, 0); |
| RET_IF_TRUE( |
| status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_gainmap_image() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setExifDataNative(JNIEnv *env, jobject thiz, |
| jbyteArray data, |
| jint size) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| jsize length = env->GetArrayLength(data); |
| RET_IF_TRUE(length < size, "java/io/IOException", |
| "compressed image byteArray size is less than configured size") |
| jbyte *body = env->GetByteArrayElements(data, nullptr); |
| uhdr_mem_block_t exif{body, (unsigned int)size, (unsigned int)length}; |
| auto status = uhdr_enc_set_exif_data((uhdr_codec_private_t *)handle, &exif); |
| env->ReleaseByteArrayElements(data, body, 0); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_exif_data() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setQualityFactorNative(JNIEnv *env, |
| jobject thiz, |
| jint quality_factor, |
| jint intent) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| auto status = uhdr_enc_set_quality((uhdr_codec_private_t *)handle, quality_factor, |
| (uhdr_img_label_t)intent); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_quality() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setMultiChannelGainMapEncodingNative( |
| JNIEnv *env, jobject thiz, jboolean enable) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| auto status = |
| uhdr_enc_set_using_multi_channel_gainmap((uhdr_codec_private_t *)handle, enable ? 1 : 0); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail |
| : "uhdr_enc_set_using_multi_channel_gainmap() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapScaleFactorNative( |
| JNIEnv *env, jobject thiz, jint scale_factor) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| auto status = uhdr_enc_set_gainmap_scale_factor((uhdr_codec_private_t *)handle, scale_factor); |
| RET_IF_TRUE( |
| status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_gainmap_scale_factor() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapGammaNative(JNIEnv *env, |
| jobject thiz, |
| jfloat gamma) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| auto status = uhdr_enc_set_gainmap_gamma((uhdr_codec_private_t *)handle, gamma); |
| RET_IF_TRUE( |
| status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_gainmap_gamma() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setEncPresetNative(JNIEnv *env, jobject thiz, |
| jint preset) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| auto status = uhdr_enc_set_preset((uhdr_codec_private_t *)handle, (uhdr_enc_preset_t)preset); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_preset() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setOutputFormatNative(JNIEnv *env, |
| jobject thiz, |
| jint media_type) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| auto status = |
| uhdr_enc_set_output_format((uhdr_codec_private_t *)handle, (uhdr_codec_t)media_type); |
| RET_IF_TRUE( |
| status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enc_set_output_format() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setMinMaxContentBoostNative( |
| JNIEnv *env, jobject thiz, jfloat min_content_boost, jfloat max_content_boost) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| auto status = uhdr_enc_set_min_max_content_boost((uhdr_codec_private_t *)handle, |
| min_content_boost, max_content_boost); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail |
| : "uhdr_enc_set_min_max_content_boost() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setTargetDisplayPeakBrightnessNative( |
| JNIEnv *env, jobject thiz, jfloat nits) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| auto status = uhdr_enc_set_target_display_peak_brightness((uhdr_codec_private_t *)handle, nits); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail |
| ? status.detail |
| : "uhdr_enc_set_target_display_peak_brightness() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_encodeNative(JNIEnv *env, jobject thiz) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| auto status = uhdr_encode((uhdr_codec_private_t *)handle); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_encode() returned with error") |
| } |
| |
| extern "C" JNIEXPORT jbyteArray JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_getOutputNative(JNIEnv *env, jobject thiz) { |
| GET_HANDLE_VAL(nullptr) |
| RET_VAL_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance", nullptr) |
| auto enc_output = uhdr_get_encoded_stream((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(enc_output == nullptr, "java/io/IOException", |
| "no output returned, may be call to uhdr_encode() was not made or encountered " |
| "error during encoding process.", |
| nullptr) |
| RET_VAL_IF_TRUE(enc_output->data_sz >= INT32_MAX, "java/lang/OutOfMemoryError", |
| "encoded output size exceeds integer max", nullptr) |
| jbyteArray output = env->NewByteArray(enc_output->data_sz); |
| RET_VAL_IF_TRUE(output == nullptr, "java/io/IOException", "failed to allocate storage for output", |
| nullptr) |
| env->SetByteArrayRegion(output, 0, enc_output->data_sz, (jbyte *)enc_output->data); |
| return output; |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_resetNative(JNIEnv *env, jobject thiz) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance") |
| uhdr_reset_encoder((uhdr_codec_private_t *)handle); |
| } |
| |
| extern "C" JNIEXPORT jint JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_isUHDRImageNative(JNIEnv *env, jclass clazz, |
| jbyteArray data, |
| jint size) { |
| jsize length = env->GetArrayLength(data); |
| RET_VAL_IF_TRUE(length < size, "java/io/IOException", |
| "compressed image byteArray size is less than configured size", 0) |
| jbyte *body = env->GetByteArrayElements(data, nullptr); |
| auto status = is_uhdr_image(body, size); |
| env->ReleaseByteArrayElements(data, body, 0); |
| return status; |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_init(JNIEnv *env, jobject thiz) { |
| jclass clazz = env->GetObjectClass(thiz); |
| RET_IF_TRUE(clazz == nullptr, "java/io/IOException", "GetObjectClass returned with error") |
| jfieldID fid = env->GetFieldID(clazz, "handle", "J"); |
| RET_IF_TRUE(fid == nullptr, "java/io/IOException", |
| "GetFieldID for field 'handle' returned with error") |
| uhdr_codec_private_t *handle = uhdr_create_decoder(); |
| RET_IF_TRUE(handle == nullptr, "java/lang/OutOfMemoryError", |
| "Unable to allocate decoder instance") |
| env->SetLongField(thiz, fid, (jlong)handle); |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_destroy(JNIEnv *env, jobject thiz) { |
| GET_HANDLE() |
| if (!handle) { |
| uhdr_release_decoder((uhdr_codec_private *)handle); |
| env->SetLongField(thiz, fid, (jlong)0); |
| } |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setCompressedImageNative( |
| JNIEnv *env, jobject thiz, jbyteArray data, jint size, jint color_gamut, jint color_transfer, |
| jint range) { |
| RET_IF_TRUE(size < 0, "java/io/IOException", "invalid compressed image size") |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance") |
| jsize length = env->GetArrayLength(data); |
| RET_IF_TRUE(length < size, "java/io/IOException", |
| "compressed image byteArray size is less than configured size") |
| jbyte *body = env->GetByteArrayElements(data, nullptr); |
| uhdr_compressed_image_t img{body, |
| (unsigned int)size, |
| (unsigned int)length, |
| (uhdr_color_gamut_t)color_gamut, |
| (uhdr_color_transfer_t)color_transfer, |
| (uhdr_color_range_t)range}; |
| uhdr_error_info_t status = uhdr_dec_set_image((uhdr_codec_private_t *)handle, &img); |
| env->ReleaseByteArrayElements(data, body, 0); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_dec_set_image() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setOutputFormatNative(JNIEnv *env, |
| jobject thiz, |
| jint fmt) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance") |
| uhdr_error_info_t status = |
| uhdr_dec_set_out_img_format((uhdr_codec_private_t *)handle, (uhdr_img_fmt_t)fmt); |
| RET_IF_TRUE( |
| status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_dec_set_out_img_format() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setColorTransferNative(JNIEnv *env, |
| jobject thiz, |
| jint ct) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance") |
| uhdr_error_info_t status = |
| uhdr_dec_set_out_color_transfer((uhdr_codec_private_t *)handle, (uhdr_color_transfer_t)ct); |
| RET_IF_TRUE( |
| status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_dec_set_out_color_transfer() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setMaxDisplayBoostNative( |
| JNIEnv *env, jobject thiz, jfloat display_boost) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance") |
| uhdr_error_info_t status = |
| uhdr_dec_set_out_max_display_boost((uhdr_codec_private_t *)handle, (float)display_boost); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail |
| : "uhdr_dec_set_out_max_display_boost() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_enableGpuAccelerationNative(JNIEnv *env, |
| jobject thiz, |
| jint enable) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance") |
| uhdr_error_info_t status = uhdr_enable_gpu_acceleration((uhdr_codec_private_t *)handle, enable); |
| RET_IF_TRUE( |
| status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_enable_gpu_acceleration() returned with error") |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_probeNative(JNIEnv *env, jobject thiz) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance") |
| uhdr_error_info_t status = uhdr_dec_probe((uhdr_codec_private_t *)handle); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_dec_probe() returned with error") |
| } |
| |
| extern "C" JNIEXPORT jint JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageWidthNative(JNIEnv *env, |
| jobject thiz) { |
| GET_HANDLE_VAL(-1) |
| auto val = uhdr_dec_get_image_width((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(val == -1, "java/io/IOException", |
| "uhdr_dec_probe() is not yet called or it has returned with error", -1) |
| return val; |
| } |
| |
| extern "C" JNIEXPORT jint JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageHeightNative(JNIEnv *env, |
| jobject thiz) { |
| GET_HANDLE_VAL(-1) |
| auto val = uhdr_dec_get_image_height((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(val == -1, "java/io/IOException", |
| "uhdr_dec_probe() is not yet called or it has returned with error", -1) |
| return val; |
| } |
| |
| extern "C" JNIEXPORT jint JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapWidthNative(JNIEnv *env, |
| jobject thiz) { |
| GET_HANDLE_VAL(-1) |
| auto val = uhdr_dec_get_gainmap_width((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(val == -1, "java/io/IOException", |
| "uhdr_dec_probe() is not yet called or it has returned with error", -1) |
| return val; |
| } |
| |
| extern "C" JNIEXPORT jint JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapHeightNative(JNIEnv *env, |
| jobject thiz) { |
| GET_HANDLE_VAL(-1) |
| auto val = uhdr_dec_get_gainmap_height((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(val == -1, "java/io/IOException", |
| "uhdr_dec_probe() is not yet called or it has returned with error", -1) |
| return val; |
| } |
| |
| extern "C" JNIEXPORT jbyteArray JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getExifNative(JNIEnv *env, jobject thiz) { |
| GET_HANDLE_VAL(nullptr) |
| uhdr_mem_block_t *exifData = uhdr_dec_get_exif((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(exifData == nullptr, "java/io/IOException", |
| "uhdr_dec_probe() is not yet called or it has returned with error", nullptr) |
| jbyteArray data = env->NewByteArray(exifData->data_sz); |
| jbyte *dataptr = env->GetByteArrayElements(data, nullptr); |
| std::memcpy(dataptr, exifData->data, exifData->data_sz); |
| env->ReleaseByteArrayElements(data, dataptr, 0); |
| return data; |
| } |
| |
| extern "C" JNIEXPORT jbyteArray JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getIccNative(JNIEnv *env, jobject thiz) { |
| GET_HANDLE_VAL(nullptr) |
| uhdr_mem_block_t *iccData = uhdr_dec_get_icc((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(iccData == nullptr, "java/io/IOException", |
| "uhdr_dec_probe() is not yet called or it has returned with error", nullptr) |
| jbyteArray data = env->NewByteArray(iccData->data_sz); |
| jbyte *dataptr = env->GetByteArrayElements(data, nullptr); |
| std::memcpy(dataptr, iccData->data, iccData->data_sz); |
| env->ReleaseByteArrayElements(data, dataptr, 0); |
| return data; |
| } |
| |
| extern "C" JNIEXPORT jbyteArray JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getBaseImageNative(JNIEnv *env, |
| jobject thiz) { |
| GET_HANDLE_VAL(nullptr) |
| uhdr_mem_block_t *baseImgData = uhdr_dec_get_base_image((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(baseImgData == nullptr, "java/io/IOException", |
| "uhdr_dec_probe() is not yet called or it has returned with error", nullptr) |
| jbyteArray data = env->NewByteArray(baseImgData->data_sz); |
| jbyte *dataptr = env->GetByteArrayElements(data, nullptr); |
| std::memcpy(dataptr, baseImgData->data, baseImgData->data_sz); |
| env->ReleaseByteArrayElements(data, dataptr, 0); |
| return data; |
| } |
| |
| extern "C" JNIEXPORT jbyteArray JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapImageNative(JNIEnv *env, |
| jobject thiz) { |
| GET_HANDLE_VAL(nullptr) |
| uhdr_mem_block_t *gainmapImgData = uhdr_dec_get_gainmap_image((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(gainmapImgData == nullptr, "java/io/IOException", |
| "uhdr_dec_probe() is not yet called or it has returned with error", nullptr) |
| jbyteArray data = env->NewByteArray(gainmapImgData->data_sz); |
| jbyte *dataptr = env->GetByteArrayElements(data, nullptr); |
| std::memcpy(dataptr, gainmapImgData->data, gainmapImgData->data_sz); |
| env->ReleaseByteArrayElements(data, dataptr, 0); |
| return data; |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainmapMetadataNative(JNIEnv *env, |
| jobject thiz) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance") |
| uhdr_gainmap_metadata_t *gainmap_metadata = |
| uhdr_dec_get_gainmap_metadata((uhdr_codec_private_t *)handle); |
| RET_IF_TRUE(gainmap_metadata == nullptr, "java/io/IOException", |
| "uhdr_dec_probe() is not yet called or it has returned with error") |
| #define SET_FLOAT_FIELD(name, val) \ |
| { \ |
| jfieldID fID = env->GetFieldID(clazz, name, "F"); \ |
| RET_IF_TRUE(fID == nullptr, "java/io/IOException", \ |
| "GetFieldID for field " #name " returned with error") \ |
| env->SetFloatField(thiz, fID, (jfloat)val); \ |
| } |
| SET_FLOAT_FIELD("maxContentBoost", gainmap_metadata->max_content_boost) |
| SET_FLOAT_FIELD("minContentBoost", gainmap_metadata->min_content_boost) |
| SET_FLOAT_FIELD("gamma", gainmap_metadata->gamma) |
| SET_FLOAT_FIELD("offsetSdr", gainmap_metadata->offset_sdr) |
| SET_FLOAT_FIELD("offsetHdr", gainmap_metadata->offset_hdr) |
| SET_FLOAT_FIELD("hdrCapacityMin", gainmap_metadata->hdr_capacity_min) |
| SET_FLOAT_FIELD("hdrCapacityMax", gainmap_metadata->hdr_capacity_max) |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_decodeNative(JNIEnv *env, jobject thiz) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance") |
| auto status = uhdr_decode((uhdr_codec_private_t *)handle); |
| RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException", |
| status.has_detail ? status.detail : "uhdr_decode() returned with error") |
| } |
| |
| extern "C" JNIEXPORT jbyteArray JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedImageNative(JNIEnv *env, |
| jobject thiz) { |
| GET_HANDLE_VAL(nullptr) |
| uhdr_raw_image_t *decodedImg = uhdr_get_decoded_image((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(decodedImg == nullptr, "java/io/IOException", |
| "uhdr_decode() is not yet called or it has returned with error", nullptr) |
| int bpp = decodedImg->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ? 8 : 4; |
| jbyteArray data = env->NewByteArray(decodedImg->stride[UHDR_PLANE_PACKED] * decodedImg->h * bpp); |
| jbyte *dataptr = env->GetByteArrayElements(data, nullptr); |
| std::memcpy(dataptr, decodedImg->planes[UHDR_PLANE_PACKED], |
| decodedImg->stride[UHDR_PLANE_PACKED] * decodedImg->h * bpp); |
| env->ReleaseByteArrayElements(data, dataptr, 0); |
| #define SET_INT_FIELD(name, val) \ |
| { \ |
| jfieldID fID = env->GetFieldID(clazz, name, "I"); \ |
| RET_VAL_IF_TRUE(fID == nullptr, "java/io/IOException", \ |
| "GetFieldID for field " #name " returned with error", nullptr) \ |
| env->SetIntField(thiz, fID, (jint)val); \ |
| } |
| SET_INT_FIELD("imgWidth", decodedImg->w) |
| SET_INT_FIELD("imgHeight", decodedImg->h) |
| SET_INT_FIELD("imgStride", decodedImg->stride[UHDR_PLANE_PACKED]) |
| SET_INT_FIELD("imgFormat", decodedImg->fmt) |
| SET_INT_FIELD("imgGamut", decodedImg->cg) |
| SET_INT_FIELD("imgTransfer", decodedImg->ct) |
| SET_INT_FIELD("imgRange", decodedImg->range) |
| return data; |
| } |
| |
| extern "C" JNIEXPORT jbyteArray JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedGainMapImageNative(JNIEnv *env, |
| jobject thiz) { |
| GET_HANDLE_VAL(nullptr) |
| uhdr_raw_image_t *gainmapImg = uhdr_get_decoded_gainmap_image((uhdr_codec_private_t *)handle); |
| RET_VAL_IF_TRUE(gainmapImg == nullptr, "java/io/IOException", |
| "uhdr_decode() is not yet called or it has returned with error", nullptr) |
| int bpp = gainmapImg->fmt == UHDR_IMG_FMT_32bppRGBA8888 ? 4 : 1; |
| jbyteArray data = env->NewByteArray(gainmapImg->stride[UHDR_PLANE_PACKED] * gainmapImg->h * bpp); |
| jbyte *dataptr = env->GetByteArrayElements(data, nullptr); |
| std::memcpy(dataptr, gainmapImg->planes[UHDR_PLANE_PACKED], |
| gainmapImg->stride[UHDR_PLANE_PACKED] * gainmapImg->h * bpp); |
| env->ReleaseByteArrayElements(data, dataptr, 0); |
| SET_INT_FIELD("gainmapWidth", gainmapImg->w) |
| SET_INT_FIELD("gainmapHeight", gainmapImg->h) |
| SET_INT_FIELD("gainmapStride", gainmapImg->stride[UHDR_PLANE_PACKED]) |
| SET_INT_FIELD("gainmapFormat", gainmapImg->fmt) |
| return data; |
| } |
| |
| extern "C" JNIEXPORT void JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_resetNative(JNIEnv *env, jobject thiz) { |
| GET_HANDLE() |
| RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance") |
| uhdr_reset_decoder((uhdr_codec_private_t *)handle); |
| } |
| |
| extern "C" JNIEXPORT jstring JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionStringNative(JNIEnv *env, |
| jclass clazz) { |
| std::string version{"v" UHDR_LIB_VERSION_STR}; |
| return env->NewStringUTF(version.c_str()); |
| } |
| |
| extern "C" JNIEXPORT jint JNICALL |
| Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionNative(JNIEnv *env, jclass clazz) { |
| return UHDR_LIB_VERSION; |
| } |