/* * 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 #include #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; }