/*
 * Copyright (C) 2012, Collabora Ltd.
 * Copyright (C) 2012, Cisco Systems, Inc.
 *   Author: Youness Alaoui <youness.alaoui@collabora.co.uk>
 *
 * Copyright (C) 2015, Collabora Ltd.
 *   Author: Justin Kim <justin.kim@collabora.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation
 * version 2.1 of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gstjniutils.h"

#include "gst-android-hardware-camera.h"

GST_DEBUG_CATEGORY_STATIC (ahc_debug);
#define GST_CAT_DEFAULT ahc_debug

#define GST_DVM_STATIC_CALL(error_statement, type, k, method, ...)      \
  (*env)->CallStatic##type##Method (env, k.klass, k.method, ## __VA_ARGS__); \
  if ((*env)->ExceptionCheck (env)) {                                   \
    GST_ERROR ("Failed to call Java method");                           \
    (*env)->ExceptionDescribe (env);                                    \
    (*env)->ExceptionClear (env);                                       \
    error_statement;                                                    \
  }

#define GST_DVM_CALL(error_statement, obj, type, k, method, ...)        \
  (*env)->Call##type##Method (env, obj, k.method, ## __VA_ARGS__);      \
  if ((*env)->ExceptionCheck (env)) {                                   \
    GST_ERROR ("Failed to call Java method");                           \
    (*env)->ExceptionDescribe (env);                                    \
    (*env)->ExceptionClear (env);                                       \
    error_statement;                                                    \
  }



static struct
{
  jclass klass;
  jmethodID addCallbackBuffer;
  jmethodID autoFocus;
  jmethodID cancelAutoFocus;
  jmethodID getCameraInfo;
  jmethodID getNumberOfCameras;
  jmethodID getParameters;
  jmethodID lock;
  jmethodID open;
  jmethodID reconnect;
  jmethodID release;
  jmethodID setErrorCallback;
  jmethodID setParameters;
  jmethodID setPreviewCallbackWithBuffer;
  jmethodID setPreviewTexture;
  jmethodID startPreview;
  jmethodID startSmoothZoom;
  jmethodID stopPreview;
  jmethodID stopSmoothZoom;
  jmethodID unlock;
} android_hardware_camera = {
0};

static struct
{
  jclass klass;
  jmethodID constructor;
  jfieldID facing;
  jfieldID orientation;
  jint CAMERA_FACING_BACK;
  jint CAMERA_FACING_FRONT;
} android_hardware_camera_camerainfo = {
0};

gint CameraInfo_CAMERA_FACING_BACK;
gint CameraInfo_CAMERA_FACING_FRONT;

static struct
{
  jclass klass;
  jfieldID width;
  jfieldID height;
} android_hardware_camera_size = {
0};

static struct
{
  jclass klass;
  jmethodID flatten;
  jmethodID getAntibanding;
  jmethodID getColorEffect;
  jmethodID getExposureCompensation;
  jmethodID getExposureCompensationStep;
  jmethodID getFlashMode;
  jmethodID getFocalLength;
  jmethodID getFocusMode;
  jmethodID getHorizontalViewAngle;
  jmethodID getMaxExposureCompensation;
  jmethodID getMaxZoom;
  jmethodID getMinExposureCompensation;
  jmethodID getPreviewFormat;
  jmethodID getPreviewFpsRange;
  jmethodID getPreviewSize;
  jmethodID getSceneMode;
  jmethodID getSupportedAntibanding;
  jmethodID getSupportedColorEffects;
  jmethodID getSupportedFlashModes;
  jmethodID getSupportedFocusModes;
  jmethodID getSupportedPreviewFormats;
  jmethodID getSupportedPreviewFpsRange;
  jmethodID getSupportedPreviewSizes;
  jmethodID getSupportedSceneModes;
  jmethodID getSupportedWhiteBalance;
  jmethodID getVerticalViewAngle;
  jmethodID getVideoStabilization;
  jmethodID getWhiteBalance;
  jmethodID getZoom;
  jmethodID getZoomRatios;
  jmethodID isSmoothZoomSupported;
  jmethodID isVideoStabilizationSupported;
  jmethodID isZoomSupported;
  jmethodID setAntibanding;
  jmethodID setColorEffect;
  jmethodID setExposureCompensation;
  jmethodID setFlashMode;
  jmethodID setFocusMode;
  jmethodID setPreviewFormat;
  jmethodID setPreviewFpsRange;
  jmethodID setPreviewSize;
  jmethodID setSceneMode;
  jmethodID setVideoStabilization;
  jmethodID setWhiteBalance;
  jmethodID setZoom;
  jmethodID unflatten;
  jstring WHITE_BALANCE_AUTO;
  jstring WHITE_BALANCE_INCANDESCENT;
  jstring WHITE_BALANCE_FLUORESCENT;
  jstring WHITE_BALANCE_WARM_FLUORESCENT;
  jstring WHITE_BALANCE_DAYLIGHT;
  jstring WHITE_BALANCE_CLOUDY_DAYLIGHT;
  jstring WHITE_BALANCE_TWILIGHT;
  jstring WHITE_BALANCE_SHADE;
  jstring EFFECT_NONE;
  jstring EFFECT_MONO;
  jstring EFFECT_NEGATIVE;
  jstring EFFECT_SOLARIZE;
  jstring EFFECT_SEPIA;
  jstring EFFECT_POSTERIZE;
  jstring EFFECT_WHITEBOARD;
  jstring EFFECT_BLACKBOARD;
  jstring EFFECT_AQUA;
  jstring ANTIBANDING_AUTO;
  jstring ANTIBANDING_50HZ;
  jstring ANTIBANDING_60HZ;
  jstring ANTIBANDING_OFF;
  jstring FLASH_MODE_OFF;
  jstring FLASH_MODE_AUTO;
  jstring FLASH_MODE_ON;
  jstring FLASH_MODE_RED_EYE;
  jstring FLASH_MODE_TORCH;
  jstring SCENE_MODE_AUTO;
  jstring SCENE_MODE_ACTION;
  jstring SCENE_MODE_PORTRAIT;
  jstring SCENE_MODE_LANDSCAPE;
  jstring SCENE_MODE_NIGHT;
  jstring SCENE_MODE_NIGHT_PORTRAIT;
  jstring SCENE_MODE_THEATRE;
  jstring SCENE_MODE_BEACH;
  jstring SCENE_MODE_SNOW;
  jstring SCENE_MODE_SUNSET;
  jstring SCENE_MODE_STEADYPHOTO;
  jstring SCENE_MODE_FIREWORKS;
  jstring SCENE_MODE_SPORTS;
  jstring SCENE_MODE_PARTY;
  jstring SCENE_MODE_CANDLELIGHT;
  jstring SCENE_MODE_BARCODE;
  jstring FOCUS_MODE_AUTO;
  jstring FOCUS_MODE_INFINITY;
  jstring FOCUS_MODE_MACRO;
  jstring FOCUS_MODE_FIXED;
  jstring FOCUS_MODE_EDOF;
  jstring FOCUS_MODE_CONTINUOUS_VIDEO;
  jstring FOCUS_MODE_CONTINUOUS_PICTURE;
} android_hardware_camera_parameters = {
0};

const gchar *Parameters_WHITE_BALANCE_AUTO;
const gchar *Parameters_WHITE_BALANCE_INCANDESCENT;
const gchar *Parameters_WHITE_BALANCE_FLUORESCENT;
const gchar *Parameters_WHITE_BALANCE_WARM_FLUORESCENT;
const gchar *Parameters_WHITE_BALANCE_DAYLIGHT;
const gchar *Parameters_WHITE_BALANCE_CLOUDY_DAYLIGHT;
const gchar *Parameters_WHITE_BALANCE_TWILIGHT;
const gchar *Parameters_WHITE_BALANCE_SHADE;
const gchar *Parameters_EFFECT_NONE;
const gchar *Parameters_EFFECT_MONO;
const gchar *Parameters_EFFECT_NEGATIVE;
const gchar *Parameters_EFFECT_SOLARIZE;
const gchar *Parameters_EFFECT_SEPIA;
const gchar *Parameters_EFFECT_POSTERIZE;
const gchar *Parameters_EFFECT_WHITEBOARD;
const gchar *Parameters_EFFECT_BLACKBOARD;
const gchar *Parameters_EFFECT_AQUA;
const gchar *Parameters_ANTIBANDING_AUTO;
const gchar *Parameters_ANTIBANDING_50HZ;
const gchar *Parameters_ANTIBANDING_60HZ;
const gchar *Parameters_ANTIBANDING_OFF;
const gchar *Parameters_FLASH_MODE_OFF;
const gchar *Parameters_FLASH_MODE_AUTO;
const gchar *Parameters_FLASH_MODE_ON;
const gchar *Parameters_FLASH_MODE_RED_EYE;
const gchar *Parameters_FLASH_MODE_TORCH;
const gchar *Parameters_SCENE_MODE_AUTO;
const gchar *Parameters_SCENE_MODE_ACTION;
const gchar *Parameters_SCENE_MODE_PORTRAIT;
const gchar *Parameters_SCENE_MODE_LANDSCAPE;
const gchar *Parameters_SCENE_MODE_NIGHT;
const gchar *Parameters_SCENE_MODE_NIGHT_PORTRAIT;
const gchar *Parameters_SCENE_MODE_THEATRE;
const gchar *Parameters_SCENE_MODE_BEACH;
const gchar *Parameters_SCENE_MODE_SNOW;
const gchar *Parameters_SCENE_MODE_SUNSET;
const gchar *Parameters_SCENE_MODE_STEADYPHOTO;
const gchar *Parameters_SCENE_MODE_FIREWORKS;
const gchar *Parameters_SCENE_MODE_SPORTS;
const gchar *Parameters_SCENE_MODE_PARTY;
const gchar *Parameters_SCENE_MODE_CANDLELIGHT;
const gchar *Parameters_SCENE_MODE_BARCODE;
const gchar *Parameters_FOCUS_MODE_AUTO;
const gchar *Parameters_FOCUS_MODE_INFINITY;
const gchar *Parameters_FOCUS_MODE_MACRO;
const gchar *Parameters_FOCUS_MODE_FIXED;
const gchar *Parameters_FOCUS_MODE_EDOF;
const gchar *Parameters_FOCUS_MODE_CONTINUOUS_VIDEO;
const gchar *Parameters_FOCUS_MODE_CONTINUOUS_PICTURE;

static struct
{
  jclass klass;
  jmethodID iterator;
} java_util_list = {
0};

static struct
{
  jclass klass;
  jmethodID hasNext;
  jmethodID next;
} java_util_iterator = {
0};

static struct
{
  jclass klass;
  jmethodID intValue;
} java_lang_integer = {
0};

static struct
{
  jclass klass;
  jmethodID equals;
} java_lang_string = {
0};

static struct
{
  jclass klass;
  jmethodID constructor;
} org_freedesktop_gstreamer_androidmedia_gstahccallback = {
0};

static void
gst_ah_camera_on_preview_frame (JNIEnv * env, jclass klass, jbyteArray data,
    jobject camera, jlong callback, jlong user_data)
{
  GstAHCPreviewCallback cb = (GstAHCPreviewCallback) (gsize) callback;

  if (cb)
    cb (data, (gpointer) (gsize) user_data);
}

static void
gst_ah_camera_on_error (JNIEnv * env, jclass klass, jint error,
    jobject camera, jlong callback, jlong user_data)
{
  GstAHCErrorCallback cb = (GstAHCErrorCallback) (gsize) callback;

  if (cb)
    cb (error, (gpointer) (gsize) user_data);
}

static void
gst_ah_camera_on_auto_focus (JNIEnv * env, jclass klass, jboolean success,
    jobject camera, jlong callback, jlong user_data)
{
  GstAHCAutoFocusCallback cb = (GstAHCAutoFocusCallback) (gsize) callback;

  if (cb)
    cb (success, (gpointer) (gsize) user_data);
}

static JNINativeMethod native_methods[] = {
  {(gchar *) "gst_ah_camera_on_preview_frame",
        (gchar *) "([BLandroid/hardware/Camera;JJ)V",
      (void *) gst_ah_camera_on_preview_frame},
  {(gchar *) "gst_ah_camera_on_error",
        (gchar *) "(ILandroid/hardware/Camera;JJ)V",
      (void *) gst_ah_camera_on_error},
//  {(gchar *) "gst_ah_camera_on_auto_focus",
//        (gchar *) "(ZLandroid/hardware/Camera;JJ)V",
//      (void *) gst_ah_camera_on_auto_focus}
};

static gboolean
_init_classes (void)
{
  JNIEnv *env;
  GError *err = NULL;

  jclass klass;
  jfieldID fieldID;

  env = gst_amc_jni_get_env ();

  /* android.hardware.Camera */
  klass = android_hardware_camera.klass =
      gst_amc_jni_get_class (env, &err, "android/hardware/Camera");
  if (!klass)
    goto failed;

  android_hardware_camera.addCallbackBuffer =
      gst_amc_jni_get_method_id (env, &err, klass,
      "addCallbackBuffer", "([B)V");

  android_hardware_camera.autoFocus =
      gst_amc_jni_get_method_id (env, &err, klass,
      "autoFocus", "(Landroid/hardware/Camera$AutoFocusCallback;)V");

  android_hardware_camera.cancelAutoFocus =
      gst_amc_jni_get_method_id (env, &err, klass, "cancelAutoFocus", "()V");

  android_hardware_camera.getCameraInfo =
      gst_amc_jni_get_static_method_id (env, &err, klass,
      "getCameraInfo", "(ILandroid/hardware/Camera$CameraInfo;)V");

  android_hardware_camera.getNumberOfCameras =
      gst_amc_jni_get_static_method_id (env, &err, klass,
      "getNumberOfCameras", "()I");

  android_hardware_camera.getParameters =
      gst_amc_jni_get_method_id (env, &err, klass,
      "getParameters", "()Landroid/hardware/Camera$Parameters;");

  android_hardware_camera.lock =
      gst_amc_jni_get_method_id (env, &err, klass, "lock", "()V");

  android_hardware_camera.open =
      gst_amc_jni_get_static_method_id (env, &err, klass,
      "open", "(I)Landroid/hardware/Camera;");

  android_hardware_camera.reconnect =
      gst_amc_jni_get_method_id (env, &err, klass, "reconnect", "()V");

  android_hardware_camera.release =
      gst_amc_jni_get_method_id (env, &err, klass, "release", "()V");

  android_hardware_camera.setErrorCallback =
      gst_amc_jni_get_method_id (env, &err, klass, "setErrorCallback",
      "(Landroid/hardware/Camera$ErrorCallback;)V");

  android_hardware_camera.setParameters =
      gst_amc_jni_get_method_id (env, &err, klass, "setParameters",
      "(Landroid/hardware/Camera$Parameters;)V");

  android_hardware_camera.setPreviewCallbackWithBuffer =
      gst_amc_jni_get_method_id (env, &err, klass,
      "setPreviewCallbackWithBuffer",
      "(Landroid/hardware/Camera$PreviewCallback;)V");

  android_hardware_camera.setPreviewTexture =
      gst_amc_jni_get_method_id (env, &err, klass,
      "setPreviewTexture", "(Landroid/graphics/SurfaceTexture;)V");

  android_hardware_camera.startPreview =
      gst_amc_jni_get_method_id (env, &err, klass, "startPreview", "()V");

  android_hardware_camera.startSmoothZoom =
      gst_amc_jni_get_method_id (env, &err, klass, "startSmoothZoom", "(I)V");

  android_hardware_camera.stopPreview =
      gst_amc_jni_get_method_id (env, &err, klass, "stopPreview", "()V");

  android_hardware_camera.stopPreview =
      gst_amc_jni_get_method_id (env, &err, klass, "stopPreview", "()V");

  android_hardware_camera.unlock =
      gst_amc_jni_get_method_id (env, &err, klass, "unlock", "()V");

  /* android.hardware.Camera.CameraInfo */
  klass = android_hardware_camera_camerainfo.klass =
      gst_amc_jni_get_class (env, &err, "android/hardware/Camera$CameraInfo");
  if (!klass)
    goto failed;

  android_hardware_camera_camerainfo.constructor =
      gst_amc_jni_get_method_id (env, &err, klass, "<init>", "()V");

  android_hardware_camera_camerainfo.facing =
      gst_amc_jni_get_field_id (env, &err, klass, "facing", "I");

  android_hardware_camera_camerainfo.orientation =
      gst_amc_jni_get_field_id (env, &err, klass, "orientation", "I");


  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "CAMERA_FACING_BACK",
      "I");
  if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID,
          &android_hardware_camera_camerainfo.CAMERA_FACING_BACK))
    goto failed;
  CameraInfo_CAMERA_FACING_BACK =
      android_hardware_camera_camerainfo.CAMERA_FACING_BACK;

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "CAMERA_FACING_FRONT",
      "I");
  if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID,
          &android_hardware_camera_camerainfo.CAMERA_FACING_FRONT))
    goto failed;
  CameraInfo_CAMERA_FACING_FRONT =
      android_hardware_camera_camerainfo.CAMERA_FACING_FRONT;

  /* android.hardware.Camera.Size */
  klass = android_hardware_camera_size.klass =
      gst_amc_jni_get_class (env, &err, "android/hardware/Camera$Size");
  if (!klass)
    goto failed;

  android_hardware_camera_size.width =
      gst_amc_jni_get_field_id (env, &err, klass, "width", "I");
  android_hardware_camera_size.height =
      gst_amc_jni_get_field_id (env, &err, klass, "height", "I");

  /* android.hardware.Camera.Parameters */
  klass = android_hardware_camera_parameters.klass =
      gst_amc_jni_get_class (env, &err, "android/hardware/Camera$Parameters");
  if (!klass)
    goto failed;

  android_hardware_camera_parameters.flatten =
      gst_amc_jni_get_method_id (env, &err, klass, "flatten",
      "()Ljava/lang/String;");

  android_hardware_camera_parameters.getAntibanding =
      gst_amc_jni_get_method_id (env, &err, klass, "getAntibanding",
      "()Ljava/lang/String;");

  android_hardware_camera_parameters.getColorEffect =
      gst_amc_jni_get_method_id (env, &err, klass, "getColorEffect",
      "()Ljava/lang/String;");

  android_hardware_camera_parameters.getExposureCompensation =
      gst_amc_jni_get_method_id (env, &err, klass, "getExposureCompensation",
      "()I");

  android_hardware_camera_parameters.getExposureCompensationStep =
      gst_amc_jni_get_method_id (env, &err, klass,
      "getExposureCompensationStep", "()F");

  android_hardware_camera_parameters.getFlashMode =
      gst_amc_jni_get_method_id (env, &err, klass, "getFlashMode",
      "()Ljava/lang/String;");

  android_hardware_camera_parameters.getFocalLength =
      gst_amc_jni_get_method_id (env, &err, klass, "getFocalLength", "()F");

  android_hardware_camera_parameters.getFocusMode =
      gst_amc_jni_get_method_id (env, &err, klass, "getFocusMode",
      "()Ljava/lang/String;");

  android_hardware_camera_parameters.getHorizontalViewAngle =
      gst_amc_jni_get_method_id (env, &err, klass, "getHorizontalViewAngle",
      "()F");

  android_hardware_camera_parameters.getMaxExposureCompensation =
      gst_amc_jni_get_method_id (env, &err, klass, "getMaxExposureCompensation",
      "()I");

  android_hardware_camera_parameters.getMaxZoom =
      gst_amc_jni_get_method_id (env, &err, klass, "getMaxZoom", "()I");

  android_hardware_camera_parameters.getMinExposureCompensation =
      gst_amc_jni_get_method_id (env, &err, klass, "getMinExposureCompensation",
      "()I");

  android_hardware_camera_parameters.getPreviewFormat =
      gst_amc_jni_get_method_id (env, &err, klass, "getPreviewFormat", "()I");

  android_hardware_camera_parameters.getPreviewFpsRange =
      gst_amc_jni_get_method_id (env, &err, klass, "getPreviewFpsRange",
      "([I)V");

  android_hardware_camera_parameters.getPreviewSize =
      gst_amc_jni_get_method_id (env, &err, klass, "getPreviewSize",
      "()Landroid/hardware/Camera$Size;");

  android_hardware_camera_parameters.getSceneMode =
      gst_amc_jni_get_method_id (env, &err, klass, "getSceneMode",
      "()Ljava/lang/String;");

  android_hardware_camera_parameters.getSupportedAntibanding =
      gst_amc_jni_get_method_id (env, &err, klass, "getSupportedAntibanding",
      "()Ljava/util/List;");

  android_hardware_camera_parameters.getSupportedColorEffects =
      gst_amc_jni_get_method_id (env, &err, klass, "getSupportedColorEffects",
      "()Ljava/util/List;");

  android_hardware_camera_parameters.getSupportedFlashModes =
      gst_amc_jni_get_method_id (env, &err, klass, "getSupportedFlashModes",
      "()Ljava/util/List;");

  android_hardware_camera_parameters.getSupportedFocusModes =
      gst_amc_jni_get_method_id (env, &err, klass, "getSupportedFocusModes",
      "()Ljava/util/List;");

  android_hardware_camera_parameters.getSupportedPreviewFormats =
      gst_amc_jni_get_method_id (env, &err, klass, "getSupportedPreviewFormats",
      "()Ljava/util/List;");

  android_hardware_camera_parameters.getSupportedPreviewFpsRange =
      gst_amc_jni_get_method_id (env, &err, klass,
      "getSupportedPreviewFpsRange", "()Ljava/util/List;");

  android_hardware_camera_parameters.getSupportedPreviewSizes =
      gst_amc_jni_get_method_id (env, &err, klass, "getSupportedPreviewSizes",
      "()Ljava/util/List;");

  android_hardware_camera_parameters.getSupportedSceneModes =
      gst_amc_jni_get_method_id (env, &err, klass, "getSupportedSceneModes",
      "()Ljava/util/List;");

  android_hardware_camera_parameters.getSupportedWhiteBalance =
      gst_amc_jni_get_method_id (env, &err, klass, "getSupportedWhiteBalance",
      "()Ljava/util/List;");

  android_hardware_camera_parameters.getVerticalViewAngle =
      gst_amc_jni_get_method_id (env, &err, klass, "getVerticalViewAngle",
      "()F");

  android_hardware_camera_parameters.getVideoStabilization =
      gst_amc_jni_get_method_id (env, &err, klass, "getVideoStabilization",
      "()Z");

  android_hardware_camera_parameters.getWhiteBalance =
      gst_amc_jni_get_method_id (env, &err, klass, "getWhiteBalance",
      "()Ljava/lang/String;");

  android_hardware_camera_parameters.getZoom =
      gst_amc_jni_get_method_id (env, &err, klass, "getZoom", "()I");

  android_hardware_camera_parameters.getZoomRatios =
      gst_amc_jni_get_method_id (env, &err, klass, "getZoomRatios",
      "()Ljava/util/List;");

  android_hardware_camera_parameters.isSmoothZoomSupported =
      gst_amc_jni_get_method_id (env, &err, klass, "isSmoothZoomSupported",
      "()Z");

  android_hardware_camera_parameters.isVideoStabilizationSupported =
      gst_amc_jni_get_method_id (env, &err, klass,
      "isVideoStabilizationSupported", "()Z");

  android_hardware_camera_parameters.isZoomSupported =
      gst_amc_jni_get_method_id (env, &err, klass, "isZoomSupported", "()Z");

  android_hardware_camera_parameters.setAntibanding =
      gst_amc_jni_get_method_id (env, &err, klass, "setAntibanding",
      "(Ljava/lang/String;)V");

  android_hardware_camera_parameters.setColorEffect =
      gst_amc_jni_get_method_id (env, &err, klass, "setColorEffect",
      "(Ljava/lang/String;)V");

  android_hardware_camera_parameters.setExposureCompensation =
      gst_amc_jni_get_method_id (env, &err, klass, "setExposureCompensation",
      "(I)V");

  android_hardware_camera_parameters.setFlashMode =
      gst_amc_jni_get_method_id (env, &err, klass, "setFlashMode",
      "(Ljava/lang/String;)V");

  android_hardware_camera_parameters.setFocusMode =
      gst_amc_jni_get_method_id (env, &err, klass, "setFocusMode",
      "(Ljava/lang/String;)V");

  android_hardware_camera_parameters.setPreviewFormat =
      gst_amc_jni_get_method_id (env, &err, klass, "setPreviewFormat", "(I)V");

  android_hardware_camera_parameters.setPreviewFpsRange =
      gst_amc_jni_get_method_id (env, &err, klass, "setPreviewFpsRange",
      "(II)V");

  android_hardware_camera_parameters.setPreviewSize =
      gst_amc_jni_get_method_id (env, &err, klass, "setPreviewSize", "(II)V");

  android_hardware_camera_parameters.setSceneMode =
      gst_amc_jni_get_method_id (env, &err, klass, "setSceneMode",
      "(Ljava/lang/String;)V");

  android_hardware_camera_parameters.setWhiteBalance =
      gst_amc_jni_get_method_id (env, &err, klass, "setWhiteBalance",
      "(Ljava/lang/String;)V");

  android_hardware_camera_parameters.setVideoStabilization =
      gst_amc_jni_get_method_id (env, &err, klass, "setVideoStabilization",
      "(Z)V");

  android_hardware_camera_parameters.setZoom =
      gst_amc_jni_get_method_id (env, &err, klass, "setZoom", "(I)V");

  android_hardware_camera_parameters.unflatten =
      gst_amc_jni_get_method_id (env, &err, klass, "unflatten",
      "(Ljava/lang/String;)V");

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "WHITE_BALANCE_AUTO",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.WHITE_BALANCE_AUTO))
    goto failed;

  Parameters_WHITE_BALANCE_AUTO =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.WHITE_BALANCE_AUTO, NULL);
  {
    jobject local = android_hardware_camera_parameters.WHITE_BALANCE_AUTO;

    android_hardware_camera_parameters.WHITE_BALANCE_AUTO =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "WHITE_BALANCE_INCANDESCENT", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT))
    goto failed;

  Parameters_WHITE_BALANCE_INCANDESCENT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT, NULL);
  {
    jobject local =
        android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT;

    android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "WHITE_BALANCE_FLUORESCENT", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT))
    goto failed;

  Parameters_WHITE_BALANCE_FLUORESCENT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT, NULL);
  {
    jobject local =
        android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT;

    android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "WHITE_BALANCE_WARM_FLUORESCENT", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT))
    goto failed;

  Parameters_WHITE_BALANCE_WARM_FLUORESCENT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT, NULL);
  {
    jobject local =
        android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT;

    android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "WHITE_BALANCE_DAYLIGHT", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT))
    goto failed;

  Parameters_WHITE_BALANCE_DAYLIGHT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT, NULL);
  {
    jobject local = android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT;

    android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "WHITE_BALANCE_CLOUDY_DAYLIGHT", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT))
    goto failed;
  Parameters_WHITE_BALANCE_CLOUDY_DAYLIGHT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT, NULL);
  {
    jobject local =
        android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT;

    android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "WHITE_BALANCE_TWILIGHT", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT))
    goto failed;
  Parameters_WHITE_BALANCE_TWILIGHT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT, NULL);
  {
    jobject local = android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT;

    android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "WHITE_BALANCE_SHADE",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.WHITE_BALANCE_SHADE))
    goto failed;

  Parameters_WHITE_BALANCE_SHADE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.WHITE_BALANCE_SHADE, NULL);
  {
    jobject local = android_hardware_camera_parameters.WHITE_BALANCE_SHADE;

    android_hardware_camera_parameters.WHITE_BALANCE_SHADE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "EFFECT_NONE",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.EFFECT_NONE))
    goto failed;

  Parameters_EFFECT_NONE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.EFFECT_NONE, NULL);
  {
    jobject local = android_hardware_camera_parameters.EFFECT_NONE;

    android_hardware_camera_parameters.EFFECT_NONE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "EFFECT_MONO",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.EFFECT_MONO))
    goto failed;

  Parameters_EFFECT_MONO =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.EFFECT_MONO, NULL);
  {
    jobject local = android_hardware_camera_parameters.EFFECT_MONO;

    android_hardware_camera_parameters.EFFECT_MONO =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "EFFECT_NEGATIVE",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.EFFECT_NEGATIVE))
    goto failed;

  Parameters_EFFECT_NEGATIVE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.EFFECT_NEGATIVE, NULL);
  {
    jobject local = android_hardware_camera_parameters.EFFECT_NEGATIVE;

    android_hardware_camera_parameters.EFFECT_NEGATIVE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "EFFECT_SOLARIZE",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.EFFECT_SOLARIZE))
    goto failed;

  Parameters_EFFECT_SOLARIZE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.EFFECT_SOLARIZE, NULL);
  {
    jobject local = android_hardware_camera_parameters.EFFECT_SOLARIZE;

    android_hardware_camera_parameters.EFFECT_SOLARIZE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "EFFECT_SEPIA",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.EFFECT_SEPIA))
    goto failed;

  Parameters_EFFECT_SEPIA =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.EFFECT_SEPIA, NULL);
  {
    jobject local = android_hardware_camera_parameters.EFFECT_SEPIA;

    android_hardware_camera_parameters.EFFECT_SEPIA =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "EFFECT_POSTERIZE",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.EFFECT_POSTERIZE))
    goto failed;

  Parameters_EFFECT_POSTERIZE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.EFFECT_POSTERIZE, NULL);
  {
    jobject local = android_hardware_camera_parameters.EFFECT_POSTERIZE;

    android_hardware_camera_parameters.EFFECT_POSTERIZE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "EFFECT_WHITEBOARD",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.EFFECT_WHITEBOARD))
    goto failed;

  Parameters_EFFECT_WHITEBOARD =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.EFFECT_WHITEBOARD, NULL);
  {
    jobject local = android_hardware_camera_parameters.EFFECT_WHITEBOARD;

    android_hardware_camera_parameters.EFFECT_WHITEBOARD =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "EFFECT_BLACKBOARD",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.EFFECT_BLACKBOARD))
    goto failed;

  Parameters_EFFECT_BLACKBOARD =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.EFFECT_BLACKBOARD, NULL);
  {
    jobject local = android_hardware_camera_parameters.EFFECT_BLACKBOARD;

    android_hardware_camera_parameters.EFFECT_BLACKBOARD =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "EFFECT_AQUA",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.EFFECT_AQUA))
    goto failed;

  Parameters_EFFECT_AQUA =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.EFFECT_AQUA, NULL);
  {
    jobject local = android_hardware_camera_parameters.EFFECT_AQUA;

    android_hardware_camera_parameters.EFFECT_AQUA =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "ANTIBANDING_AUTO",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.ANTIBANDING_AUTO))
    goto failed;

  Parameters_ANTIBANDING_AUTO =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.ANTIBANDING_AUTO, NULL);
  {
    jobject local = android_hardware_camera_parameters.ANTIBANDING_AUTO;

    android_hardware_camera_parameters.ANTIBANDING_AUTO =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "ANTIBANDING_50HZ",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.ANTIBANDING_50HZ))
    goto failed;

  Parameters_ANTIBANDING_50HZ =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.ANTIBANDING_50HZ, NULL);
  {
    jobject local = android_hardware_camera_parameters.ANTIBANDING_50HZ;

    android_hardware_camera_parameters.ANTIBANDING_50HZ =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "ANTIBANDING_60HZ",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.ANTIBANDING_60HZ))
    goto failed;

  Parameters_ANTIBANDING_60HZ =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.ANTIBANDING_60HZ, NULL);
  {
    jobject local = android_hardware_camera_parameters.ANTIBANDING_60HZ;

    android_hardware_camera_parameters.ANTIBANDING_60HZ =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "ANTIBANDING_OFF",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.ANTIBANDING_OFF))
    goto failed;

  Parameters_ANTIBANDING_OFF =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.ANTIBANDING_OFF, NULL);
  {
    jobject local = android_hardware_camera_parameters.ANTIBANDING_OFF;

    android_hardware_camera_parameters.ANTIBANDING_OFF =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FLASH_MODE_OFF",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FLASH_MODE_OFF))
    goto failed;

  Parameters_FLASH_MODE_OFF =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FLASH_MODE_OFF, NULL);
  {
    jobject local = android_hardware_camera_parameters.FLASH_MODE_OFF;

    android_hardware_camera_parameters.FLASH_MODE_OFF =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FLASH_MODE_AUTO",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FLASH_MODE_AUTO))
    goto failed;

  Parameters_FLASH_MODE_AUTO =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FLASH_MODE_AUTO, NULL);
  {
    jobject local = android_hardware_camera_parameters.FLASH_MODE_AUTO;

    android_hardware_camera_parameters.FLASH_MODE_AUTO =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FLASH_MODE_ON",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FLASH_MODE_ON))
    goto failed;

  Parameters_FLASH_MODE_ON =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FLASH_MODE_ON, NULL);
  {
    jobject local = android_hardware_camera_parameters.FLASH_MODE_ON;

    android_hardware_camera_parameters.FLASH_MODE_ON =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FLASH_MODE_RED_EYE",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FLASH_MODE_RED_EYE))
    goto failed;

  Parameters_FLASH_MODE_RED_EYE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FLASH_MODE_RED_EYE, NULL);
  {
    jobject local = android_hardware_camera_parameters.FLASH_MODE_RED_EYE;

    android_hardware_camera_parameters.FLASH_MODE_RED_EYE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FLASH_MODE_TORCH",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FLASH_MODE_TORCH))
    goto failed;

  Parameters_FLASH_MODE_TORCH =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FLASH_MODE_TORCH, NULL);
  {
    jobject local = android_hardware_camera_parameters.FLASH_MODE_TORCH;

    android_hardware_camera_parameters.FLASH_MODE_TORCH =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_AUTO",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_AUTO))
    goto failed;

  Parameters_SCENE_MODE_AUTO =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_AUTO, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_AUTO;

    android_hardware_camera_parameters.SCENE_MODE_AUTO =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_ACTION",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_ACTION))
    goto failed;

  Parameters_SCENE_MODE_ACTION =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_ACTION, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_ACTION;

    android_hardware_camera_parameters.SCENE_MODE_ACTION =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_PORTRAIT",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_PORTRAIT))
    goto failed;

  Parameters_SCENE_MODE_PORTRAIT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_PORTRAIT, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_PORTRAIT;

    android_hardware_camera_parameters.SCENE_MODE_PORTRAIT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_LANDSCAPE",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE))
    goto failed;
  Parameters_SCENE_MODE_LANDSCAPE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE;

    android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_NIGHT",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_NIGHT))
    goto failed;

  Parameters_SCENE_MODE_NIGHT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_NIGHT, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_NIGHT;

    android_hardware_camera_parameters.SCENE_MODE_NIGHT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "SCENE_MODE_NIGHT_PORTRAIT", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT))
    goto failed;
  Parameters_SCENE_MODE_NIGHT_PORTRAIT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT, NULL);
  {
    jobject local =
        android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT;

    android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }
  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_THEATRE",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_THEATRE))
    goto failed;

  Parameters_SCENE_MODE_THEATRE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_THEATRE, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_THEATRE;

    android_hardware_camera_parameters.SCENE_MODE_THEATRE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_BEACH",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_BEACH))
    goto failed;

  Parameters_SCENE_MODE_BEACH =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_BEACH, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_BEACH;

    android_hardware_camera_parameters.SCENE_MODE_BEACH =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_SNOW",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_SNOW))
    goto failed;

  Parameters_SCENE_MODE_SNOW =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_SNOW, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_SNOW;

    android_hardware_camera_parameters.SCENE_MODE_SNOW =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_SUNSET",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_SUNSET))
    goto failed;


  Parameters_SCENE_MODE_SUNSET =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_SUNSET, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_SUNSET;

    android_hardware_camera_parameters.SCENE_MODE_SUNSET =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "SCENE_MODE_STEADYPHOTO", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO))
    goto failed;


  Parameters_SCENE_MODE_STEADYPHOTO =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO;

    android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_FIREWORKS",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_FIREWORKS))
    goto failed;

  Parameters_SCENE_MODE_FIREWORKS =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_FIREWORKS, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_FIREWORKS;

    android_hardware_camera_parameters.SCENE_MODE_FIREWORKS =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_SPORTS",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_SPORTS))
    goto failed;


  Parameters_SCENE_MODE_SPORTS =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_SPORTS, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_SPORTS;

    android_hardware_camera_parameters.SCENE_MODE_SPORTS =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_PARTY",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_PARTY))
    goto failed;

  Parameters_SCENE_MODE_PARTY =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_PARTY, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_PARTY;

    android_hardware_camera_parameters.SCENE_MODE_PARTY =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "SCENE_MODE_CANDLELIGHT", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT))
    goto failed;

  Parameters_SCENE_MODE_CANDLELIGHT =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT;

    android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }


  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "SCENE_MODE_BARCODE",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.SCENE_MODE_BARCODE))
    goto failed;

  Parameters_SCENE_MODE_BARCODE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.SCENE_MODE_BARCODE, NULL);
  {
    jobject local = android_hardware_camera_parameters.SCENE_MODE_BARCODE;

    android_hardware_camera_parameters.SCENE_MODE_BARCODE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FOCUS_MODE_AUTO",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FOCUS_MODE_AUTO))
    goto failed;

  Parameters_FOCUS_MODE_AUTO =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FOCUS_MODE_AUTO, NULL);
  {
    jobject local = android_hardware_camera_parameters.FOCUS_MODE_AUTO;

    android_hardware_camera_parameters.FOCUS_MODE_AUTO =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FOCUS_MODE_INFINITY",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FOCUS_MODE_INFINITY))
    goto failed;

  Parameters_FOCUS_MODE_INFINITY =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FOCUS_MODE_INFINITY, NULL);
  {
    jobject local = android_hardware_camera_parameters.FOCUS_MODE_INFINITY;

    android_hardware_camera_parameters.FOCUS_MODE_INFINITY =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FOCUS_MODE_MACRO",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FOCUS_MODE_MACRO))
    goto failed;

  Parameters_FOCUS_MODE_MACRO =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FOCUS_MODE_MACRO, NULL);
  {
    jobject local = android_hardware_camera_parameters.FOCUS_MODE_MACRO;

    android_hardware_camera_parameters.FOCUS_MODE_MACRO =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FOCUS_MODE_FIXED",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FOCUS_MODE_FIXED))
    goto failed;

  Parameters_FOCUS_MODE_FIXED =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FOCUS_MODE_FIXED, NULL);
  {
    jobject local = android_hardware_camera_parameters.FOCUS_MODE_FIXED;

    android_hardware_camera_parameters.FOCUS_MODE_FIXED =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass, "FOCUS_MODE_EDOF",
      "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FOCUS_MODE_EDOF))
    goto failed;

  Parameters_FOCUS_MODE_EDOF =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FOCUS_MODE_EDOF, NULL);
  {
    jobject local = android_hardware_camera_parameters.FOCUS_MODE_EDOF;

    android_hardware_camera_parameters.FOCUS_MODE_EDOF =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "FOCUS_MODE_CONTINUOUS_VIDEO", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
    goto failed;

  Parameters_FOCUS_MODE_CONTINUOUS_VIDEO =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO, NULL);
  {
    jobject local =
        android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO;

    android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  fieldID =
      gst_amc_jni_get_static_field_id (env, &err, klass,
      "FOCUS_MODE_CONTINUOUS_PICTURE", "Ljava/lang/String;");
  if (!fieldID)
    goto failed;
  if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID,
          &android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
    goto failed;


  Parameters_FOCUS_MODE_CONTINUOUS_PICTURE =
      (*env)->GetStringUTFChars (env,
      android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE, NULL);
  {
    jobject local =
        android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE;

    android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE =
        (*env)->NewGlobalRef (env, local);
    (*env)->DeleteLocalRef (env, local);
  }

  /* java.lang.String */
  klass = java_lang_string.klass =
      gst_amc_jni_get_class (env, &err, "java/lang/String");
  java_lang_string.equals =
      gst_amc_jni_get_method_id (env, &err, klass, "equals",
      "(Ljava/lang/Object;)Z");

  /* java.util.List */
  klass = java_util_list.klass =
      gst_amc_jni_get_class (env, &err, "java/util/List");
  java_util_list.iterator =
      gst_amc_jni_get_method_id (env, &err, klass, "iterator",
      "()Ljava/util/Iterator;");

  /* java.util.Iterator */
  klass = java_util_iterator.klass =
      gst_amc_jni_get_class (env, &err, "java/util/Iterator");
  java_util_iterator.hasNext =
      gst_amc_jni_get_method_id (env, &err, klass, "hasNext", "()Z");
  java_util_iterator.next =
      gst_amc_jni_get_method_id (env, &err, klass, "next",
      "()Ljava/lang/Object;");

  /* java.lang.Integer */
  klass = java_lang_integer.klass =
      gst_amc_jni_get_class (env, &err, "java/lang/Integer");
  java_lang_integer.intValue =
      gst_amc_jni_get_method_id (env, &err, klass, "intValue", "()I");

  if (!org_freedesktop_gstreamer_androidmedia_gstahccallback.klass) {
    org_freedesktop_gstreamer_androidmedia_gstahccallback.klass =
        gst_amc_jni_get_class (env, &err,
        "org/freedesktop/gstreamer/androidmedia/GstAhcCallback");
  }
  if (!org_freedesktop_gstreamer_androidmedia_gstahccallback.klass)
    goto failed;

  org_freedesktop_gstreamer_androidmedia_gstahccallback.constructor =
      gst_amc_jni_get_method_id (env, &err,
      org_freedesktop_gstreamer_androidmedia_gstahccallback.klass, "<init>",
      "(JJ)V");

  if ((*env)->RegisterNatives (env,
          org_freedesktop_gstreamer_androidmedia_gstahccallback.klass,
          native_methods, G_N_ELEMENTS (native_methods))) {
    GST_ERROR ("Failed to register native methods for GstAhcCallback");
    return FALSE;
  }

  return TRUE;

failed:
  if (err) {
    GST_ERROR ("Failed to initialize android.hardware.Camera classes: %s",
        err->message);
    g_clear_error (&err);
  }

  return FALSE;

}


gboolean
gst_android_hardware_camera_init (void)
{
  GST_DEBUG_CATEGORY_INIT (ahc_debug, "ahc", 0,
      "Android Gstreamer Hardware Camera");
  if (!_init_classes ()) {
    gst_android_hardware_camera_deinit ();
    return FALSE;
  }

  return TRUE;
}

void
gst_android_hardware_camera_deinit (void)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  if (android_hardware_camera.klass)
    (*env)->DeleteGlobalRef (env, android_hardware_camera.klass);
  android_hardware_camera.klass = NULL;

  if (android_hardware_camera_camerainfo.klass)
    (*env)->DeleteGlobalRef (env, android_hardware_camera_camerainfo.klass);
  android_hardware_camera_camerainfo.klass = NULL;

  if (android_hardware_camera_size.klass)
    (*env)->DeleteGlobalRef (env, android_hardware_camera_size.klass);
  android_hardware_camera_size.klass = NULL;

  if (android_hardware_camera_parameters.klass)
    (*env)->DeleteGlobalRef (env, android_hardware_camera_parameters.klass);
  android_hardware_camera_parameters.klass = NULL;
  if (Parameters_WHITE_BALANCE_AUTO)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.WHITE_BALANCE_AUTO,
        Parameters_WHITE_BALANCE_AUTO);
  Parameters_WHITE_BALANCE_AUTO = NULL;
  if (android_hardware_camera_parameters.WHITE_BALANCE_AUTO)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.WHITE_BALANCE_AUTO);
  android_hardware_camera_parameters.WHITE_BALANCE_AUTO = NULL;
  if (Parameters_WHITE_BALANCE_INCANDESCENT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT,
        Parameters_WHITE_BALANCE_INCANDESCENT);
  Parameters_WHITE_BALANCE_INCANDESCENT = NULL;
  if (android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT);
  android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT = NULL;
  if (Parameters_WHITE_BALANCE_FLUORESCENT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT,
        Parameters_WHITE_BALANCE_FLUORESCENT);
  Parameters_WHITE_BALANCE_FLUORESCENT = NULL;
  if (android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT);
  android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT = NULL;
  if (Parameters_WHITE_BALANCE_WARM_FLUORESCENT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT,
        Parameters_WHITE_BALANCE_WARM_FLUORESCENT);
  Parameters_WHITE_BALANCE_WARM_FLUORESCENT = NULL;
  if (android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT);
  android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT = NULL;
  if (Parameters_WHITE_BALANCE_DAYLIGHT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT,
        Parameters_WHITE_BALANCE_DAYLIGHT);
  Parameters_WHITE_BALANCE_DAYLIGHT = NULL;
  if (android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT);
  android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT = NULL;
  if (Parameters_WHITE_BALANCE_CLOUDY_DAYLIGHT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT,
        Parameters_WHITE_BALANCE_CLOUDY_DAYLIGHT);
  Parameters_WHITE_BALANCE_CLOUDY_DAYLIGHT = NULL;
  if (android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT);
  android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT = NULL;
  if (Parameters_WHITE_BALANCE_TWILIGHT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT,
        Parameters_WHITE_BALANCE_TWILIGHT);
  Parameters_WHITE_BALANCE_TWILIGHT = NULL;
  if (android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT);
  android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT = NULL;
  if (Parameters_WHITE_BALANCE_SHADE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.WHITE_BALANCE_SHADE,
        Parameters_WHITE_BALANCE_SHADE);
  Parameters_WHITE_BALANCE_SHADE = NULL;
  if (android_hardware_camera_parameters.WHITE_BALANCE_SHADE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.WHITE_BALANCE_SHADE);
  android_hardware_camera_parameters.WHITE_BALANCE_SHADE = NULL;
  if (Parameters_EFFECT_NONE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.EFFECT_NONE, Parameters_EFFECT_NONE);
  Parameters_EFFECT_NONE = NULL;
  if (android_hardware_camera_parameters.EFFECT_NONE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.EFFECT_NONE);
  android_hardware_camera_parameters.EFFECT_NONE = NULL;
  if (Parameters_EFFECT_MONO)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.EFFECT_MONO, Parameters_EFFECT_MONO);
  Parameters_EFFECT_MONO = NULL;
  if (android_hardware_camera_parameters.EFFECT_MONO)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.EFFECT_MONO);
  android_hardware_camera_parameters.EFFECT_MONO = NULL;
  if (Parameters_EFFECT_NEGATIVE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.EFFECT_NEGATIVE,
        Parameters_EFFECT_NEGATIVE);
  Parameters_EFFECT_NEGATIVE = NULL;
  if (android_hardware_camera_parameters.EFFECT_NEGATIVE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.EFFECT_NEGATIVE);
  android_hardware_camera_parameters.EFFECT_NEGATIVE = NULL;
  if (Parameters_EFFECT_SOLARIZE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.EFFECT_SOLARIZE,
        Parameters_EFFECT_SOLARIZE);
  Parameters_EFFECT_SOLARIZE = NULL;
  if (android_hardware_camera_parameters.EFFECT_SOLARIZE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.EFFECT_SOLARIZE);
  android_hardware_camera_parameters.EFFECT_SOLARIZE = NULL;
  if (Parameters_EFFECT_SEPIA)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.EFFECT_SEPIA,
        Parameters_EFFECT_SEPIA);
  Parameters_EFFECT_SEPIA = NULL;
  if (android_hardware_camera_parameters.EFFECT_SEPIA)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.EFFECT_SEPIA);
  android_hardware_camera_parameters.EFFECT_SEPIA = NULL;
  if (Parameters_EFFECT_POSTERIZE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.EFFECT_POSTERIZE,
        Parameters_EFFECT_POSTERIZE);
  Parameters_EFFECT_POSTERIZE = NULL;
  if (android_hardware_camera_parameters.EFFECT_POSTERIZE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.EFFECT_POSTERIZE);
  android_hardware_camera_parameters.EFFECT_POSTERIZE = NULL;
  if (Parameters_EFFECT_WHITEBOARD)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.EFFECT_WHITEBOARD,
        Parameters_EFFECT_WHITEBOARD);
  Parameters_EFFECT_WHITEBOARD = NULL;
  if (android_hardware_camera_parameters.EFFECT_WHITEBOARD)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.EFFECT_WHITEBOARD);
  android_hardware_camera_parameters.EFFECT_WHITEBOARD = NULL;
  if (Parameters_EFFECT_BLACKBOARD)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.EFFECT_BLACKBOARD,
        Parameters_EFFECT_BLACKBOARD);
  Parameters_EFFECT_BLACKBOARD = NULL;
  if (android_hardware_camera_parameters.EFFECT_BLACKBOARD)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.EFFECT_BLACKBOARD);
  android_hardware_camera_parameters.EFFECT_BLACKBOARD = NULL;
  if (Parameters_EFFECT_AQUA)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.EFFECT_AQUA, Parameters_EFFECT_AQUA);
  Parameters_EFFECT_AQUA = NULL;
  if (android_hardware_camera_parameters.EFFECT_AQUA)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.EFFECT_AQUA);
  android_hardware_camera_parameters.EFFECT_AQUA = NULL;
  if (Parameters_ANTIBANDING_AUTO)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.ANTIBANDING_AUTO,
        Parameters_ANTIBANDING_AUTO);
  Parameters_ANTIBANDING_AUTO = NULL;
  if (android_hardware_camera_parameters.ANTIBANDING_AUTO)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.ANTIBANDING_AUTO);
  android_hardware_camera_parameters.ANTIBANDING_AUTO = NULL;
  if (Parameters_ANTIBANDING_50HZ)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.ANTIBANDING_50HZ,
        Parameters_ANTIBANDING_50HZ);
  Parameters_ANTIBANDING_50HZ = NULL;
  if (android_hardware_camera_parameters.ANTIBANDING_50HZ)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.ANTIBANDING_50HZ);
  android_hardware_camera_parameters.ANTIBANDING_50HZ = NULL;
  if (Parameters_ANTIBANDING_60HZ)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.ANTIBANDING_60HZ,
        Parameters_ANTIBANDING_60HZ);
  Parameters_ANTIBANDING_60HZ = NULL;
  if (android_hardware_camera_parameters.ANTIBANDING_60HZ)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.ANTIBANDING_60HZ);
  android_hardware_camera_parameters.ANTIBANDING_60HZ = NULL;
  if (Parameters_ANTIBANDING_OFF)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.ANTIBANDING_OFF,
        Parameters_ANTIBANDING_OFF);
  Parameters_ANTIBANDING_OFF = NULL;
  if (android_hardware_camera_parameters.ANTIBANDING_OFF)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.ANTIBANDING_OFF);
  android_hardware_camera_parameters.ANTIBANDING_OFF = NULL;
  if (Parameters_FLASH_MODE_OFF)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FLASH_MODE_OFF,
        Parameters_FLASH_MODE_OFF);
  Parameters_FLASH_MODE_OFF = NULL;
  if (android_hardware_camera_parameters.FLASH_MODE_OFF)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FLASH_MODE_OFF);
  android_hardware_camera_parameters.FLASH_MODE_OFF = NULL;
  if (Parameters_FLASH_MODE_AUTO)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FLASH_MODE_AUTO,
        Parameters_FLASH_MODE_AUTO);
  Parameters_FLASH_MODE_AUTO = NULL;
  if (android_hardware_camera_parameters.FLASH_MODE_AUTO)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FLASH_MODE_AUTO);
  android_hardware_camera_parameters.FLASH_MODE_AUTO = NULL;
  if (Parameters_FLASH_MODE_ON)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FLASH_MODE_ON,
        Parameters_FLASH_MODE_ON);
  Parameters_FLASH_MODE_ON = NULL;
  if (android_hardware_camera_parameters.FLASH_MODE_ON)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FLASH_MODE_ON);
  android_hardware_camera_parameters.FLASH_MODE_ON = NULL;
  if (Parameters_FLASH_MODE_RED_EYE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FLASH_MODE_RED_EYE,
        Parameters_FLASH_MODE_RED_EYE);
  Parameters_FLASH_MODE_RED_EYE = NULL;
  if (android_hardware_camera_parameters.FLASH_MODE_RED_EYE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FLASH_MODE_RED_EYE);
  android_hardware_camera_parameters.FLASH_MODE_RED_EYE = NULL;
  if (Parameters_FLASH_MODE_TORCH)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FLASH_MODE_TORCH,
        Parameters_FLASH_MODE_TORCH);
  Parameters_FLASH_MODE_TORCH = NULL;
  if (android_hardware_camera_parameters.FLASH_MODE_TORCH)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FLASH_MODE_TORCH);
  android_hardware_camera_parameters.FLASH_MODE_TORCH = NULL;
  if (Parameters_SCENE_MODE_AUTO)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_AUTO,
        Parameters_SCENE_MODE_AUTO);
  Parameters_SCENE_MODE_AUTO = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_AUTO)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_AUTO);
  android_hardware_camera_parameters.SCENE_MODE_AUTO = NULL;
  if (Parameters_SCENE_MODE_ACTION)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_ACTION,
        Parameters_SCENE_MODE_ACTION);
  Parameters_SCENE_MODE_ACTION = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_ACTION)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_ACTION);
  android_hardware_camera_parameters.SCENE_MODE_ACTION = NULL;
  if (Parameters_SCENE_MODE_PORTRAIT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_PORTRAIT,
        Parameters_SCENE_MODE_PORTRAIT);
  Parameters_SCENE_MODE_PORTRAIT = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_PORTRAIT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_PORTRAIT);
  android_hardware_camera_parameters.SCENE_MODE_PORTRAIT = NULL;
  if (Parameters_SCENE_MODE_LANDSCAPE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE,
        Parameters_SCENE_MODE_LANDSCAPE);
  Parameters_SCENE_MODE_LANDSCAPE = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE);
  android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE = NULL;
  if (Parameters_SCENE_MODE_NIGHT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_NIGHT,
        Parameters_SCENE_MODE_NIGHT);
  Parameters_SCENE_MODE_NIGHT = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_NIGHT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_NIGHT);
  android_hardware_camera_parameters.SCENE_MODE_NIGHT = NULL;
  if (Parameters_SCENE_MODE_NIGHT_PORTRAIT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT,
        Parameters_SCENE_MODE_NIGHT_PORTRAIT);
  Parameters_SCENE_MODE_NIGHT_PORTRAIT = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT);
  android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT = NULL;
  if (Parameters_SCENE_MODE_THEATRE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_THEATRE,
        Parameters_SCENE_MODE_THEATRE);
  Parameters_SCENE_MODE_THEATRE = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_THEATRE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_THEATRE);
  android_hardware_camera_parameters.SCENE_MODE_THEATRE = NULL;
  if (Parameters_SCENE_MODE_BEACH)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_BEACH,
        Parameters_SCENE_MODE_BEACH);
  Parameters_SCENE_MODE_BEACH = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_BEACH)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_BEACH);
  android_hardware_camera_parameters.SCENE_MODE_BEACH = NULL;
  if (Parameters_SCENE_MODE_SNOW)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_SNOW,
        Parameters_SCENE_MODE_SNOW);
  Parameters_SCENE_MODE_SNOW = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_SNOW)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_SNOW);
  android_hardware_camera_parameters.SCENE_MODE_SNOW = NULL;
  if (Parameters_SCENE_MODE_SUNSET)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_SUNSET,
        Parameters_SCENE_MODE_SUNSET);
  Parameters_SCENE_MODE_SUNSET = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_SUNSET)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_SUNSET);
  android_hardware_camera_parameters.SCENE_MODE_SUNSET = NULL;
  if (Parameters_SCENE_MODE_STEADYPHOTO)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO,
        Parameters_SCENE_MODE_STEADYPHOTO);
  Parameters_SCENE_MODE_STEADYPHOTO = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO);
  android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO = NULL;
  if (Parameters_SCENE_MODE_FIREWORKS)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_FIREWORKS,
        Parameters_SCENE_MODE_FIREWORKS);
  Parameters_SCENE_MODE_FIREWORKS = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_FIREWORKS)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_FIREWORKS);
  android_hardware_camera_parameters.SCENE_MODE_FIREWORKS = NULL;
  if (Parameters_SCENE_MODE_SPORTS)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_SPORTS,
        Parameters_SCENE_MODE_SPORTS);
  Parameters_SCENE_MODE_SPORTS = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_SPORTS)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_SPORTS);
  android_hardware_camera_parameters.SCENE_MODE_SPORTS = NULL;
  if (Parameters_SCENE_MODE_PARTY)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_PARTY,
        Parameters_SCENE_MODE_PARTY);
  Parameters_SCENE_MODE_PARTY = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_PARTY)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_PARTY);
  android_hardware_camera_parameters.SCENE_MODE_PARTY = NULL;
  if (Parameters_SCENE_MODE_CANDLELIGHT)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT,
        Parameters_SCENE_MODE_CANDLELIGHT);
  Parameters_SCENE_MODE_CANDLELIGHT = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT);
  android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT = NULL;
  if (Parameters_SCENE_MODE_BARCODE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.SCENE_MODE_BARCODE,
        Parameters_SCENE_MODE_BARCODE);
  Parameters_SCENE_MODE_BARCODE = NULL;
  if (android_hardware_camera_parameters.SCENE_MODE_BARCODE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.SCENE_MODE_BARCODE);
  android_hardware_camera_parameters.SCENE_MODE_BARCODE = NULL;
  if (Parameters_FOCUS_MODE_AUTO)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FOCUS_MODE_AUTO,
        Parameters_FOCUS_MODE_AUTO);
  Parameters_FOCUS_MODE_AUTO = NULL;
  if (android_hardware_camera_parameters.FOCUS_MODE_AUTO)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FOCUS_MODE_AUTO);
  android_hardware_camera_parameters.FOCUS_MODE_AUTO = NULL;
  if (Parameters_FOCUS_MODE_INFINITY)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FOCUS_MODE_INFINITY,
        Parameters_FOCUS_MODE_INFINITY);
  Parameters_FOCUS_MODE_INFINITY = NULL;
  if (android_hardware_camera_parameters.FOCUS_MODE_INFINITY)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FOCUS_MODE_INFINITY);
  android_hardware_camera_parameters.FOCUS_MODE_INFINITY = NULL;
  if (Parameters_FOCUS_MODE_MACRO)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FOCUS_MODE_MACRO,
        Parameters_FOCUS_MODE_MACRO);
  Parameters_FOCUS_MODE_MACRO = NULL;
  if (android_hardware_camera_parameters.FOCUS_MODE_MACRO)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FOCUS_MODE_MACRO);
  android_hardware_camera_parameters.FOCUS_MODE_MACRO = NULL;
  if (Parameters_FOCUS_MODE_FIXED)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FOCUS_MODE_FIXED,
        Parameters_FOCUS_MODE_FIXED);
  Parameters_FOCUS_MODE_FIXED = NULL;
  if (android_hardware_camera_parameters.FOCUS_MODE_FIXED)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FOCUS_MODE_FIXED);
  android_hardware_camera_parameters.FOCUS_MODE_FIXED = NULL;
  if (Parameters_FOCUS_MODE_EDOF)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FOCUS_MODE_EDOF,
        Parameters_FOCUS_MODE_EDOF);
  Parameters_FOCUS_MODE_EDOF = NULL;
  if (android_hardware_camera_parameters.FOCUS_MODE_EDOF)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FOCUS_MODE_EDOF);
  android_hardware_camera_parameters.FOCUS_MODE_EDOF = NULL;
  if (Parameters_FOCUS_MODE_CONTINUOUS_VIDEO)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
        Parameters_FOCUS_MODE_CONTINUOUS_VIDEO);
  Parameters_FOCUS_MODE_CONTINUOUS_VIDEO = NULL;
  if (android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
  android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO = NULL;
  if (Parameters_FOCUS_MODE_CONTINUOUS_PICTURE)
    (*env)->ReleaseStringUTFChars (env,
        android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
        Parameters_FOCUS_MODE_CONTINUOUS_PICTURE);
  Parameters_FOCUS_MODE_CONTINUOUS_PICTURE = NULL;
  if (android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE)
    (*env)->DeleteGlobalRef (env,
        android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
  android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE = NULL;

  if (java_lang_string.klass)
    (*env)->DeleteGlobalRef (env, java_lang_string.klass);
  java_lang_string.klass = NULL;

  if (java_util_list.klass)
    (*env)->DeleteGlobalRef (env, java_util_list.klass);
  java_util_list.klass = NULL;

  if (java_util_iterator.klass)
    (*env)->DeleteGlobalRef (env, java_util_iterator.klass);
  java_util_iterator.klass = NULL;

  if (java_lang_integer.klass)
    (*env)->DeleteGlobalRef (env, java_lang_integer.klass);
  java_lang_integer.klass = NULL;

  if (org_freedesktop_gstreamer_androidmedia_gstahccallback.klass) {
    (*env)->UnregisterNatives (env,
        org_freedesktop_gstreamer_androidmedia_gstahccallback.klass);
    (*env)->DeleteGlobalRef (env,
        org_freedesktop_gstreamer_androidmedia_gstahccallback.klass);
  }
  org_freedesktop_gstreamer_androidmedia_gstahccallback.klass = NULL;
}

/* android.hardware.Camera */
#define AHC_CALL(error_statement, type, method, ...)                    \
  GST_DVM_CALL (error_statement, self->object, type, android_hardware_camera, \
      method, ## __VA_ARGS__);
#define AHC_STATIC_CALL(error_statement, type, method, ...)             \
  GST_DVM_STATIC_CALL (error_statement, type, android_hardware_camera,  \
      method, ## __VA_ARGS__);

void
gst_ah_camera_add_callback_buffer (GstAHCamera * self, jbyteArray buffer)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  GST_DEBUG ("add callback_buffer %p", buffer);

  AHC_CALL (, Void, addCallbackBuffer, buffer);
}

gboolean
gst_ah_camera_auto_focus (GstAHCamera * self,
    GstAHCAutoFocusCallback cb, gpointer user_data)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject object = NULL;
  gboolean ret = FALSE;

  if (cb) {
    object = (*env)->NewObject (env,
        org_freedesktop_gstreamer_androidmedia_gstahccallback.klass,
        org_freedesktop_gstreamer_androidmedia_gstahccallback.constructor,
        *((jlong *) & cb), *((jlong *) & user_data));
    if (!object) {
      GST_ERROR ("Failed to create callback object");
      (*env)->ExceptionClear (env);
      goto done;
    }
  }

  AHC_CALL (goto done, Void, autoFocus, object);

  ret = TRUE;
done:
  if (object)
    (*env)->DeleteLocalRef (env, object);

  return ret;
}

gboolean
gst_ah_camera_cancel_auto_focus (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (return FALSE, Void, cancelAutoFocus);

  return TRUE;
}

gboolean
gst_ah_camera_get_camera_info (gint camera_id, GstAHCCameraInfo * camera_info)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject jcamera_info = NULL;
  gboolean ret = FALSE;

  jcamera_info = (*env)->NewObject (env,
      android_hardware_camera_camerainfo.klass,
      android_hardware_camera_camerainfo.constructor);
  if (!jcamera_info) {
    GST_ERROR ("Failed to call Java method");
    (*env)->ExceptionClear (env);
    goto done;
  }

  AHC_STATIC_CALL (goto done, Void, getCameraInfo, camera_id, jcamera_info);

  camera_info->facing = (*env)->GetIntField (env, jcamera_info,
      android_hardware_camera_camerainfo.facing);
  if ((*env)->ExceptionCheck (env)) {
    GST_ERROR ("Failed to get CameraInfo.facing field");
    (*env)->ExceptionClear (env);
    goto done;
  }

  camera_info->orientation = (*env)->GetIntField (env, jcamera_info,
      android_hardware_camera_camerainfo.orientation);
  if ((*env)->ExceptionCheck (env)) {
    GST_ERROR ("Failed to get CameraInfo.orientation field");
    (*env)->ExceptionClear (env);
    goto done;
  }

  ret = TRUE;
done:
  if (jcamera_info)
    (*env)->DeleteLocalRef (env, jcamera_info);

  return ret;
}

gint
gst_ah_camera_get_number_of_cameras (void)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gint num_cameras;

  num_cameras = AHC_STATIC_CALL (return -1, Int, getNumberOfCameras);

  return num_cameras;
}

GstAHCParameters *
gst_ah_camera_get_parameters (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject object = NULL;
  GstAHCParameters *params = NULL;

  object = AHC_CALL (return NULL, Object, getParameters);
  if (!object) {
    GST_WARNING ("android.hardware.Camera.getParameter is NULL");
    return NULL;
  }

  params = g_slice_new0 (GstAHCParameters);
  params->object = (*env)->NewGlobalRef (env, object);
  (*env)->DeleteLocalRef (env, object);
  if (!params->object) {
    GST_ERROR ("Failed to create global reference");
    (*env)->ExceptionClear (env);
    g_slice_free (GstAHCParameters, params);
    return NULL;
  }

  GST_DEBUG ("return parameters %p", params->object);

  return params;
}

gboolean
gst_ah_camera_lock (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (return FALSE, Void, lock);

  return TRUE;
}

GstAHCamera *
gst_ah_camera_open (gint camera_id)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject object = NULL;
  GstAHCamera *camera = NULL;

  object = AHC_STATIC_CALL (goto done, Object, open, camera_id);
  if (object) {
    camera = g_slice_new0 (GstAHCamera);
    camera->object = (*env)->NewGlobalRef (env, object);
    (*env)->DeleteLocalRef (env, object);
    if (!camera->object) {
      GST_ERROR ("Failed to create global reference");
      (*env)->ExceptionClear (env);
      g_slice_free (GstAHCamera, camera);
      camera = NULL;
    }
  }

done:
  return camera;
}

gboolean
gst_ah_camera_reconnect (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (return FALSE, Void, reconnect);

  return TRUE;
}

void
gst_ah_camera_release (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (, Void, release);
}

void
gst_ah_camera_free (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  (*env)->DeleteGlobalRef (env, self->object);
  g_slice_free (GstAHCamera, self);
}


gboolean
gst_ah_camera_set_parameters (GstAHCamera * self, GstAHCParameters * params)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (return FALSE, Void, setParameters, params->object);

  return TRUE;
}

gboolean
gst_ah_camera_set_error_callback (GstAHCamera * self, GstAHCErrorCallback cb,
    gpointer user_data)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject object = NULL;
  gboolean ret = FALSE;

  if (cb) {
    object = (*env)->NewObject (env,
        org_freedesktop_gstreamer_androidmedia_gstahccallback.klass,
        org_freedesktop_gstreamer_androidmedia_gstahccallback.constructor,
        *((jlong *) & cb), *((jlong *) & user_data));
    if (!object) {
      GST_ERROR ("Failed to create callback object");
      (*env)->ExceptionClear (env);
      goto done;
    }
  }

  AHC_CALL (goto done, Void, setErrorCallback, object);

  ret = TRUE;
done:
  if (object)
    (*env)->DeleteLocalRef (env, object);

  return ret;
}

gboolean
gst_ah_camera_set_preview_callback_with_buffer (GstAHCamera * self,
    GstAHCPreviewCallback cb, gpointer user_data)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject object = NULL;
  gboolean ret = FALSE;

  if (cb) {
    object = (*env)->NewObject (env,
        org_freedesktop_gstreamer_androidmedia_gstahccallback.klass,
        org_freedesktop_gstreamer_androidmedia_gstahccallback.constructor,
        *((jlong *) & cb), *((jlong *) & user_data));
    if (!object) {
      GST_ERROR ("Failed to create callback object");
      (*env)->ExceptionClear (env);
      goto done;
    }
  }

  AHC_CALL (goto done, Void, setPreviewCallbackWithBuffer, object);

  ret = TRUE;
done:
  if (object)
    (*env)->DeleteLocalRef (env, object);

  return ret;
}

void
gst_ah_camera_set_preview_texture (GstAHCamera * self,
    GstAGSurfaceTexture * surfaceTexture)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (, Void, setPreviewTexture, surfaceTexture->object);
}

gboolean
gst_ah_camera_start_preview (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (return FALSE, Void, startPreview);

  return TRUE;
}

gboolean
gst_ah_camera_start_smooth_zoom (GstAHCamera * self, gint value)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (return FALSE, Void, startSmoothZoom, value);

  return TRUE;
}

gboolean
gst_ah_camera_stop_preview (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (return FALSE, Void, stopPreview);

  return TRUE;
}

gboolean
gst_ah_camera_stop_smooth_zoom (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (return FALSE, Void, stopSmoothZoom);

  return TRUE;
}

gboolean
gst_ah_camera_unlock (GstAHCamera * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHC_CALL (return FALSE, Void, unlock);

  return TRUE;
}

#undef AHC_CALL
#undef AHC_STATIC_CALL

/* android.hardware.Camera.Size */
GstAHCSize *
gst_ahc_size_new (gint width, gint height)
{
  GstAHCSize *self = g_slice_new0 (GstAHCSize);

  self->width = width;
  self->height = height;

  return self;
}

void
gst_ahc_size_free (GstAHCSize * self)
{
  g_slice_free (GstAHCSize, self);
}

/* java.lang.String */
static jboolean
java_lang_string_equals (JNIEnv * env, jstring str, jstring obj)
{
  return (*env)->CallBooleanMethod (env, str, java_lang_string.equals, obj);
}

/* java.util.List */
static jobject
java_util_list_iterator (JNIEnv * env, jobject obj)
{
  return (*env)->CallObjectMethod (env, obj, java_util_list.iterator);
}

/* java.util.Iterator */
static jobject
java_util_iterator_next (JNIEnv * env, jobject obj)
{
  return (*env)->CallObjectMethod (env, obj, java_util_iterator.next);
}

static jboolean
java_util_iterator_has_next (JNIEnv * env, jobject obj)
{
  return (*env)->CallBooleanMethod (env, obj, java_util_iterator.hasNext);
}

/* java.lang.Integer */
static jint
java_lang_integer_int_value (JNIEnv * env, jobject obj)
{
  return (*env)->CallIntMethod (env, obj, java_lang_integer.intValue);
}


/* android.hardware.Camera.Parameters */
#define AHCP_CALL(error_statement, type, method, ...)                   \
  GST_DVM_CALL (error_statement, self->object, type,                    \
      android_hardware_camera_parameters, method, ## __VA_ARGS__);

#define AHCP_STATIC_CALL(error_statement, type, method, ...)            \
  GST_DVM_STATIC_CALL (error_statement, type,                           \
      android_hardware_camera_parameters, method, ## __VA_ARGS__);

static const gchar *
_white_balance_to_gchar (JNIEnv * env, jstring white_balance)
{
  if (!white_balance)
    return NULL;

  if (java_lang_string_equals (env, white_balance,
          android_hardware_camera_parameters.WHITE_BALANCE_AUTO))
    return Parameters_WHITE_BALANCE_AUTO;
  else if (java_lang_string_equals (env, white_balance,
          android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT))
    return Parameters_WHITE_BALANCE_INCANDESCENT;
  else if (java_lang_string_equals (env, white_balance,
          android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT))
    return Parameters_WHITE_BALANCE_FLUORESCENT;
  else if (java_lang_string_equals (env, white_balance,
          android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT))
    return Parameters_WHITE_BALANCE_WARM_FLUORESCENT;
  else if (java_lang_string_equals (env, white_balance,
          android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT))
    return Parameters_WHITE_BALANCE_DAYLIGHT;
  else if (java_lang_string_equals (env, white_balance,
          android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT))
    return Parameters_WHITE_BALANCE_CLOUDY_DAYLIGHT;
  else if (java_lang_string_equals (env, white_balance,
          android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT))
    return Parameters_WHITE_BALANCE_TWILIGHT;
  else if (java_lang_string_equals (env, white_balance,
          android_hardware_camera_parameters.WHITE_BALANCE_SHADE))
    return Parameters_WHITE_BALANCE_SHADE;

  return NULL;
}

static jstring
_white_balance_to_jstring (const gchar * white_balance)
{
  if (!white_balance)
    return NULL;

  if (!g_strcmp0 (white_balance, Parameters_WHITE_BALANCE_AUTO))
    return android_hardware_camera_parameters.WHITE_BALANCE_AUTO;
  else if (!g_strcmp0 (white_balance, Parameters_WHITE_BALANCE_INCANDESCENT))
    return android_hardware_camera_parameters.WHITE_BALANCE_INCANDESCENT;
  else if (!g_strcmp0 (white_balance, Parameters_WHITE_BALANCE_FLUORESCENT))
    return android_hardware_camera_parameters.WHITE_BALANCE_FLUORESCENT;
  else if (!g_strcmp0 (white_balance,
          Parameters_WHITE_BALANCE_WARM_FLUORESCENT))
    return android_hardware_camera_parameters.WHITE_BALANCE_WARM_FLUORESCENT;
  else if (!g_strcmp0 (white_balance, Parameters_WHITE_BALANCE_DAYLIGHT))
    return android_hardware_camera_parameters.WHITE_BALANCE_DAYLIGHT;
  else if (!g_strcmp0 (white_balance, Parameters_WHITE_BALANCE_CLOUDY_DAYLIGHT))
    return android_hardware_camera_parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT;
  else if (!g_strcmp0 (white_balance, Parameters_WHITE_BALANCE_TWILIGHT))
    return android_hardware_camera_parameters.WHITE_BALANCE_TWILIGHT;
  else if (!g_strcmp0 (white_balance, Parameters_WHITE_BALANCE_SHADE))
    return android_hardware_camera_parameters.WHITE_BALANCE_SHADE;

  return NULL;
}

static const gchar *
_color_effect_to_gchar (JNIEnv * env, jstring color_effect)
{
  if (!color_effect)
    return NULL;

  if (java_lang_string_equals (env, color_effect,
          android_hardware_camera_parameters.EFFECT_NONE))
    return Parameters_EFFECT_NONE;
  else if (java_lang_string_equals (env, color_effect,
          android_hardware_camera_parameters.EFFECT_MONO))
    return Parameters_EFFECT_MONO;
  else if (java_lang_string_equals (env, color_effect,
          android_hardware_camera_parameters.EFFECT_NEGATIVE))
    return Parameters_EFFECT_NEGATIVE;
  else if (java_lang_string_equals (env, color_effect,
          android_hardware_camera_parameters.EFFECT_SOLARIZE))
    return Parameters_EFFECT_SOLARIZE;
  else if (java_lang_string_equals (env, color_effect,
          android_hardware_camera_parameters.EFFECT_SEPIA))
    return Parameters_EFFECT_SEPIA;
  else if (java_lang_string_equals (env, color_effect,
          android_hardware_camera_parameters.EFFECT_POSTERIZE))
    return Parameters_EFFECT_POSTERIZE;
  else if (java_lang_string_equals (env, color_effect,
          android_hardware_camera_parameters.EFFECT_WHITEBOARD))
    return Parameters_EFFECT_WHITEBOARD;
  else if (java_lang_string_equals (env, color_effect,
          android_hardware_camera_parameters.EFFECT_BLACKBOARD))
    return Parameters_EFFECT_BLACKBOARD;
  else if (java_lang_string_equals (env, color_effect,
          android_hardware_camera_parameters.EFFECT_AQUA))
    return Parameters_EFFECT_AQUA;

  return NULL;
}

static jstring
_color_effect_to_jstring (const gchar * color_effect)
{
  if (!color_effect)
    return NULL;

  if (!g_strcmp0 (color_effect, Parameters_EFFECT_NONE))
    return android_hardware_camera_parameters.EFFECT_NONE;
  else if (!g_strcmp0 (color_effect, Parameters_EFFECT_MONO))
    return android_hardware_camera_parameters.EFFECT_MONO;
  else if (!g_strcmp0 (color_effect, Parameters_EFFECT_NEGATIVE))
    return android_hardware_camera_parameters.EFFECT_NEGATIVE;
  else if (!g_strcmp0 (color_effect, Parameters_EFFECT_SOLARIZE))
    return android_hardware_camera_parameters.EFFECT_SOLARIZE;
  else if (!g_strcmp0 (color_effect, Parameters_EFFECT_SEPIA))
    return android_hardware_camera_parameters.EFFECT_SEPIA;
  else if (!g_strcmp0 (color_effect, Parameters_EFFECT_POSTERIZE))
    return android_hardware_camera_parameters.EFFECT_POSTERIZE;
  else if (!g_strcmp0 (color_effect, Parameters_EFFECT_WHITEBOARD))
    return android_hardware_camera_parameters.EFFECT_WHITEBOARD;
  else if (!g_strcmp0 (color_effect, Parameters_EFFECT_BLACKBOARD))
    return android_hardware_camera_parameters.EFFECT_BLACKBOARD;
  else if (!g_strcmp0 (color_effect, Parameters_EFFECT_AQUA))
    return android_hardware_camera_parameters.EFFECT_AQUA;

  return NULL;
}

static const gchar *
_antibanding_to_gchar (JNIEnv * env, jstring antibanding)
{
  if (!antibanding)
    return NULL;

  if (java_lang_string_equals (env, antibanding,
          android_hardware_camera_parameters.ANTIBANDING_AUTO))
    return Parameters_ANTIBANDING_AUTO;
  else if (java_lang_string_equals (env, antibanding,
          android_hardware_camera_parameters.ANTIBANDING_50HZ))
    return Parameters_ANTIBANDING_50HZ;
  else if (java_lang_string_equals (env, antibanding,
          android_hardware_camera_parameters.ANTIBANDING_60HZ))
    return Parameters_ANTIBANDING_60HZ;
  else if (java_lang_string_equals (env, antibanding,
          android_hardware_camera_parameters.ANTIBANDING_OFF))
    return Parameters_ANTIBANDING_OFF;

  return NULL;
}

static jstring
_antibanding_to_jstring (const gchar * antibanding)
{
  if (!antibanding)
    return NULL;

  if (!g_strcmp0 (antibanding, Parameters_ANTIBANDING_AUTO))
    return android_hardware_camera_parameters.ANTIBANDING_AUTO;
  else if (!g_strcmp0 (antibanding, Parameters_ANTIBANDING_50HZ))
    return android_hardware_camera_parameters.ANTIBANDING_50HZ;
  else if (!g_strcmp0 (antibanding, Parameters_ANTIBANDING_60HZ))
    return android_hardware_camera_parameters.ANTIBANDING_60HZ;
  else if (!g_strcmp0 (antibanding, Parameters_ANTIBANDING_OFF))
    return android_hardware_camera_parameters.ANTIBANDING_OFF;

  return NULL;
}

static const gchar *
_flash_mode_to_gchar (JNIEnv * env, jstring flash_mode)
{
  if (!flash_mode)
    return NULL;

  if (java_lang_string_equals (env, flash_mode,
          android_hardware_camera_parameters.FLASH_MODE_OFF))
    return Parameters_FLASH_MODE_OFF;
  else if (java_lang_string_equals (env, flash_mode,
          android_hardware_camera_parameters.FLASH_MODE_AUTO))
    return Parameters_FLASH_MODE_AUTO;
  else if (java_lang_string_equals (env, flash_mode,
          android_hardware_camera_parameters.FLASH_MODE_ON))
    return Parameters_FLASH_MODE_ON;
  else if (java_lang_string_equals (env, flash_mode,
          android_hardware_camera_parameters.FLASH_MODE_RED_EYE))
    return Parameters_FLASH_MODE_RED_EYE;
  else if (java_lang_string_equals (env, flash_mode,
          android_hardware_camera_parameters.FLASH_MODE_TORCH))
    return Parameters_FLASH_MODE_TORCH;

  return NULL;
}

static jstring
_flash_mode_to_jstring (const gchar * flash_mode)
{
  if (!flash_mode)
    return NULL;

  if (!g_strcmp0 (flash_mode, Parameters_FLASH_MODE_OFF))
    return android_hardware_camera_parameters.FLASH_MODE_OFF;
  else if (!g_strcmp0 (flash_mode, Parameters_FLASH_MODE_AUTO))
    return android_hardware_camera_parameters.FLASH_MODE_AUTO;
  else if (!g_strcmp0 (flash_mode, Parameters_FLASH_MODE_ON))
    return android_hardware_camera_parameters.FLASH_MODE_ON;
  else if (!g_strcmp0 (flash_mode, Parameters_FLASH_MODE_RED_EYE))
    return android_hardware_camera_parameters.FLASH_MODE_RED_EYE;
  else if (!g_strcmp0 (flash_mode, Parameters_FLASH_MODE_TORCH))
    return android_hardware_camera_parameters.FLASH_MODE_TORCH;

  return NULL;
}

static const gchar *
_scene_mode_to_gchar (JNIEnv * env, jstring scene_mode)
{
  if (!scene_mode)
    return NULL;

  if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_AUTO))
    return Parameters_SCENE_MODE_AUTO;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_ACTION))
    return Parameters_SCENE_MODE_ACTION;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_PORTRAIT))
    return Parameters_SCENE_MODE_PORTRAIT;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE))
    return Parameters_SCENE_MODE_LANDSCAPE;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_NIGHT))
    return Parameters_SCENE_MODE_NIGHT;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT))
    return Parameters_SCENE_MODE_NIGHT_PORTRAIT;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_THEATRE))
    return Parameters_SCENE_MODE_THEATRE;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_BEACH))
    return Parameters_SCENE_MODE_BEACH;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_SNOW))
    return Parameters_SCENE_MODE_SNOW;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_SUNSET))
    return Parameters_SCENE_MODE_SUNSET;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO))
    return Parameters_SCENE_MODE_STEADYPHOTO;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_FIREWORKS))
    return Parameters_SCENE_MODE_FIREWORKS;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_SPORTS))
    return Parameters_SCENE_MODE_SPORTS;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_PARTY))
    return Parameters_SCENE_MODE_PARTY;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT))
    return Parameters_SCENE_MODE_CANDLELIGHT;
  else if (java_lang_string_equals (env, scene_mode,
          android_hardware_camera_parameters.SCENE_MODE_BARCODE))
    return Parameters_SCENE_MODE_BARCODE;

  return NULL;
}

static const jstring
_scene_mode_to_jstring (const gchar * scene_mode)
{
  if (!scene_mode)
    return NULL;

  if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_AUTO))
    return android_hardware_camera_parameters.SCENE_MODE_AUTO;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_ACTION))
    return android_hardware_camera_parameters.SCENE_MODE_ACTION;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_PORTRAIT))
    return android_hardware_camera_parameters.SCENE_MODE_PORTRAIT;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_LANDSCAPE))
    return android_hardware_camera_parameters.SCENE_MODE_LANDSCAPE;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_NIGHT))
    return android_hardware_camera_parameters.SCENE_MODE_NIGHT;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_NIGHT_PORTRAIT))
    return android_hardware_camera_parameters.SCENE_MODE_NIGHT_PORTRAIT;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_THEATRE))
    return android_hardware_camera_parameters.SCENE_MODE_THEATRE;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_BEACH))
    return android_hardware_camera_parameters.SCENE_MODE_BEACH;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_SNOW))
    return android_hardware_camera_parameters.SCENE_MODE_SNOW;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_SUNSET))
    return android_hardware_camera_parameters.SCENE_MODE_SUNSET;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_STEADYPHOTO))
    return android_hardware_camera_parameters.SCENE_MODE_STEADYPHOTO;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_FIREWORKS))
    return android_hardware_camera_parameters.SCENE_MODE_FIREWORKS;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_SPORTS))
    return android_hardware_camera_parameters.SCENE_MODE_SPORTS;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_PARTY))
    return android_hardware_camera_parameters.SCENE_MODE_PARTY;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_CANDLELIGHT))
    return android_hardware_camera_parameters.SCENE_MODE_CANDLELIGHT;
  else if (!g_strcmp0 (scene_mode, Parameters_SCENE_MODE_BARCODE))
    return android_hardware_camera_parameters.SCENE_MODE_BARCODE;

  return NULL;
}

static const gchar *
_focus_mode_to_gchar (JNIEnv * env, jstring focus_mode)
{
  if (!focus_mode)
    return NULL;

  if (java_lang_string_equals (env, focus_mode,
          android_hardware_camera_parameters.FOCUS_MODE_AUTO))
    return Parameters_FOCUS_MODE_AUTO;
  else if (java_lang_string_equals (env, focus_mode,
          android_hardware_camera_parameters.FOCUS_MODE_INFINITY))
    return Parameters_FOCUS_MODE_INFINITY;
  else if (java_lang_string_equals (env, focus_mode,
          android_hardware_camera_parameters.FOCUS_MODE_MACRO))
    return Parameters_FOCUS_MODE_MACRO;
  else if (java_lang_string_equals (env, focus_mode,
          android_hardware_camera_parameters.FOCUS_MODE_FIXED))
    return Parameters_FOCUS_MODE_FIXED;
  else if (java_lang_string_equals (env, focus_mode,
          android_hardware_camera_parameters.FOCUS_MODE_EDOF))
    return Parameters_FOCUS_MODE_EDOF;
  else if (java_lang_string_equals (env, focus_mode,
          android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
    return Parameters_FOCUS_MODE_CONTINUOUS_VIDEO;
  else if (java_lang_string_equals (env, focus_mode,
          android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
    return Parameters_FOCUS_MODE_CONTINUOUS_PICTURE;

  return NULL;
}

static jstring
_focus_mode_to_jstring (const gchar * focus_mode)
{
  if (!focus_mode)
    return NULL;

  if (!g_strcmp0 (focus_mode, Parameters_FOCUS_MODE_AUTO))
    return android_hardware_camera_parameters.FOCUS_MODE_AUTO;
  else if (!g_strcmp0 (focus_mode, Parameters_FOCUS_MODE_INFINITY))
    return android_hardware_camera_parameters.FOCUS_MODE_INFINITY;
  else if (!g_strcmp0 (focus_mode, Parameters_FOCUS_MODE_MACRO))
    return android_hardware_camera_parameters.FOCUS_MODE_MACRO;
  else if (!g_strcmp0 (focus_mode, Parameters_FOCUS_MODE_FIXED))
    return android_hardware_camera_parameters.FOCUS_MODE_FIXED;
  else if (!g_strcmp0 (focus_mode, Parameters_FOCUS_MODE_EDOF))
    return android_hardware_camera_parameters.FOCUS_MODE_EDOF;
  else if (!g_strcmp0 (focus_mode, Parameters_FOCUS_MODE_CONTINUOUS_VIDEO))
    return android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
  else if (!g_strcmp0 (focus_mode, Parameters_FOCUS_MODE_CONTINUOUS_PICTURE))
    return android_hardware_camera_parameters.FOCUS_MODE_CONTINUOUS_PICTURE;

  return NULL;
}

gchar *
gst_ahc_parameters_flatten (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jstring v_str = NULL;
  const gchar *v = NULL;
  gchar *ret = NULL;

  v_str = AHCP_CALL (goto done, Object, flatten);
  v = (*env)->GetStringUTFChars (env, v_str, NULL);
  if (!v) {
    GST_ERROR ("Failed to convert string to UTF8");
    (*env)->ExceptionClear (env);
    goto done;
  }

  ret = g_strdup (v);
done:
  if (v)
    (*env)->ReleaseStringUTFChars (env, v_str, v);
  if (v_str)
    (*env)->DeleteLocalRef (env, v_str);

  return ret;
}

const gchar *
gst_ahc_parameters_get_antibanding (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  const gchar *ret = NULL;
  jstring antibanding;

  antibanding = AHCP_CALL (return NULL, Object, getAntibanding);

  ret = _antibanding_to_gchar (env, antibanding);

  if (antibanding)
    (*env)->DeleteLocalRef (env, antibanding);

  return ret;
}

const gchar *
gst_ahc_parameters_get_color_effect (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  const gchar *ret = NULL;
  jstring color_effect;

  color_effect = AHCP_CALL (return NULL, Object, getColorEffect);

  ret = _color_effect_to_gchar (env, color_effect);

  if (color_effect)
    (*env)->DeleteLocalRef (env, color_effect);

  return ret;
}

gint
gst_ahc_parameters_get_exposure_compensation (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gint ev;

  ev = AHCP_CALL (return -1, Int, getExposureCompensation);

  return ev;
}

gfloat
gst_ahc_parameters_get_exposure_compensation_step (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gfloat step;

  step = AHCP_CALL (return 0.0, Float, getExposureCompensationStep);

  return step;
}

const gchar *
gst_ahc_parameters_get_flash_mode (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  const gchar *ret = NULL;
  jstring flash_mode;

  flash_mode = AHCP_CALL (return NULL, Object, getFlashMode);

  ret = _flash_mode_to_gchar (env, flash_mode);

  if (flash_mode)
    (*env)->DeleteLocalRef (env, flash_mode);

  return ret;
}

gfloat
gst_ahc_parameters_get_focal_length (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gfloat length;

  length = AHCP_CALL (return 0.0, Float, getFocalLength);

  return length;
}

const gchar *
gst_ahc_parameters_get_focus_mode (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  const gchar *ret = NULL;
  jstring focus_mode;

  focus_mode = AHCP_CALL (return NULL, Object, getFocusMode);

  ret = _focus_mode_to_gchar (env, focus_mode);

  if (focus_mode)
    (*env)->DeleteLocalRef (env, focus_mode);

  return ret;
}

gfloat
gst_ahc_parameters_get_horizontal_view_angle (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gfloat angle;

  angle = AHCP_CALL (return 0.0, Float, getHorizontalViewAngle);

  return angle;
}

gint
gst_ahc_parameters_get_max_exposure_compensation (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gint max;

  max = AHCP_CALL (return 0, Int, getMaxExposureCompensation);

  return max;
}

gint
gst_ahc_parameters_get_max_zoom (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gint max;

  max = AHCP_CALL (return -1, Int, getMaxZoom);

  return max;
}

gint
gst_ahc_parameters_get_min_exposure_compensation (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gint min;

  min = AHCP_CALL (return 0, Int, getMinExposureCompensation);

  return min;
}

gint
gst_ahc_parameters_get_preview_format (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gint format;

  format = AHCP_CALL (return 0, Int, getPreviewFormat);

  return format;
}

gboolean
gst_ahc_parameters_get_preview_fps_range (GstAHCParameters * self,
    gint * min, gint * max)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gboolean ret = FALSE;
  jintArray range = NULL;
  jint *fps = NULL;

  range = (*env)->NewIntArray (env, 2);
  if (!fps) {
    (*env)->ExceptionClear (env);
    GST_ERROR ("Failed to create array");
    goto done;
  }

  AHCP_CALL (goto done, Void, getPreviewFpsRange, range);

  fps = (*env)->GetIntArrayElements (env, range, NULL);
  if ((*env)->ExceptionCheck (env) || !fps) {
    (*env)->ExceptionClear (env);
    GST_ERROR ("Failed to get array elements");
    goto done;
  }
  if (min)
    *min = fps[0];
  if (max)
    *max = fps[1];

  ret = TRUE;
done:
  if (fps)
    (*env)->ReleaseIntArrayElements (env, range, fps, JNI_ABORT);
  if (range)
    (*env)->DeleteLocalRef (env, range);

  return ret;
}

GstAHCSize *
gst_ahc_parameters_get_preview_size (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject jsize = NULL;
  GstAHCSize *size = NULL;

  jsize = AHCP_CALL (goto done, Object, getPreviewSize);

  size = g_slice_new0 (GstAHCSize);

  size->width = (*env)->GetIntField (env, jsize,
      android_hardware_camera_size.width);
  if ((*env)->ExceptionCheck (env)) {
    GST_ERROR ("Failed to get Camera.Size.width field");
    (*env)->ExceptionClear (env);
    g_slice_free (GstAHCSize, size);
    size = NULL;
    goto done;
  }

  size->height = (*env)->GetIntField (env, jsize,
      android_hardware_camera_size.height);
  if ((*env)->ExceptionCheck (env)) {
    GST_ERROR ("Failed to get Camera.Size.height field");
    (*env)->ExceptionClear (env);
    g_slice_free (GstAHCSize, size);
    size = NULL;
    goto done;
  }

done:
  if (jsize)
    (*env)->DeleteLocalRef (env, jsize);

  return size;
}

const gchar *
gst_ahc_parameters_get_scene_mode (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  const gchar *ret = NULL;
  jstring scene_mode;

  scene_mode = AHCP_CALL (return NULL, Object, getSceneMode);

  ret = _scene_mode_to_gchar (env, scene_mode);

  if (scene_mode)
    (*env)->DeleteLocalRef (env, scene_mode);

  return ret;
}

GList *
gst_ahc_parameters_get_supported_antibanding (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getSupportedAntibanding);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jobject str = java_util_iterator_next (env, iterator);

        if (str) {
          const gchar *value = _antibanding_to_gchar (env, str);

          ret = g_list_append (ret, (gchar *) value);
          (*env)->DeleteLocalRef (env, str);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_supported_antibanding_free (GList * list)
{
  g_list_free (list);
}

GList *
gst_ahc_parameters_get_supported_color_effects (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getSupportedColorEffects);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jobject str = java_util_iterator_next (env, iterator);

        if (str) {
          const gchar *value = _color_effect_to_gchar (env, str);

          ret = g_list_append (ret, (gchar *) value);
          (*env)->DeleteLocalRef (env, str);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_supported_color_effects_free (GList * list)
{
  g_list_free (list);
}

GList *
gst_ahc_parameters_get_supported_flash_modes (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getSupportedFlashModes);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jobject str = java_util_iterator_next (env, iterator);

        if (str) {
          const gchar *value = _flash_mode_to_gchar (env, str);

          ret = g_list_append (ret, (gchar *) value);
          (*env)->DeleteLocalRef (env, str);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_supported_flash_modes_free (GList * list)
{
  g_list_free (list);
}

GList *
gst_ahc_parameters_get_supported_focus_modes (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getSupportedFocusModes);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jobject str = java_util_iterator_next (env, iterator);

        if (str) {
          const gchar *value = _focus_mode_to_gchar (env, str);

          ret = g_list_append (ret, (gchar *) value);
          (*env)->DeleteLocalRef (env, str);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_supported_focus_modes_free (GList * list)
{
  g_list_free (list);
}

GList *
gst_ahc_parameters_get_supported_preview_formats (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getSupportedPreviewFormats);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jobject integer = java_util_iterator_next (env, iterator);

        if (integer) {
          jint value = java_lang_integer_int_value (env, integer);

          ret = g_list_append (ret, GINT_TO_POINTER (value));
          (*env)->DeleteLocalRef (env, integer);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_supported_preview_formats_free (GList * list)
{
  g_list_free (list);
}

GList *
gst_ahc_parameters_get_supported_preview_fps_range (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getSupportedPreviewFpsRange);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jintArray range = java_util_iterator_next (env, iterator);

        if (range) {
          jint *fps = g_new (jint, 2);

          (*env)->GetIntArrayRegion (env, range, 0, 2, fps);
          ret = g_list_append (ret, fps);
          (*env)->DeleteLocalRef (env, range);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_supported_preview_fps_range_free (GList * list)
{
  g_list_foreach (list, (GFunc) g_free, NULL);
  g_list_free (list);
}

GList *
gst_ahc_parameters_get_supported_preview_sizes (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getSupportedPreviewSizes);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jobject jsize = java_util_iterator_next (env, iterator);

        if (jsize) {
          jint width, height;

          width = (*env)->GetIntField (env, jsize,
              android_hardware_camera_size.width);
          height = (*env)->GetIntField (env, jsize,
              android_hardware_camera_size.height);

          ret = g_list_append (ret, gst_ahc_size_new (width, height));
          (*env)->DeleteLocalRef (env, jsize);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_supported_preview_sizes_free (GList * list)
{
  g_list_foreach (list, (GFunc) gst_ahc_size_free, NULL);
  g_list_free (list);
}

GList *
gst_ahc_parameters_get_supported_scene_modes (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getSupportedSceneModes);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jobject str = java_util_iterator_next (env, iterator);

        if (str) {
          const gchar *value = _scene_mode_to_gchar (env, str);

          ret = g_list_append (ret, (gchar *) value);
          (*env)->DeleteLocalRef (env, str);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_supported_scene_modes_free (GList * list)
{
  g_list_free (list);
}

GList *
gst_ahc_parameters_get_supported_white_balance (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getSupportedWhiteBalance);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jobject str = java_util_iterator_next (env, iterator);

        if (str) {
          const gchar *value = _white_balance_to_gchar (env, str);

          ret = g_list_append (ret, (gchar *) value);
          (*env)->DeleteLocalRef (env, str);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_supported_white_balance_free (GList * list)
{
  g_list_free (list);
}

gfloat
gst_ahc_parameters_get_vertical_view_angle (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gfloat angle;

  angle = AHCP_CALL (return 0.0, Float, getVerticalViewAngle);

  return angle;
}

gboolean
gst_ahc_parameters_get_video_stabilization (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gboolean ret;

  ret = AHCP_CALL (return FALSE, Boolean, getVideoStabilization);

  return ret;
}

const gchar *
gst_ahc_parameters_get_white_balance (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  const gchar *ret = NULL;
  jstring white_balance;

  white_balance = AHCP_CALL (return NULL, Object, getWhiteBalance);

  ret = _white_balance_to_gchar (env, white_balance);

  if (white_balance)
    (*env)->DeleteLocalRef (env, white_balance);

  return ret;
}

gint
gst_ahc_parameters_get_zoom (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gint zoom;

  zoom = AHCP_CALL (return -1, Int, getZoom);

  return zoom;
}

GList *
gst_ahc_parameters_get_zoom_ratios (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jobject list = NULL;
  GList *ret = NULL;

  list = AHCP_CALL (return NULL, Object, getZoomRatios);

  if (list) {
    jobject iterator = NULL;

    iterator = java_util_list_iterator (env, list);
    if (iterator) {
      while (java_util_iterator_has_next (env, iterator)) {
        jobject integer = java_util_iterator_next (env, iterator);

        if (integer) {
          jint value = java_lang_integer_int_value (env, integer);

          ret = g_list_append (ret, GINT_TO_POINTER (value));
          (*env)->DeleteLocalRef (env, integer);
        }
      }
      (*env)->DeleteLocalRef (env, iterator);
    }
    (*env)->DeleteLocalRef (env, list);
  }

  return ret;
}

void
gst_ahc_parameters_zoom_ratios_free (GList * list)
{
  g_list_free (list);
}

gboolean
gst_ahc_parameters_is_smooth_zoom_supported (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gboolean supported;

  supported = AHCP_CALL (return FALSE, Boolean, isSmoothZoomSupported);

  return supported;
}

gboolean
gst_ahc_parameters_is_video_stabilization_supported (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gboolean supported;

  supported = AHCP_CALL (return FALSE, Boolean, isVideoStabilizationSupported);

  return supported;
}

gboolean
gst_ahc_parameters_is_zoom_supported (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  gboolean supported;

  supported = AHCP_CALL (return FALSE, Boolean, isZoomSupported);

  return supported;
}

gboolean
gst_ahc_parameters_set_antibanding (GstAHCParameters * self,
    const gchar * value)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jstring antibanding;

  antibanding = _antibanding_to_jstring (value);
  if (!antibanding)
    return FALSE;

  AHCP_CALL (return FALSE, Void, setAntibanding, antibanding);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_color_effect (GstAHCParameters * self,
    const gchar * value)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jstring color_effect;

  color_effect = _color_effect_to_jstring (value);
  if (!color_effect)
    return FALSE;

  AHCP_CALL (return FALSE, Void, setColorEffect, color_effect);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_exposure_compensation (GstAHCParameters * self,
    gint value)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHCP_CALL (return FALSE, Void, setExposureCompensation, value);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_flash_mode (GstAHCParameters * self, const gchar * value)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jstring flash_mode;

  flash_mode = _flash_mode_to_jstring (value);
  if (!flash_mode)
    return FALSE;

  AHCP_CALL (return FALSE, Void, setFlashMode, flash_mode);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_focus_mode (GstAHCParameters * self, const gchar * value)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jstring focus_mode;

  focus_mode = _focus_mode_to_jstring (value);
  if (!focus_mode)
    return FALSE;

  AHCP_CALL (return FALSE, Void, setFocusMode, focus_mode);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_preview_format (GstAHCParameters * self, gint format)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHCP_CALL (return FALSE, Void, setPreviewFormat, format);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_preview_fps_range (GstAHCParameters * self,
    gint min, gint max)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHCP_CALL (return FALSE, Void, setPreviewFpsRange, min, max);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_preview_size (GstAHCParameters * self,
    gint width, gint height)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHCP_CALL (return FALSE, Void, setPreviewSize, width, height);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_scene_mode (GstAHCParameters * self, const gchar * value)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jstring scene_mode;

  scene_mode = _scene_mode_to_jstring (value);
  if (!scene_mode)
    return FALSE;

  AHCP_CALL (return FALSE, Void, setSceneMode, scene_mode);

  return TRUE;
}


gboolean
gst_ahc_parameters_set_video_stabilization (GstAHCParameters * self,
    gboolean toggle)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHCP_CALL (return FALSE, Void, setVideoStabilization, toggle);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_white_balance (GstAHCParameters * self,
    const gchar * value)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jstring white_balance;

  white_balance = _white_balance_to_jstring (value);
  if (!white_balance)
    return FALSE;

  AHCP_CALL (return FALSE, Void, setWhiteBalance, white_balance);

  return TRUE;
}

gboolean
gst_ahc_parameters_set_zoom (GstAHCParameters * self, gint value)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  AHCP_CALL (return FALSE, Void, setZoom, value);

  return TRUE;
}

gboolean
gst_ahc_parameters_unflatten (GstAHCParameters * self, const gchar * flattened)
{
  JNIEnv *env = gst_amc_jni_get_env ();
  jstring v_str = NULL;
  gboolean ret = TRUE;

  v_str = (*env)->NewStringUTF (env, flattened);
  if (v_str == NULL)
    return FALSE;

  AHCP_CALL (ret = FALSE, Void, unflatten, v_str);

  (*env)->DeleteLocalRef (env, v_str);

  return ret;
}

void
gst_ahc_parameters_free (GstAHCParameters * self)
{
  JNIEnv *env = gst_amc_jni_get_env ();

  g_return_if_fail (self != NULL);
  g_return_if_fail (self->object != NULL);

  GST_DEBUG ("freeing parameters %p", self->object);

  (*env)->DeleteGlobalRef (env, self->object);
  g_slice_free (GstAHCParameters, self);
}
