• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,jfloatArray max_content_boost,jfloatArray min_content_boost,jfloatArray gainmap_gamma,jfloatArray offset_sdr,jfloatArray offset_hdr,jfloat hdr_capacity_min,jfloat hdr_capacity_max,jboolean use_base_color_space)235 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapImageInfoNative(
236     JNIEnv *env, jobject thiz, jbyteArray data, jint size, jfloatArray max_content_boost,
237     jfloatArray min_content_boost, jfloatArray gainmap_gamma, jfloatArray offset_sdr,
238     jfloatArray offset_hdr, jfloat hdr_capacity_min, jfloat hdr_capacity_max,
239     jboolean use_base_color_space) {
240   GET_HANDLE()
241   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
242   jsize length = env->GetArrayLength(data);
243   RET_IF_TRUE(length < size, "java/io/IOException",
244               "compressed image byteArray size is less than configured size")
245   jbyte *body = env->GetByteArrayElements(data, nullptr);
246   uhdr_compressed_image_t img{body,
247                               (unsigned int)size,
248                               (unsigned int)length,
249                               UHDR_CG_UNSPECIFIED,
250                               UHDR_CT_UNSPECIFIED,
251                               UHDR_CR_UNSPECIFIED};
252 
253 #define GET_FLOAT_ARRAY(env, srcArray, dstArray)                                   \
254   {                                                                                \
255     RET_IF_TRUE(srcArray == nullptr, "java/io/IOException", "received nullptr");   \
256     jsize length = env->GetArrayLength(srcArray);                                  \
257     RET_IF_TRUE(length != 3, "java/io/IOException", "array must have 3 elements"); \
258     env->GetFloatArrayRegion(srcArray, 0, 3, dstArray);                            \
259   }
260   uhdr_gainmap_metadata_t metadata{};
261   GET_FLOAT_ARRAY(env, max_content_boost, metadata.max_content_boost)
262   GET_FLOAT_ARRAY(env, min_content_boost, metadata.min_content_boost)
263   GET_FLOAT_ARRAY(env, gainmap_gamma, metadata.gamma)
264   GET_FLOAT_ARRAY(env, offset_sdr, metadata.offset_sdr)
265   GET_FLOAT_ARRAY(env, offset_hdr, metadata.offset_hdr)
266   metadata.hdr_capacity_min = hdr_capacity_min;
267   metadata.hdr_capacity_max = hdr_capacity_max;
268   metadata.use_base_cg = use_base_color_space;
269   auto status = uhdr_enc_set_gainmap_image((uhdr_codec_private_t *)handle, &img, &metadata);
270   env->ReleaseByteArrayElements(data, body, 0);
271   RET_IF_TRUE(
272       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
273       status.has_detail ? status.detail : "uhdr_enc_set_gainmap_image() returned with error")
274 }
275 
276 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setExifDataNative(JNIEnv * env,jobject thiz,jbyteArray data,jint size)277 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setExifDataNative(JNIEnv *env, jobject thiz,
278                                                                         jbyteArray data,
279                                                                         jint size) {
280   GET_HANDLE()
281   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
282   jsize length = env->GetArrayLength(data);
283   RET_IF_TRUE(length < size, "java/io/IOException",
284               "compressed image byteArray size is less than configured size")
285   jbyte *body = env->GetByteArrayElements(data, nullptr);
286   uhdr_mem_block_t exif{body, (unsigned int)size, (unsigned int)length};
287   auto status = uhdr_enc_set_exif_data((uhdr_codec_private_t *)handle, &exif);
288   env->ReleaseByteArrayElements(data, body, 0);
289   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
290               status.has_detail ? status.detail : "uhdr_enc_set_exif_data() returned with error")
291 }
292 
293 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setQualityFactorNative(JNIEnv * env,jobject thiz,jint quality_factor,jint intent)294 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setQualityFactorNative(JNIEnv *env,
295                                                                              jobject thiz,
296                                                                              jint quality_factor,
297                                                                              jint intent) {
298   GET_HANDLE()
299   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
300   auto status = uhdr_enc_set_quality((uhdr_codec_private_t *)handle, quality_factor,
301                                      (uhdr_img_label_t)intent);
302   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
303               status.has_detail ? status.detail : "uhdr_enc_set_quality() returned with error")
304 }
305 
306 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setMultiChannelGainMapEncodingNative(JNIEnv * env,jobject thiz,jboolean enable)307 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setMultiChannelGainMapEncodingNative(
308     JNIEnv *env, jobject thiz, jboolean enable) {
309   GET_HANDLE()
310   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
311   auto status =
312       uhdr_enc_set_using_multi_channel_gainmap((uhdr_codec_private_t *)handle, enable ? 1 : 0);
313   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
314               status.has_detail ? status.detail
315                                 : "uhdr_enc_set_using_multi_channel_gainmap() returned with error")
316 }
317 
318 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapScaleFactorNative(JNIEnv * env,jobject thiz,jint scale_factor)319 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapScaleFactorNative(
320     JNIEnv *env, jobject thiz, jint scale_factor) {
321   GET_HANDLE()
322   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
323   auto status = uhdr_enc_set_gainmap_scale_factor((uhdr_codec_private_t *)handle, scale_factor);
324   RET_IF_TRUE(
325       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
326       status.has_detail ? status.detail : "uhdr_enc_set_gainmap_scale_factor() returned with error")
327 }
328 
329 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapGammaNative(JNIEnv * env,jobject thiz,jfloat gamma)330 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setGainMapGammaNative(JNIEnv *env,
331                                                                             jobject thiz,
332                                                                             jfloat gamma) {
333   GET_HANDLE()
334   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
335   auto status = uhdr_enc_set_gainmap_gamma((uhdr_codec_private_t *)handle, gamma);
336   RET_IF_TRUE(
337       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
338       status.has_detail ? status.detail : "uhdr_enc_set_gainmap_gamma() returned with error")
339 }
340 
341 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setEncPresetNative(JNIEnv * env,jobject thiz,jint preset)342 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setEncPresetNative(JNIEnv *env, jobject thiz,
343                                                                          jint preset) {
344   GET_HANDLE()
345   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
346   auto status = uhdr_enc_set_preset((uhdr_codec_private_t *)handle, (uhdr_enc_preset_t)preset);
347   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
348               status.has_detail ? status.detail : "uhdr_enc_set_preset() returned with error")
349 }
350 
351 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setOutputFormatNative(JNIEnv * env,jobject thiz,jint media_type)352 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setOutputFormatNative(JNIEnv *env,
353                                                                             jobject thiz,
354                                                                             jint media_type) {
355   GET_HANDLE()
356   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
357   auto status =
358       uhdr_enc_set_output_format((uhdr_codec_private_t *)handle, (uhdr_codec_t)media_type);
359   RET_IF_TRUE(
360       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
361       status.has_detail ? status.detail : "uhdr_enc_set_output_format() returned with error")
362 }
363 
364 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)365 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setMinMaxContentBoostNative(
366     JNIEnv *env, jobject thiz, jfloat min_content_boost, jfloat max_content_boost) {
367   GET_HANDLE()
368   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
369   auto status = uhdr_enc_set_min_max_content_boost((uhdr_codec_private_t *)handle,
370                                                    min_content_boost, max_content_boost);
371   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
372               status.has_detail ? status.detail
373                                 : "uhdr_enc_set_min_max_content_boost() returned with error")
374 }
375 
376 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setTargetDisplayPeakBrightnessNative(JNIEnv * env,jobject thiz,jfloat nits)377 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_setTargetDisplayPeakBrightnessNative(
378     JNIEnv *env, jobject thiz, jfloat nits) {
379   GET_HANDLE()
380   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
381   auto status = uhdr_enc_set_target_display_peak_brightness((uhdr_codec_private_t *)handle, nits);
382   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
383               status.has_detail
384                   ? status.detail
385                   : "uhdr_enc_set_target_display_peak_brightness() returned with error")
386 }
387 
388 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_encodeNative(JNIEnv * env,jobject thiz)389 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_encodeNative(JNIEnv *env, jobject thiz) {
390   GET_HANDLE()
391   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
392   auto status = uhdr_encode((uhdr_codec_private_t *)handle);
393   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
394               status.has_detail ? status.detail : "uhdr_encode() returned with error")
395 }
396 
397 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_getOutputNative(JNIEnv * env,jobject thiz)398 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_getOutputNative(JNIEnv *env, jobject thiz) {
399   GET_HANDLE_VAL(nullptr)
400   RET_VAL_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance", nullptr)
401   auto enc_output = uhdr_get_encoded_stream((uhdr_codec_private_t *)handle);
402   RET_VAL_IF_TRUE(enc_output == nullptr, "java/io/IOException",
403                   "no output returned, may be call to uhdr_encode() was not made or encountered "
404                   "error during encoding process.",
405                   nullptr)
406   RET_VAL_IF_TRUE(enc_output->data_sz >= INT32_MAX, "java/lang/OutOfMemoryError",
407                   "encoded output size exceeds integer max", nullptr)
408   jbyteArray output = env->NewByteArray(enc_output->data_sz);
409   RET_VAL_IF_TRUE(output == nullptr, "java/io/IOException", "failed to allocate storage for output",
410                   nullptr)
411   env->SetByteArrayRegion(output, 0, enc_output->data_sz, (jbyte *)enc_output->data);
412   return output;
413 }
414 
415 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_resetNative(JNIEnv * env,jobject thiz)416 Java_com_google_media_codecs_ultrahdr_UltraHDREncoder_resetNative(JNIEnv *env, jobject thiz) {
417   GET_HANDLE()
418   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid encoder instance")
419   uhdr_reset_encoder((uhdr_codec_private_t *)handle);
420 }
421 
422 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_isUHDRImageNative(JNIEnv * env,jclass clazz,jbyteArray data,jint size)423 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_isUHDRImageNative(JNIEnv *env, jclass clazz,
424                                                                         jbyteArray data,
425                                                                         jint size) {
426   jsize length = env->GetArrayLength(data);
427   RET_VAL_IF_TRUE(length < size, "java/io/IOException",
428                   "compressed image byteArray size is less than configured size", 0)
429   jbyte *body = env->GetByteArrayElements(data, nullptr);
430   auto status = is_uhdr_image(body, size);
431   env->ReleaseByteArrayElements(data, body, 0);
432   return status;
433 }
434 
435 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_init(JNIEnv * env,jobject thiz)436 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_init(JNIEnv *env, jobject thiz) {
437   jclass clazz = env->GetObjectClass(thiz);
438   RET_IF_TRUE(clazz == nullptr, "java/io/IOException", "GetObjectClass returned with error")
439   jfieldID fid = env->GetFieldID(clazz, "handle", "J");
440   RET_IF_TRUE(fid == nullptr, "java/io/IOException",
441               "GetFieldID for field 'handle' returned with error")
442   uhdr_codec_private_t *handle = uhdr_create_decoder();
443   RET_IF_TRUE(handle == nullptr, "java/lang/OutOfMemoryError",
444               "Unable to allocate decoder instance")
445   env->SetLongField(thiz, fid, (jlong)handle);
446 }
447 
448 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_destroy(JNIEnv * env,jobject thiz)449 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_destroy(JNIEnv *env, jobject thiz) {
450   GET_HANDLE()
451   if (!handle) {
452     uhdr_release_decoder((uhdr_codec_private *)handle);
453     env->SetLongField(thiz, fid, (jlong)0);
454   }
455 }
456 
457 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)458 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setCompressedImageNative(
459     JNIEnv *env, jobject thiz, jbyteArray data, jint size, jint color_gamut, jint color_transfer,
460     jint range) {
461   RET_IF_TRUE(size < 0, "java/io/IOException", "invalid compressed image size")
462   GET_HANDLE()
463   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
464   jsize length = env->GetArrayLength(data);
465   RET_IF_TRUE(length < size, "java/io/IOException",
466               "compressed image byteArray size is less than configured size")
467   jbyte *body = env->GetByteArrayElements(data, nullptr);
468   uhdr_compressed_image_t img{body,
469                               (unsigned int)size,
470                               (unsigned int)length,
471                               (uhdr_color_gamut_t)color_gamut,
472                               (uhdr_color_transfer_t)color_transfer,
473                               (uhdr_color_range_t)range};
474   uhdr_error_info_t status = uhdr_dec_set_image((uhdr_codec_private_t *)handle, &img);
475   env->ReleaseByteArrayElements(data, body, 0);
476   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
477               status.has_detail ? status.detail : "uhdr_dec_set_image() returned with error")
478 }
479 
480 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setOutputFormatNative(JNIEnv * env,jobject thiz,jint fmt)481 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setOutputFormatNative(JNIEnv *env,
482                                                                             jobject thiz,
483                                                                             jint fmt) {
484   GET_HANDLE()
485   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
486   uhdr_error_info_t status =
487       uhdr_dec_set_out_img_format((uhdr_codec_private_t *)handle, (uhdr_img_fmt_t)fmt);
488   RET_IF_TRUE(
489       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
490       status.has_detail ? status.detail : "uhdr_dec_set_out_img_format() returned with error")
491 }
492 
493 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setColorTransferNative(JNIEnv * env,jobject thiz,jint ct)494 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setColorTransferNative(JNIEnv *env,
495                                                                              jobject thiz,
496                                                                              jint ct) {
497   GET_HANDLE()
498   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
499   uhdr_error_info_t status =
500       uhdr_dec_set_out_color_transfer((uhdr_codec_private_t *)handle, (uhdr_color_transfer_t)ct);
501   RET_IF_TRUE(
502       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
503       status.has_detail ? status.detail : "uhdr_dec_set_out_color_transfer() returned with error")
504 }
505 
506 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setMaxDisplayBoostNative(JNIEnv * env,jobject thiz,jfloat display_boost)507 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_setMaxDisplayBoostNative(
508     JNIEnv *env, jobject thiz, jfloat display_boost) {
509   GET_HANDLE()
510   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
511   uhdr_error_info_t status =
512       uhdr_dec_set_out_max_display_boost((uhdr_codec_private_t *)handle, (float)display_boost);
513   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
514               status.has_detail ? status.detail
515                                 : "uhdr_dec_set_out_max_display_boost() returned with error")
516 }
517 
518 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_enableGpuAccelerationNative(JNIEnv * env,jobject thiz,jint enable)519 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_enableGpuAccelerationNative(JNIEnv *env,
520                                                                                   jobject thiz,
521                                                                                   jint enable) {
522   GET_HANDLE()
523   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
524   uhdr_error_info_t status = uhdr_enable_gpu_acceleration((uhdr_codec_private_t *)handle, enable);
525   RET_IF_TRUE(
526       status.error_code != UHDR_CODEC_OK, "java/io/IOException",
527       status.has_detail ? status.detail : "uhdr_enable_gpu_acceleration() returned with error")
528 }
529 
530 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_probeNative(JNIEnv * env,jobject thiz)531 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_probeNative(JNIEnv *env, jobject thiz) {
532   GET_HANDLE()
533   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
534   uhdr_error_info_t status = uhdr_dec_probe((uhdr_codec_private_t *)handle);
535   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
536               status.has_detail ? status.detail : "uhdr_dec_probe() returned with error")
537 }
538 
539 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageWidthNative(JNIEnv * env,jobject thiz)540 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageWidthNative(JNIEnv *env,
541                                                                           jobject thiz) {
542   GET_HANDLE_VAL(-1)
543   auto val = uhdr_dec_get_image_width((uhdr_codec_private_t *)handle);
544   RET_VAL_IF_TRUE(val == -1, "java/io/IOException",
545                   "uhdr_dec_probe() is not yet called or it has returned with error", -1)
546   return val;
547 }
548 
549 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageHeightNative(JNIEnv * env,jobject thiz)550 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getImageHeightNative(JNIEnv *env,
551                                                                            jobject thiz) {
552   GET_HANDLE_VAL(-1)
553   auto val = uhdr_dec_get_image_height((uhdr_codec_private_t *)handle);
554   RET_VAL_IF_TRUE(val == -1, "java/io/IOException",
555                   "uhdr_dec_probe() is not yet called or it has returned with error", -1)
556   return val;
557 }
558 
559 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapWidthNative(JNIEnv * env,jobject thiz)560 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapWidthNative(JNIEnv *env,
561                                                                             jobject thiz) {
562   GET_HANDLE_VAL(-1)
563   auto val = uhdr_dec_get_gainmap_width((uhdr_codec_private_t *)handle);
564   RET_VAL_IF_TRUE(val == -1, "java/io/IOException",
565                   "uhdr_dec_probe() is not yet called or it has returned with error", -1)
566   return val;
567 }
568 
569 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapHeightNative(JNIEnv * env,jobject thiz)570 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapHeightNative(JNIEnv *env,
571                                                                              jobject thiz) {
572   GET_HANDLE_VAL(-1)
573   auto val = uhdr_dec_get_gainmap_height((uhdr_codec_private_t *)handle);
574   RET_VAL_IF_TRUE(val == -1, "java/io/IOException",
575                   "uhdr_dec_probe() is not yet called or it has returned with error", -1)
576   return val;
577 }
578 
579 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getExifNative(JNIEnv * env,jobject thiz)580 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getExifNative(JNIEnv *env, jobject thiz) {
581   GET_HANDLE_VAL(nullptr)
582   uhdr_mem_block_t *exifData = uhdr_dec_get_exif((uhdr_codec_private_t *)handle);
583   RET_VAL_IF_TRUE(exifData == nullptr, "java/io/IOException",
584                   "uhdr_dec_probe() is not yet called or it has returned with error", nullptr)
585   jbyteArray data = env->NewByteArray(exifData->data_sz);
586   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
587   std::memcpy(dataptr, exifData->data, exifData->data_sz);
588   env->ReleaseByteArrayElements(data, dataptr, 0);
589   return data;
590 }
591 
592 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getIccNative(JNIEnv * env,jobject thiz)593 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getIccNative(JNIEnv *env, jobject thiz) {
594   GET_HANDLE_VAL(nullptr)
595   uhdr_mem_block_t *iccData = uhdr_dec_get_icc((uhdr_codec_private_t *)handle);
596   RET_VAL_IF_TRUE(iccData == nullptr, "java/io/IOException",
597                   "uhdr_dec_probe() is not yet called or it has returned with error", nullptr)
598   jbyteArray data = env->NewByteArray(iccData->data_sz);
599   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
600   std::memcpy(dataptr, iccData->data, iccData->data_sz);
601   env->ReleaseByteArrayElements(data, dataptr, 0);
602   return data;
603 }
604 
605 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getBaseImageNative(JNIEnv * env,jobject thiz)606 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getBaseImageNative(JNIEnv *env,
607                                                                          jobject thiz) {
608   GET_HANDLE_VAL(nullptr)
609   uhdr_mem_block_t *baseImgData = uhdr_dec_get_base_image((uhdr_codec_private_t *)handle);
610   RET_VAL_IF_TRUE(baseImgData == nullptr, "java/io/IOException",
611                   "uhdr_dec_probe() is not yet called or it has returned with error", nullptr)
612   jbyteArray data = env->NewByteArray(baseImgData->data_sz);
613   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
614   std::memcpy(dataptr, baseImgData->data, baseImgData->data_sz);
615   env->ReleaseByteArrayElements(data, dataptr, 0);
616   return data;
617 }
618 
619 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapImageNative(JNIEnv * env,jobject thiz)620 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainMapImageNative(JNIEnv *env,
621                                                                             jobject thiz) {
622   GET_HANDLE_VAL(nullptr)
623   uhdr_mem_block_t *gainmapImgData = uhdr_dec_get_gainmap_image((uhdr_codec_private_t *)handle);
624   RET_VAL_IF_TRUE(gainmapImgData == nullptr, "java/io/IOException",
625                   "uhdr_dec_probe() is not yet called or it has returned with error", nullptr)
626   jbyteArray data = env->NewByteArray(gainmapImgData->data_sz);
627   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
628   std::memcpy(dataptr, gainmapImgData->data, gainmapImgData->data_sz);
629   env->ReleaseByteArrayElements(data, dataptr, 0);
630   return data;
631 }
632 
633 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainmapMetadataNative(JNIEnv * env,jobject thiz)634 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getGainmapMetadataNative(JNIEnv *env,
635                                                                                jobject thiz) {
636   GET_HANDLE()
637   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
638   uhdr_gainmap_metadata_t *gainmap_metadata =
639       uhdr_dec_get_gainmap_metadata((uhdr_codec_private_t *)handle);
640   RET_IF_TRUE(gainmap_metadata == nullptr, "java/io/IOException",
641               "uhdr_dec_probe() is not yet called or it has returned with error")
642 #define SET_FLOAT_ARRAY_FIELD(name, valArray)                         \
643   {                                                                   \
644     jfieldID fID = env->GetFieldID(clazz, name, "[F");                \
645     RET_IF_TRUE(fID == nullptr, "java/io/IOException",                \
646                 "GetFieldID for field " #name " returned with error") \
647     jfloatArray array = env->NewFloatArray(3);                        \
648     RET_IF_TRUE(array == nullptr, "java/io/IOException",              \
649                 "Failed to allocate float array for field " #name)    \
650     env->SetFloatArrayRegion(array, 0, 3, (const jfloat *)valArray);  \
651     env->SetObjectField(thiz, fID, array);                            \
652     env->DeleteLocalRef(array);                                       \
653   }
654 
655 #define SET_FLOAT_FIELD(name, val)                                    \
656   {                                                                   \
657     jfieldID fID = env->GetFieldID(clazz, name, "F");                 \
658     RET_IF_TRUE(fID == nullptr, "java/io/IOException",                \
659                 "GetFieldID for field " #name " returned with error") \
660     env->SetFloatField(thiz, fID, (jfloat)val);                       \
661   }
662   SET_FLOAT_ARRAY_FIELD("maxContentBoost", gainmap_metadata->max_content_boost)
663   SET_FLOAT_ARRAY_FIELD("minContentBoost", gainmap_metadata->min_content_boost)
664   SET_FLOAT_ARRAY_FIELD("gamma", gainmap_metadata->gamma)
665   SET_FLOAT_ARRAY_FIELD("offsetSdr", gainmap_metadata->offset_sdr)
666   SET_FLOAT_ARRAY_FIELD("offsetHdr", gainmap_metadata->offset_hdr)
667   SET_FLOAT_FIELD("hdrCapacityMin", gainmap_metadata->hdr_capacity_min)
668   SET_FLOAT_FIELD("hdrCapacityMax", gainmap_metadata->hdr_capacity_max)
669 #define SET_BOOLEAN_FIELD(name, val)                                  \
670   {                                                                   \
671     jfieldID fID = env->GetFieldID(clazz, name, "Z");                 \
672     RET_IF_TRUE(fID == nullptr, "java/io/IOException",                \
673                 "GetFieldID for field " #name " returned with error") \
674     env->SetBooleanField(thiz, fID, (jboolean)val);                   \
675   }
676   SET_BOOLEAN_FIELD("useBaseColorSpace", gainmap_metadata->use_base_cg)
677 }
678 
679 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_decodeNative(JNIEnv * env,jobject thiz)680 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_decodeNative(JNIEnv *env, jobject thiz) {
681   GET_HANDLE()
682   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
683   auto status = uhdr_decode((uhdr_codec_private_t *)handle);
684   RET_IF_TRUE(status.error_code != UHDR_CODEC_OK, "java/io/IOException",
685               status.has_detail ? status.detail : "uhdr_decode() returned with error")
686 }
687 
688 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedImageNative(JNIEnv * env,jobject thiz)689 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedImageNative(JNIEnv *env,
690                                                                             jobject thiz) {
691   GET_HANDLE_VAL(nullptr)
692   uhdr_raw_image_t *decodedImg = uhdr_get_decoded_image((uhdr_codec_private_t *)handle);
693   RET_VAL_IF_TRUE(decodedImg == nullptr, "java/io/IOException",
694                   "uhdr_decode() is not yet called or it has returned with error", nullptr)
695   int bpp = decodedImg->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ? 8 : 4;
696   jbyteArray data = env->NewByteArray(decodedImg->stride[UHDR_PLANE_PACKED] * decodedImg->h * bpp);
697   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
698   std::memcpy(dataptr, decodedImg->planes[UHDR_PLANE_PACKED],
699               decodedImg->stride[UHDR_PLANE_PACKED] * decodedImg->h * bpp);
700   env->ReleaseByteArrayElements(data, dataptr, 0);
701 #define SET_INT_FIELD(name, val)                                                   \
702   {                                                                                \
703     jfieldID fID = env->GetFieldID(clazz, name, "I");                              \
704     RET_VAL_IF_TRUE(fID == nullptr, "java/io/IOException",                         \
705                     "GetFieldID for field " #name " returned with error", nullptr) \
706     env->SetIntField(thiz, fID, (jint)val);                                        \
707   }
708   SET_INT_FIELD("imgWidth", decodedImg->w)
709   SET_INT_FIELD("imgHeight", decodedImg->h)
710   SET_INT_FIELD("imgStride", decodedImg->stride[UHDR_PLANE_PACKED])
711   SET_INT_FIELD("imgFormat", decodedImg->fmt)
712   SET_INT_FIELD("imgGamut", decodedImg->cg)
713   SET_INT_FIELD("imgTransfer", decodedImg->ct)
714   SET_INT_FIELD("imgRange", decodedImg->range)
715   return data;
716 }
717 
718 extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedGainMapImageNative(JNIEnv * env,jobject thiz)719 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_getDecodedGainMapImageNative(JNIEnv *env,
720                                                                                    jobject thiz) {
721   GET_HANDLE_VAL(nullptr)
722   uhdr_raw_image_t *gainmapImg = uhdr_get_decoded_gainmap_image((uhdr_codec_private_t *)handle);
723   RET_VAL_IF_TRUE(gainmapImg == nullptr, "java/io/IOException",
724                   "uhdr_decode() is not yet called or it has returned with error", nullptr)
725   int bpp = gainmapImg->fmt == UHDR_IMG_FMT_32bppRGBA8888 ? 4 : 1;
726   jbyteArray data = env->NewByteArray(gainmapImg->stride[UHDR_PLANE_PACKED] * gainmapImg->h * bpp);
727   jbyte *dataptr = env->GetByteArrayElements(data, nullptr);
728   std::memcpy(dataptr, gainmapImg->planes[UHDR_PLANE_PACKED],
729               gainmapImg->stride[UHDR_PLANE_PACKED] * gainmapImg->h * bpp);
730   env->ReleaseByteArrayElements(data, dataptr, 0);
731   SET_INT_FIELD("gainmapWidth", gainmapImg->w)
732   SET_INT_FIELD("gainmapHeight", gainmapImg->h)
733   SET_INT_FIELD("gainmapStride", gainmapImg->stride[UHDR_PLANE_PACKED])
734   SET_INT_FIELD("gainmapFormat", gainmapImg->fmt)
735   return data;
736 }
737 
738 extern "C" JNIEXPORT void JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_resetNative(JNIEnv * env,jobject thiz)739 Java_com_google_media_codecs_ultrahdr_UltraHDRDecoder_resetNative(JNIEnv *env, jobject thiz) {
740   GET_HANDLE()
741   RET_IF_TRUE(handle == 0, "java/io/IOException", "invalid decoder instance")
742   uhdr_reset_decoder((uhdr_codec_private_t *)handle);
743 }
744 
745 extern "C" JNIEXPORT jstring JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionStringNative(JNIEnv * env,jclass clazz)746 Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionStringNative(JNIEnv *env,
747                                                                             jclass clazz) {
748   std::string version{"v" UHDR_LIB_VERSION_STR};
749   return env->NewStringUTF(version.c_str());
750 }
751 
752 extern "C" JNIEXPORT jint JNICALL
Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionNative(JNIEnv * env,jclass clazz)753 Java_com_google_media_codecs_ultrahdr_UltraHDRCommon_getVersionNative(JNIEnv *env, jclass clazz) {
754   return UHDR_LIB_VERSION;
755 }
756