2

I have an app, which sets the hardware parameters of the Camera programmatically.

However, as I've been told, and have come to observe, not all chipsets support all parameters.

For example, the Nexus 4 (Qualcomm) has sharpness, and sharpness-max parameters, the Galaxy Note II 3g doesn't have any.

Hence, when I set sharpness parameter, the Nexus responds well, but the Galaxy force closes:

java.lang.RuntimeException: setParameters failed
at android.hardware.Camera.native_setParameters(Native Method)
at android.hardware.Camera.setParameters(Camera.java:1452)

My question is, how can I get the RAW info programmatically? I need to get the parameters, their values, and whether they exist or not.

I wish to get the RAW-Metadata parameters, as like this: database

Kev
  • 118,037
  • 53
  • 300
  • 385
Avijit
  • 391
  • 2
  • 21

1 Answers1

3

Alright, thought this would be a fun bit of practice. So, Android does not give a public API into this information. Why? I have no idea. Looks like you can do a Camera.Parameters#get(String) to check for any particular parameter that you're interested in, but lets say you're greedy and want the whole list to yourself. In that case, we can dive in using Reflection, but be aware that there is a strong possibility that this will not work on all versions of Android or may break in future versions. With that said, here's how you do it:

private static Map<String, String> getFullCameraParameters (Camera cam) {
    Map<String, String> result = new HashMap<String, String>(64);
    final String TAG = "CameraParametersRetrieval";

    try {
        Class camClass = cam.getClass();

        //Internally, Android goes into native code to retrieve this String of values
        Method getNativeParams = camClass.getDeclaredMethod("native_getParameters");
        getNativeParams.setAccessible(true);

        //Boom. Here's the raw String from the hardware
        String rawParamsStr = (String) getNativeParams.invoke(cam);

        //But let's do better. Here's what Android uses to parse the
        //String into a usable Map -- a simple ';' StringSplitter, followed
        //by splitting on '='
        //
        //Taken from Camera.Parameters unflatten() method
        TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(';');
        splitter.setString(rawParamsStr);

        for (String kv : splitter) {
            int pos = kv.indexOf('=');
            if (pos == -1) {
                continue;
            }
            String k = kv.substring(0, pos);
            String v = kv.substring(pos + 1);
            result.put(k, v);
        }

        //And voila, you have a map of ALL supported parameters
        return result;
    } catch (NoSuchMethodException ex) {
        Log.e(TAG, ex.toString());
    } catch (IllegalAccessException ex) {
        Log.e(TAG, ex.toString());
    } catch (InvocationTargetException ex) {
        Log.e(TAG, ex.toString());
    }

    //If there was any error, just return an empty Map
    Log.e(TAG, "Unable to retrieve parameters from Camera.");
    return result;
}
Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • Wow! This looks like a great solution. I never used splitter though, maybe using two arrays, one for the strings, and one for the values, would be easier? Thanks again. :) – Avijit Sep 08 '13 at 10:18
  • 1
    No prob. :) And don't worry about the splitter, the result is that you get a map -- keys and values. The splitter just breaks up the semicolor-separated string into its parts. Using a Map for this is much easier IMO than keeping two unsynchronized arrays. – Kevin Coppock Sep 08 '13 at 10:22
  • There's a bit of a problem: int cont= Camera.Parameters#get("contrast"); says Camera.Parameters cannot be resolved to a variable. I need to invoke this in a simple non-activity class, and get the values. Could you tell what import and adjustments are needed to catch the values? – Avijit Sep 08 '13 at 10:56
  • Uh oh, I get force close at Class camClass = cam.getClass(); As a parameter cam to your function I've passed a public static variable mCamera, which is in another class, and mCamera s the only and main Camera object in my app. – Avijit Sep 08 '13 at 16:16
  • #get is just Javadoc syntax referring to that method, that's not actual Java code. There's a `get()` method on `Camera.Parameters`. Did you step through and debug, and check the logs to see why the crash occurred? I can tell you that your Camera variable would have to have been null for it to crash there. – Kevin Coppock Sep 08 '13 at 18:58
  • So now the null is fixed,but the toast below is never displayed. `void contrastexist() { boolean exist=true; String key1="sharpness"; String sharp="N/A"; Map para= getFullCameraParameters(MyCameraActivity.getCamera()); try{if(key1!=null) {sharp = para.get(key1);} else{ exist=false;} } catch(NullPointerException e) { e.printStackTrace();} if(exist) { Toast.makeText(context, key1+" "+sharp+" "+, Toast.LENGTH_LONG).show(); } }` – Avijit Sep 09 '13 at 01:35
  • 1
    Sorry, but this is far outside the scope of this question. You need to learn how to debug your app and figure out where and why it's failing. Firstly, you have an egregious amount of null checks. You're checking if `key1` (which you JUST assigned) is null, and also doing a try/catch for NPE? That entire method could be changed to `getFullCameraParameters(camera).containsKey("sharpness");` – Kevin Coppock Sep 09 '13 at 03:46
  • OK, I fixed it.Instead of calling a camera instance that might have been released long ago, I created a new one, used it in the above method, and released it. Thanks thanks thanks! :) – Avijit Sep 09 '13 at 11:48