xref: /aosp_15_r20/external/libultrahdr/java/jni/ultrahdr-jni.cpp (revision 89a0ef05262152531a00a15832a2d3b1e3990773)
1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <cstring>
18 #include <string>
19 
20 #include "com_google_media_codecs_ultrahdr_UltraHDRCommon.h"
21 #include "com_google_media_codecs_ultrahdr_UltraHDRDecoder.h"
22 #include "com_google_media_codecs_ultrahdr_UltraHDREncoder.h"
23 #include "ultrahdr_api.h"
24 
25 static_assert(sizeof(void *) <= sizeof(jlong),
26               "unsupported architecture, size of pointer address exceeds jlong storage");
27 
28 #define RET_IF_TRUE(cond, exception_class, msg)      \
29   {                                                  \
30     if ((cond) || env->ExceptionCheck()) {           \
31       env->ExceptionClear();                         \
32       auto _clazz = env->FindClass(exception_class); \
33       if (!_clazz || env->ExceptionCheck()) {        \
34         return;                                      \
35       }                                              \
36       env->ThrowNew(_clazz, msg);                    \
37       return;                                        \
38     }                                                \
39   }
40 
41 #define GET_HANDLE()                                                                         \
42   jclass clazz = env->GetObjectClass(thiz);                                                  \
43   RET_IF_TRUE(clazz == nullptr, "java/io/IOException", "GetObjectClass returned with error") \
44   jfieldID fid = env->GetFieldID(clazz, "handle", "J");                                      \
45   RET_IF_TRUE(fid == nullptr, "java/io/IOException",                                         \
46               "GetFieldID for field 'handle' returned with error")                           \
47   jlong handle = env->GetLongField(thiz, fid);
48 
49 #define RET_VAL_IF_TRUE(cond, exception_class, msg, val) \
50   {                                                      \
51     if ((cond) || env->ExceptionCheck()) {               \
52       env->ExceptionClear();                             \
53       auto _clazz = env->FindClass(exception_class);     \
54       if (!_clazz || env->ExceptionCheck()) {            \
55         return (val);                                    \
56       }                                                  \
57       env->ThrowNew(_clazz, msg);                        \
58       return (val);                                      \
59     }                                                    \
60   }
61 
62 #define GET_HANDLE_VAL(val)                                                                      \
63   jclass clazz = env->GetObjectClass(thiz);                                                      \
64   RET_VAL_IF_TRUE(clazz == nullptr, "java/io/IOException", "GetObjectClass returned with error", \
65                   (val))                                                                         \
66   jfieldID fid = env->GetFieldID(clazz, "handle", "J");                                          \
67   RET_VAL_IF_TRUE(fid == nullptr, "java/io/IOException",                                         \
68                   "GetFieldID for field 'handle' returned with error", (val))                    \
69   jlong handle = env->GetLongField(thiz, fid);
70 
71 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_init(JNIEnv * env,jobject thiz)72 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_init(JNIEnv *env, jobject thiz) {
73   jclass clazz = env->GetObjectClass(thiz);
74   RET_IF_TRUE(clazz == nullptr, "java/io/IOException", "GetObjectClass returned with error")
75   jfieldID fid = env->GetFieldID(clazz, "handle", "J");
76   RET_IF_TRUE(fid == nullptr, "java/io/IOException",
77               "GetFieldID for field 'handle' returned with error")
78   uhdr_codec_private_t *handle = uhdr_create_encoder();
79   RET_IF_TRUE(handle == nullptr, "java/lang/OutOfMemoryError",
80               "Unable to allocate encoder instance")
81   env->SetLongField(thiz, fid, (jlong)handle);
82 }
83 
84 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_destroy(JNIEnv * env,jobject thiz)85 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_destroy(JNIEnv *env, jobject thiz) {
86   GET_HANDLE()
87   if (!handle) {
88     uhdr_release_encoder((uhdr_codec_private_t *)handle);
89     env->SetLongField(thiz, fid, (jlong)0);
90   }
91 }
92 
93 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)94 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setRawImageNative___3IIIIIIIII(
95     JNIEnv *env, jobject thiz, jintArray rgb_buff, jint width, jint height, jint rgb_stride,
96     jint color_gamut, jint color_transfer, jint color_range, jint color_format, jint intent) {
97   GET_HANDLE()
98   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
99   jsize length = env->GetArrayLength(rgb_buff);
100   RET_IF_TRUE(length < height * rgb_stride, "java/io/IOException",
101               "raw image rgba byteArray size is less than required size")
102   jint *rgbBody = env->GetIntArrayElements(rgb_buff, nullptr);
103   uhdr_raw_image_t img{(uhdr_img_fmt_t)color_format,
104                        (uhdr_color_gamut_t)color_gamut,
105                        (uhdr_color_transfer_t)color_transfer,
106                        (uhdr_color_range_t)color_range,
107                        (unsigned int)width,
108                        (unsigned int)height,
109                        {rgbBody, nullptr, nullptr},
110                        {(unsigned int)rgb_stride, 0u, 0u}};
111   auto status =
112       uhdr_enc_set_raw_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent);
113   env->ReleaseIntArrayElements(rgb_buff, rgbBody, 0);
114   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
115               status.has_detail ? status.detail : "uhdr_enc_set_raw_image() returned with error")
116 }
117 
118 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)119 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setRawImageNative___3JIIIIIIII(
120     JNIEnv *env, jobject thiz, jlongArray rgb_buff, jint width, jint height, jint rgb_stride,
121     jint color_gamut, jint color_transfer, jint color_range, jint color_format, jint intent) {
122   GET_HANDLE()
123   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
124   jsize length = env->GetArrayLength(rgb_buff);
125   RET_IF_TRUE(length < height * rgb_stride, "java/io/IOException",
126               "raw image rgba byteArray size is less than required size")
127   jlong *rgbBody = env->GetLongArrayElements(rgb_buff, nullptr);
128   uhdr_raw_image_t img{(uhdr_img_fmt_t)color_format,
129                        (uhdr_color_gamut_t)color_gamut,
130                        (uhdr_color_transfer_t)color_transfer,
131                        (uhdr_color_range_t)color_range,
132                        (unsigned int)width,
133                        (unsigned int)height,
134                        {rgbBody, nullptr, nullptr},
135                        {(unsigned int)rgb_stride, 0u, 0u}};
136   auto status =
137       uhdr_enc_set_raw_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent);
138   env->ReleaseLongArrayElements(rgb_buff, rgbBody, 0);
139   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
140               status.has_detail ? status.detail : "uhdr_enc_set_raw_image() returned with error")
141 }
142 
143 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)144 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setRawImageNative___3S_3SIIIIIIIII(
145     JNIEnv *env, jobject thiz, jshortArray y_buff, jshortArray uv_buff, jint width, jint height,
146     jint y_stride, jint uv_stride, jint color_gamut, jint color_transfer, jint color_range,
147     jint color_format, jint intent) {
148   GET_HANDLE()
149   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
150   jsize length = env->GetArrayLength(y_buff);
151   RET_IF_TRUE(length < height * y_stride, "java/io/IOException",
152               "raw image luma byteArray size is less than required size")
153   length = env->GetArrayLength(uv_buff);
154   RET_IF_TRUE(length < height * uv_stride / 2, "java/io/IOException",
155               "raw image chroma byteArray size is less than required size")
156   jshort *lumaBody = env->GetShortArrayElements(y_buff, nullptr);
157   jshort *chromaBody = env->GetShortArrayElements(uv_buff, nullptr);
158   uhdr_raw_image_t img{(uhdr_img_fmt_t)color_format,
159                        (uhdr_color_gamut_t)color_gamut,
160                        (uhdr_color_transfer_t)color_transfer,
161                        (uhdr_color_range_t)color_range,
162                        (unsigned int)width,
163                        (unsigned int)height,
164                        {lumaBody, chromaBody, nullptr},
165                        {(unsigned int)y_stride, (unsigned int)uv_stride, 0u}};
166   auto status =
167       uhdr_enc_set_raw_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent);
168   env->ReleaseShortArrayElements(y_buff, lumaBody, 0);
169   env->ReleaseShortArrayElements(uv_buff, chromaBody, 0);
170   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
171               status.has_detail ? status.detail : "uhdr_enc_set_raw_image() returned with error")
172 }
173 
174 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)175 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setRawImageNative___3B_3B_3BIIIIIIIIII(
176     JNIEnv *env, jobject thiz, jbyteArray y_buff, jbyteArray u_buff, jbyteArray v_buff, jint width,
177     jint height, jint y_stride, jint u_stride, jint v_stride, jint color_gamut, jint color_transfer,
178     jint color_range, jint color_format, jint intent) {
179   GET_HANDLE()
180   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
181   jsize length = env->GetArrayLength(y_buff);
182   RET_IF_TRUE(length < height * y_stride, "java/io/IOException",
183               "raw image luma byteArray size is less than required size")
184   length = env->GetArrayLength(u_buff);
185   RET_IF_TRUE(length < height * u_stride / 4, "java/io/IOException",
186               "raw image cb byteArray size is less than required size")
187   length = env->GetArrayLength(v_buff);
188   RET_IF_TRUE(length < height * v_stride / 4, "java/io/IOException",
189               "raw image cb byteArray size is less than required size")
190   jbyte *lumaBody = env->GetByteArrayElements(y_buff, nullptr);
191   jbyte *cbBody = env->GetByteArrayElements(u_buff, nullptr);
192   jbyte *crBody = env->GetByteArrayElements(v_buff, nullptr);
193   uhdr_raw_image_t img{(uhdr_img_fmt_t)color_format,
194                        (uhdr_color_gamut_t)color_gamut,
195                        (uhdr_color_transfer_t)color_transfer,
196                        (uhdr_color_range_t)color_range,
197                        (unsigned int)width,
198                        (unsigned int)height,
199                        {lumaBody, cbBody, crBody},
200                        {(unsigned int)y_stride, (unsigned int)u_stride, (unsigned int)v_stride}};
201   auto status =
202       uhdr_enc_set_raw_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent);
203   env->ReleaseByteArrayElements(y_buff, lumaBody, 0);
204   env->ReleaseByteArrayElements(u_buff, cbBody, 0);
205   env->ReleaseByteArrayElements(v_buff, crBody, 0);
206   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
207               status.has_detail ? status.detail : "uhdr_enc_set_raw_image() returned with error")
208 }
209 
210 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)211 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setCompressedImageNative(
212     JNIEnv *env, jobject thiz, jbyteArray data, jint size, jint color_gamut, jint color_transfer,
213     jint range, jint intent) {
214   GET_HANDLE()
215   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
216   jsize length = env->GetArrayLength(data);
217   RET_IF_TRUE(length < size, "java/io/IOException",
218               "compressed image byteArray size is less than configured size")
219   jbyte *body = env->GetByteArrayElements(data, nullptr);
220   uhdr_compressed_image_t img{body,
221                               (unsigned int)size,
222                               (unsigned int)length,
223                               (uhdr_color_gamut_t)color_gamut,
224                               (uhdr_color_transfer_t)color_transfer,
225                               (uhdr_color_range_t)range};
226   auto status =
227       uhdr_enc_set_compressed_image((uhdr_codec_private_t *)handle, &img, (uhdr_img_label_t)intent);
228   env->ReleaseByteArrayElements(data, body, 0);
229   RET_IF_TRUE(
230       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
231       status.has_detail ? status.detail : "uhdr_enc_set_compressed_image() returned with error")
232 }
233 
234 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)235 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapImageInfoNative(
236     JNIEnv *env, jobject thiz, jbyteArray data, jint size, jfloat max_content_boost,
237     jfloat min_content_boost, jfloat gainmap_gamma, jfloat offset_sdr, jfloat offset_hdr,
238     jfloat hdr_capacity_min, jfloat hdr_capacity_max) {
239   GET_HANDLE()
240   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
241   jsize length = env->GetArrayLength(data);
242   RET_IF_TRUE(length < size, "java/io/IOException",
243               "compressed image byteArray size is less than configured size")
244   jbyte *body = env->GetByteArrayElements(data, nullptr);
245   uhdr_compressed_image_t img{body,
246                               (unsigned int)size,
247                               (unsigned int)length,
248                               UHDR_CG_UNSPECIFIED,
249                               UHDR_CT_UNSPECIFIED,
250                               UHDR_CR_UNSPECIFIED};
251   uhdr_gainmap_metadata_t metadata{max_content_boost, min_content_boost, gainmap_gamma,
252                                    offset_sdr,        offset_hdr,        hdr_capacity_min,
253                                    hdr_capacity_max};
254   auto status = uhdr_enc_set_gainmap_image((uhdr_codec_private_t *)handle, &img, &metadata);
255   env->ReleaseByteArrayElements(data, body, 0);
256   RET_IF_TRUE(
257       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
258       status.has_detail ? status.detail : "uhdr_enc_set_gainmap_image() returned with error")
259 }
260 
261 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setExifDataNative(JNIEnv * env,jobject thiz,jbyteArray data,jint size)262 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setExifDataNative(JNIEnv *env, jobject thiz,
263                                                                         jbyteArray data,
264                                                                         jint size) {
265   GET_HANDLE()
266   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
267   jsize length = env->GetArrayLength(data);
268   RET_IF_TRUE(length < size, "java/io/IOException",
269               "compressed image byteArray size is less than configured size")
270   jbyte *body = env->GetByteArrayElements(data, nullptr);
271   uhdr_mem_block_t exif{body, (unsigned int)size, (unsigned int)length};
272   auto status = uhdr_enc_set_exif_data((uhdr_codec_private_t *)handle, &exif);
273   env->ReleaseByteArrayElements(data, body, 0);
274   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
275               status.has_detail ? status.detail : "uhdr_enc_set_exif_data() returned with error")
276 }
277 
278 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setQualityFactorNative(JNIEnv * env,jobject thiz,jint quality_factor,jint intent)279 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setQualityFactorNative(JNIEnv *env,
280                                                                              jobject thiz,
281                                                                              jint quality_factor,
282                                                                              jint intent) {
283   GET_HANDLE()
284   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
285   auto status = uhdr_enc_set_quality((uhdr_codec_private_t *)handle, quality_factor,
286                                      (uhdr_img_label_t)intent);
287   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
288               status.has_detail ? status.detail : "uhdr_enc_set_quality() returned with error")
289 }
290 
291 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setMultiChannelGainMapEncodingNative(JNIEnv * env,jobject thiz,jboolean enable)292 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setMultiChannelGainMapEncodingNative(
293     JNIEnv *env, jobject thiz, jboolean enable) {
294   GET_HANDLE()
295   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
296   auto status =
297       uhdr_enc_set_using_multi_channel_gainmap((uhdr_codec_private_t *)handle, enable ? 1 : 0);
298   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
299               status.has_detail ? status.detail
300                                 : "uhdr_enc_set_using_multi_channel_gainmap() returned with error")
301 }
302 
303 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapScaleFactorNative(JNIEnv * env,jobject thiz,jint scale_factor)304 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapScaleFactorNative(
305     JNIEnv *env, jobject thiz, jint scale_factor) {
306   GET_HANDLE()
307   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
308   auto status = uhdr_enc_set_gainmap_scale_factor((uhdr_codec_private_t *)handle, scale_factor);
309   RET_IF_TRUE(
310       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
311       status.has_detail ? status.detail : "uhdr_enc_set_gainmap_scale_factor() returned with error")
312 }
313 
314 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapGammaNative(JNIEnv * env,jobject thiz,jfloat gamma)315 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapGammaNative(JNIEnv *env,
316                                                                             jobject thiz,
317                                                                             jfloat gamma) {
318   GET_HANDLE()
319   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
320   auto status = uhdr_enc_set_gainmap_gamma((uhdr_codec_private_t *)handle, gamma);
321   RET_IF_TRUE(
322       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
323       status.has_detail ? status.detail : "uhdr_enc_set_gainmap_gamma() returned with error")
324 }
325 
326 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setEncPresetNative(JNIEnv * env,jobject thiz,jint preset)327 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setEncPresetNative(JNIEnv *env, jobject thiz,
328                                                                          jint preset) {
329   GET_HANDLE()
330   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
331   auto status = uhdr_enc_set_preset((uhdr_codec_private_t *)handle, (uhdr_enc_preset_t)preset);
332   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
333               status.has_detail ? status.detail : "uhdr_enc_set_preset() returned with error")
334 }
335 
336 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setOutputFormatNative(JNIEnv * env,jobject thiz,jint media_type)337 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setOutputFormatNative(JNIEnv *env,
338                                                                             jobject thiz,
339                                                                             jint media_type) {
340   GET_HANDLE()
341   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
342   auto status =
343       uhdr_enc_set_output_format((uhdr_codec_private_t *)handle, (uhdr_codec_t)media_type);
344   RET_IF_TRUE(
345       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
346       status.has_detail ? status.detail : "uhdr_enc_set_output_format() returned with error")
347 }
348 
349 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)350 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setMinMaxContentBoostNative(
351     JNIEnv *env, jobject thiz, jfloat min_content_boost, jfloat max_content_boost) {
352   GET_HANDLE()
353   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
354   auto status = uhdr_enc_set_min_max_content_boost((uhdr_codec_private_t *)handle,
355                                                    min_content_boost, max_content_boost);
356   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
357               status.has_detail ? status.detail
358                                 : "uhdr_enc_set_min_max_content_boost() returned with error")
359 }
360 
361 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setTargetDisplayPeakBrightnessNative(JNIEnv * env,jobject thiz,jfloat nits)362 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setTargetDisplayPeakBrightnessNative(
363     JNIEnv *env, jobject thiz, jfloat nits) {
364   GET_HANDLE()
365   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
366   auto status = uhdr_enc_set_target_display_peak_brightness((uhdr_codec_private_t *)handle, nits);
367   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
368               status.has_detail
369                   ? status.detail
370                   : "uhdr_enc_set_target_display_peak_brightness() returned with error")
371 }
372 
373 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_encodeNative(JNIEnv * env,jobject thiz)374 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_encodeNative(JNIEnv *env, jobject thiz) {
375   GET_HANDLE()
376   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
377   auto status = uhdr_encode((uhdr_codec_private_t *)handle);
378   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
379               status.has_detail ? status.detail : "uhdr_encode() returned with error")
380 }
381 
382 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_getOutputNative(JNIEnv * env,jobject thiz)383 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_getOutputNative(JNIEnv *env, jobject thiz) {
384   GET_HANDLE_VAL(nullptr)
385   RET_VAL_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance", nullptr)
386   auto enc_output = uhdr_get_encoded_stream((uhdr_codec_private_t *)handle);
387   RET_VAL_IF_TRUE(enc_output == nullptr, "java/io/IOException",
388                   "no output returned, may be call to uhdr_encode() was not made or encountered "
389                   "error during encoding process.",
390                   nullptr)
391   RET_VAL_IF_TRUE(enc_output->data_sz >= INT32_MAX, "java/lang/OutOfMemoryError",
392                   "encoded output size exceeds integer max", nullptr)
393   jbyteArray output = env->NewByteArray(enc_output->data_sz);
394   RET_VAL_IF_TRUE(output == nullptr, "java/io/IOException", "failed to allocate storage for output",
395                   nullptr)
396   env->SetByteArrayRegion(output, 0, enc_output->data_sz, (jbyte *)enc_output->data);
397   return output;
398 }
399 
400 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_resetNative(JNIEnv * env,jobject thiz)401 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_resetNative(JNIEnv *env, jobject thiz) {
402   GET_HANDLE()
403   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
404   uhdr_reset_encoder((uhdr_codec_private_t *)handle);
405 }
406 
407 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_isUHDRImageNative(JNIEnv * env,jclass clazz,jbyteArray data,jint size)408 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_isUHDRImageNative(JNIEnv *env, jclass clazz,
409                                                                         jbyteArray data,
410                                                                         jint size) {
411   jsize length = env->GetArrayLength(data);
412   RET_VAL_IF_TRUE(length < size, "java/io/IOException",
413                   "compressed image byteArray size is less than configured size", 0)
414   jbyte *body = env->GetByteArrayElements(data, nullptr);
415   auto status = is_uhdr_image(body, size);
416   env->ReleaseByteArrayElements(data, body, 0);
417   return status;
418 }
419 
420 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_init(JNIEnv * env,jobject thiz)421 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_init(JNIEnv *env, jobject thiz) {
422   jclass clazz = env->GetObjectClass(thiz);
423   RET_IF_TRUE(clazz == nullptr, "java/io/IOException", "GetObjectClass returned with error")
424   jfieldID fid = env->GetFieldID(clazz, "handle", "J");
425   RET_IF_TRUE(fid == nullptr, "java/io/IOException",
426               "GetFieldID for field 'handle' returned with error")
427   uhdr_codec_private_t *handle = uhdr_create_decoder();
428   RET_IF_TRUE(handle == nullptr, "java/lang/OutOfMemoryError",
429               "Unable to allocate decoder instance")
430   env->SetLongField(thiz, fid, (jlong)handle);
431 }
432 
433 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_destroy(JNIEnv * env,jobject thiz)434 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_destroy(JNIEnv *env, jobject thiz) {
435   GET_HANDLE()
436   if (!handle) {
437     uhdr_release_decoder((uhdr_codec_private *)handle);
438     env->SetLongField(thiz, fid, (jlong)0);
439   }
440 }
441 
442 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)443 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setCompressedImageNative(
444     JNIEnv *env, jobject thiz, jbyteArray data, jint size, jint color_gamut, jint color_transfer,
445     jint range) {
446   RET_IF_TRUE(size < 0, "java/io/IOException", "invalid compressed image size")
447   GET_HANDLE()
448   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
449   jsize length = env->GetArrayLength(data);
450   RET_IF_TRUE(length < size, "java/io/IOException",
451               "compressed image byteArray size is less than configured size")
452   jbyte *body = env->GetByteArrayElements(data, nullptr);
453   uhdr_compressed_image_t img{body,
454                               (unsigned int)size,
455                               (unsigned int)length,
456                               (uhdr_color_gamut_t)color_gamut,
457                               (uhdr_color_transfer_t)color_transfer,
458                               (uhdr_color_range_t)range};
459   uhdr_error_info_t status = uhdr_dec_set_image((uhdr_codec_private_t *)handle, &img);
460   env->ReleaseByteArrayElements(data, body, 0);
461   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
462               status.has_detail ? status.detail : "uhdr_dec_set_image() returned with error")
463 }
464 
465 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setOutputFormatNative(JNIEnv * env,jobject thiz,jint fmt)466 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setOutputFormatNative(JNIEnv *env,
467                                                                             jobject thiz,
468                                                                             jint fmt) {
469   GET_HANDLE()
470   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
471   uhdr_error_info_t status =
472       uhdr_dec_set_out_img_format((uhdr_codec_private_t *)handle, (uhdr_img_fmt_t)fmt);
473   RET_IF_TRUE(
474       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
475       status.has_detail ? status.detail : "uhdr_dec_set_out_img_format() returned with error")
476 }
477 
478 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setColorTransferNative(JNIEnv * env,jobject thiz,jint ct)479 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setColorTransferNative(JNIEnv *env,
480                                                                              jobject thiz,
481                                                                              jint ct) {
482   GET_HANDLE()
483   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
484   uhdr_error_info_t status =
485       uhdr_dec_set_out_color_transfer((uhdr_codec_private_t *)handle, (uhdr_color_transfer_t)ct);
486   RET_IF_TRUE(
487       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
488       status.has_detail ? status.detail : "uhdr_dec_set_out_color_transfer() returned with error")
489 }
490 
491 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setMaxDisplayBoostNative(JNIEnv * env,jobject thiz,jfloat display_boost)492 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setMaxDisplayBoostNative(
493     JNIEnv *env, jobject thiz, jfloat display_boost) {
494   GET_HANDLE()
495   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
496   uhdr_error_info_t status =
497       uhdr_dec_set_out_max_display_boost((uhdr_codec_private_t *)handle, (float)display_boost);
498   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
499               status.has_detail ? status.detail
500                                 : "uhdr_dec_set_out_max_display_boost() returned with error")
501 }
502 
503 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_enableGpuAccelerationNative(JNIEnv * env,jobject thiz,jint enable)504 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_enableGpuAccelerationNative(JNIEnv *env,
505                                                                                   jobject thiz,
506                                                                                   jint enable) {
507   GET_HANDLE()
508   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
509   uhdr_error_info_t status = uhdr_enable_gpu_acceleration((uhdr_codec_private_t *)handle, enable);
510   RET_IF_TRUE(
511       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
512       status.has_detail ? status.detail : "uhdr_enable_gpu_acceleration() returned with error")
513 }
514 
515 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_probeNative(JNIEnv * env,jobject thiz)516 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_probeNative(JNIEnv *env, jobject thiz) {
517   GET_HANDLE()
518   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
519   uhdr_error_info_t status = uhdr_dec_probe((uhdr_codec_private_t *)handle);
520   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
521               status.has_detail ? status.detail : "uhdr_dec_probe() returned with error")
522 }
523 
524 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageWidthNative(JNIEnv * env,jobject thiz)525 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageWidthNative(JNIEnv *env,
526                                                                           jobject thiz) {
527   GET_HANDLE_VAL(-1)
528   auto val = uhdr_dec_get_image_width((uhdr_codec_private_t *)handle);
529   RET_VAL_IF_TRUE(val == -1, "java/io/IOException",
530                   "uhdr_dec_probe() is not yet called or it has returned with error", -1)
531   return val;
532 }
533 
534 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageHeightNative(JNIEnv * env,jobject thiz)535 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageHeightNative(JNIEnv *env,
536                                                                            jobject thiz) {
537   GET_HANDLE_VAL(-1)
538   auto val = uhdr_dec_get_image_height((uhdr_codec_private_t *)handle);
539   RET_VAL_IF_TRUE(val == -1, "java/io/IOException",
540                   "uhdr_dec_probe() is not yet called or it has returned with error", -1)
541   return val;
542 }
543 
544 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapWidthNative(JNIEnv * env,jobject thiz)545 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapWidthNative(JNIEnv *env,
546                                                                             jobject thiz) {
547   GET_HANDLE_VAL(-1)
548   auto val = uhdr_dec_get_gainmap_width((uhdr_codec_private_t *)handle);
549   RET_VAL_IF_TRUE(val == -1, "java/io/IOException",
550                   "uhdr_dec_probe() is not yet called or it has returned with error", -1)
551   return val;
552 }
553 
554 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapHeightNative(JNIEnv * env,jobject thiz)555 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapHeightNative(JNIEnv *env,
556                                                                              jobject thiz) {
557   GET_HANDLE_VAL(-1)
558   auto val = uhdr_dec_get_gainmap_height((uhdr_codec_private_t *)handle);
559   RET_VAL_IF_TRUE(val == -1, "java/io/IOException",
560                   "uhdr_dec_probe() is not yet called or it has returned with error", -1)
561   return val;
562 }
563 
564 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getExifNative(JNIEnv * env,jobject thiz)565 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getExifNative(JNIEnv *env, jobject thiz) {
566   GET_HANDLE_VAL(nullptr)
567   uhdr_mem_block_t *exifData = uhdr_dec_get_exif((uhdr_codec_private_t *)handle);
568   RET_VAL_IF_TRUE(exifData == nullptr, "java/io/IOException",
569                   "uhdr_dec_probe() is not yet called or it has returned with error", nullptr)
570   jbyteArray data = env->NewByteArray(exifData->data_sz);
571   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
572   std::memcpy(dataptr, exifData->data, exifData->data_sz);
573   env->ReleaseByteArrayElements(data, dataptr, 0);
574   return data;
575 }
576 
577 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getIccNative(JNIEnv * env,jobject thiz)578 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getIccNative(JNIEnv *env, jobject thiz) {
579   GET_HANDLE_VAL(nullptr)
580   uhdr_mem_block_t *iccData = uhdr_dec_get_icc((uhdr_codec_private_t *)handle);
581   RET_VAL_IF_TRUE(iccData == nullptr, "java/io/IOException",
582                   "uhdr_dec_probe() is not yet called or it has returned with error", nullptr)
583   jbyteArray data = env->NewByteArray(iccData->data_sz);
584   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
585   std::memcpy(dataptr, iccData->data, iccData->data_sz);
586   env->ReleaseByteArrayElements(data, dataptr, 0);
587   return data;
588 }
589 
590 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getBaseImageNative(JNIEnv * env,jobject thiz)591 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getBaseImageNative(JNIEnv *env,
592                                                                          jobject thiz) {
593   GET_HANDLE_VAL(nullptr)
594   uhdr_mem_block_t *baseImgData = uhdr_dec_get_base_image((uhdr_codec_private_t *)handle);
595   RET_VAL_IF_TRUE(baseImgData == nullptr, "java/io/IOException",
596                   "uhdr_dec_probe() is not yet called or it has returned with error", nullptr)
597   jbyteArray data = env->NewByteArray(baseImgData->data_sz);
598   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
599   std::memcpy(dataptr, baseImgData->data, baseImgData->data_sz);
600   env->ReleaseByteArrayElements(data, dataptr, 0);
601   return data;
602 }
603 
604 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapImageNative(JNIEnv * env,jobject thiz)605 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapImageNative(JNIEnv *env,
606                                                                             jobject thiz) {
607   GET_HANDLE_VAL(nullptr)
608   uhdr_mem_block_t *gainmapImgData = uhdr_dec_get_gainmap_image((uhdr_codec_private_t *)handle);
609   RET_VAL_IF_TRUE(gainmapImgData == nullptr, "java/io/IOException",
610                   "uhdr_dec_probe() is not yet called or it has returned with error", nullptr)
611   jbyteArray data = env->NewByteArray(gainmapImgData->data_sz);
612   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
613   std::memcpy(dataptr, gainmapImgData->data, gainmapImgData->data_sz);
614   env->ReleaseByteArrayElements(data, dataptr, 0);
615   return data;
616 }
617 
618 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainmapMetadataNative(JNIEnv * env,jobject thiz)619 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainmapMetadataNative(JNIEnv *env,
620                                                                                jobject thiz) {
621   GET_HANDLE()
622   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
623   uhdr_gainmap_metadata_t *gainmap_metadata =
624       uhdr_dec_get_gainmap_metadata((uhdr_codec_private_t *)handle);
625   RET_IF_TRUE(gainmap_metadata == nullptr, "java/io/IOException",
626               "uhdr_dec_probe() is not yet called or it has returned with error")
627 #define SET_FLOAT_FIELD(name, val)                                    \
628   {                                                                   \
629     jfieldID fID = env->GetFieldID(clazz, name, "F");                 \
630     RET_IF_TRUE(fID == nullptr, "java/io/IOException",                \
631                 "GetFieldID for field " #name " returned with error") \
632     env->SetFloatField(thiz, fID, (jfloat)val);                       \
633   }
634   SET_FLOAT_FIELD("maxContentBoost", gainmap_metadata->max_content_boost)
635   SET_FLOAT_FIELD("minContentBoost", gainmap_metadata->min_content_boost)
636   SET_FLOAT_FIELD("gamma", gainmap_metadata->gamma)
637   SET_FLOAT_FIELD("offsetSdr", gainmap_metadata->offset_sdr)
638   SET_FLOAT_FIELD("offsetHdr", gainmap_metadata->offset_hdr)
639   SET_FLOAT_FIELD("hdrCapacityMin", gainmap_metadata->hdr_capacity_min)
640   SET_FLOAT_FIELD("hdrCapacityMax", gainmap_metadata->hdr_capacity_max)
641 }
642 
643 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_decodeNative(JNIEnv * env,jobject thiz)644 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_decodeNative(JNIEnv *env, jobject thiz) {
645   GET_HANDLE()
646   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
647   auto status = uhdr_decode((uhdr_codec_private_t *)handle);
648   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
649               status.has_detail ? status.detail : "uhdr_decode() returned with error")
650 }
651 
652 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedImageNative(JNIEnv * env,jobject thiz)653 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedImageNative(JNIEnv *env,
654                                                                             jobject thiz) {
655   GET_HANDLE_VAL(nullptr)
656   uhdr_raw_image_t *decodedImg = uhdr_get_decoded_image((uhdr_codec_private_t *)handle);
657   RET_VAL_IF_TRUE(decodedImg == nullptr, "java/io/IOException",
658                   "uhdr_decode() is not yet called or it has returned with error", nullptr)
659   int bpp = decodedImg->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ? 8 : 4;
660   jbyteArray data = env->NewByteArray(decodedImg->stride[UHDR_PLANE_PACKED] * decodedImg->h * bpp);
661   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
662   std::memcpy(dataptr, decodedImg->planes[UHDR_PLANE_PACKED],
663               decodedImg->stride[UHDR_PLANE_PACKED] * decodedImg->h * bpp);
664   env->ReleaseByteArrayElements(data, dataptr, 0);
665 #define SET_INT_FIELD(name, val)                                                   \
666   {                                                                                \
667     jfieldID fID = env->GetFieldID(clazz, name, "I");                              \
668     RET_VAL_IF_TRUE(fID == nullptr, "java/io/IOException",                         \
669                     "GetFieldID for field " #name " returned with error", nullptr) \
670     env->SetIntField(thiz, fID, (jint)val);                                        \
671   }
672   SET_INT_FIELD("imgWidth", decodedImg->w)
673   SET_INT_FIELD("imgHeight", decodedImg->h)
674   SET_INT_FIELD("imgStride", decodedImg->stride[UHDR_PLANE_PACKED])
675   SET_INT_FIELD("imgFormat", decodedImg->fmt)
676   SET_INT_FIELD("imgGamut", decodedImg->cg)
677   SET_INT_FIELD("imgTransfer", decodedImg->ct)
678   SET_INT_FIELD("imgRange", decodedImg->range)
679   return data;
680 }
681 
682 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedGainMapImageNative(JNIEnv * env,jobject thiz)683 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedGainMapImageNative(JNIEnv *env,
684                                                                                    jobject thiz) {
685   GET_HANDLE_VAL(nullptr)
686   uhdr_raw_image_t *gainmapImg = uhdr_get_decoded_gainmap_image((uhdr_codec_private_t *)handle);
687   RET_VAL_IF_TRUE(gainmapImg == nullptr, "java/io/IOException",
688                   "uhdr_decode() is not yet called or it has returned with error", nullptr)
689   int bpp = gainmapImg->fmt == UHDR_IMG_FMT_32bppRGBA8888 ? 4 : 1;
690   jbyteArray data = env->NewByteArray(gainmapImg->stride[UHDR_PLANE_PACKED] * gainmapImg->h * bpp);
691   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
692   std::memcpy(dataptr, gainmapImg->planes[UHDR_PLANE_PACKED],
693               gainmapImg->stride[UHDR_PLANE_PACKED] * gainmapImg->h * bpp);
694   env->ReleaseByteArrayElements(data, dataptr, 0);
695   SET_INT_FIELD("gainmapWidth", gainmapImg->w)
696   SET_INT_FIELD("gainmapHeight", gainmapImg->h)
697   SET_INT_FIELD("gainmapStride", gainmapImg->stride[UHDR_PLANE_PACKED])
698   SET_INT_FIELD("gainmapFormat", gainmapImg->fmt)
699   return data;
700 }
701 
702 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_resetNative(JNIEnv * env,jobject thiz)703 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_resetNative(JNIEnv *env, jobject thiz) {
704   GET_HANDLE()
705   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
706   uhdr_reset_decoder((uhdr_codec_private_t *)handle);
707 }
708 
709 extern "C" JNIEXPORT jstring JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionStringNative(JNIEnv * env,jclass clazz)710 Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionStringNative(JNIEnv *env,
711                                                                             jclass clazz) {
712   std::string version{"v" UHDR_LIB_VERSION_STR};
713   return env->NewStringUTF(version.c_str());
714 }
715 
716 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionNative(JNIEnv * env,jclass clazz)717 Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionNative(JNIEnv *env, jclass clazz) {
718   return UHDR_LIB_VERSION;
719 }
720