aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShuzhen Wang <shuzhenwang@google.com>2019-02-06 13:30:25 -0800
committerShuzhen Wang <shuzhenwang@google.com>2019-02-11 10:43:34 -0800
commitcf2d36dc9f0c949e298f9c4116ed7634bea4f302 (patch)
tree64c4ec1837dada5e62e9a064f43dbe657fbda4e9
parent6831f5bddffd8916cd176aaadc799866d88c0410 (diff)
downloadpdk-cf2d36dc9f0c949e298f9c4116ed7634bea4f302.tar.gz
TestingCamera2: Add HEIC image capture support
Test: Take a HEIC picture using the app Bug: 124071759 Change-Id: I0965037f9cddd40bb471effe0234a2d4aca230b0
-rw-r--r--apps/TestingCamera2/res/layout/main.xml8
-rw-r--r--apps/TestingCamera2/res/values/strings.xml3
-rw-r--r--apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java78
-rw-r--r--apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java61
4 files changed, 112 insertions, 38 deletions
diff --git a/apps/TestingCamera2/res/layout/main.xml b/apps/TestingCamera2/res/layout/main.xml
index 488265d..acc8594 100644
--- a/apps/TestingCamera2/res/layout/main.xml
+++ b/apps/TestingCamera2/res/layout/main.xml
@@ -66,7 +66,13 @@
android:spinnerMode="dropdown"
android:prompt="@string/camera_id_spinner_prompt"
/>
-
+ <Spinner
+ android:id="@+id/still_format_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:spinnerMode="dropdown"
+ android:prompt="@string/still_format_spinner_prompt"
+ />
<Button
android:id="@+id/info_button"
android:text="@string/info_button_label"
diff --git a/apps/TestingCamera2/res/values/strings.xml b/apps/TestingCamera2/res/values/strings.xml
index c3bc711..71c88dc 100644
--- a/apps/TestingCamera2/res/values/strings.xml
+++ b/apps/TestingCamera2/res/values/strings.xml
@@ -87,7 +87,8 @@
<string name="v1_app_name">TestingCam2</string>
<string name="camera_id_spinner_prompt">Camera Id</string>
- <string name="info_button_label">JPEG!</string>
+ <string name="still_format_spinner_prompt">Still Capture Format</string>
+ <string name="info_button_label">Capture!</string>
<string name="flush_button_label">Flush device</string>
<string name="focus_lock_button_label">Focus Lock</string>
<string name="focus_unlock_button_label">Focus Unlock</string>
diff --git a/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java b/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java
index 753fa00..486c245 100644
--- a/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java
+++ b/apps/TestingCamera2/src/com/android/testingcamera2/v1/CameraOps.java
@@ -31,6 +31,7 @@ import android.util.Size;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaCodec;
+import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
@@ -84,8 +85,8 @@ public class CameraOps {
List<Surface> mOutputSurfaces = new ArrayList<Surface>(2);
private Surface mPreviewSurface;
private Surface mPreviewSurface2;
- // How many JPEG buffers do we want to hold on to at once
- private static final int MAX_CONCURRENT_JPEGS = 2;
+ // How many still capture buffers do we want to hold on to at once
+ private static final int MAX_CONCURRENT_STILL_CAPTURES = 2;
private static final int STATUS_ERROR = 0;
private static final int STATUS_UNINITIALIZED = 1;
@@ -408,33 +409,65 @@ public class CameraOps {
}
}
- public void minimalJpegCapture(final CaptureCallback listener, CaptureResultListener l,
- Handler h, CameraControls cameraControl) throws ApiFailureException {
+ private static class SimpleImageListener implements ImageReader.OnImageAvailableListener {
+ private final ConditionVariable imageAvailable = new ConditionVariable();
+ private final CaptureCallback mListener;
+
+ SimpleImageListener(final CaptureCallback listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image i = null;
+ try {
+ i = reader.acquireNextImage();
+ mListener.onCaptureAvailable(i);
+ } finally {
+ if (i != null) {
+ i.close();
+ }
+ imageAvailable.open();
+ }
+ }
+
+ public void waitForImageAvailable(long timeout) {
+ if (imageAvailable.block(timeout)) {
+ imageAvailable.close();
+ } else {
+ Log.e(TAG, "wait for image available timed out after " + timeout + "ms");
+ }
+ }
+ }
+
+ public void minimalStillCapture(final CaptureCallback listener, CaptureResultListener l,
+ Handler h, CameraControls cameraControl, int format) throws ApiFailureException {
minimalOpenCamera();
try {
CameraCharacteristics properties =
mCameraManager.getCameraCharacteristics(mCamera.getId());
- Size[] jpegSizes = null;
+ Size[] stillSizes = null;
if (properties != null) {
- jpegSizes = properties.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).
- getOutputSizes(ImageFormat.JPEG);
+ stillSizes = properties.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).
+ getOutputSizes(format);
}
int width = 640;
int height = 480;
- if (jpegSizes != null && jpegSizes.length > 0) {
- width = jpegSizes[0].getWidth();
- height = jpegSizes[0].getHeight();
+ if (stillSizes != null && stillSizes.length > 0) {
+ width = stillSizes[0].getWidth();
+ height = stillSizes[0].getHeight();
}
if (mCaptureReader == null || mCaptureReader.getWidth() != width ||
- mCaptureReader.getHeight() != height) {
+ mCaptureReader.getHeight() != height ||
+ mCaptureReader.getImageFormat() != format) {
if (mCaptureReader != null) {
mCaptureReader.close();
}
mCaptureReader = ImageReader.newInstance(width, height,
- ImageFormat.JPEG, MAX_CONCURRENT_JPEGS);
+ format, MAX_CONCURRENT_STILL_CAPTURES);
}
List<Surface> outputSurfaces = new ArrayList<Surface>(/*capacity*/1);
@@ -450,26 +483,15 @@ public class CameraOps {
updateCaptureRequest(captureBuilder, cameraControl);
- ImageReader.OnImageAvailableListener readerListener =
- new ImageReader.OnImageAvailableListener() {
- @Override
- public void onImageAvailable(ImageReader reader) {
- Image i = null;
- try {
- i = reader.acquireNextImage();
- listener.onCaptureAvailable(i);
- } finally {
- if (i != null) {
- i.close();
- }
- }
- }
- };
+ SimpleImageListener readerListener = new SimpleImageListener(listener);
+
mCaptureReader.setOnImageAvailableListener(readerListener, h);
mSession.capture(captureBuilder.build(), l, mOpsHandler);
+
+ readerListener.waitForImageAvailable(1000L/*timeout*/);
} catch (CameraAccessException e) {
- throw new ApiFailureException("Error in minimal JPEG capture", e);
+ throw new ApiFailureException("Error in minimal still capture", e);
}
}
diff --git a/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java b/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java
index 7a4a9b5..c5e9ae5 100644
--- a/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java
+++ b/apps/TestingCamera2/src/com/android/testingcamera2/v1/TestingCamera2.java
@@ -29,6 +29,7 @@ import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image;
import android.media.MediaMuxer;
@@ -73,6 +74,7 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
private CameraOps mCameraOps;
private String[] mAvailableCameraIds;
private String mCameraId;
+ private int mCaptureFormat = ImageFormat.JPEG;
private static final int mSeekBarMax = 100;
private static final long MAX_EXPOSURE = 200000000L; // 200ms
private static final long MIN_EXPOSURE = 100000L; // 100us
@@ -94,7 +96,9 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
private SurfaceHolder mCurrentPreviewHolder2 = null;
private Spinner mCameraIdSpinner;
+ private Spinner mCaptureFormatSpinner;
private OnItemSelectedListener mCameraIdSelectionListener;
+ private OnItemSelectedListener mCaptureFormatSelectionListener;
private Button mInfoButton;
private Button mFlushButton;
private ToggleButton mFocusLockToggle;
@@ -139,6 +143,7 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
mStillView = (ImageView) findViewById(R.id.still_view);
mCameraIdSpinner = (Spinner) findViewById(R.id.camera_id_spinner);
+ mCaptureFormatSpinner = (Spinner) findViewById(R.id.still_format_spinner);
mInfoButton = (Button) findViewById(R.id.info_button);
mInfoButton.setOnClickListener(mInfoButtonListener);
mFlushButton = (Button) findViewById(R.id.flush_button);
@@ -402,14 +407,14 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
@Override
public void run() {
try {
- mCameraOps.minimalJpegCapture(mCaptureCallback, mCaptureResultListener,
- uiHandler, mCameraControl);
+ mCameraOps.minimalStillCapture(mCaptureCallback, mCaptureResultListener,
+ uiHandler, mCameraControl, mCaptureFormat);
if (mCurrentPreviewHolder != null && mCurrentPreviewHolder2 != null) {
mCameraOps.minimalPreview(mCurrentPreviewHolder,
mCurrentPreviewHolder2, mCameraControl);
}
} catch (ApiFailureException e) {
- logException("Can't take a JPEG! ", e);
+ logException("Can't take a still capture! ", e);
}
}
});
@@ -448,15 +453,16 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
private final CameraOps.CaptureCallback mCaptureCallback = new CameraOps.CaptureCallback() {
@Override
public void onCaptureAvailable(Image capture) {
- if (capture.getFormat() != ImageFormat.JPEG) {
+ if (capture.getFormat() != ImageFormat.JPEG &&
+ capture.getFormat() != ImageFormat.HEIC) {
Log.e(TAG, "Unexpected format: " + capture.getFormat());
return;
}
- ByteBuffer jpegBuffer = capture.getPlanes()[0].getBuffer();
- byte[] jpegData = new byte[jpegBuffer.capacity()];
- jpegBuffer.get(jpegData);
+ ByteBuffer encodedBuffer = capture.getPlanes()[0].getBuffer();
+ byte[] encodedData = new byte[encodedBuffer.capacity()];
+ encodedBuffer.get(encodedData);
- Bitmap b = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
+ Bitmap b = BitmapFactory.decodeByteArray(encodedData, 0, encodedData.length);
mStillView.setImageBitmap(b);
}
};
@@ -822,6 +828,45 @@ public class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
// Do nothing
}
});
+
+ // Map available still capture formats -> capture format spinner dropdown list of
+ // strings
+ StreamConfigurationMap streamConfigMap =
+ characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ final List<String> captureFormatList = new ArrayList<>();
+
+ captureFormatList.add("JPEG");
+ if (streamConfigMap.isOutputSupportedFor(ImageFormat.HEIC)) {
+ captureFormatList.add("HEIC");
+ }
+
+ dataAdapter = new ArrayAdapter<>(TestingCamera2.this,
+ android.R.layout.simple_spinner_item, captureFormatList);
+ dataAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ mCaptureFormatSpinner.setAdapter(dataAdapter);
+
+ /*
+ * Change the capture format and update preview when format spinner's selected item changes
+ */
+ mCaptureFormatSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position,
+ long id) {
+ int format = (position == 0 ? ImageFormat.JPEG : ImageFormat.HEIC);
+
+ Log.i(TAG, "Change image capture format to " + captureFormatList.get(position)
+ + " " + format);
+
+ mCaptureFormat = format;
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Do nothing
+ }
+ });
}
};
}