android_jni: Make thread count configurable

Add a new function which lets the user pass the number of decoding
threads as part of the JNI API.
diff --git a/android_jni/avifandroidjni/src/main/java/org/aomedia/avif/android/AvifDecoder.java b/android_jni/avifandroidjni/src/main/java/org/aomedia/avif/android/AvifDecoder.java
index 931b07c..25c3b3c 100644
--- a/android_jni/avifandroidjni/src/main/java/org/aomedia/avif/android/AvifDecoder.java
+++ b/android_jni/avifandroidjni/src/main/java/org/aomedia/avif/android/AvifDecoder.java
@@ -58,5 +58,23 @@
    * @return true on success and false on failure. A few possible reasons for failure are: 1) Input
    *     was not valid AVIF. 2) Bitmap was not large enough to store the decoded image.
    */
-  public static native boolean decode(ByteBuffer encoded, int length, Bitmap bitmap);
+  public static boolean decode(ByteBuffer encoded, int length, Bitmap bitmap) {
+    return decode(encoded, length, bitmap, 0);
+  }
+
+  /**
+   * Decodes the AVIF image into the bitmap.
+   *
+   * @param encoded The encoded AVIF image. encoded.position() must be 0.
+   * @param length Length of the encoded buffer.
+   * @param bitmap The decoded pixels will be copied into the bitmap.
+   * @param threads Number of threads to be used for the AVIF decode. Zero means use number of CPU
+   *     cores as the thread count. Negative values are invalid. When this value is > 0, it is
+   *     simply mapped to the maxThreads parameter in libavif. For more details, see the
+   *     documentation for maxThreads variable in avif.h.
+   * @return true on success and false on failure. A few possible reasons for failure are: 1) Input
+   *     was not valid AVIF. 2) Bitmap was not large enough to store the decoded image. 3) Negative
+   *     value was passed for the threads parameter.
+   */
+  public static native boolean decode(ByteBuffer encoded, int length, Bitmap bitmap, int threads);
 }
diff --git a/android_jni/avifandroidjni/src/main/jni/libavif_jni.cc b/android_jni/avifandroidjni/src/main/jni/libavif_jni.cc
index 8e0afa5..33a7d49 100644
--- a/android_jni/avifandroidjni/src/main/jni/libavif_jni.cc
+++ b/android_jni/avifandroidjni/src/main/jni/libavif_jni.cc
@@ -112,12 +112,18 @@
   return true;
 }
 
-FUNC(jboolean, decode, jobject encoded, int length, jobject bitmap) {
+FUNC(jboolean, decode, jobject encoded, int length, jobject bitmap,
+     jint threads) {
+  if (threads < 0) {
+    LOGE("Invalid value for threads (%d).", threads);
+    return false;
+  }
   const uint8_t* const buffer =
       static_cast<const uint8_t*>(env->GetDirectBufferAddress(encoded));
   AvifDecoderWrapper decoder;
-  if (!CreateDecoderAndParse(&decoder, buffer, length,
-                             android_getCpuCount())) {
+  if (!CreateDecoderAndParse(
+      &decoder, buffer, length,
+      (threads == 0) ? android_getCpuCount() : threads)) {
     return false;
   }
   avifResult res = avifDecoderNextImage(decoder.decoder);