OSDN Git Service

camera2: Add jpeg metadata for LEGACY shim.
authorRuben Brunk <rubenbrunk@google.com>
Thu, 31 Jul 2014 18:43:27 +0000 (11:43 -0700)
committerRuben Brunk <rubenbrunk@google.com>
Sat, 16 Aug 2014 00:03:04 +0000 (00:03 +0000)
Bug: 15116722
Change-Id: I8abef3ca9a47b2f93978a758aa59c3b915a7e000

core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
core/java/android/hardware/camera2/legacy/ParameterUtils.java
core/java/android/hardware/camera2/legacy/RequestThreadManager.java
core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp

index cbf4a3d..1cf7797 100644 (file)
@@ -510,4 +510,6 @@ public class LegacyCameraDevice implements AutoCloseable {
             /*out*/int[/*2*/] dimens);
 
     private static native int nativeSetNextTimestamp(Surface surface, long timestamp);
+
+    static native int nativeGetJpegFooterSize();
 }
index 0337c96..fbe26e5 100644 (file)
@@ -33,6 +33,7 @@ import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.utils.ArrayUtils;
 import android.hardware.camera2.utils.ListUtils;
 import android.hardware.camera2.utils.ParamsUtils;
+import android.hardware.camera2.utils.SizeAreaComparator;
 import android.util.Log;
 import android.util.Range;
 import android.util.Size;
@@ -40,6 +41,8 @@ import android.util.SizeF;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 import static com.android.internal.util.Preconditions.*;
@@ -187,8 +190,10 @@ public class LegacyMetadataMapper {
          * flash.*
          */
         mapFlash(m, p);
-
-        // TODO: map other fields
+        /*
+         * jpeg.*
+         */
+        mapJpeg(m, p);
 
         /*
          * scaler.*
@@ -595,6 +600,16 @@ public class LegacyMetadataMapper {
         m.set(FLASH_INFO_AVAILABLE, flashAvailable);
     }
 
+    private static void mapJpeg(CameraMetadataNative m, Camera.Parameters p) {
+        List<Camera.Size> thumbnailSizes = p.getSupportedJpegThumbnailSizes();
+
+        if (thumbnailSizes != null) {
+            Size[] sizes = convertSizeListToArray(thumbnailSizes);
+            Arrays.sort(sizes, new SizeAreaComparator());
+            m.set(JPEG_AVAILABLE_THUMBNAIL_SIZES, sizes);
+        }
+    }
+
     private static void mapRequest(CameraMetadataNative m, Parameters p) {
         /*
          * request.availableCapabilities
index 35646fe..4c4ad0d 100644 (file)
@@ -24,6 +24,7 @@ import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.utils.ListUtils;
 import android.hardware.camera2.utils.ParamsUtils;
+import android.location.Location;
 import android.util.Log;
 import android.util.Range;
 import android.util.Size;
@@ -44,6 +45,8 @@ public class LegacyRequestMapper {
     private static final String TAG = "LegacyRequestMapper";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
 
+    private static final byte DEFAULT_JPEG_QUALITY = 85;
+
     /**
      * Set the legacy parameters using the {@link LegacyRequest legacy request}.
      *
@@ -350,6 +353,70 @@ public class LegacyRequestMapper {
                         + testPatternMode + "; only OFF is supported");
             }
         }
+
+        /*
+         * jpeg.*
+         */
+
+        // jpeg.gpsLocation
+        {
+            Location location = request.get(JPEG_GPS_LOCATION);
+            if (location != null) {
+                if (checkForCompleteGpsData(location)) {
+                    params.setGpsAltitude(location.getAltitude());
+                    params.setGpsLatitude(location.getLatitude());
+                    params.setGpsLongitude(location.getLongitude());
+                    params.setGpsProcessingMethod(location.getProvider().toUpperCase());
+                    params.setGpsTimestamp(location.getTime());
+                } else {
+                    Log.w(TAG, "Incomplete GPS parameters provided in location " + location);
+                }
+            } else {
+                params.removeGpsData();
+            }
+        }
+
+        // jpeg.orientation
+        {
+            int orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+            params.setRotation(ParamsUtils.getOrDefault(request, JPEG_ORIENTATION, orientation));
+        }
+
+        // jpeg.quality
+        {
+            params.setJpegQuality(0xFF & ParamsUtils.getOrDefault(request, JPEG_QUALITY,
+                    DEFAULT_JPEG_QUALITY));
+        }
+
+        // jpeg.thumbnailQuality
+        {
+            params.setJpegQuality(0xFF & ParamsUtils.getOrDefault(request, JPEG_THUMBNAIL_QUALITY,
+                    DEFAULT_JPEG_QUALITY));
+        }
+
+        // jpeg.thumbnailSize
+        {
+            List<Camera.Size> sizes = params.getSupportedJpegThumbnailSizes();
+
+            if (sizes != null && sizes.size() > 0) {
+                Size s = request.get(JPEG_THUMBNAIL_SIZE);
+                boolean invalidSize = (s == null) ? false : !ParameterUtils.containsSize(sizes,
+                        s.getWidth(), s.getHeight());
+                if (invalidSize) {
+                    Log.w(TAG, "Invalid JPEG thumbnail size set " + s + ", skipping thumbnail...");
+                }
+                if (s == null || invalidSize) {
+                    // (0,0) = "no thumbnail" in Camera API 1
+                    params.setJpegThumbnailSize(/*width*/0, /*height*/0);
+                } else {
+                    params.setJpegThumbnailSize(s.getWidth(), s.getHeight());
+                }
+            }
+        }
+    }
+
+    private static boolean checkForCompleteGpsData(Location location) {
+        return location != null && location.getProvider() != null && location.getTime() != 0;
     }
 
     static int filterSupportedCaptureIntent(int captureIntent) {
index a2f9b4c..090a822 100644 (file)
@@ -28,6 +28,7 @@ import android.hardware.camera2.legacy.ParameterUtils.ZoomData;
 import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.utils.ListUtils;
 import android.hardware.camera2.utils.ParamsUtils;
+import android.location.Location;
 import android.util.Log;
 import android.util.Size;
 
@@ -250,6 +251,29 @@ public class LegacyResultMapper {
             result.set(SENSOR_TEST_PATTERN_MODE, SENSOR_TEST_PATTERN_MODE_OFF);
         }
 
+        /*
+         * jpeg
+         */
+        // jpeg.gpsLocation
+        result.set(JPEG_GPS_LOCATION, request.get(CaptureRequest.JPEG_GPS_LOCATION));
+
+        // jpeg.orientation
+        result.set(JPEG_ORIENTATION, request.get(CaptureRequest.JPEG_ORIENTATION));
+
+        // jpeg.quality
+        result.set(JPEG_QUALITY, (byte) params.getJpegQuality());
+
+        // jpeg.thumbnailQuality
+        result.set(JPEG_THUMBNAIL_QUALITY, (byte) params.getJpegThumbnailQuality());
+
+        // jpeg.thumbnailSize
+        Camera.Size s = params.getJpegThumbnailSize();
+        if (s != null) {
+            result.set(JPEG_THUMBNAIL_SIZE, ParameterUtils.convertSize(s));
+        } else {
+            Log.w(TAG, "Null thumbnail size received from parameters.");
+        }
+
         // TODO: Remaining result metadata tags conversions.
         return result;
     }
index 385f844..98adcea 100644 (file)
@@ -253,6 +253,33 @@ public class ParameterUtils {
     }
 
     /**
+     * Convert a camera API1 list of sizes into an array of sizes
+     */
+    public static Size[] convertSizeListToArray(List<Camera.Size> sizeList) {
+        checkNotNull(sizeList, "sizeList must not be null");
+
+        Size[] array = new Size[sizeList.size()];
+        int ctr = 0;
+        for (Camera.Size s : sizeList) {
+            array[ctr++] = new Size(s.width, s.height);
+        }
+        return array;
+    }
+
+    /**
+     * Check if the camera API1 list of sizes contains a size with the given dimens.
+     */
+    public static boolean containsSize(List<Camera.Size> sizeList, int width, int height) {
+        checkNotNull(sizeList, "sizeList must not be null");
+        for (Camera.Size s : sizeList) {
+            if (s.height == height && s.width == width) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Returns the largest supported picture size, as compared by its area.
      */
     public static Size getLargestSupportedJpegSizeByArea(Camera.Parameters params) {
index 5c66753..eb8debb 100644 (file)
@@ -190,7 +190,8 @@ public class RequestThreadManager {
                 try {
                     if (RequestHolder.jpegType(s)) {
                         Log.i(TAG, "Producing jpeg buffer...");
-                        LegacyCameraDevice.setSurfaceDimens(s, data.length, /*height*/1);
+                        LegacyCameraDevice.setSurfaceDimens(s, data.length +
+                                LegacyCameraDevice.nativeGetJpegFooterSize(), /*height*/1);
                         LegacyCameraDevice.setNextTimestamp(s, timestamp);
                         LegacyCameraDevice.produceFrame(s, data, data.length, /*height*/1,
                                 CameraMetadataNative.NATIVE_JPEG_FORMAT);
@@ -665,10 +666,6 @@ public class RequestThreadManager {
                                 }
                                 mReceivedJpeg.close();
                                 doJpegCapturePrepare(holder);
-                                if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
-                                    // TODO: report error to CameraDevice
-                                    Log.e(TAG, "Hit timeout for jpeg callback!");
-                                }
                             }
 
                             /*
index 697cdc6..b704224 100644 (file)
@@ -624,6 +624,11 @@ static jint LegacyCameraDevice_nativeSetNextTimestamp(JNIEnv* env, jobject thiz,
     return NO_ERROR;
 }
 
+static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz) {
+    ALOGV("nativeGetJpegFooterSize");
+    return static_cast<jint>(sizeof(struct camera3_jpeg_blob));
+}
+
 } // extern "C"
 
 static JNINativeMethod gCameraDeviceMethods[] = {
@@ -657,6 +662,9 @@ static JNINativeMethod gCameraDeviceMethods[] = {
     { "nativeSetNextTimestamp",
     "(Landroid/view/Surface;J)I",
     (void *)LegacyCameraDevice_nativeSetNextTimestamp },
+    { "nativeGetJpegFooterSize",
+    "()I",
+    (void *)LegacyCameraDevice_nativeGetJpegFooterSize },
 };
 
 // Get all the required offsets in java class and register native functions