summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt3
-rw-r--r--api/system-current.txt3
-rw-r--r--core/java/android/hardware/camera2/CameraCaptureSession.java117
-rw-r--r--core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl1
-rw-r--r--core/java/android/hardware/camera2/ICameraDeviceUser.aidl2
-rw-r--r--core/java/android/hardware/camera2/impl/CallbackProxies.java7
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java12
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java56
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java18
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java10
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java10
11 files changed, 219 insertions, 20 deletions
diff --git a/api/current.txt b/api/current.txt
index 8f87163e45d4..818114d14c71 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13056,6 +13056,7 @@ package android.hardware.camera2 {
method public abstract android.hardware.camera2.CameraDevice getDevice();
method public abstract android.view.Surface getInputSurface();
method public abstract boolean isReprocessible();
+ method public abstract void prepare(android.view.Surface) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
@@ -13078,6 +13079,7 @@ package android.hardware.camera2 {
method public abstract void onConfigureFailed(android.hardware.camera2.CameraCaptureSession);
method public abstract void onConfigured(android.hardware.camera2.CameraCaptureSession);
method public void onReady(android.hardware.camera2.CameraCaptureSession);
+ method public void onSurfacePrepared(android.hardware.camera2.CameraCaptureSession, android.view.Surface);
}
public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
@@ -57345,4 +57347,3 @@ package org.xmlpull.v1.sax2 {
}
}
-
diff --git a/api/system-current.txt b/api/system-current.txt
index a9a5211864a9..bef85ada74df 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -13352,6 +13352,7 @@ package android.hardware.camera2 {
method public abstract android.hardware.camera2.CameraDevice getDevice();
method public abstract android.view.Surface getInputSurface();
method public abstract boolean isReprocessible();
+ method public abstract void prepare(android.view.Surface) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
@@ -13374,6 +13375,7 @@ package android.hardware.camera2 {
method public abstract void onConfigureFailed(android.hardware.camera2.CameraCaptureSession);
method public abstract void onConfigured(android.hardware.camera2.CameraCaptureSession);
method public void onReady(android.hardware.camera2.CameraCaptureSession);
+ method public void onSurfacePrepared(android.hardware.camera2.CameraCaptureSession, android.view.Surface);
}
public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata {
@@ -60223,4 +60225,3 @@ package org.xmlpull.v1.sax2 {
}
}
-
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 6b6f026db929..31e6e254a951 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -18,6 +18,7 @@ package android.hardware.camera2;
import android.os.Handler;
import android.view.Surface;
+
import java.util.List;
@@ -69,6 +70,61 @@ public abstract class CameraCaptureSession implements AutoCloseable {
public abstract CameraDevice getDevice();
/**
+ * <p>Pre-allocate all buffers for an output Surface.</p>
+ *
+ * <p>Normally, the image buffers for a given output Surface are allocated on-demand,
+ * to minimize startup latency and memory overhead.</p>
+ *
+ * <p>However, in some cases, it may be desirable for the buffers to be allocated before
+ * any requests targeting the Surface are actually submitted to the device. Large buffers
+ * may take some time to allocate, which can result in delays in submitting requests until
+ * sufficient buffers are allocated to reach steady-state behavior. Such delays can cause
+ * bursts to take longer than desired, or cause skips or stutters in preview output.</p>
+ *
+ * <p>The prepare() method can be used to perform this preallocation. It may only be called for
+ * a given output Surface before that Surface is used as a target for a request. The number of
+ * buffers allocated is the sum of the count needed by the consumer providing the output
+ * Surface, and the maximum number needed by the camera device to fill its pipeline. Since this
+ * may be a larger number than what is actually required for steady-state operation, using
+ * prepare may result in higher memory consumption than the normal on-demand behavior results
+ * in. Prepare() will also delay the time to first output to a given Surface, in exchange for
+ * smoother frame rate once the allocation is complete.</p>
+ *
+ * <p>For example, an application that creates an
+ * {@link android.media.ImageReader#newInstance ImageReader} with a maxImages argument of 10,
+ * but only uses 3 simultaneous Images at once would normally only cause those 3 images to be
+ * allocated (plus what is needed by the camera device for smooth operation). But using
+ * prepare() on the ImageReader Surface will result in all 10 Images being allocated. So
+ * applications using this method should take care to request only the number of buffers
+ * actually necessary for their application.</p>
+ *
+ * <p>If the same output Surface is used in consecutive sessions (without closing the first
+ * session explicitly), then its already-allocated buffers are carried over, and if it was
+ * used as a target of a capture request in the first session, prepare cannot be called on it
+ * in the second session.</p>
+ *
+ * <p>Once allocation is complete, {@link StateCallback#onSurfacePrepared} will be invoked with
+ * the Surface provided to this method. Between the prepare call and the onSurfacePrepared call,
+ * the Surface provided to prepare must not be used as a target of a CaptureRequest submitted
+ * to this session.</p>
+ *
+ * @param surface the output Surface for which buffers should be pre-allocated. Must be one of
+ * the output Surfaces used to create this session.
+ *
+ * @throws CameraAccessException if the camera device is no longer connected or has
+ * encountered a fatal error
+ * @throws IllegalStateException if this session is no longer active, either because the session
+ * was explicitly closed, a new session has been created
+ * or the camera device has been closed.
+ * @throws IllegalArgumentException if the Surface is invalid, not part of this Session, or has
+ * already been used as a target of a CaptureRequest in this
+ * session or immediately prior sessions.
+ *
+ * @see StateCallback#onSurfacePrepared
+ */
+ public abstract void prepare(Surface surface) throws CameraAccessException;
+
+ /**
* <p>Submit a request for an image to be captured by the camera device.</p>
*
* <p>The request defines all the parameters for capturing the single image,
@@ -110,9 +166,10 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* was explicitly closed, a new session has been created
* or the camera device has been closed.
* @throws IllegalArgumentException if the request targets no Surfaces or Surfaces that are not
- * configured as outputs for this session. Or if a reprocess
+ * configured as outputs for this session; or a reprocess
* capture request is submitted in a non-reprocessible capture
- * session. Or if the handler is
+ * session; or the capture targets a Surface in the middle
+ * of being {@link #prepare prepared}; or the handler is
* null, the listener is not null, and the calling thread has
* no looper.
*
@@ -164,13 +221,15 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* @throws IllegalStateException if this session is no longer active, either because the session
* was explicitly closed, a new session has been created
* or the camera device has been closed.
- * @throws IllegalArgumentException If the requests target no Surfaces, or target Surfaces not
- * currently configured as outputs. Or if a reprocess
+ * @throws IllegalArgumentException If the requests target no Surfaces, or the requests target
+ * Surfaces not currently configured as outputs; or a reprocess
* capture request is submitted in a non-reprocessible capture
- * session. Or if the list of requests contains both requests
- * to capture images from the camera and reprocess capture
- * requests. Or if the handler is null, the listener is not
- * null, and the calling thread has no looper.
+ * session; or the list of requests contains both requests to
+ * capture images from the camera and reprocess capture
+ * requests; or one of the captures targets a Surface in the
+ * middle of being {@link #prepare prepared}; or if the handler
+ * is null, the listener is not null, and the calling thread
+ * has no looper.
*
* @see #capture
* @see #setRepeatingRequest
@@ -230,11 +289,12 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* @throws IllegalStateException if this session is no longer active, either because the session
* was explicitly closed, a new session has been created
* or the camera device has been closed.
- * @throws IllegalArgumentException If the requests reference no Surfaces or Surfaces that are
- * not currently configured as outputs. Or if the request is
- * a reprocess capture request. Or if the handler is null, the
- * listener is not null, and the calling thread has no looper.
- * Or if no requests were passed in.
+ * @throws IllegalArgumentException If the request references no Surfaces or references Surfaces
+ * that are not currently configured as outputs; or the request
+ * is a reprocess capture request; or the capture targets a
+ * Surface in the middle of being {@link #prepare prepared}; or
+ * the handler is null, the listener is not null, and the
+ * calling thread has no looper; or no requests were passed in.
*
* @see #capture
* @see #captureBurst
@@ -299,11 +359,13 @@ public abstract class CameraCaptureSession implements AutoCloseable {
* @throws IllegalStateException if this session is no longer active, either because the session
* was explicitly closed, a new session has been created
* or the camera device has been closed.
- * @throws IllegalArgumentException If the requests reference no Surfaces or Surfaces not
- * currently configured as outputs. Or if one of the requests
- * is a reprocess capture request. Or if the handler is null,
- * the listener is not null, and the calling thread has no
- * looper. Or if no requests were passed in.
+ * @throws IllegalArgumentException If the requests reference no Surfaces or reference Surfaces
+ * not currently configured as outputs; or one of the requests
+ * is a reprocess capture request; or one of the captures
+ * targets a Surface in the middle of being
+ * {@link #prepare prepared}; or the handler is null, the
+ * listener is not null, and the calling thread has no looper;
+ * or no requests were passed in.
*
* @see #capture
* @see #captureBurst
@@ -514,6 +576,25 @@ public abstract class CameraCaptureSession implements AutoCloseable {
public void onClosed(CameraCaptureSession session) {
// default empty implementation
}
+
+ /**
+ * This method is called when the buffer pre-allocation for an output Surface is complete.
+ *
+ * <p>Buffer pre-allocation for an output Surface is started by the {@link #prepare} call.
+ * While allocation is underway, the Surface must not be used as a capture target.
+ * Once this callback fires, the output Surface provided can again be used as a target for
+ * a capture request.</p>
+ *
+ * <p>In case of a error during pre-allocation (such as running out of suitable memory),
+ * this callback is still invoked after the error is encountered, though some buffers may
+ * not have been successfully pre-allocated.</p>
+ *
+ * @param session the session returned by {@link CameraDevice#createCaptureSession}
+ * @param surface the Surface that was used with the {@link #prepare} call.
+ */
+ public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
+ // default empty implementation
+ }
}
/**
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index ca0935cce54e..151c9183d731 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -31,4 +31,5 @@ interface ICameraDeviceCallbacks
oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
oneway void onResultReceived(in CameraMetadataNative result,
in CaptureResultExtras resultExtras);
+ oneway void onPrepared(int streamId);
}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index 23bfa66c9a88..375b310e1bfb 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -98,4 +98,6 @@ interface ICameraDeviceUser
int waitUntilIdle();
int flush(out LongParcelable lastFrameNumber);
+
+ int prepare(int streamId);
}
diff --git a/core/java/android/hardware/camera2/impl/CallbackProxies.java b/core/java/android/hardware/camera2/impl/CallbackProxies.java
index f0217acc0116..dac2ef8c6245 100644
--- a/core/java/android/hardware/camera2/impl/CallbackProxies.java
+++ b/core/java/android/hardware/camera2/impl/CallbackProxies.java
@@ -23,6 +23,7 @@ import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.dispatch.Dispatchable;
import android.hardware.camera2.dispatch.MethodNameInvoker;
+import android.view.Surface;
import static com.android.internal.util.Preconditions.*;
@@ -175,6 +176,12 @@ public class CallbackProxies {
public void onClosed(CameraCaptureSession session) {
mProxy.invoke("onClosed", session);
}
+
+ @Override
+ public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
+ mProxy.invoke("onSurfacePrepared", session, surface);
+ }
+
}
private CallbackProxies() {
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index fb5b13c9f650..c74204d63c96 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -144,6 +144,11 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
}
@Override
+ public void prepare(Surface surface) throws CameraAccessException {
+ mDeviceImpl.prepare(surface);
+ }
+
+ @Override
public synchronized int capture(CaptureRequest request, CaptureCallback callback,
Handler handler) throws CameraAccessException {
if (request == null) {
@@ -589,6 +594,13 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
}
}
}
+
+ @Override
+ public void onSurfacePrepared(Surface surface) {
+ if (VERBOSE) Log.v(TAG, mIdString + "onPrepared");
+ mStateCallback.onSurfacePrepared(session, surface);
+ }
+
};
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 91388c3aa73d..1e680dfd21b3 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -605,6 +605,29 @@ public class CameraDeviceImpl extends CameraDevice {
}
}
+ public void prepare(Surface surface) throws CameraAccessException {
+ synchronized(mInterfaceLock) {
+ int streamId = -1;
+ for (int i = 0; i < mConfiguredOutputs.size(); i++) {
+ if (surface == mConfiguredOutputs.valueAt(i).getSurface()) {
+ streamId = mConfiguredOutputs.keyAt(i);
+ break;
+ }
+ }
+ if (streamId == -1) {
+ throw new IllegalArgumentException("Surface is not part of this session");
+ }
+ try {
+ mRemoteDevice.prepare(streamId);
+ } catch (CameraRuntimeException e) {
+ throw e.asChecked();
+ } catch (RemoteException e) {
+ // impossible
+ return;
+ }
+ }
+ }
+
public int capture(CaptureRequest request, CaptureCallback callback, Handler handler)
throws CameraAccessException {
if (DEBUG) {
@@ -1056,6 +1079,14 @@ public class CameraDeviceImpl extends CameraDevice {
public void onIdle(CameraDevice camera) {
// Default empty implementation
}
+
+ /**
+ * The method called when the camera device has finished preparing
+ * an output Surface
+ */
+ public void onSurfacePrepared(Surface surface) {
+ // Default empty implementation
+ }
}
static class CaptureCallbackHolder {
@@ -1643,6 +1674,31 @@ public class CameraDeviceImpl extends CameraDevice {
}
}
+ @Override
+ public void onPrepared(int streamId) {
+ final OutputConfiguration output;
+ final StateCallbackKK sessionCallback;
+
+ if (DEBUG) {
+ Log.v(TAG, "Stream " + streamId + " is prepared");
+ }
+
+ synchronized(mInterfaceLock) {
+ output = mConfiguredOutputs.get(streamId);
+ sessionCallback = mSessionStateCallback;
+ }
+
+ if (sessionCallback == null) return;
+
+ if (output == null) {
+ Log.w(TAG, "onPrepared invoked for unknown output Surface");
+ return;
+ }
+ final Surface surface = output.getSurface();
+
+ sessionCallback.onSurfacePrepared(surface);
+ }
+
/**
* Called by onDeviceError for handling single-capture failures.
*/
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 4cd9414c601f..abe26ead2170 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -252,6 +252,11 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
@Override
+ public void onPrepared(int streamId) {
+ // TODO
+ }
+
+ @Override
public IBinder asBinder() {
// This is solely intended to be used for in-process binding.
return null;
@@ -617,6 +622,19 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
return CameraBinderDecorator.NO_ERROR;
}
+ public int prepare(int streamId) {
+ if (DEBUG) {
+ Log.d(TAG, "prepare called.");
+ }
+ if (mLegacyDevice.isClosed()) {
+ Log.e(TAG, "Cannot prepare stream, device has been closed.");
+ return CameraBinderDecorator.ENODEV;
+ }
+
+ // TODO: Implement and fire callback
+ return CameraBinderDecorator.NO_ERROR;
+ }
+
@Override
public IBinder asBinder() {
// This is solely intended to be used for in-process binding.
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 3bb5f012623f..14c261904d26 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -261,6 +261,16 @@ public class CameraBinderTest extends AndroidTestCase {
// TODO Auto-generated method stub
}
+
+ /*
+ * (non-Javadoc)
+ * @see android.hardware.camera2.ICameraDeviceCallbacks#onPrepared()
+ */
+ @Override
+ public void onPrepared(int streamId) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
}
@SmallTest
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 0466540f0925..6f336725eab5 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -132,6 +132,16 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
// TODO Auto-generated method stub
}
+
+ /*
+ * (non-Javadoc)
+ * @see android.hardware.camera2.ICameraDeviceCallbacks#onPrepared()
+ */
+ @Override
+ public void onPrepared(int streamId) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
}
class IsMetadataNotEmpty extends ArgumentMatcher<CameraMetadataNative> {