summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShashi Shekhar <shashishekhar@google.com>2015-01-16 10:16:25 -0800
committerShashi Shekhar <shashishekhar@google.com>2015-02-11 17:24:13 -0800
commitb4b27f2c7738cd5e3f31a281d66a33f4698810b3 (patch)
tree1f5c3f83cee9632816724d718817ef0947815f48
parentf27cf91653d6be413e14c362a0887d3bf1f5ca50 (diff)
downloadandroid_packages_apps_Camera2-b4b27f2c7738cd5e3f31a281d66a33f4698810b3.tar.gz
android_packages_apps_Camera2-b4b27f2c7738cd5e3f31a281d66a33f4698810b3.tar.bz2
android_packages_apps_Camera2-b4b27f2c7738cd5e3f31a281d66a33f4698810b3.zip
Port burst to use FrameServer.
Port burst to frameserver - simplifies burst interfaces - removes burst methods from OneCamera. - locks orientation when burst is running. - Deletes most old code for burst integration. - Removes frame distributor preview forwarding, instead frames are streamed using a surface texture the Surface for which is passed as a output target to the create capture session. - Deletes FrameDistributor, now the low-res frames are streamed to a new surface specifically setup for burst. Change-Id: I50f2955bb48610a7e284f9609cd70b8e4e1f1059
-rw-r--r--src/com/android/camera/CaptureModule.java118
-rw-r--r--src/com/android/camera/burst/BurstCaptureCommand.java176
-rw-r--r--src/com/android/camera/burst/BurstConfiguration.java78
-rw-r--r--src/com/android/camera/burst/BurstController.java110
-rw-r--r--src/com/android/camera/burst/BurstFacade.java95
-rw-r--r--src/com/android/camera/burst/BurstFacadeFactory.java69
-rw-r--r--src/com/android/camera/burst/BurstFacadeImpl.java411
-rw-r--r--src/com/android/camera/burst/BurstImage.java58
-rw-r--r--src/com/android/camera/burst/BurstResultsSaver.java188
-rw-r--r--src/com/android/camera/burst/BurstTaker.java41
-rw-r--r--src/com/android/camera/burst/BurstTakerImpl.java105
-rw-r--r--src/com/android/camera/burst/EvictionHandler.java67
-rw-r--r--src/com/android/camera/burst/OrientationLockController.java34
-rw-r--r--src/com/android/camera/burst/ResultsAccessor.java59
-rw-r--r--src/com/android/camera/burst/RingBuffer.java103
-rw-r--r--src/com/android/camera/burst/SurfaceTextureContainer.java49
-rw-r--r--src/com/android/camera/burst/ToastingBurstFacadeDecorator.java61
-rw-r--r--src/com/android/camera/gl/CopyShader.java244
-rw-r--r--src/com/android/camera/gl/FrameDistributor.java105
-rw-r--r--src/com/android/camera/gl/FrameDistributorImpl.java340
-rw-r--r--src/com/android/camera/gl/FrameDistributorWrapper.java101
-rw-r--r--src/com/android/camera/gl/GLToolbox.java119
-rw-r--r--src/com/android/camera/gl/RenderTarget.java285
-rw-r--r--src/com/android/camera/gl/SurfaceTextureConsumer.java126
-rw-r--r--src/com/android/camera/one/AbstractOneCamera.java10
-rw-r--r--src/com/android/camera/one/OneCamera.java41
-rw-r--r--src/com/android/camera/one/OneCameraManager.java5
-rw-r--r--src/com/android/camera/one/v1/OneCameraManagerImpl.java3
-rw-r--r--src/com/android/camera/one/v2/ImageCaptureManager.java129
-rw-r--r--src/com/android/camera/one/v2/OneCameraFactory.java4
-rw-r--r--src/com/android/camera/one/v2/OneCameraManagerImpl.java6
-rw-r--r--src/com/android/camera/one/v2/OneCameraZslImpl.java75
-rw-r--r--src/com/android/camera/one/v2/SimpleOneCameraFactory.java4
-rw-r--r--src/com/android/camera/one/v2/ZslOneCameraFactory.java17
-rw-r--r--src/com/android/camera/one/v2/initialization/GenericOneCameraImpl.java10
-rw-r--r--src/com/android/camera/one/v2/sharedimagereader/ZslSharedImageReaderFactory.java1
-rw-r--r--src_pd/com/android/camera/burst/BurstControllerImpl.java36
-rw-r--r--src_pd/com/android/camera/one/v2/OneCameraCreator.java4
38 files changed, 1124 insertions, 2363 deletions
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index 3d92a7891..9c555b94b 100644
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -39,10 +39,12 @@ import com.android.camera.app.AppController;
import com.android.camera.app.CameraAppUI;
import com.android.camera.app.CameraAppUI.BottomBarUISpec;
import com.android.camera.app.LocationManager;
+import com.android.camera.app.OrientationManager.DeviceOrientation;
import com.android.camera.async.MainThread;
import com.android.camera.burst.BurstFacade;
import com.android.camera.burst.BurstFacadeFactory;
import com.android.camera.burst.BurstReadyStateChangeListener;
+import com.android.camera.burst.OrientationLockController;
import com.android.camera.debug.DebugPropertyHelper;
import com.android.camera.debug.Log;
import com.android.camera.debug.Log.Tag;
@@ -78,8 +80,6 @@ import com.android.camera.util.Size;
import com.android.camera2.R;
import com.android.ex.camera2.portability.CameraAgent.CameraProxy;
-import java.io.File;
-import java.io.IOException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -139,6 +139,7 @@ public class CaptureModule extends CameraModule implements
private Facing mCameraFacing;
/** Whether HDR is currently enabled. */
private boolean mHdrEnabled = false;
+ private final Object mSurfaceTextureLock = new Object();
private FocusController mFocusController;
private OneCameraCharacteristics mCameraCharacteristics;
@@ -172,7 +173,6 @@ public class CaptureModule extends CameraModule implements
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
int width = right - left;
int height = bottom - top;
- mBurstController.setPreviewConsumerSize(width, height);
updatePreviewTransform(width, height, false);
}
@@ -216,13 +216,18 @@ public class CaptureModule extends CameraModule implements
// Force to re-apply transform matrix here as a workaround for
// b/11168275
updatePreviewTransform(width, height, true);
- initSurfaceTextureConsumer(surface, width, height);
+ synchronized (mSurfaceTextureLock) {
+ mPreviewSurfaceTexture = surface;
+ }
+ reopenCamera();
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
Log.d(TAG, "onSurfaceTextureDestroyed");
- mBurstController.setSurfaceTexture(null, 0, 0);
+ synchronized (mSurfaceTextureLock) {
+ mPreviewSurfaceTexture = null;
+ }
closeCamera();
return true;
}
@@ -230,7 +235,7 @@ public class CaptureModule extends CameraModule implements
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
Log.d(TAG, "onSurfaceTextureSizeChanged");
- updateFrameDistributorBufferSize();
+ updatePreviewBufferSize();
}
@Override
@@ -323,6 +328,8 @@ public class CaptureModule extends CameraModule implements
/** The current preview transformation matrix. */
private Matrix mPreviewTranformationMatrix = new Matrix();
+ /** The surface texture for the preview. */
+ private SurfaceTexture mPreviewSurfaceTexture;
/** The burst manager for controlling the burst. */
private final BurstFacade mBurstController;
@@ -343,15 +350,26 @@ public class CaptureModule extends CameraModule implements
mStickyGcamCamera = stickyHdr;
mLocationManager = mAppController.getLocationManager();
- mBurstController = BurstFacadeFactory.create(mContext, mAppController
- .getOrientationManager(), new BurstReadyStateChangeListener() {
- @Override
- public void onBurstReadyStateChanged(boolean ready) {
- // TODO: This needs to take into account the state of the whole
- // system, not just burst.
- mAppController.setShutterEnabled(ready);
- }
- });
+ mBurstController = BurstFacadeFactory.create(mContext,
+ new OrientationLockController() {
+ @Override
+ public void unlockOrientation() {
+ mAppController.getOrientationManager().unlockOrientation();
+ }
+
+ @Override
+ public void lockOrientation() {
+ mAppController.getOrientationManager().lockOrientation();
+ }
+ },
+ new BurstReadyStateChangeListener() {
+ @Override
+ public void onBurstReadyStateChanged(boolean ready) {
+ // TODO: This needs to take into account the state of
+ // the whole system, not just burst.
+ mAppController.setShutterEnabled(ready);
+ }
+ });
mMediaActionSound = new MediaActionSound();
}
@@ -383,12 +401,6 @@ public class CaptureModule extends CameraModule implements
FocusSound focusSound = new FocusSound(mSoundPlayer, R.raw.material_camera_focus);
mFocusController = new FocusController(mUI.getFocusRing(), focusSound, mMainThread);
- // Set the preview texture from UI for the SurfaceTextureConsumer.
- mBurstController.setSurfaceTexture(
- mAppController.getCameraAppUI().getSurfaceTexture(),
- mAppController.getCameraAppUI().getSurfaceWidth(),
- mAppController.getCameraAppUI().getSurfaceHeight());
-
mHeadingSensor = new HeadingSensor(AndroidServices.instance().provideSensorManager());
View cancelButton = activity.findViewById(R.id.shutter_cancel_button);
@@ -404,13 +416,22 @@ public class CaptureModule extends CameraModule implements
@Override
public void onShutterButtonLongPressed() {
- File tempSessionDataDirectory;
try {
- tempSessionDataDirectory = getServices().getCaptureSessionManager()
- .getSessionDirectory(BURST_SESSIONS_DIR);
CaptureSession session = createAndStartCaptureSession();
- mBurstController.startBurst(session, tempSessionDataDirectory);
- } catch (IOException e) {
+
+ OneCameraCharacteristics cameraCharacteristics;
+ cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraFacing);
+ DeviceOrientation deviceOrientation = mAppController.getOrientationManager()
+ .getDeviceOrientation();
+ ImageRotationCalculator imageRotationCalculator = ImageRotationCalculatorImpl
+ .from(mAppController.getOrientationManager(), cameraCharacteristics);
+
+ mBurstController.startBurst(session,
+ deviceOrientation,
+ mCamera.getDirection(),
+ imageRotationCalculator.toImageRotation().getDegrees());
+
+ } catch (OneCameraAccessException e) {
Log.e(TAG, "Cannot start burst", e);
return;
}
@@ -530,14 +551,13 @@ public class CaptureModule extends CameraModule implements
}
private void initSurfaceTextureConsumer() {
- mBurstController.initializeSurfaceTextureConsumer(
- mAppController.getCameraAppUI().getSurfaceWidth(),
- mAppController.getCameraAppUI().getSurfaceHeight());
- reopenCamera();
- }
-
- private void initSurfaceTextureConsumer(SurfaceTexture surfaceTexture, int width, int height) {
- mBurstController.initializeSurfaceTextureConsumer(surfaceTexture, width, height);
+ synchronized (mSurfaceTextureLock) {
+ if (mPreviewSurfaceTexture != null) {
+ mPreviewSurfaceTexture.setDefaultBufferSize(
+ mAppController.getCameraAppUI().getSurfaceWidth(),
+ mAppController.getCameraAppUI().getSurfaceHeight());
+ }
+ }
reopenCamera();
}
@@ -550,11 +570,18 @@ public class CaptureModule extends CameraModule implements
}
private SurfaceTexture getPreviewSurfaceTexture() {
- return mBurstController.getInputSurfaceTexture();
+ synchronized (mSurfaceTextureLock) {
+ return mPreviewSurfaceTexture;
+ }
}
- private void updateFrameDistributorBufferSize() {
- mBurstController.updatePreviewBufferSize(mPreviewBufferWidth, mPreviewBufferHeight);
+ private void updatePreviewBufferSize() {
+ synchronized (mSurfaceTextureLock) {
+ if (mPreviewSurfaceTexture != null) {
+ mPreviewSurfaceTexture.setDefaultBufferSize(mPreviewBufferWidth,
+ mPreviewBufferHeight);
+ }
+ }
}
@Override
@@ -568,9 +595,8 @@ public class CaptureModule extends CameraModule implements
mAppController.addPreviewAreaSizeChangedListener(mPreviewAreaChangedListener);
mAppController.addPreviewAreaSizeChangedListener(mUI);
mAppController.getCameraAppUI().onChangeCamera();
- mBurstController.initializeAndStartFrameDistributor();
- updateFrameDistributorBufferSize();
getServices().getRemoteShutterListener().onModuleReady(this);
+ mBurstController.initialize(new SurfaceTexture(0));
// TODO: Check if we can really take a photo right now (memory, camera
// state, ... ).
mAppController.getCameraAppUI().enableModeOptions();
@@ -607,11 +633,10 @@ public class CaptureModule extends CameraModule implements
mAppController.removePreviewAreaSizeChangedListener(mUI);
mAppController.removePreviewAreaSizeChangedListener(mPreviewAreaChangedListener);
getServices().getRemoteShutterListener().onModuleExit();
- mBurstController.stopBurst();
+ mBurstController.release();
cancelCountDown();
closeCamera();
resetTextureBufferSize();
- mBurstController.closeFrameDistributor();
mSoundPlayer.unloadSound(R.raw.timer_final_second);
mSoundPlayer.unloadSound(R.raw.timer_increment);
}
@@ -626,7 +651,6 @@ public class CaptureModule extends CameraModule implements
@Override
public void onLayoutOrientationChanged(boolean isLandscape) {
Log.d(TAG, "onLayoutOrientationChanged");
- mBurstController.stopBurst();
}
@Override
@@ -1145,7 +1169,7 @@ public class CaptureModule extends CameraModule implements
Size previewBufferSize = mCamera.pickPreviewSize(mPictureSize, mContext);
mPreviewBufferWidth = previewBufferSize.getWidth();
mPreviewBufferHeight = previewBufferSize.getHeight();
- updateFrameDistributorBufferSize();
+ updatePreviewBufferSize();
}
/**
@@ -1209,7 +1233,6 @@ public class CaptureModule extends CameraModule implements
@Override
public void onCameraClosed() {
mCamera = null;
- mBurstController.onCameraDetached();
mCameraOpenCloseLock.release();
}
@@ -1217,13 +1240,12 @@ public class CaptureModule extends CameraModule implements
public void onCameraOpened(final OneCamera camera) {
Log.d(TAG, "onCameraOpened: " + camera);
mCamera = camera;
- mBurstController.onCameraAttached(mCamera);
updatePreviewBufferDimension();
// If the surface texture is not destroyed, it may have
// the last frame lingering. We need to hold off setting
// transform until preview is started.
- updateFrameDistributorBufferSize();
+ updatePreviewBufferSize();
mState = ModuleState.WATCH_FOR_NEXT_FRAME_AFTER_PREVIEW_STARTED;
Log.d(TAG, "starting preview ...");
@@ -1290,7 +1312,7 @@ public class CaptureModule extends CameraModule implements
}
});
}
- }, mCameraHandler, mainThread, imageRotationCalculator);
+ }, mCameraHandler, mainThread, imageRotationCalculator, mBurstController);
}
private void closeCamera() {
@@ -1347,6 +1369,6 @@ public class CaptureModule extends CameraModule implements
// SurfaceTexture must have these buffer sizes reset manually. Otherwise
// the SurfaceTexture cannot be transformed by matrix set on the
// TextureView.
- updateFrameDistributorBufferSize();
+ updatePreviewBufferSize();
}
}
diff --git a/src/com/android/camera/burst/BurstCaptureCommand.java b/src/com/android/camera/burst/BurstCaptureCommand.java
new file mode 100644
index 000000000..91da26e00
--- /dev/null
+++ b/src/com/android/camera/burst/BurstCaptureCommand.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.burst;
+
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+import android.view.Surface;
+
+import com.android.camera.async.BufferQueue;
+import com.android.camera.async.BufferQueue.BufferQueueClosedException;
+import com.android.camera.async.Lifetime;
+import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionClosedException;
+import com.android.camera.one.v2.camera2proxy.ImageProxy;
+import com.android.camera.one.v2.commands.CameraCommand;
+import com.android.camera.one.v2.core.CaptureStream;
+import com.android.camera.one.v2.core.FrameServer;
+import com.android.camera.one.v2.core.Request;
+import com.android.camera.one.v2.core.RequestBuilder;
+import com.android.camera.one.v2.core.ResourceAcquisitionFailedException;
+import com.android.camera.one.v2.core.ResponseListener;
+import com.android.camera.one.v2.sharedimagereader.ManagedImageReader;
+import com.android.camera.one.v2.sharedimagereader.imagedistributor.ImageStream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+@ParametersAreNonnullByDefault
+public class BurstCaptureCommand implements CameraCommand {
+ /**
+ * Template to use for the burst capture.
+ */
+ private static final int BURST_TEMPLATE_TYPE = CameraDevice.TEMPLATE_VIDEO_SNAPSHOT;
+
+ private final FrameServer mFrameServer;
+ private final RequestBuilder.Factory mBuilderFactory;
+ private final ManagedImageReader mManagedImageReader;
+ private final Surface mBurstInputSurface;
+ private final EvictionHandler mBurstEvictionHandler;
+ private final BurstController mBurstController;
+ private final Runnable mRestorePreviewCommand;
+ /**
+ * The max images supported by the {@link ImageStream}.
+ */
+ private final int mMaxImageCount;
+ private final Lifetime mBurstLifetime;
+
+ /**
+ * Initializes a new burst capture command.
+ *
+ * @param frameServer the {@link FrameServer} instance for creating session
+ * @param builder factory to use for creating the {@link Request} for burst
+ * capture
+ * @param managedImageReader the factory to use for creating a stream of
+ * images
+ * @param burstInputSurface the input surface to use for streaming preview
+ * frames to burst
+ * @param lifetime the lifetime of the burst, the burst stops capturing
+ * images once the lifetime is closed
+ * @param burstEvictionHandler the eviction handler to use for
+ * {@link RingBuffer}
+ * @param burstController the burst controller
+ * @param restorePreviewCommand the command to run to restore the preview,
+ * once burst capture is complete
+ * @param maxImageCount the maximum number of images supported by the image
+ * reader
+ */
+ public BurstCaptureCommand(FrameServer frameServer, RequestBuilder.Factory builder,
+ ManagedImageReader managedImageReader, Surface burstInputSurface,
+ Lifetime lifetime,
+ EvictionHandler burstEvictionHandler,
+ BurstController burstController,
+ Runnable restorePreviewCommand,
+ int maxImageCount) {
+ mFrameServer = frameServer;
+ mBuilderFactory = builder;
+ mManagedImageReader = managedImageReader;
+ mBurstInputSurface = burstInputSurface;
+ mBurstLifetime = lifetime;
+ mBurstEvictionHandler = burstEvictionHandler;
+ mBurstController = burstController;
+ mRestorePreviewCommand = restorePreviewCommand;
+ mMaxImageCount = maxImageCount;
+ }
+
+ @Override
+ public void run() throws InterruptedException, CameraAccessException,
+ CameraCaptureSessionClosedException, ResourceAcquisitionFailedException {
+ List<ImageProxy> capturedImages = new ArrayList<>();
+ try (FrameServer.Session session = mFrameServer.createExclusiveSession()) {
+ // Create a ring buffer and with the passed burst eviction
+ // handler and insert images in it from the image stream.
+ // The ring buffer size is one less than the image count.
+ int ringBufferSize = mMaxImageCount - 1;
+ try (RingBuffer ringBuffer = new RingBuffer(ringBufferSize,
+ mBurstEvictionHandler)) {
+ try (ImageStream imageStream =
+ mManagedImageReader.createStream(mMaxImageCount)) {
+ mBurstLifetime.add(imageStream);
+
+ // Use the video snapshot template for the burst.
+ RequestBuilder photoRequest =
+ mBuilderFactory.create(BURST_TEMPLATE_TYPE);
+ photoRequest.setParam(CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO);
+
+ photoRequest.addStream(imageStream);
+ // Hook up the camera stream to burst input surface.
+ photoRequest.addStream(new CaptureStream() {
+ @Override
+ public Surface bind(BufferQueue<Long> timestamps)
+ throws InterruptedException,
+ ResourceAcquisitionFailedException {
+ return mBurstInputSurface;
+ }
+ });
+
+ // Hook the response listener to invoke eviction handler
+ // frame capture result.
+ photoRequest.addResponseListener(new ResponseListener() {
+ @Override
+ public void onCompleted(TotalCaptureResult result) {
+ final long timestamp = result.get(TotalCaptureResult.SENSOR_TIMESTAMP);
+ mBurstEvictionHandler.onFrameCaptureResultAvailable(timestamp, result);
+ }
+ });
+ session.submitRequest(Arrays.asList(photoRequest.build()),
+ FrameServer.RequestType.REPEATING);
+
+ try {
+ while (!imageStream.isClosed()) {
+ ringBuffer.insertImage(
+ imageStream.getNext());
+ }
+ } catch (BufferQueueClosedException e) {
+ // This is normal. the image stream was closed.
+ }
+ } finally {
+ // Burst was completed call remove the images from the ring
+ // buffer.
+ capturedImages = ringBuffer.getAndRemoveAllImages();
+ }
+ }
+ } finally {
+ // Make sure the images are closed after the callback.
+ try (Lifetime capturedImagesLifetime = new Lifetime()) {
+ for (ImageProxy image : capturedImages) {
+ capturedImagesLifetime.add(image);
+ }
+ mBurstController.processBurstResults(capturedImages);
+ } finally {
+ // Switch back to the old request.
+ mRestorePreviewCommand.run();
+ }
+ }
+ }
+
+}
diff --git a/src/com/android/camera/burst/BurstConfiguration.java b/src/com/android/camera/burst/BurstConfiguration.java
deleted file mode 100644
index 08688e33d..000000000
--- a/src/com/android/camera/burst/BurstConfiguration.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.camera.burst;
-
-import android.hardware.camera2.TotalCaptureResult;
-
-/**
- * The burst configuration parameters.
- */
-public interface BurstConfiguration {
- /**
- * The eviction strategy of the internal Camera image buffer.
- * <p/>
- * For a burst the Camera maintains an internal image buffer. This image
- * buffer has limited memory and old images need to be evicted for storing
- * new images. The eviction handler encapsulates the eviction strategy that
- * the Camera uses to evict frames.
- */
- public interface EvictionHandler {
- /**
- * Return the timestamp of the image that should be dropped.
- * <p/>
- * This method is called when the internal image buffer is out of
- * capacity and needs to drop an image from the buffer.
- * <p/>
- * This should return one of the timestamps passed into
- * {@link #onFrameInserted(long, TotalCaptureResult)}, and which has not
- * yet been dropped.
- *
- * @return the timestamp of the frame to drop.
- */
- long selectFrameToDrop();
-
- /**
- * Called when the capture result for a frame is available.
- *
- * @param timestamp the timestamp of the frame, this frame may or may
- * not be present in the image buffer.
- * @param captureResult the capture result of the image.
- */
- void onFrameCaptureResultAvailable(long timestamp,
- TotalCaptureResult captureResult);
-
- /**
- * Called when an image is inserted in the image buffer.
- *
- * @param timestamp the timestamp of the inserted frame in the image
- * buffer.
- */
- void onFrameInserted(long timestamp);
-
- /**
- * Called when a frame is dropped from the image buffer.
- *
- * @param timestamp the timestamp of the dropped frame.
- */
- void onFrameDropped(long timestamp);
- }
-
- /**
- * Return the eviction handler associated with this instance of burst.
- */
- public EvictionHandler getEvictionHandler();
-}
diff --git a/src/com/android/camera/burst/BurstController.java b/src/com/android/camera/burst/BurstController.java
index c501906b6..da89d4c0e 100644
--- a/src/com/android/camera/burst/BurstController.java
+++ b/src/com/android/camera/burst/BurstController.java
@@ -14,7 +14,11 @@
package com.android.camera.burst;
-import com.android.camera.gl.FrameDistributor.FrameConsumer;
+import android.graphics.SurfaceTexture;
+
+import com.android.camera.one.v2.camera2proxy.ImageProxy;
+
+import java.util.List;
/**
* Controls the interactions with burst.
@@ -27,19 +31,15 @@ import com.android.camera.gl.FrameDistributor.FrameConsumer;
* module retrieves results from the internal camera buffer and can do post
* processing on the results.
* <p/>
- * Camera hooks up the frame consumer for the burst module returned by
- * {@link #getPreviewFrameConsumer()} and initializes the burst module by
- * calling {@link #startBurst()}. The returned configuration for initialized
- * burst module contains the eviction strategy for the internal camera buffer.
- * This {@link BurstConfiguration#getEvictionHandler()} is then used by camera
- * to decide which frames to keep and which to reject.
+ * Camera initializes the burst module by calling {@link #startBurst(SurfaceTexture,
+ * ImageStreamProperties, BurstResultsListener)}. The returned eviction strategy
+ * is used by the internal camera buffer to decide which frames to keep and
+ * which to reject.
* <p/>
- * Once burst finishes, camera calls the {@link #stopBurst(ResultsAccessor)} to
- * let the burst module retrieve burst results from the internal buffer. Results
- * of burst can be extracted by calling the
- * {@link ResultsAccessor#extractImage(long)} method. Once extraction is
- * finished the burst module should call {@link ResultsAccessor#close()} method
- * to let camera free resources used by burst.
+ * Once burst finishes, camera calls the {@link #processBurstResults(List)} to
+ * let the burst module retrieve burst results from the internal buffer. Once
+ * {@link #processBurstResults(List)} completes all resources allocated for the
+ * burst are freed.
* <p/>
* Once post processing is complete, the burst module returns the final results
* by calling {@link BurstResultsListener#onBurstCompleted(BurstResult)} method.
@@ -47,46 +47,68 @@ import com.android.camera.gl.FrameDistributor.FrameConsumer;
interface BurstController {
/**
- * Starts the burst.
- *
- * @return the configuration of burst that can be used to control the
- * ongoing burst.
+ * Properties of the image stream.
*/
- public BurstConfiguration startBurst();
+ public static class ImageStreamProperties {
+ private final int width;
+ private final int height;
+ private final int imageRotation;
+ private final boolean isMirrored;
- /**
- * Stops the burst.
- *
- * @param resultsAccessor an instance of results accessor that can be used
- * to query the results of the burst.
- */
- public void stopBurst(ResultsAccessor resultsAccessor);
+ public ImageStreamProperties(int width, int height,
+ int imageRotation,
+ boolean isMirrored) {
+ this.width = width;
+ this.height = height;
+ this.imageRotation = imageRotation;
+ this.isMirrored = isMirrored;
+ }
- /**
- * Called when size of the preview changes.
- * <p>
- * Preview size can change in case of rotation or switching cameras.
- *
- * @param width the width of the preview.
- * @param height the height of the preview.
- */
- public void onPreviewSizeChanged(int width, int height);
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public int getImageRotation() {
+ return imageRotation;
+ }
+
+ public boolean isMirrored() {
+ return isMirrored;
+ }
+ }
/**
- * Called when the orientation of the preview changes.
+ * Starts the burst.
+ * <p/>
+ * Takes a SurfaceTexture that is not attached to any context (call
+ * {@link android.graphics.SurfaceTexture#detachFromGLContext()} before
+ * passing it here. Can register as a frame available listener by calling
+ * {@link SurfaceTexture#setOnFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener,
+ * android.os.Handler)}.
*
- * @param orientation orientation of preview in degrees.
- * @param isMirrored true if preview is mirrored.
+ * @param surfaceTexture the SurfaceTexture for the low-res image stream.
+ * This surface should not be attached to any GL context.
+ * @param imageStreamProperties the properties of the low-res image stream.
+ * @param burstResultsListener the listener for burst results.
+ * @return the configuration of burst that can be used to control the
+ * ongoing burst.
*/
- public void onOrientationChanged(int orientation, boolean isMirrored);
+ public EvictionHandler startBurst(SurfaceTexture surfaceTexture,
+ ImageStreamProperties imageStreamProperties,
+ BurstResultsListener burstResultsListener);
/**
- * Get the consumer for preview frames.
+ * Stops the burst.
* <p/>
- * Burst module streams preview frames and selects "good" frames by
- * analyzing preview frames. Preview frames should have exact timestamps as
- * the high-res images held in the internal image buffer.
+ *
+ * @param capturedImages list of images captured from the burst. All images
+ * are closed after this call completes. If implementations need
+ * to access images after this call they need to make a copy of
+ * images before returning.
*/
- public FrameConsumer getPreviewFrameConsumer();
-
+ public void processBurstResults(List<ImageProxy> capturedImages);
}
diff --git a/src/com/android/camera/burst/BurstFacade.java b/src/com/android/camera/burst/BurstFacade.java
index f1e19afb0..6cda927db 100644
--- a/src/com/android/camera/burst/BurstFacade.java
+++ b/src/com/android/camera/burst/BurstFacade.java
@@ -17,37 +17,46 @@
package com.android.camera.burst;
import android.graphics.SurfaceTexture;
+import android.view.Surface;
-import com.android.camera.one.OneCamera;
+import com.android.camera.app.OrientationManager.DeviceOrientation;
+import com.android.camera.one.OneCamera.Facing;
import com.android.camera.session.CaptureSession;
-import java.io.File;
-
/**
- * Facade for {@link BurstController} provides a simpler interface.
+ * Facade for the entire burst acquisition pipeline. Provides a simplified
+ * interface over the {@link BurstController}.
+ * <p/>
+ * The expected usage of BurstFacade can be described by the regular expression
+ * "<code>initialize (startBurst stopBurst)* release</code>". That is there can
+ * be multiple calls to
+ * {@link #startBurst(CaptureSession, DeviceOrientation, Facing, int)} and
+ * {@link #stopBurst()} between {@link #initialize(SurfaceTexture)} and
+ * {@link #release()} calls.
*/
public interface BurstFacade {
- /**
- * Called when camera is available.
- *
- * @param camera an instance of {@link OneCamera} that is used to start or
- * stop the burst.
- */
- public void onCameraAttached(OneCamera camera);
/**
- * Called when camera becomes unavailable.
+ * Starts the burst.
+ *
+ * @param captureSession the capture session to use for this burst
+ * @param deviceOrientation the orientation of the device
+ * @param cameraFacing the camera facing
+ * @param imageOrientationDegrees the orientation of captured image in
+ * degrees
*/
- public void onCameraDetached();
+ public void startBurst(CaptureSession captureSession,
+ DeviceOrientation deviceOrientation,
+ Facing cameraFacing,
+ int imageOrientationDegrees);
/**
- * Starts the burst.
+ * Stops the burst.
*
- * @param captureSession the capture session to use for this burst.
- * @param tempSessionDirectory a directory in which temporary data can be
- * put.
+ * @return Whether a burst was actually stopped. Returns false if no burst
+ * was running at the time.
*/
- public void startBurst(CaptureSession captureSession, File tempSessionDirectory);
+ public boolean stopBurst();
/**
* @return Whether this burst controller is ready to start another burst.
@@ -55,42 +64,34 @@ public interface BurstFacade {
public boolean isReady();
/**
- * Stops the burst.
+ * Initialize resources and use the provided {@link SurfaceTexture} for
+ * streaming low-res preview frames for the burst.
*
- * @return Whether a burst was actually stopped. Returns false if no burst
- * was running at the time.
+ * @param surfaceTexture to use for streaming
*/
- public boolean stopBurst();
-
- /** Sets the surface texture from which frames will be consumed. */
- public void setSurfaceTexture(SurfaceTexture surfaceTexture, int width, int height);
+ public void initialize(SurfaceTexture surfaceTexture);
/**
- * Initializes the surface texture consumer with the current surface
- * texture and its dimensions.
+ * Release any resources used by the burst.
+ * <p/>
+ * {@link #initialize(SurfaceTexture)} should be called in order to start
+ * capturing bursts again.
*/
- public void initializeSurfaceTextureConsumer(int surfaceWidth, int surfaceHeight);
+ public void release();
/**
- * Initializes the surface texture consumer with the give surface
- * texture and dimensions.
+ * Returns the input surface for preview stream used by burst module.
+ * <p/>
+ * This is an instance of {@link Surface} that is created for the passed in
+ * surface texture {@link #initialize(SurfaceTexture)}.
*/
- public void initializeSurfaceTextureConsumer(SurfaceTexture surfaceTexture, int surfaceWidth,
- int surfaceHeight);
-
- /** Updates the size of the preview buffer. */
- public void updatePreviewBufferSize(int width, int height);
-
- /** Initializes and starts the frame distributor. */
- public void initializeAndStartFrameDistributor();
-
- /** Closed the frame distributor. */
- public void closeFrameDistributor();
-
- /** Returns the frame distributor's input surface texture. */
- public SurfaceTexture getInputSurfaceTexture();
-
- /** Sets the preview size (in pixels) of the preview consumer. */
- public void setPreviewConsumerSize(int width, int height);
+ public Surface getInputSurface();
+ /**
+ * Sets an instance of {@link BurstTaker}.
+ * <p/>
+ * The instance of {@link BurstTaker} is available only when the capture
+ * session with Camera is complete.
+ */
+ public void setBurstTaker(BurstTaker burstTaker);
}
diff --git a/src/com/android/camera/burst/BurstFacadeFactory.java b/src/com/android/camera/burst/BurstFacadeFactory.java
index 993409269..cd97ed096 100644
--- a/src/com/android/camera/burst/BurstFacadeFactory.java
+++ b/src/com/android/camera/burst/BurstFacadeFactory.java
@@ -18,15 +18,12 @@ package com.android.camera.burst;
import android.content.Context;
import android.graphics.SurfaceTexture;
+import android.view.Surface;
-import com.android.camera.app.OrientationManager;
-import com.android.camera.gl.FrameDistributorWrapper;
-import com.android.camera.gl.SurfaceTextureConsumer;
-import com.android.camera.one.OneCamera;
+import com.android.camera.app.OrientationManager.DeviceOrientation;
+import com.android.camera.one.OneCamera.Facing;
import com.android.camera.session.CaptureSession;
-import java.io.File;
-
/**
* Factory for creating burst manager objects.
*/
@@ -42,18 +39,10 @@ public class BurstFacadeFactory {
* burst is not enabled.
*/
private static class BurstFacadeStub implements BurstFacade {
- private SurfaceTexture mPreviewSurfaceTexture;
-
- @Override
- public void onCameraAttached(OneCamera camera) {
- }
-
- @Override
- public void onCameraDetached() {
- }
-
@Override
- public void startBurst(CaptureSession captureSession, File tempSessionDirectory) {
+ public void startBurst(CaptureSession captureSession,
+ DeviceOrientation deviceOrientation, Facing cameraFacing,
+ int imageOrientationDegrees) {
}
@Override
@@ -67,44 +56,18 @@ public class BurstFacadeFactory {
}
@Override
- public void setSurfaceTexture(SurfaceTexture surfaceTexture, int width, int height) {
- mPreviewSurfaceTexture = surfaceTexture;
- }
-
- @Override
- public void initializeSurfaceTextureConsumer(int surfaceWidth, int surfaceHeight) {
- }
-
- @Override
- public void initializeSurfaceTextureConsumer(SurfaceTexture surfaceTexture, int
- surfaceWidth, int surfaceHeight) {
- mPreviewSurfaceTexture = surfaceTexture;
-
- }
-
- @Override
- public void updatePreviewBufferSize(int width, int height) {
- if (mPreviewSurfaceTexture != null) {
- mPreviewSurfaceTexture.setDefaultBufferSize(width, height);
- }
- }
-
- @Override
- public void initializeAndStartFrameDistributor() {
- }
+ public void initialize(SurfaceTexture surfaceTexture) {}
@Override
- public void closeFrameDistributor() {
- }
+ public void release() {}
@Override
- public SurfaceTexture getInputSurfaceTexture() {
- return mPreviewSurfaceTexture;
+ public Surface getInputSurface() {
+ return null;
}
@Override
- public void setPreviewConsumerSize(int width, int height) {
- }
+ public void setBurstTaker(BurstTaker burstTaker) {}
}
/**
@@ -112,16 +75,16 @@ public class BurstFacadeFactory {
*
* @param appContext the Android application context which is passes through
* to the burst controller.
- * @param orientationManager for querying orientation of burst.
+ * @param orientationController for locking orientation when burst is running.
* @param readyStateListener gets called when the ready state of Burst
* changes.
*/
- public static BurstFacade create(Context appContext, OrientationManager orientationManager,
+ public static BurstFacade create(Context appContext,
+ OrientationLockController orientationController,
BurstReadyStateChangeListener readyStateListener) {
if (BurstControllerImpl.isBurstModeSupported(appContext)) {
- BurstFacade burstController = new BurstFacadeImpl(appContext, orientationManager,
- readyStateListener,
- new FrameDistributorWrapper(), new SurfaceTextureConsumer());
+ BurstFacade burstController = new BurstFacadeImpl(appContext, orientationController,
+ readyStateListener);
ToastingBurstFacadeDecorator.BurstToaster toaster =
new ToastingBurstFacadeDecorator.BurstToaster(appContext);
return new ToastingBurstFacadeDecorator(burstController, toaster);
diff --git a/src/com/android/camera/burst/BurstFacadeImpl.java b/src/com/android/camera/burst/BurstFacadeImpl.java
index 811195632..253d50d9d 100644
--- a/src/com/android/camera/burst/BurstFacadeImpl.java
+++ b/src/com/android/camera/burst/BurstFacadeImpl.java
@@ -16,33 +16,18 @@ package com.android.camera.burst;
import android.content.Context;
import android.graphics.SurfaceTexture;
-import android.location.Location;
-import android.os.AsyncTask;
-import android.text.TextUtils;
+import android.view.Surface;
-import com.android.camera.app.OrientationManager;
import com.android.camera.app.OrientationManager.DeviceOrientation;
-import com.android.camera.app.OrientationManager.OnOrientationChangeListener;
-import com.android.camera.data.FilmstripItemData;
+import com.android.camera.async.MainThread;
+import com.android.camera.burst.BurstController.ImageStreamProperties;
import com.android.camera.debug.Log;
import com.android.camera.debug.Log.Tag;
-import com.android.camera.exif.ExifInterface;
-import com.android.camera.gl.FrameDistributor.FrameConsumer;
-import com.android.camera.gl.FrameDistributorWrapper;
-import com.android.camera.gl.SurfaceTextureConsumer;
-import com.android.camera.one.OneCamera;
-import com.android.camera.one.OneCamera.BurstParameters;
-import com.android.camera.one.OneCamera.BurstResultsCallback;
import com.android.camera.one.OneCamera.Facing;
import com.android.camera.session.CaptureSession;
import com.android.camera.session.StackSaver;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
-import java.util.TimeZone;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -66,41 +51,19 @@ class BurstFacadeImpl implements BurstFacade {
private static final Tag TAG = new Tag("BurstFacadeImpl");
- /**
- * The format string of burst media item file name (without extension).
- * <p/>
- * An media item file name has the following format: "Burst_" + artifact
- * type + "_" + index of artifact + "_" + index of media item + "_" +
- * timestamp
- */
- private static final String MEDIA_ITEM_FILENAME_FORMAT_STRING = "Burst_%s_%d_%d_%d";
-
- private static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("UTC");
+ private static final int DEFAULT_PREVIEW_WIDTH = 320;
+ private static final int DEFAULT_PREVIEW_HEIGHT = 240;
private final AtomicReference<BurstModuleState> mBurstModuleState =
new AtomicReference<BurstModuleState>(BurstModuleState.IDLE);
-
- /** Lock to protect starting and stopping of the burst. */
- private final Object mStartStopBurstLock = new Object();
+ private final AtomicReference<BurstTaker> mBurstTaker =
+ new AtomicReference<>(null);
private final BurstController mBurstController;
- /**
- * Results callback that is invoked by camera when results are available.
- */
- private final BurstResultsCallback mBurstExtractsResultsCallback = new BurstResultsCallback() {
- @Override
- public void onBurstComplete(ResultsAccessor resultAccessor) {
- // Pass the results accessor to the controller.
- mBurstController.stopBurst(resultAccessor);
- }
- };
/** A stack saver for the outstanding burst request. */
private StackSaver mActiveStackSaver;
- /** The image orientation of the active burst. */
- private int mImageOrientation;
-
/**
* Listener for burst controller. Saves the results and interacts with the
* UI.
@@ -114,113 +77,88 @@ class BurstFacadeImpl implements BurstFacade {
@Override
public void onBurstError(Exception error) {
Log.e(TAG, "Exception while running the burst" + error);
- mActiveStackSaver = null;
-
- // Transition to idle state, ready to take another burst.
- mBurstModuleState.set(BurstModuleState.IDLE);
-
- // Re-enable the shutter button.
- mReadyStateListener.onBurstReadyStateChanged(true);
+ reEnableUI();
}
@Override
public void onBurstCompleted(BurstResult burstResult) {
- saveBurstResultAndEnableShutterButton(burstResult, mActiveStackSaver);
+ BurstResultsSaver.saveBurstResultsInBackground(burstResult, mActiveStackSaver,
+ new Runnable() {
+ @Override
+ public void run() {
+ reEnableUI();
+ }
+ });
}
@Override
public void onArtifactCountAvailable(
final Map<String, Integer> artifactTypeCount) {
- logArtifactCount(artifactTypeCount);
+ BurstResultsSaver.logArtifactCount(artifactTypeCount);
}
};
- private final OrientationManager.OnOrientationChangeListener mOrientationChangeListener =
- new OnOrientationChangeListener() {
- @Override
- public void onOrientationChanged(OrientationManager orientationManager,
- DeviceOrientation orientation) {
- mBurstController.onOrientationChanged(orientation.getDegrees(),
- mCamera.getDirection() == Facing.FRONT);
- }
- };
-
- /** Camera instance for starting/stopping the burst. */
- private OneCamera mCamera;
-
- private final OrientationManager mOrientationManager;
+ private final OrientationLockController mOrientationLockController;
private final BurstReadyStateChangeListener mReadyStateListener;
- /** Used to distribute camera frames to consumers. */
- private final FrameDistributorWrapper mFrameDistributor;
-
- /** The frame consumer that renders frames to the preview. */
- private final SurfaceTextureConsumer mPreviewConsumer;
+ private final AtomicReference<SurfaceTextureContainer> mSurfaceTextureContainer =
+ new AtomicReference<>();
/**
* Create a new BurstManagerImpl instance.
*
- * @param appContext the Android application context.
- * @param orientationManager orientationManager
+ * @param appContext the application context
+ * @param orientationLockController for locking orientation when burst is
+ * running.
* @param readyStateListener gets called when the ready state of Burst
* changes.
*/
- public BurstFacadeImpl(Context appContext, OrientationManager orientationManager,
- BurstReadyStateChangeListener readyStateListener,
- FrameDistributorWrapper frameDistributor, SurfaceTextureConsumer previewConsumer) {
- mOrientationManager = orientationManager;
- mBurstController = new BurstControllerImpl(appContext, mBurstResultsListener);
+ public BurstFacadeImpl(Context appContext,
+ OrientationLockController orientationLockController,
+ BurstReadyStateChangeListener readyStateListener) {
+ mOrientationLockController = orientationLockController;
+ mBurstController = new BurstControllerImpl(appContext);
mReadyStateListener = readyStateListener;
- mFrameDistributor = frameDistributor;
- mPreviewConsumer = previewConsumer;
}
@Override
- public void onCameraAttached(OneCamera camera) {
- synchronized (mStartStopBurstLock) {
- mCamera = camera;
- }
- }
-
- @Override
- public void onCameraDetached() {
- synchronized (mStartStopBurstLock) {
- mCamera = null;
- }
- }
-
- @Override
- public void startBurst(CaptureSession captureSession, File tempSessionDirectory) {
- synchronized (mStartStopBurstLock) {
- if (mCamera != null &&
- mBurstModuleState.compareAndSet(BurstModuleState.IDLE,
- BurstModuleState.RUNNING)) {
- Log.d(TAG, "Starting burst.");
- Location location = captureSession.getLocation();
-
- mOrientationManager.addOnOrientationChangeListener(mOrientationChangeListener);
- int orientation = mOrientationManager.getDeviceOrientation().getDegrees();
- mBurstController.onOrientationChanged(orientation,
- mCamera.getDirection() == Facing.FRONT);
-
- BurstConfiguration burstConfig = mBurstController.startBurst();
- BurstParameters params = new BurstParameters(captureSession.getTitle(),
- orientation, location, tempSessionDirectory, burstConfig,
- mBurstExtractsResultsCallback);
-
- if (mActiveStackSaver != null) {
- throw new IllegalStateException(
- "Cannot start a burst while another is in progress.");
- }
- mActiveStackSaver = captureSession.getStackSaver();
- mImageOrientation = mOrientationManager.getDeviceOrientation().getDegrees();
-
- // Disable the shutter button.
- mReadyStateListener.onBurstReadyStateChanged(false);
-
- // Start burst.
- mCamera.startBurst(params, captureSession);
+ public void startBurst(CaptureSession captureSession,
+ DeviceOrientation deviceOrientation,
+ Facing cameraFacing,
+ int imageOrientationDegrees) {
+ MainThread.checkMainThread();
+ if (mBurstTaker.get() != null &&
+ mBurstModuleState.compareAndSet(BurstModuleState.IDLE,
+ BurstModuleState.RUNNING)) {
+ mActiveStackSaver = captureSession.getStackSaver();
+
+ mOrientationLockController.lockOrientation();
+ // Disable the shutter button.
+ mReadyStateListener.onBurstReadyStateChanged(false);
+
+ Log.d(TAG, "Starting burst. Device orientation: " + deviceOrientation.getDegrees()
+ + " image orientation: " + imageOrientationDegrees);
+ int width = DEFAULT_PREVIEW_WIDTH;
+ int height = DEFAULT_PREVIEW_HEIGHT;
+ if (imageOrientationDegrees % 180 == 90) {
+ int tmp = width;
+ width = height;
+ height = tmp;
}
+
+ ImageStreamProperties imageStreamProperties =
+ new ImageStreamProperties(width, height,
+ imageOrientationDegrees, cameraFacing == Facing.FRONT);
+ EvictionHandler evictionHandler =
+ mBurstController.startBurst(
+ mSurfaceTextureContainer.get().getSurfaceTexture(),
+ imageStreamProperties,
+ mBurstResultsListener);
+
+ // Start burst.
+ mBurstTaker.get().startBurst(evictionHandler, mBurstController);
+ } else {
+ Log.e(TAG, "Cannot start burst.");
}
}
@@ -231,221 +169,54 @@ class BurstFacadeImpl implements BurstFacade {
@Override
public boolean stopBurst() {
- synchronized (mStartStopBurstLock) {
+ MainThread.checkMainThread();
boolean wasStopped = false;
if (mBurstModuleState.compareAndSet(BurstModuleState.RUNNING,
BurstModuleState.STOPPING)) {
- mOrientationManager.removeOnOrientationChangeListener(mOrientationChangeListener);
- if (mCamera != null) {
- mCamera.stopBurst();
- wasStopped = true;
- }
+ mBurstTaker.get().stopBurst();
+ wasStopped = true;
}
return wasStopped;
- }
- }
-
- @Override
- public void setSurfaceTexture(SurfaceTexture surfaceTexture, int width, int height) {
- mPreviewConsumer.setSurfaceTexture(surfaceTexture, width, height);
}
@Override
- public void initializeSurfaceTextureConsumer(int surfaceWidth, int surfaceHeight) {
- initializeSurfaceTextureConsumer(mPreviewConsumer.getSurfaceTexture(), surfaceWidth,
- surfaceHeight);
+ public Surface getInputSurface() {
+ return mSurfaceTextureContainer.get().getSurface();
}
@Override
- public void initializeSurfaceTextureConsumer(SurfaceTexture surface, int surfaceWidth,
- int surfaceHeight) {
- if (surface == null) {
- return;
- }
+ public void initialize(SurfaceTexture surfaceTexture) {
+ MainThread.checkMainThread();
+ // TODO: Use preview sizes from Camera API here instead of using the
+ // default.
+ surfaceTexture.setDefaultBufferSize(DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT);
- if (mPreviewConsumer.getSurfaceTexture() != surface) {
- mPreviewConsumer.setSurfaceTexture(surface, surfaceWidth, surfaceHeight);
- } else if (mPreviewConsumer.getWidth() != surfaceWidth
- || mPreviewConsumer.getHeight() != surfaceHeight) {
- mPreviewConsumer.setSize(surfaceWidth, surfaceHeight);
- }
+ // Detach from GL context, to allow frame distributor to attach to the
+ // GL context.
+ surfaceTexture.detachFromGLContext();
+ mSurfaceTextureContainer.set(new SurfaceTextureContainer(surfaceTexture));
}
@Override
- public void initializeAndStartFrameDistributor() {
- // Currently, there is only one consumer to FrameDistributor for
- // rendering the frames to the preview texture.
- List<FrameConsumer> frameConsumers = new ArrayList<>();
- frameConsumers.add(mBurstController.getPreviewFrameConsumer());
- frameConsumers.add(mPreviewConsumer);
- mFrameDistributor.start(frameConsumers);
- }
-
- @Override
- public void updatePreviewBufferSize(int width, int height) {
- mFrameDistributor.updatePreviewBufferSize(width, height);
- }
-
- @Override
- public void closeFrameDistributor() {
- mFrameDistributor.close();
- }
-
- @Override
- public SurfaceTexture getInputSurfaceTexture() {
- if (mFrameDistributor != null) {
- return mFrameDistributor.getInputSurfaceTexture();
- } else {
- return null;
+ public void release() {
+ MainThread.checkMainThread();
+ stopBurst();
+ if (mSurfaceTextureContainer.get() != null) {
+ mSurfaceTextureContainer.get().close();
+ mSurfaceTextureContainer.set(null);
}
}
@Override
- public void setPreviewConsumerSize(int previewWidth, int previewHeight) {
- mPreviewConsumer.setSize(previewWidth, previewHeight);
- }
-
- /**
- * Generates sequential timestamp with 1 second difference.
- */
- private static class SequentialTimestampGenerator {
- private long mSeedTimestampMillis;
-
- /**
- * New instance of generator.
- *
- * @param seedTimestampMillis the timestamp in milliseconds for
- * initializing the generator.
- */
- public SequentialTimestampGenerator(long seedTimestampMillis) {
- mSeedTimestampMillis = seedTimestampMillis;
- }
-
- /**
- * Returns the next timestamp.
- */
- public synchronized long getNextTimestampMillis() {
- mSeedTimestampMillis += TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS);
- return mSeedTimestampMillis;
- }
- }
-
- /**
- * Saves the burst result and on completion re-enables the shutter button.
- *
- * @param burstResult the result of the burst.
- */
- private void saveBurstResultAndEnableShutterButton(final BurstResult burstResult,
- final StackSaver stackSaver) {
- Log.i(TAG, "Saving results of of the burst.");
-
- AsyncTask<Void, String, Void> saveTask =
- new AsyncTask<Void, String, Void>() {
- @Override
- protected Void doInBackground(Void... arg0) {
- // The timestamp with which a media item is saved
- // determines its place in the film strip. The newer
- // items appear first.
- // We save artifacts and their corresponding media
- // items sequentially in the desired order. The order
- // of the artifacts is implicitly defined by
- // burstResult.getTypes() and the media items inside the
- // artifacts are assumed to be sorted in ascending order
- // by timestamps.
- // We create a timestamp-generator that generates
- // timestamps in order and use it to save timestamps.
- SequentialTimestampGenerator timestampGen =
- new SequentialTimestampGenerator(System.currentTimeMillis());
- for (String artifactType : burstResult.getTypes()) {
- publishProgress(artifactType);
- saveArtifacts(stackSaver, burstResult, artifactType,
- timestampGen);
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- mBurstModuleState.set(BurstModuleState.IDLE);
- mActiveStackSaver = null;
- // Re-enable the shutter button.
- mReadyStateListener.onBurstReadyStateChanged(true);
- }
-
- @Override
- protected void onProgressUpdate(String... artifactTypes) {
- logProgressUpdate(artifactTypes, burstResult);
- }
- };
- saveTask.execute(null, null, null);
- }
-
- /**
- * Save individual artifacts for bursts.
- */
- private void saveArtifacts(final StackSaver stackSaver, final BurstResult burstResult,
- final String artifactType, SequentialTimestampGenerator timestampGenerator) {
- List<BurstArtifact> artifactList = burstResult.getArtifactsByType(artifactType);
- for (int artifactIndex = 0; artifactIndex < artifactList.size(); artifactIndex++) {
- List<BurstMediaItem> mediaItems = artifactList.get(artifactIndex).getMediaItems();
- for (int index = 0; index < mediaItems.size(); index++) {
- saveBurstMediaItem(stackSaver, mediaItems.get(index),
- artifactType, artifactIndex + 1, index + 1, timestampGenerator);
- }
- }
+ public void setBurstTaker(BurstTaker burstTaker) {
+ mBurstTaker.set(burstTaker);
}
- private void saveBurstMediaItem(StackSaver stackSaver,
- BurstMediaItem mediaItem,
- String artifactType,
- int artifactIndex,
- int index,
- SequentialTimestampGenerator timestampGenerator) {
- // Use ordered timestamp for saving the media item, this way media
- // items appear to be in the correct order when user swipes to the
- // film strip.
- long timestamp = timestampGenerator.getNextTimestampMillis();
- final String title = String.format(MEDIA_ITEM_FILENAME_FORMAT_STRING,
- artifactType, artifactIndex, index, mediaItem.getTimestamp());
- String mimeType = mediaItem.getMimeType();
- ExifInterface exif = null;
- if (FilmstripItemData.MIME_TYPE_JPEG.equals(mimeType)) {
- exif = new ExifInterface();
- exif.addDateTimeStampTag(
- ExifInterface.TAG_DATE_TIME,
- timestamp,
- UTC_TIMEZONE);
- }
-
- stackSaver.saveStackedImage(mediaItem.getData(),
- title,
- mediaItem.getWidth(),
- mediaItem.getHeight(),
- mImageOrientation,
- exif,
- timestamp,
- mimeType);
- }
-
- private void logArtifactCount(final Map<String, Integer> artifactTypeCount) {
- final String prefix = "Finished burst. Creating ";
- List<String> artifactDescription = new ArrayList<String>();
- for (Map.Entry<String, Integer> entry : artifactTypeCount.entrySet()) {
- artifactDescription.add(entry.getValue() + " " + entry.getKey());
- }
-
- String message = prefix + TextUtils.join(" and ", artifactDescription) + ".";
- Log.d(TAG, message);
- }
-
- private void logProgressUpdate(String[] artifactTypes, BurstResult burstResult) {
- for (String artifactType : artifactTypes) {
- List<BurstArtifact> artifacts =
- burstResult.getArtifactsByType(artifactType);
- if (!artifacts.isEmpty()) {
- Log.d(TAG, "Saving " + artifacts.size()
- + " " + artifactType + "s.");
- }
- }
+ private void reEnableUI() {
+ MainThread.checkMainThread();
+ mBurstModuleState.set(BurstModuleState.IDLE);
+ mOrientationLockController.unlockOrientation();
+ // Re-enable the shutter button.
+ mReadyStateListener.onBurstReadyStateChanged(true);
}
}
diff --git a/src/com/android/camera/burst/BurstImage.java b/src/com/android/camera/burst/BurstImage.java
deleted file mode 100644
index cc5d4fdc7..000000000
--- a/src/com/android/camera/burst/BurstImage.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.camera.burst;
-
-import android.hardware.camera2.TotalCaptureResult;
-
-/**
- * Holds image data and meta-data for a single image that is part of a burst.
- * <p/>
- * Bursts are an ordered collection of images. This class holds the data for one
- * of these images.
- */
-public class BurstImage {
- /**
- * The bytes of image that can be decoded by
- * {@link android.graphics.BitmapFactory#decodeByteArray(byte[],
- * int, int, android.graphics.BitmapFactory.Options)}.
- */
- // TODO: Fix this and use a URI here for saved image.
- public byte[] data;
-
- /**
- * The timestamp of the image measured in nanoseconds.
- * <p/>
- * The timestamp is monotonically increasing. It is mostly useful for
- * determining time offsets between images in burst. The zero-point and the
- * value of the timestamp cannot be in general compared between two
- * different bursts.
- */
- public long timestamp;
-
- /**
- * The width of the image in pixels.
- */
- public int width;
-
- /**
- * The height of the image in pixels.
- */
- public int height;
-
- /**
- * The capture result associated with the image.
- */
- public TotalCaptureResult captureResult;
-}
diff --git a/src/com/android/camera/burst/BurstResultsSaver.java b/src/com/android/camera/burst/BurstResultsSaver.java
new file mode 100644
index 000000000..104931700
--- /dev/null
+++ b/src/com/android/camera/burst/BurstResultsSaver.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.burst;
+
+import android.os.AsyncTask;
+import android.text.TextUtils;
+
+import com.android.camera.data.FilmstripItemData;
+import com.android.camera.debug.Log;
+import com.android.camera.debug.Log.Tag;
+import com.android.camera.exif.ExifInterface;
+import com.android.camera.session.StackSaver;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+
+class BurstResultsSaver {
+ private static final Tag TAG = new Tag("BurstResultsSaver");
+
+ /**
+ * The format string of burst media item file name (without extension).
+ * <p/>
+ * An media item file name has the following format: "Burst_" + artifact
+ * type + "_" + index of artifact + "_" + index of media item + "_" +
+ * timestamp
+ */
+ private static final String MEDIA_ITEM_FILENAME_FORMAT_STRING = "Burst_%s_%d_%d_%d";
+ private static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("UTC");
+
+ /**
+ * Generates sequential timestamp with 1 second difference.
+ */
+ private static class SequentialTimestampGenerator {
+ private long mSeedTimestampMillis;
+
+ /**
+ * New instance of generator.
+ *
+ * @param seedTimestampMillis the timestamp in milliseconds for
+ * initializing the generator.
+ */
+ public SequentialTimestampGenerator(long seedTimestampMillis) {
+ mSeedTimestampMillis = seedTimestampMillis;
+ }
+
+ /**
+ * Returns the next timestamp.
+ */
+ public synchronized long getNextTimestampMillis() {
+ mSeedTimestampMillis += TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS);
+ return mSeedTimestampMillis;
+ }
+ }
+
+ public static void logArtifactCount(final Map<String, Integer> artifactTypeCount) {
+ final String prefix = "Finished burst. Creating ";
+ List<String> artifactDescription = new ArrayList<String>();
+ for (Map.Entry<String, Integer> entry : artifactTypeCount.entrySet()) {
+ artifactDescription.add(entry.getValue() + " " + entry.getKey());
+ }
+
+ String message = prefix + TextUtils.join(" and ", artifactDescription) + ".";
+ Log.d(TAG, message);
+ }
+
+ /**
+ * Saves the burst result and on completion re-enables the shutter button.
+ *
+ * @param burstResult the result of the burst.
+ */
+ public static void saveBurstResultsInBackground(final BurstResult burstResult,
+ final StackSaver stackSaver, final Runnable onCompletetionCallback) {
+ Log.i(TAG, "Saving results of of the burst.");
+
+ AsyncTask<Void, String, Void> saveTask =
+ new AsyncTask<Void, String, Void>() {
+ @Override
+ protected Void doInBackground(Void... arg0) {
+ // The timestamp with which a media item is saved
+ // determines its place in the film strip. The newer
+ // items appear first.
+ // We save artifacts and their corresponding media
+ // items sequentially in the desired order. The order
+ // of the artifacts is implicitly defined by
+ // burstResult.getTypes() and the media items inside the
+ // artifacts are assumed to be sorted in ascending order
+ // by timestamps.
+ // We create a timestamp-generator that generates
+ // timestamps in order and use it to save timestamps.
+ SequentialTimestampGenerator timestampGen =
+ new SequentialTimestampGenerator(System.currentTimeMillis());
+ for (String artifactType : burstResult.getTypes()) {
+ publishProgress(artifactType);
+ saveArtifacts(stackSaver, burstResult, artifactType,
+ timestampGen);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ onCompletetionCallback.run();
+ }
+
+ @Override
+ protected void onProgressUpdate(String... artifactTypes) {
+ logProgressUpdate(artifactTypes, burstResult);
+ }
+ };
+ saveTask.execute(null, null, null);
+ }
+
+ /**
+ * Save individual artifacts for bursts.
+ */
+ private static void saveArtifacts(final StackSaver stackSaver, final BurstResult burstResult,
+ final String artifactType, SequentialTimestampGenerator timestampGenerator) {
+ List<BurstArtifact> artifactList = burstResult.getArtifactsByType(artifactType);
+ for (int artifactIndex = 0; artifactIndex < artifactList.size(); artifactIndex++) {
+ List<BurstMediaItem> mediaItems = artifactList.get(artifactIndex).getMediaItems();
+ for (int index = 0; index < mediaItems.size(); index++) {
+ saveBurstMediaItem(stackSaver, mediaItems.get(index),
+ artifactType, artifactIndex + 1, index + 1, timestampGenerator);
+ }
+ }
+ }
+
+ private static void saveBurstMediaItem(StackSaver stackSaver,
+ BurstMediaItem mediaItem,
+ String artifactType,
+ int artifactIndex,
+ int index,
+ SequentialTimestampGenerator timestampGenerator) {
+ // Use ordered timestamp for saving the media item, this way media
+ // items appear to be in the correct order when user swipes to the
+ // film strip.
+ long timestamp = timestampGenerator.getNextTimestampMillis();
+ final String title = String.format(MEDIA_ITEM_FILENAME_FORMAT_STRING,
+ artifactType, artifactIndex, index, mediaItem.getTimestamp());
+ String mimeType = mediaItem.getMimeType();
+ ExifInterface exif = null;
+ if (FilmstripItemData.MIME_TYPE_JPEG.equals(mimeType)) {
+ exif = new ExifInterface();
+ exif.addDateTimeStampTag(
+ ExifInterface.TAG_DATE_TIME,
+ timestamp,
+ UTC_TIMEZONE);
+ }
+
+ stackSaver.saveStackedImage(mediaItem.getData(),
+ title,
+ mediaItem.getWidth(),
+ mediaItem.getHeight(),
+ 0, // Artifacts returned from burst have upright orientation.
+ exif,
+ timestamp,
+ mimeType);
+ }
+
+ private static void logProgressUpdate(String[] artifactTypes, BurstResult burstResult) {
+ for (String artifactType : artifactTypes) {
+ List<BurstArtifact> artifacts =
+ burstResult.getArtifactsByType(artifactType);
+ if (!artifacts.isEmpty()) {
+ Log.d(TAG, "Saving " + artifacts.size()
+ + " " + artifactType + "s.");
+ }
+ }
+ }
+
+}
diff --git a/src/com/android/camera/burst/BurstTaker.java b/src/com/android/camera/burst/BurstTaker.java
new file mode 100644
index 000000000..d819b1637
--- /dev/null
+++ b/src/com/android/camera/burst/BurstTaker.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.burst;
+
+import com.android.camera.burst.EvictionHandler;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+/**
+ * Helper for taking bursts.
+ */
+@ParametersAreNonnullByDefault
+public interface BurstTaker {
+ /**
+ * Start the burst.
+ *
+ * @param evictionHandler the strategy to use for evicting frames from the
+ * internal ring buffer.
+ * @param burstController the instance for {@link BurstController}.
+ */
+ public void startBurst(EvictionHandler evictionHandler, BurstController burstController);
+
+ /**
+ * Stop the burst.
+ */
+ public void stopBurst();
+}
diff --git a/src/com/android/camera/burst/BurstTakerImpl.java b/src/com/android/camera/burst/BurstTakerImpl.java
new file mode 100644
index 000000000..cf9d1e071
--- /dev/null
+++ b/src/com/android/camera/burst/BurstTakerImpl.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.burst;
+
+import android.view.Surface;
+
+import com.android.camera.async.Lifetime;
+import com.android.camera.async.MainThread;
+import com.android.camera.one.v2.commands.CameraCommandExecutor;
+import com.android.camera.one.v2.core.FrameServer;
+import com.android.camera.one.v2.core.Request;
+import com.android.camera.one.v2.core.RequestBuilder;
+import com.android.camera.one.v2.sharedimagereader.ManagedImageReader;
+import com.google.common.base.Preconditions;
+
+import javax.annotation.Nullable;
+import javax.annotation.ParametersAreNonnullByDefault;
+
+@ParametersAreNonnullByDefault
+public class BurstTakerImpl implements BurstTaker {
+
+ private final CameraCommandExecutor mCameraCommandExecutor;
+ private final FrameServer mFrameServer;
+ private final ManagedImageReader mImageFactory;
+ private final RequestBuilder.Factory mRequestBuilder;
+ private final Surface mBurstInputSurface;
+ private final Runnable mRestorePreviewCommand;
+ private final int mMaxImageCount;
+ /**
+ * The lifetime of the burst, the burst stops capturing images once the
+ * lifetime is closed
+ */
+ @Nullable
+ private Lifetime mBurstLifetime;
+
+ /**
+ * Creates an instance for burst taker.
+ * <p/>
+ *
+ * @param cameraCommandExecutor the executor to use for executing
+ * {@link BurstCaptureCommand}
+ * @param frameServer the {@link FrameServer} instance for creating session
+ * @param builder factory to use for creating the {@link Request} for burst
+ * capture
+ * @param imageFactory the factory to use for creating a stream of images
+ * @param burstInputSurface the input surface to use for streaming preview
+ * frames to burst
+ * @param restorePreviewCommand the command to run to restore the preview,
+ * once burst capture is complete
+ * @param maxImageCount the maximum number of images supported by the image
+ * reader
+ */
+ public BurstTakerImpl(CameraCommandExecutor cameraCommandExecutor,
+ FrameServer frameServer, RequestBuilder.Factory builder,
+ ManagedImageReader imageFactory, Surface burstInputSurface,
+ Runnable restorePreviewCommand,
+ int maxImageCount) {
+ mCameraCommandExecutor = cameraCommandExecutor;
+ mFrameServer = frameServer;
+ mRequestBuilder = builder;
+ mImageFactory = imageFactory;
+ mBurstInputSurface = burstInputSurface;
+ mRestorePreviewCommand = restorePreviewCommand;
+ mMaxImageCount = maxImageCount;
+ }
+
+ @Override
+ public void startBurst(EvictionHandler evictionHandler,
+ BurstController burstController) {
+ MainThread.checkMainThread();
+ Preconditions.checkState(mBurstLifetime == null,
+ "Burst cannot be started, while another is running.");
+ mBurstLifetime = new Lifetime();
+ BurstCaptureCommand burstCommand = new BurstCaptureCommand(
+ mFrameServer, mRequestBuilder,
+ mImageFactory, mBurstInputSurface,
+ mBurstLifetime, evictionHandler, burstController, mRestorePreviewCommand,
+ mMaxImageCount);
+
+ mCameraCommandExecutor.execute(burstCommand);
+ }
+
+ @Override
+ public synchronized void stopBurst() {
+ MainThread.checkMainThread();
+ if (mBurstLifetime != null) {
+ mBurstLifetime.close();
+ mBurstLifetime = null;
+ }
+ }
+}
diff --git a/src/com/android/camera/burst/EvictionHandler.java b/src/com/android/camera/burst/EvictionHandler.java
new file mode 100644
index 000000000..18ff772dc
--- /dev/null
+++ b/src/com/android/camera/burst/EvictionHandler.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.burst;
+
+import android.hardware.camera2.TotalCaptureResult;
+
+/**
+ * The eviction strategy of the internal Camera image buffer.
+ * <p/>
+ * For a burst the Camera maintains an internal image buffer. This image buffer
+ * has limited memory and old images need to be evicted for storing new images.
+ * The eviction handler encapsulates the eviction strategy that the Camera uses
+ * to evict frames.
+ */
+public interface EvictionHandler {
+ /**
+ * Return the timestamp of the image that should be dropped.
+ * <p/>
+ * This method is called when the internal image buffer is out of capacity
+ * and needs to drop an image from the buffer.
+ * <p/>
+ * This should return one of the timestamps passed into
+ * {@link #onFrameInserted(long)}, and which has not yet
+ * been dropped.
+ *
+ * @return the timestamp of the frame to drop.
+ */
+ long selectFrameToDrop();
+
+ /**
+ * Called when the capture result for a frame is available.
+ *
+ * @param timestamp the timestamp of the frame, this frame may or may not be
+ * present in the image buffer.
+ * @param captureResult the capture result of the image.
+ */
+ void onFrameCaptureResultAvailable(long timestamp,
+ TotalCaptureResult captureResult);
+
+ /**
+ * Called when an image is inserted in the image buffer.
+ *
+ * @param timestamp the timestamp of the inserted frame in the image buffer.
+ */
+ void onFrameInserted(long timestamp);
+
+ /**
+ * Called when a frame is dropped from the image buffer.
+ *
+ * @param timestamp the timestamp of the dropped frame.
+ */
+ void onFrameDropped(long timestamp);
+}
diff --git a/src/com/android/camera/burst/OrientationLockController.java b/src/com/android/camera/burst/OrientationLockController.java
new file mode 100644
index 000000000..a9ead861b
--- /dev/null
+++ b/src/com/android/camera/burst/OrientationLockController.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.burst;
+
+/**
+ * Controls the framework the orientation lock.
+ */
+public interface OrientationLockController {
+ /**
+ * Lock the framework orientation to the current device orientation
+ * rotation.
+ */
+ void lockOrientation();
+
+ /**
+ * Unlock the framework orientation, so it can change when the device
+ * rotates.
+ */
+ void unlockOrientation();
+}
diff --git a/src/com/android/camera/burst/ResultsAccessor.java b/src/com/android/camera/burst/ResultsAccessor.java
deleted file mode 100644
index be2904c99..000000000
--- a/src/com/android/camera/burst/ResultsAccessor.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.camera.burst;
-
-import java.util.concurrent.Future;
-
-/**
- * Accessor that can be used for retrieving high-res burst images from the
- * internal camera image buffer.
- * <p/>
- * On completion of a burst Camera hands over an instance of
- * {@link ResultsAccessor} to the burst module by calling the
- * {@link BurstControllerImpl#stopBurst(ResultsAccessor)} method. The burst
- * module can then retrieve images from the internal buffer by calling
- * {@link #extractImage(long)} with the timestamp of each image.
- * <p/>
- * When burst module has completed retrieving the high-res images from the
- * buffer it should call {@link #close()} to let camera free the internal buffer
- * and resources used by the burst.
- */
-public interface ResultsAccessor extends AutoCloseable {
- /**
- * Extract image which has the given timestamp.
- * <p/>
- * Extracting an image is an expensive operation and is done asynchronously.
- * This method returns a <code>Future<BurstImage></code> which can be used
- * to retrieve the image. If the provided timestamp is not a result of burst
- * or internal buffer of Camera does not have the image, the
- * {@link Future#get()} will return null. Camera frees up resources related
- * to the timestamp after the first call. Calling this method with the same
- * timestamp will result in a null image.
- *
- * @param timestamp the timestamp of the image to be extracted
- * @return the future for BurstImage.
- */
- Future<BurstImage> extractImage(long timestamp);
-
- /**
- * Called when results extraction has been completed and the Camera can free
- * up resources related to results of burst.
- * <p/>
- * No further images can be extracted after calling this method. Any
- * computations for extracting images are cancelled.
- */
- @Override
- void close();
-}
diff --git a/src/com/android/camera/burst/RingBuffer.java b/src/com/android/camera/burst/RingBuffer.java
new file mode 100644
index 000000000..5831b7c82
--- /dev/null
+++ b/src/com/android/camera/burst/RingBuffer.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.burst;
+
+import android.support.v4.util.LongSparseArray;
+
+import com.android.camera.async.SafeCloseable;
+import com.android.camera.burst.EvictionHandler;
+import com.android.camera.one.v2.camera2proxy.ImageProxy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A RingBuffer that is used during burst capture. It takes a
+ * {@link EvictionHandler} instance and uses it to evict frames when the ring
+ * buffer runs out of capacity.
+ */
+class RingBuffer implements SafeCloseable {
+ private final int mMaxCapacity;
+ private final EvictionHandler mEvictionHandler;
+ private final LongSparseArray<ImageProxy> mImages = new LongSparseArray<>();
+
+ /**
+ * Create a new ring buffer instance.
+ *
+ * @param maxCapacity the maximum number of images in the ring buffer.
+ * @param evictionHandler
+ */
+ public RingBuffer(int maxCapacity, EvictionHandler evictionHandler) {
+ mMaxCapacity = maxCapacity;
+ mEvictionHandler = evictionHandler;
+ }
+
+ /**
+ * Insert an image in the ring buffer, evicting any frames if necessary.
+ *
+ * @param image the image to be inserted.
+ */
+ public synchronized void insertImage(ImageProxy image) {
+ long timestamp = image.getTimestamp();
+ if (mImages.get(timestamp) != null) {
+ image.close();
+ return;
+ }
+ // Add image to ring buffer so it can be closed in case eviction
+ // handler throws.
+ addImage(image);
+ mEvictionHandler.onFrameInserted(timestamp);
+ if (mImages.size() > mMaxCapacity) {
+ long selectFrameToDrop = mEvictionHandler.selectFrameToDrop();
+ removeAndCloseImage(selectFrameToDrop);
+ mEvictionHandler.onFrameDropped(selectFrameToDrop);
+ }
+ }
+
+ /**
+ * Returns all images present in the ring buffer.
+ */
+ public synchronized List<ImageProxy> getAndRemoveAllImages() {
+ List<ImageProxy> allImages = new ArrayList<ImageProxy>(mImages.size());
+ for (int i = 0; i < mImages.size(); i++) {
+ allImages.add(mImages.valueAt(i));
+ }
+ mImages.clear();
+ return allImages;
+ }
+
+ /**
+ * Closes the ring buffer and any images in the ring buffer.
+ */
+ @Override
+ public synchronized void close() {
+ for (int i = 0; i < mImages.size(); i++) {
+ mImages.valueAt(i).close();
+ }
+ mImages.clear();
+ }
+
+ private synchronized void removeAndCloseImage(long timestampNs) {
+ ImageProxy imageProxy = mImages.get(timestampNs);
+ imageProxy.close();
+ mImages.remove(timestampNs);
+ }
+
+ private synchronized void addImage(ImageProxy image) {
+ mImages.put(image.getTimestamp(), image);
+ }
+}
diff --git a/src/com/android/camera/burst/SurfaceTextureContainer.java b/src/com/android/camera/burst/SurfaceTextureContainer.java
new file mode 100644
index 000000000..3fdd12392
--- /dev/null
+++ b/src/com/android/camera/burst/SurfaceTextureContainer.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera.burst;
+
+import android.graphics.SurfaceTexture;
+import android.view.Surface;
+
+import com.android.camera.async.SafeCloseable;
+
+/**
+ * A container that stores the {@link SurfaceTexture} and the stored
+ * {@link Surface} instance together.
+ */
+public class SurfaceTextureContainer implements SafeCloseable {
+ private final SurfaceTexture mSurfaceTexture;
+ private final Surface mSurface;
+
+ public SurfaceTextureContainer(SurfaceTexture surfaceTexture) {
+ mSurfaceTexture = surfaceTexture;
+ mSurface = new Surface(mSurfaceTexture);
+ }
+
+ public SurfaceTexture getSurfaceTexture() {
+ return mSurfaceTexture;
+ }
+
+ public Surface getSurface() {
+ return mSurface;
+ }
+
+ @Override
+ public void close() {
+ mSurfaceTexture.release();
+ }
+}
diff --git a/src/com/android/camera/burst/ToastingBurstFacadeDecorator.java b/src/com/android/camera/burst/ToastingBurstFacadeDecorator.java
index ecebde499..86043ab7c 100644
--- a/src/com/android/camera/burst/ToastingBurstFacadeDecorator.java
+++ b/src/com/android/camera/burst/ToastingBurstFacadeDecorator.java
@@ -18,15 +18,15 @@ package com.android.camera.burst;
import android.content.Context;
import android.graphics.SurfaceTexture;
+import android.view.Surface;
import android.widget.Toast;
-import com.android.camera.one.OneCamera;
+import com.android.camera.app.OrientationManager.DeviceOrientation;
+import com.android.camera.one.OneCamera.Facing;
import com.android.camera.session.CaptureSession;
-import java.io.File;
-
/**
- * A simle decorator for a {@link BurstFacade} that shows toasts for when a
+ * A simple decorator for a {@link BurstFacade} that shows toasts for when a
* burst starts or stops.
* <p>
* This class can simply be removed once we have proper UI for this.
@@ -70,19 +70,11 @@ public class ToastingBurstFacadeDecorator implements BurstFacade {
}
@Override
- public void onCameraAttached(OneCamera camera) {
- mBurstFacade.onCameraAttached(camera);
- }
-
- @Override
- public void onCameraDetached() {
- mBurstFacade.onCameraDetached();
- }
-
- @Override
- public void startBurst(CaptureSession captureSession, File tempSessionDirectory) {
+ public void startBurst(CaptureSession captureSession,
+ DeviceOrientation deviceOrientation, Facing cameraFacing, int imageOrientationDegrees) {
mToaster.showToastBurstStarted();
- mBurstFacade.startBurst(captureSession, tempSessionDirectory);
+ mBurstFacade.startBurst(captureSession,
+ deviceOrientation, cameraFacing, imageOrientationDegrees);
}
@Override
@@ -102,43 +94,22 @@ public class ToastingBurstFacadeDecorator implements BurstFacade {
}
@Override
- public void setSurfaceTexture(SurfaceTexture surfaceTexture, int width, int height) {
- mBurstFacade.setSurfaceTexture(surfaceTexture, width, height);
- }
-
- @Override
- public void initializeSurfaceTextureConsumer(int surfaceWidth, int surfaceHeight) {
- mBurstFacade.initializeSurfaceTextureConsumer(surfaceWidth, surfaceHeight);
- }
-
- @Override
- public void initializeSurfaceTextureConsumer(SurfaceTexture surfaceTexture, int surfaceWidth,
- int surfaceHeight) {
- mBurstFacade.initializeSurfaceTextureConsumer(surfaceTexture, surfaceWidth, surfaceHeight);
- }
-
- @Override
- public void updatePreviewBufferSize(int width, int height) {
- mBurstFacade.updatePreviewBufferSize(width, height);
- }
-
- @Override
- public void initializeAndStartFrameDistributor() {
- mBurstFacade.initializeAndStartFrameDistributor();
+ public void initialize(SurfaceTexture surfaceTexture) {
+ mBurstFacade.initialize(surfaceTexture);
}
@Override
- public void closeFrameDistributor() {
- mBurstFacade.closeFrameDistributor();
+ public void release() {
+ mBurstFacade.release();
}
@Override
- public SurfaceTexture getInputSurfaceTexture() {
- return mBurstFacade.getInputSurfaceTexture();
+ public Surface getInputSurface() {
+ return mBurstFacade.getInputSurface();
}
@Override
- public void setPreviewConsumerSize(int width, int height) {
- mBurstFacade.setPreviewConsumerSize(width, height);
+ public void setBurstTaker(BurstTaker burstTaker) {
+ mBurstFacade.setBurstTaker(burstTaker);
}
}
diff --git a/src/com/android/camera/gl/CopyShader.java b/src/com/android/camera/gl/CopyShader.java
deleted file mode 100644
index cff3d3cd3..000000000
--- a/src/com/android/camera/gl/CopyShader.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.camera.gl;
-
-import android.opengl.GLES11Ext;
-import android.opengl.GLES20;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-
-/**
- * Allows copying a GL texture to a {@link RenderTarget}.
- */
-// TODO: Document this class a bit more and add a test for the class.
-public class CopyShader {
-
- private static final String VERTEX_SHADER =
- "attribute vec4 a_position;\n" +
- "attribute vec2 a_texcoord;\n" +
- "varying vec2 v_texcoord;\n" +
- "void main() {\n" +
- " gl_Position = a_position;\n" +
- " v_texcoord = a_texcoord;\n" +
- "}\n";
-
- private static final String FRAGMENT_SHADER =
- "precision mediump float;\n" +
- "uniform sampler2D tex_sampler;\n" +
- "varying vec2 v_texcoord;\n" +
- "void main() {\n" +
- " gl_FragColor = texture2D(tex_sampler, v_texcoord);\n" +
- "}\n";
-
- private static final String FRAGMENT_SHADER_EXTERNAL =
- "#extension GL_OES_EGL_image_external : require\n" +
- "precision mediump float;\n" +
- "uniform samplerExternalOES tex_sampler;\n" +
- "varying vec2 v_texcoord;\n" +
- "void main() {\n" +
- " gl_FragColor = texture2D(tex_sampler, v_texcoord);\n" +
- "}\n";
-
- private static final float[] SOURCE_COORDS = new float[] {
- 0f, 0f, 1f, 0f, 0f, 1f, 1f, 1f };
- private static final float[] TARGET_COORDS = new float[] {
- -1f, -1f, 1f, -1f, -1f, 1f, 1f, 1f };
-
- private final int mProgram;
- private final int mTextureTarget;
-
- private final FloatBuffer mSourceCoords;
- private final FloatBuffer mTargetCoords;
-
- private final int mSourceAttrib;
- private final int mTargetAttrib;
-
- private final int mTextureUniform;
-
- private CopyShader(int program, int textureTarget) {
- mProgram = program;
- mTextureTarget = textureTarget;
- mSourceCoords = readFloats(SOURCE_COORDS);
- mTargetCoords = readFloats(TARGET_COORDS);
- mSourceAttrib = GLES20.glGetAttribLocation(mProgram, "a_texcoord");
- mTargetAttrib = GLES20.glGetAttribLocation(mProgram, "a_position");
- mTextureUniform = GLES20.glGetUniformLocation(mProgram, "tex_sampler");
- }
-
- /**
- * Compiles a new shader that is valid in the current context.
- *
- * @return a new shader instance that is valid in the current context
- */
- public static CopyShader compileNewShader() {
- return new CopyShader(createProgram(VERTEX_SHADER, FRAGMENT_SHADER), GLES20.GL_TEXTURE);
- }
-
- /**
- * Compiles a new shader that binds textures as GL_TEXTURE_EXTERNAL_OES.
- *
- * @return a new shader instance that is valid in the current context
- */
- public static CopyShader compileNewExternalShader() {
- return new CopyShader(createProgram(VERTEX_SHADER, FRAGMENT_SHADER_EXTERNAL),
- GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
- }
-
- /**
- * Sets the 4x4 transform matrix to apply when copying the texture.
- * <p/>
- * Note: Non-affine components of the transformation are ignored.
- *
- * @param matrix a 16-length float array containing the transform matrix in
- * column-major order.
- */
- public void setTransform(float[] matrix) {
- /**
- * Multiply transformation matrix by column vectors (s,t, 0, 1) for
- * coordinates {(0,0),(1,0), (0,1), (1,1) } and store (s,t) values of
- * the resulting matrix in column-major order.
- */
- float[] coords = new float[] {
- matrix[12], matrix[13],
- matrix[0] + matrix[12],
- matrix[1] + matrix[13],
- matrix[4] + matrix[12],
- matrix[5] + matrix[13],
- matrix[0] + matrix[4] + matrix[12],
- matrix[1] + matrix[5] + matrix[13]
- };
- mSourceCoords.put(coords).position(0);
- }
-
- /**
- * Renders the specified texture to the specified target.
- *
- * @param texName name of a valid texture
- * @param target to render into
- * @param width of output
- * @param height of output
- */
- public void renderTextureToTarget(int texName, RenderTarget target, int width, int height) {
- useProgram();
- focusTarget(target, width, height);
- assignAttribute(mSourceAttrib, mSourceCoords);
- assignAttribute(mTargetAttrib, mTargetCoords);
- bindTexture(mTextureUniform, texName, mTextureTarget);
- render();
- }
-
- /**
- * Releases the current shader.
- * <p>
- * This must be called in the shader's GL thread.
- */
- public void release() {
- GLES20.glDeleteProgram(mProgram);
- }
-
- private void focusTarget(RenderTarget target, int width, int height) {
- target.focus();
- GLES20.glViewport(0, 0, width, height);
- GLToolbox.checkGlError("focus");
- }
-
- private void useProgram() {
- GLES20.glUseProgram(mProgram);
- GLToolbox.checkGlError("glUseProgram");
- }
-
- private void render() {
- GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
- GLToolbox.checkGlError("glDrawArrays");
- }
-
- private void bindTexture(int uniformName, int texName, int texTarget) {
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- GLES20.glBindTexture(texTarget, texName);
- GLES20.glUniform1i(uniformName, 0);
- GLToolbox.checkGlError(
- "bindTexture(" + uniformName + "," + texName + "," + texTarget + ")");
- }
-
- private void assignAttribute(int index, FloatBuffer values) {
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
- GLES20.glVertexAttribPointer(index, 2, GLES20.GL_FLOAT, false, 8, values);
- GLES20.glEnableVertexAttribArray(index);
- GLToolbox.checkGlError("glVertexAttribPointer(" + index + ")");
- }
-
- private static FloatBuffer readFloats(float[] values) {
- FloatBuffer result = ByteBuffer.allocateDirect(values.length * 4)
- .order(ByteOrder.nativeOrder()).asFloatBuffer();
- result.put(values).position(0);
- return result;
- }
-
- private static int loadShader(int shaderType, String source) {
- int shader = GLES20.glCreateShader(shaderType);
- if (shader != 0) {
- GLES20.glShaderSource(shader, source);
- GLES20.glCompileShader(shader);
- int[] compiled = new int[1];
- GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
- if (compiled[0] == 0) {
- String info = GLES20.glGetShaderInfoLog(shader);
- GLES20.glDeleteShader(shader);
- shader = 0;
- throw new RuntimeException("Could not compile shader " + shaderType + ":" + info);
- }
- }
- return shader;
- }
-
- private static int createProgram(String vertexSource, String fragmentSource) {
- int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
- if (vertexShader == 0) {
- throw new RuntimeException("Could not create shader-program as vertex shader "
- + "could not be compiled!");
- }
- int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
- if (pixelShader == 0) {
- throw new RuntimeException("Could not create shader-program as fragment shader "
- + "could not be compiled!");
- }
-
- int program = GLES20.glCreateProgram();
- if (program != 0) {
- GLES20.glAttachShader(program, vertexShader);
- GLToolbox.checkGlError("glAttachShader");
- GLES20.glAttachShader(program, pixelShader);
- GLToolbox.checkGlError("glAttachShader");
- GLES20.glLinkProgram(program);
- int[] linkStatus = new int[1];
- GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
- if (linkStatus[0] != GLES20.GL_TRUE) {
- String info = GLES20.glGetProgramInfoLog(program);
- GLES20.glDeleteProgram(program);
- program = 0;
- throw new RuntimeException("Could not link program: " + info);
- }
- }
-
- GLES20.glDeleteShader(vertexShader);
- GLES20.glDeleteShader(pixelShader);
-
- return program;
- }
-}
diff --git a/src/com/android/camera/gl/FrameDistributor.java b/src/com/android/camera/gl/FrameDistributor.java
deleted file mode 100644
index 1ecb5bf28..000000000
--- a/src/com/android/camera/gl/FrameDistributor.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.camera.gl;
-
-import android.graphics.SurfaceTexture;
-
-/**
- * Distributes frames from a {@link SurfaceTexture} to multiple consumers.
- * <p>
- * Frames are distributed as OpenGL textures, that can be used for further
- * processing. This is a flexible approach that allows processing both using GL
- * methods (e.g. shaders) and CPU methods by sending frames through an
- * {@link ImageReader}.
- * <p>
- * Consumers receive {@link FrameConsumer#onNewFrameAvailable(FrameDistributor)}
- * callbacks for new frames. Each consumer can grab the most current frame from
- * its GL thread by calling {@link #acquireNextFrame(int, float[])}. After
- * accessing the data, the consumer needs to call {@link #releaseFrame()}.
- */
-public interface FrameDistributor {
- /**
- * Consumes frames streamed from a distributor.
- */
- public interface FrameConsumer {
- /**
- * Called when frame processing is about to start.
- * <p>
- * You can use this to do any setup required to process frames. Note
- * that this is called on the distributor's thread.
- */
- public void onStart();
-
- /**
- * Called when a new frame is available for processing.
- * <p>
- * Note that as this is called on the frameProducer's thread, you should
- * typically not call {@code acquireNextFrame()} from this callback.
- * Instead, call it from your GL thread, after receiving this callback.
- * When you are done processing the frame, you must call
- * {@code releaseFrame()}.
- *
- * @param frameDistributor that issued the callback
- * @param timestampNs timestamp in nanoseconds of the available frame.
- */
- public void onNewFrameAvailable(FrameDistributor frameDistributor, long timestampNs);
-
- /**
- * Called when frame processing is about to stop.
- * <p>
- * You can use this to release any resources that your consumer uses.
- * You must reinstate resources when {@link #onStart()} is called again.
- */
- public void onStop();
- }
-
- /**
- * Acquire the next available frame.
- * <p>
- * Call this after having received a
- * {@link FrameConsumer#onNewFrameAvailable(FrameDistributor)} callback. You
- * must call this from the thread in which your texture name is current and
- * valid. The texture will be filled with the frame data and must be bound
- * using GL_TEXTURE_EXTERNAL_OES. It must be a valid texture name created
- * with {@code glGenTextures()} . You must call {@link #releaseFrame()} as
- * soon as you are done processing this frame. All other consumers are
- * blocked from processing frames until you have released it, so any
- * processing should be done as efficiently as possible.
- *
- * @param textureName to fill with image data. Must be a valid texture name.
- * @param transform of the frame that needs to be applied for an upright
- * image.
- * @return the timestamp in nanoseconds of the frame.
- */
- public long acquireNextFrame(int textureName, float[] transform);
-
- /**
- * Release the currently acquired frame.
- */
- public void releaseFrame();
-
- /**
- * Get the {@link RenderTarget} that the producer uses for GL operations.
- * <p>
- * You should rarely need to use this method. It is used exclusively by
- * consumers that reuse the FrameProducer's EGL context, and must be handled
- * with great care.
- *
- * @return the RenderTarget used by the FrameProducer.
- */
- public RenderTarget getRenderTarget();
-}
diff --git a/src/com/android/camera/gl/FrameDistributorImpl.java b/src/com/android/camera/gl/FrameDistributorImpl.java
deleted file mode 100644
index 54998aca0..000000000
--- a/src/com/android/camera/gl/FrameDistributorImpl.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.camera.gl;
-
-import android.graphics.SurfaceTexture;
-import android.graphics.SurfaceTexture.OnFrameAvailableListener;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Size;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Implementation of {@link FrameDistributor}.
- * <p>
- * The typical way to use this is as follows:
- * <ol>
- * <li>Create a new instance and add all the {@link FrameConsumer} instances.
- * </li>
- * <li>Call {@link #start()} on the distributor.</li>
- * <li>Obtain the {@link SurfaceTexture} used by the distributor and hook it up
- * to your producer e.g. a Camera instance.</li>
- * <li>Your consumers now start receiving
- * {@link FrameConsumer#onNewFrameAvailable(FrameDistributor)} callbacks for new
- * frames.</li>
- * <li>Each consumer grabs the most current frame from its GL thread by calling
- * {@link #acquireNextFrame(int, float[])}.</li>
- * <li>After accessing the data, the consumer calls {@link #releaseFrame()}.
- * </li>
- * <li>When all processing is complete, call {@link #stop()}.</li>
- * </ol>
- */
-class FrameDistributorImpl implements FrameDistributor, AutoCloseable {
-
- private final DistributionHandler mDistributionHandler;
-
- private final HandlerThread mDistributionThread;
-
- private static class DistributionHandler extends Handler implements OnFrameAvailableListener {
-
- public static final int MSG_SETUP = 1;
- public static final int MSG_RELEASE = 2;
- public static final int MSG_UPDATE_SURFACE = 3;
- public static final int MSG_UPDATE_PREVIEW_BUFFER_SIZE = 4;
-
- private static final int DEFAULT_SURFACE_BUFFER_WIDTH = 1440;
- private static final int DEFAULT_SURFACE_BUFFER_HEIGHT = 1080;
-
- private final FrameDistributorImpl mDistributor;
-
- private final AtomicBoolean mNewFrame = new AtomicBoolean(false);
-
- final ConditionVariable mCommandDoneCondition = new ConditionVariable(true);
-
- private final Lock mSurfaceTextureAccessLock = new ReentrantLock();
-
- private final List<FrameConsumer> mConsumers;
-
- private SurfaceTexture mSurfaceTexture;
-
- private long mTimestamp;
-
- private int mTexture;
-
- private RenderTarget mServerTarget;
-
- private boolean mIsSetup = false;
-
- public DistributionHandler(FrameDistributorImpl distributor, Looper looper,
- List<FrameConsumer> consumers) {
- super(looper);
- mDistributor = distributor;
- mConsumers = consumers;
- }
-
- @Override
- public void handleMessage(Message message) {
- try {
- switch (message.what) {
- case MSG_SETUP:
- setup();
- break;
- case MSG_UPDATE_SURFACE:
- updateSurfaceTexture();
- break;
- case MSG_RELEASE:
- release();
- break;
- case MSG_UPDATE_PREVIEW_BUFFER_SIZE:
- updatePreviewBufferSize((Size) message.obj);
- break;
- default:
- throw new IllegalStateException("Unknown message: " + message + "!");
- }
- } finally {
- mCommandDoneCondition.open();
- }
- }
-
- private synchronized void setup() {
- if (!mIsSetup) {
- mServerTarget = RenderTarget.newTarget(1, 1);
- mServerTarget.focus();
- mSurfaceTexture = createSurfaceTexture();
- informListenersOfStart();
- mIsSetup = true;
- }
- }
-
- private synchronized void release() {
- if (mIsSetup) {
- // Notify listeners
- informListenersOfStop();
-
- // Release our resources
- mServerTarget.close();
- mServerTarget = null;
- mSurfaceTexture.release();
- mSurfaceTexture = null;
- GLToolbox.deleteTexture(mTexture);
-
- // It is VERY important we unfocus the current EGL context, as
- // the SurfaceTextures
- // will not properly detach if this is not done.
- RenderTarget.focusNone();
-
- // Update internal state
- mNewFrame.set(false);
- mIsSetup = false;
- }
- }
-
- private void updateSurfaceTexture() {
- if (mIsSetup) {
- mSurfaceTextureAccessLock.lock();
- mSurfaceTexture.attachToGLContext(mTexture);
- mSurfaceTexture.updateTexImage();
- mSurfaceTexture.detachFromGLContext();
- mSurfaceTextureAccessLock.unlock();
- mTimestamp = mSurfaceTexture.getTimestamp();
- informListenersOfNewFrame(mTimestamp);
- }
- }
-
- private void updatePreviewBufferSize(Size size) {
- if (size != null && mIsSetup) {
- mSurfaceTexture.setDefaultBufferSize(size.getWidth(), size.getHeight());
- }
- }
-
- public void postMessageType(int kind) {
- mCommandDoneCondition.close();
- sendMessage(Message.obtain(this, kind));
- }
-
- public void postMessageType(int kind, Object params) {
- mCommandDoneCondition.close();
- sendMessage(Message.obtain(this, kind, params));
- }
-
- private void informListenersOfStart() {
- synchronized (mConsumers) {
- for (FrameConsumer consumer : mConsumers) {
- consumer.onStart();
- }
- }
- }
-
- private void informListenersOfNewFrame(long timestamp) {
- synchronized (mConsumers) {
- for (FrameConsumer consumer : mConsumers) {
- consumer.onNewFrameAvailable(mDistributor, timestamp);
- }
- }
- }
-
- private void informListenersOfStop() {
- synchronized (mConsumers) {
- for (FrameConsumer consumer : mConsumers) {
- consumer.onStop();
- }
- }
- }
-
- public long acquireNextFrame(int textureName, float[] transform) {
- if (transform == null || transform.length != 16) {
- throw new
- IllegalArgumentException("acquireNextFrame: invalid transform array.");
- }
- mSurfaceTextureAccessLock.lock();
- mSurfaceTexture.attachToGLContext(textureName);
- mSurfaceTexture.getTransformMatrix(transform);
-
- return mTimestamp;
- }
-
- public void releaseFrame() {
- mSurfaceTexture.detachFromGLContext();
- mSurfaceTextureAccessLock.unlock();
- }
-
- public synchronized SurfaceTexture getSurfaceTexture() {
- return mSurfaceTexture;
- }
-
- public synchronized RenderTarget getRenderTarget() {
- return mServerTarget;
- }
-
- @Override
- public void onFrameAvailable(SurfaceTexture surfaceTexture) {
- postMessageType(MSG_UPDATE_SURFACE);
- }
-
- private SurfaceTexture createSurfaceTexture() {
- mTexture = GLToolbox.generateTexture();
- SurfaceTexture surfaceTexture = new SurfaceTexture(mTexture);
- surfaceTexture.setDefaultBufferSize(DEFAULT_SURFACE_BUFFER_WIDTH,
- DEFAULT_SURFACE_BUFFER_HEIGHT);
- surfaceTexture.setOnFrameAvailableListener(this);
- surfaceTexture.detachFromGLContext();
- return surfaceTexture;
- }
-
- }
-
- /**
- * Creates a new distributor with the specified consumers.
- *
- * @param consumers list of consumers that will process incoming frames.
- */
- public FrameDistributorImpl(List<FrameConsumer> consumers) {
- mDistributionThread = new HandlerThread("FrameDistributor");
- mDistributionThread.start();
- mDistributionHandler = new DistributionHandler(this, mDistributionThread.getLooper(),
- consumers);
- }
-
- /**
- * Start processing frames and sending them to consumers.
- */
- public void start() {
- mDistributionHandler.postMessageType(DistributionHandler.MSG_SETUP);
- }
-
- /**
- * Stop processing frames and release any resources required for doing so.
- */
- public void stop() {
- mDistributionHandler.postMessageType(DistributionHandler.MSG_RELEASE);
- }
-
- /**
- * Wait until the current start/stop command has finished executing.
- * <p>
- * Use this command if you need to make sure that the distributor has fully
- * started or stopped.
- */
- public void waitForCommand() {
- mDistributionHandler.mCommandDoneCondition.block();
- }
-
- /**
- * Close the current distributor and release its resources.
- * <p>
- * You must not use the distributor after calling this method.
- */
- @Override
- public void close() {
- stop();
- mDistributionThread.quitSafely();
- }
-
- @Override
- public long acquireNextFrame(int textureName, float[] transform) {
- return mDistributionHandler.acquireNextFrame(textureName, transform);
- }
-
- @Override
- public void releaseFrame() {
- mDistributionHandler.releaseFrame();
- }
-
- /**
- * Get the {@link SurfaceTexture} whose frames will be distributed.
- * <p>
- * You must call this after distribution has started with a call to
- * {@link #start()}.
- *
- * @return the input SurfaceTexture or null, if none is yet available.
- */
- public SurfaceTexture getInputSurfaceTexture() {
- return mDistributionHandler.getSurfaceTexture();
- }
-
- /**
- * Get the {@link RenderTarget} that the distributor uses for GL operations.
- * <p>
- * You should rarely need to use this method. It is used exclusively by
- * consumers that reuse the FrameDistributor's EGL context, and must be
- * handled with great care.
- *
- * @return the RenderTarget used by the FrameDistributor.
- */
- @Override
- public RenderTarget getRenderTarget() {
- return mDistributionHandler.getRenderTarget();
- }
-
- /**
- * Update the default buffer size of the input {@link SurfaceTexture}.
- *
- * @param width the new value of width of the preview buffer.
- * @param height the new value of height of the preview buffer.
- */
- public void updatePreviewBufferSize(int width, int height) {
- mDistributionHandler.postMessageType(DistributionHandler.MSG_UPDATE_PREVIEW_BUFFER_SIZE,
- new Size(width, height));
- }
-}
diff --git a/src/com/android/camera/gl/FrameDistributorWrapper.java b/src/com/android/camera/gl/FrameDistributorWrapper.java
deleted file mode 100644
index 687d16a48..000000000
--- a/src/com/android/camera/gl/FrameDistributorWrapper.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.camera.gl;
-
-import android.graphics.SurfaceTexture;
-import android.os.Looper;
-
-import com.android.camera.gl.FrameDistributor.FrameConsumer;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * A wrapper class for {@link FrameDistributorImpl} that provides thread safe
- * access to the frame distributor.
- */
-public class FrameDistributorWrapper implements AutoCloseable {
- private final AtomicReference<FrameDistributorImpl> mFrameDistributor =
- new AtomicReference<FrameDistributorImpl>();
-
- /**
- * Start processing frames and sending them to consumers.
- * <p/>
- * Can only be called from the main thread.
- *
- * @param consumers list of consumers that will process incoming frames.
- */
- public void start(List<FrameConsumer> consumers) {
- assertOnMainThread();
- if (mFrameDistributor.get() != null) {
- throw new IllegalStateException("FrameDistributorWrapper: start called before close.");
- } else {
- FrameDistributorImpl distributor = new FrameDistributorImpl(consumers);
- mFrameDistributor.set(distributor);
- distributor.start();
- distributor.waitForCommand();
- }
- }
-
- /**
- * Get the {@link SurfaceTexture} whose frames will be distributed.
- * <p>
- * You must call this after distribution has started with a call to
- * {@link #start(List)}.
- *
- * @return the input SurfaceTexture or null, if none is yet available.
- */
- public SurfaceTexture getInputSurfaceTexture() {
- FrameDistributorImpl distributor = mFrameDistributor.get();
- return (distributor != null) ? distributor.getInputSurfaceTexture() : null;
- }
-
- /**
- * Update the default buffer size of the input {@link SurfaceTexture}.
- *
- * @param width the new value of width of the preview buffer.
- * @param height the new value of height of the preview buffer.
- */
- public void updatePreviewBufferSize(int width, int height) {
- FrameDistributorImpl distributor = mFrameDistributor.get();
- if (distributor != null) {
- distributor.updatePreviewBufferSize(width, height);
- }
- }
-
- /**
- * Close the current distributor and release its resources.
- * <p>
- * Can only be called from the main thread.
- */
- @Override
- public void close() {
- assertOnMainThread();
- if (mFrameDistributor.get() != null) {
- mFrameDistributor.get().close();
- mFrameDistributor.set(null);
- } else {
- throw new IllegalStateException("FrameDistributorWrapper: close called before start.");
- }
- }
-
- private static void assertOnMainThread() {
- if (Looper.getMainLooper().getThread() != Thread.currentThread()) {
- throw new IllegalStateException("Must be called on the main thread.");
- }
- }
-}
diff --git a/src/com/android/camera/gl/GLToolbox.java b/src/com/android/camera/gl/GLToolbox.java
deleted file mode 100644
index 581f811ea..000000000
--- a/src/com/android/camera/gl/GLToolbox.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.camera.gl;
-
-import android.opengl.GLES20;
-import android.os.Looper;
-
-/**
- * Collection of utility functions used for GL operations.
- */
-public class GLToolbox {
-
- public static int textureNone() {
- return 0;
- }
-
- public static boolean isTexture(int texId) {
- return GLES20.glIsTexture(texId);
- }
-
- public static void deleteTexture(int texId) {
- int[] textures = new int[] {
- texId };
- assertNonUiThread("glDeleteTextures");
- GLES20.glDeleteTextures(1, textures, 0);
- checkGlError("glDeleteTextures");
- }
-
- public static void deleteFbo(int fboId) {
- int[] fbos = new int[] {
- fboId };
- assertNonUiThread("glDeleteFramebuffers");
- GLES20.glDeleteFramebuffers(1, fbos, 0);
- checkGlError("glDeleteFramebuffers");
- }
-
- public static int generateTexture() {
- int[] textures = new int[1];
- GLES20.glGenTextures(1, textures, 0);
- checkGlError("glGenTextures");
- return textures[0];
- }
-
- public static int generateFbo() {
- int[] fbos = new int[1];
- GLES20.glGenFramebuffers(1, fbos, 0);
- checkGlError("glGenFramebuffers");
- return fbos[0];
- }
-
- public static int attachedTexture(int fboId) {
- int[] params = new int[1];
- GLES20.glGetFramebufferAttachmentParameteriv(
- GLES20.GL_FRAMEBUFFER,
- GLES20.GL_COLOR_ATTACHMENT0,
- GLES20.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
- params, 0);
- checkGlError("glGetFramebufferAttachmentParameteriv");
- return params[0];
- }
-
- public static void attachTextureToFbo(int texId, int fboId) {
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
- GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
- GLES20.GL_COLOR_ATTACHMENT0,
- GLES20.GL_TEXTURE_2D,
- texId,
- 0);
- checkGlError("glFramebufferTexture2D");
- }
-
- public static void setDefaultTexParams() {
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
- GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
- checkGlError("glTexParameteri");
- }
-
- public static void checkGlError(String operation) {
- int error;
- while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
- throw new RuntimeException("GL Operation '" + operation + "' caused error "
- + Integer.toHexString(error) + "!");
- }
- }
-
- /**
- * Make sure we are not operating in the UI thread. It is often tricky to
- * track down bugs that happen when issuing GL commands in the UI thread.
- * This is especially true when releasing GL resources. Often this will
- * cause errors much later on. Therefore we make sure we do not do these
- * dangerous operations on the UI thread.
- */
- private static void assertNonUiThread(String operation) {
- if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
- throw new RuntimeException("Attempting to perform GL operation '" + operation
- + "' on UI thread!");
- }
- }
-}
diff --git a/src/com/android/camera/gl/RenderTarget.java b/src/com/android/camera/gl/RenderTarget.java
deleted file mode 100644
index d126fa1df..000000000
--- a/src/com/android/camera/gl/RenderTarget.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.camera.gl;
-
-import android.graphics.SurfaceTexture;
-import android.opengl.GLES20;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-
-/**
- * Encapsulates a target into which a GL operation can draw into.
- * <p>
- * A RenderTarget can take on many forms, such as an offscreen buffer, an FBO
- * attached to a texture, or a SurfaceTexture target. Regardless of output type,
- * once a RenderTarget is focused, any issued OpenGL draw commands will be
- * rasterized into that target.
- * <p>
- * Note, that this class is a simplified version of the MFF's
- * {@code RenderTarget} class.
- */
-// TODO: Add a test for the class.
-public class RenderTarget implements AutoCloseable {
-
- private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
- private static final int EGL_OPENGL_ES2_BIT = 4;
-
- /** The cached EGLConfig instance. */
- private static EGLConfig mEglConfig = null;
-
- /** The display for which the EGLConfig was chosen. We expect only one. */
- private static EGLDisplay mConfiguredDisplay;
-
- private final EGL10 mEgl;
- private final EGLDisplay mDisplay;
- private final EGLContext mContext;
- private final EGLSurface mSurface;
- private final int mFbo;
-
- private final boolean mOwnsContext;
- private final boolean mOwnsSurface;
-
- private static int sRedSize = 8;
- private static int sGreenSize = 8;
- private static int sBlueSize = 8;
- private static int sAlphaSize = 8;
- private static int sDepthSize = 0;
- private static int sStencilSize = 0;
-
- public static RenderTarget newTarget(int width, int height) {
- EGL10 egl = (EGL10) EGLContext.getEGL();
- EGLDisplay eglDisplay = createDefaultDisplay(egl);
- EGLConfig eglConfig = chooseEglConfig(egl, eglDisplay);
- EGLContext eglContext = createContext(egl, eglDisplay, eglConfig);
- EGLSurface eglSurface = createSurface(egl, eglDisplay, width, height);
- RenderTarget result = new RenderTarget(eglDisplay, eglContext, eglSurface, 0, true, true);
- return result;
- }
-
- public RenderTarget forTexture(int texName, int texTarget, int width, int height) {
- // NOTE: We do not need to lookup any previous bindings of this texture
- // to an FBO, as
- // multiple FBOs to a single texture is valid.
- int fbo = GLToolbox.generateFbo();
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo);
- GLToolbox.checkGlError("glBindFramebuffer");
- GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,
- GLES20.GL_COLOR_ATTACHMENT0,
- texName,
- texTarget,
- 0);
- GLToolbox.checkGlError("glFramebufferTexture2D");
- return new RenderTarget(mDisplay, mContext, surface(), fbo, false, false);
- }
-
- public RenderTarget forSurfaceHolder(SurfaceHolder surfaceHolder) {
- EGLConfig eglConfig = chooseEglConfig(mEgl, mDisplay);
- EGLSurface eglSurf = mEgl.eglCreateWindowSurface(mDisplay, eglConfig, surfaceHolder, null);
- checkEglError(mEgl, "eglCreateWindowSurface");
- checkSurface(mEgl, eglSurf);
- RenderTarget result = new RenderTarget(mDisplay, mContext, eglSurf, 0, false, true);
- return result;
- }
-
- public RenderTarget forSurfaceTexture(SurfaceTexture surfaceTexture) {
- EGLConfig eglConfig = chooseEglConfig(mEgl, mDisplay);
- EGLSurface eglSurf = mEgl.eglCreateWindowSurface(mDisplay, eglConfig, surfaceTexture, null);
- checkEglError(mEgl, "eglCreateWindowSurface");
- checkSurface(mEgl, eglSurf);
- RenderTarget result = new RenderTarget(mDisplay, mContext, eglSurf, 0, false, true);
- return result;
- }
-
- public RenderTarget forSurface(Surface surface) {
- EGLConfig eglConfig = chooseEglConfig(mEgl, mDisplay);
- EGLSurface eglSurf = mEgl.eglCreateWindowSurface(mDisplay, eglConfig, surface, null);
- checkEglError(mEgl, "eglCreateWindowSurface");
- checkSurface(mEgl, eglSurf);
- RenderTarget result = new RenderTarget(mDisplay, mContext, eglSurf, 0, false, true);
- return result;
- }
-
- public static void setEGLConfigChooser(int redSize, int greenSize, int blueSize, int alphaSize,
- int depthSize, int stencilSize) {
- sRedSize = redSize;
- sGreenSize = greenSize;
- sBlueSize = blueSize;
- sAlphaSize = alphaSize;
- sDepthSize = depthSize;
- sStencilSize = stencilSize;
- }
-
- public void focus() {
- mEgl.eglMakeCurrent(mDisplay, surface(), surface(), mContext);
- if (getCurrentFbo() != mFbo) {
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFbo);
- GLToolbox.checkGlError("glBindFramebuffer");
- }
- }
-
- public static void focusNone() {
- EGL10 egl = (EGL10) EGLContext.getEGL();
- egl.eglMakeCurrent(egl.eglGetCurrentDisplay(),
- EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_CONTEXT);
- checkEglError(egl, "eglMakeCurrent");
- }
-
- public void swapBuffers() {
- mEgl.eglSwapBuffers(mDisplay, surface());
- }
-
- public EGLContext getContext() {
- return mContext;
- }
-
- @Override
- public void close() {
- if (mOwnsContext) {
- mEgl.eglDestroyContext(mDisplay, mContext);
- }
- if (mOwnsSurface) {
- mEgl.eglDestroySurface(mDisplay, mSurface);
- }
- if (mFbo != 0) {
- GLToolbox.deleteFbo(mFbo);
- }
- }
-
- @Override
- public String toString() {
- return "RenderTarget(" + mDisplay + ", " + mContext + ", " + mSurface + ", " + mFbo + ")";
- }
-
- private static EGLConfig chooseEglConfig(EGL10 egl, EGLDisplay display) {
- if (mEglConfig == null || !display.equals(mConfiguredDisplay)) {
- int[] configsCount = new int[1];
- EGLConfig[] configs = new EGLConfig[1];
- int[] configSpec = getDesiredConfig();
- if (!egl.eglChooseConfig(display, configSpec, configs, 1, configsCount)) {
- throw new IllegalArgumentException("EGL Error: eglChooseConfig failed " +
- getEGLErrorString(egl));
- } else if (configsCount[0] > 0) {
- mEglConfig = configs[0];
- mConfiguredDisplay = display;
- }
- }
- return mEglConfig;
- }
-
- private static int[] getDesiredConfig() {
- return new int[] {
- EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL10.EGL_RED_SIZE, sRedSize,
- EGL10.EGL_GREEN_SIZE, sGreenSize,
- EGL10.EGL_BLUE_SIZE, sBlueSize,
- EGL10.EGL_ALPHA_SIZE, sAlphaSize,
- EGL10.EGL_DEPTH_SIZE, sDepthSize,
- EGL10.EGL_STENCIL_SIZE, sStencilSize,
- EGL10.EGL_NONE
- };
- }
-
- private RenderTarget(EGLDisplay display, EGLContext context, EGLSurface surface, int fbo,
- boolean ownsContext, boolean ownsSurface) {
- mEgl = (EGL10) EGLContext.getEGL();
- mDisplay = display;
- mContext = context;
- mSurface = surface;
- mFbo = fbo;
- mOwnsContext = ownsContext;
- mOwnsSurface = ownsSurface;
- }
-
- private EGLSurface surface() {
- return mSurface;
- }
-
- private static void initEgl(EGL10 egl, EGLDisplay display) {
- int[] version = new int[2];
- if (!egl.eglInitialize(display, version)) {
- throw new RuntimeException("EGL Error: eglInitialize failed " + getEGLErrorString(egl));
- }
- }
-
- private static EGLDisplay createDefaultDisplay(EGL10 egl) {
- EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
- checkDisplay(egl, display);
- initEgl(egl, display);
- return display;
- }
-
- private static EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
- int[] attrib_list = {
- EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
- EGLContext ctxt = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, attrib_list);
- checkContext(egl, ctxt);
- return ctxt;
- }
-
- private static EGLSurface createSurface(EGL10 egl, EGLDisplay display, int width, int height) {
- EGLConfig eglConfig = chooseEglConfig(egl, display);
- int[] attribs = {
- EGL10.EGL_WIDTH, width, EGL10.EGL_HEIGHT, height, EGL10.EGL_NONE };
- return egl.eglCreatePbufferSurface(display, eglConfig, attribs);
- }
-
- private static int getCurrentFbo() {
- int[] result = new int[1];
- GLES20.glGetIntegerv(GLES20.GL_FRAMEBUFFER_BINDING, result, 0);
- return result[0];
- }
-
- private static void checkDisplay(EGL10 egl, EGLDisplay display) {
- if (display == EGL10.EGL_NO_DISPLAY) {
- throw new RuntimeException("EGL Error: Bad display: " + getEGLErrorString(egl));
- }
- }
-
- private static void checkContext(EGL10 egl, EGLContext context) {
- if (context == EGL10.EGL_NO_CONTEXT) {
- throw new RuntimeException("EGL Error: Bad context: " + getEGLErrorString(egl));
- }
- }
-
- private static void checkSurface(EGL10 egl, EGLSurface surface) {
- if (surface == EGL10.EGL_NO_SURFACE) {
- throw new RuntimeException("EGL Error: Bad surface: " + getEGLErrorString(egl));
- }
- }
-
- private static void checkEglError(EGL10 egl, String command) {
- int error = egl.eglGetError();
- if (error != EGL10.EGL_SUCCESS) {
- throw new RuntimeException("Error executing " + command + "! EGL error = 0x"
- + Integer.toHexString(error));
- }
- }
-
- private static String getEGLErrorString(EGL10 egl) {
- int eglError = egl.eglGetError();
- return "EGL Error 0x" + Integer.toHexString(eglError);
- }
-
-}
diff --git a/src/com/android/camera/gl/SurfaceTextureConsumer.java b/src/com/android/camera/gl/SurfaceTextureConsumer.java
deleted file mode 100644
index 096f5e066..000000000
--- a/src/com/android/camera/gl/SurfaceTextureConsumer.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.camera.gl;
-
-import android.graphics.SurfaceTexture;
-
-import com.android.camera.debug.Log;
-import com.android.camera.debug.Log.Tag;
-import com.android.camera.gl.FrameDistributor;
-import com.android.camera.gl.FrameDistributor.FrameConsumer;
-
-/**
- * Consumes frames from a {@link FrameDistributor} and passes them into a
- * SurfaceTexture.
- */
-// TODO: Document this class a bit more and add a test for this class.
-public class SurfaceTextureConsumer implements FrameConsumer {
- private static final Tag TAG = new Tag("SurfaceTexConsumer");
-
- private SurfaceTexture mSurfaceTexture;
- private final float[] mTransform = new float[16];
- private CopyShader mCopyShader;
- private RenderTarget mTarget;
- private int mWidth;
- private int mHeight;
-
- @Override
- public synchronized void onStart() {}
-
- @Override
- public synchronized void onNewFrameAvailable(FrameDistributor frameDistributor,
- long timestampNs) {
- if (mSurfaceTexture == null) {
- Log.d(TAG, "Ignoring frame without a SurfaceTexture!");
- return;
- }
- if (mTarget == null) {
- mTarget = frameDistributor.getRenderTarget().forSurfaceTexture(mSurfaceTexture);
- }
- renderFrameToTarget(frameDistributor);
- }
-
- @Override
- public synchronized void onStop() {
- releaseResources();
- }
-
- public synchronized SurfaceTexture getSurfaceTexture() {
- return mSurfaceTexture;
- }
-
- public synchronized void setSurfaceTexture(SurfaceTexture surfaceTexture,
- int width,
- int height) {
- mSurfaceTexture = surfaceTexture;
- mWidth = width;
- mHeight = height;
- releaseResources();
- }
-
- public synchronized void setSize(int width, int height) {
- mWidth = width;
- mHeight = height;
- }
-
- public synchronized void setDefaultBufferSize(int width, int height) {
- if (mSurfaceTexture != null) {
- mSurfaceTexture.setDefaultBufferSize(width, height);
- }
- }
-
- public synchronized int getWidth() {
- return mWidth;
- }
-
- public synchronized int getHeight() {
- return mHeight;
- }
-
- private void releaseResources() {
- if (mTarget != null) {
- mTarget.close();
- mTarget = null;
- }
- if (mCopyShader != null) {
- mCopyShader.release();
- mCopyShader = null;
- }
- }
-
- private void renderFrameToTarget(FrameDistributor frameDistributor) {
- CopyShader shader = getCopyShader();
- int texture = GLToolbox.generateTexture();
- frameDistributor.acquireNextFrame(texture, mTransform);
- try {
- shader.setTransform(mTransform);
- shader.renderTextureToTarget(texture, mTarget, mWidth, mHeight);
- } finally {
- frameDistributor.releaseFrame();
- GLToolbox.deleteTexture(texture);
- }
- mTarget.swapBuffers();
- }
-
- private CopyShader getCopyShader() {
- if (mCopyShader == null) {
- mCopyShader = CopyShader.compileNewExternalShader();
- }
- return mCopyShader;
- }
-
-}
diff --git a/src/com/android/camera/one/AbstractOneCamera.java b/src/com/android/camera/one/AbstractOneCamera.java
index b9514b96f..b059d8034 100644
--- a/src/com/android/camera/one/AbstractOneCamera.java
+++ b/src/com/android/camera/one/AbstractOneCamera.java
@@ -122,14 +122,4 @@ public abstract class AbstractOneCamera implements OneCamera {
public void setZoom(float zoom) {
// If not implemented, no-op.
}
-
- @Override
- public void startBurst(BurstParameters params, CaptureSession session) {
- throw new UnsupportedOperationException("Not implemented yet.");
- }
-
- @Override
- public void stopBurst() {
- throw new UnsupportedOperationException("Not implemented yet.");
- }
}
diff --git a/src/com/android/camera/one/OneCamera.java b/src/com/android/camera/one/OneCamera.java
index 49fb2c0a9..aa6aab5f9 100644
--- a/src/com/android/camera/one/OneCamera.java
+++ b/src/com/android/camera/one/OneCamera.java
@@ -22,8 +22,6 @@ import android.location.Location;
import android.net.Uri;
import android.view.Surface;
-import com.android.camera.burst.BurstConfiguration;
-import com.android.camera.burst.ResultsAccessor;
import com.android.camera.session.CaptureSession;
import com.android.camera.settings.SettingsManager;
import com.android.camera.util.Size;
@@ -350,29 +348,6 @@ public interface OneCamera {
}
}
- /**
- * The callback to be invoked when results are available.
- */
- public interface BurstResultsCallback {
- void onBurstComplete(ResultsAccessor resultAccessor);
- }
-
- /**
- * Parameters to be given to burst requests.
- */
- public static class BurstParameters extends CaptureParameters {
- /** The title/filename (without suffix) for this capture. */
- public final BurstConfiguration burstConfiguration;
- public final BurstResultsCallback callback;
-
- public BurstParameters(String title, int orientation, Location location,
- File debugDataFolder, BurstConfiguration burstConfiguration,
- BurstResultsCallback callback) {
- super(title, orientation, location, debugDataFolder);
- this.burstConfiguration = burstConfiguration;
- this.callback = callback;
- }
- }
/**
* Meters and triggers auto focus scan with ROI around tap point.
@@ -394,20 +369,6 @@ public interface OneCamera {
public void takePicture(PhotoCaptureParameters params, CaptureSession session);
/**
- * Call this to take a burst.
- *
- * @param params parameters for taking burst.
- * @param session the capture session for this burst.
- */
-
- public void startBurst(BurstParameters params, CaptureSession session);
-
- /**
- * Call this to stop taking burst.
- */
- public void stopBurst();
-
- /**
* Sets or replaces a listener that is called whenever the focus state of
* the camera changes.
*/
@@ -427,7 +388,7 @@ public interface OneCamera {
/**
* Starts a preview stream and renders it to the given surface.
- *
+ *
* @param Surface the surface on which to render preview frames
* @param listener
*/
diff --git a/src/com/android/camera/one/OneCameraManager.java b/src/com/android/camera/one/OneCameraManager.java
index 405b581d5..36953b23e 100644
--- a/src/com/android/camera/one/OneCameraManager.java
+++ b/src/com/android/camera/one/OneCameraManager.java
@@ -21,6 +21,7 @@ import android.util.DisplayMetrics;
import com.android.camera.CameraActivity;
import com.android.camera.async.MainThread;
+import com.android.camera.burst.BurstFacade;
import com.android.camera.debug.Log.Tag;
import com.android.camera.one.OneCamera.Facing;
import com.android.camera.one.OneCamera.OpenCallback;
@@ -53,10 +54,12 @@ public abstract class OneCameraManager {
* @param mainThread Main thread executor
* @param imageRotationCalculator Image rotation calculator required for
* Camera Factory initialization
+ * @param burstController the burst facade to configure
*/
public abstract void open(Facing facing, boolean enableHdr, Size captureSize,
OpenCallback callback, Handler handler,
- MainThread mainThread, final ImageRotationCalculator imageRotationCalculator);
+ MainThread mainThread, final ImageRotationCalculator imageRotationCalculator,
+ BurstFacade burstController);
// TODO: Move this to OneCameraCharacteristics class.
/**
diff --git a/src/com/android/camera/one/v1/OneCameraManagerImpl.java b/src/com/android/camera/one/v1/OneCameraManagerImpl.java
index e2fbc59f9..ac6073267 100644
--- a/src/com/android/camera/one/v1/OneCameraManagerImpl.java
+++ b/src/com/android/camera/one/v1/OneCameraManagerImpl.java
@@ -21,6 +21,7 @@ import android.os.Handler;
import com.android.camera.CameraActivity;
import com.android.camera.async.MainThread;
+import com.android.camera.burst.BurstFacade;
import com.android.camera.debug.Log;
import com.android.camera.one.OneCamera.Facing;
import com.android.camera.one.OneCamera.OpenCallback;
@@ -94,7 +95,7 @@ public class OneCameraManagerImpl extends OneCameraManager {
public void open(Facing facing, boolean enableHdr, Size pictureSize,
OpenCallback callback, Handler handler,
MainThread mainThread,
- ImageRotationCalculator imageRotationCalculator) {
+ ImageRotationCalculator imageRotationCalculator, BurstFacade burstController) {
throw new RuntimeException("Not implemented yet.");
}
diff --git a/src/com/android/camera/one/v2/ImageCaptureManager.java b/src/com/android/camera/one/v2/ImageCaptureManager.java
index 09b3e180a..38b968e21 100644
--- a/src/com/android/camera/one/v2/ImageCaptureManager.java
+++ b/src/com/android/camera/one/v2/ImageCaptureManager.java
@@ -29,7 +29,6 @@ import android.os.Handler;
import android.os.SystemClock;
import android.util.Pair;
-import com.android.camera.burst.BurstConfiguration.EvictionHandler;
import com.android.camera.debug.Log;
import com.android.camera.debug.Log.Tag;
import com.android.camera.util.ConcurrentSharedRingBuffer;
@@ -45,9 +44,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
/**
* Implements {@link android.media.ImageReader.OnImageAvailableListener} and
@@ -233,35 +230,6 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
}
}
- /**
- * A stub implementation of eviction handler that returns -1 as timestamp of
- * the frame to be dropped.
- * <p/>
- * This forces the ring buffer to use its default eviction strategy.
- */
- private static class DefaultEvictionHandler implements EvictionHandler {
- @Override
- public long selectFrameToDrop() {
- return -1;
- }
-
- @Override
- public void onFrameCaptureResultAvailable(long timestamp,
- TotalCaptureResult captureResult) {
- }
-
- @Override
- public void onFrameInserted(long timestamp) {
- }
-
- @Override
- public void onFrameDropped(long timestamp) {
- }
- }
-
- private static final EvictionHandler DEFAULT_EVICTION_HANDLER =
- new DefaultEvictionHandler();
-
private static final Tag TAG = new Tag("ZSLImageListener");
/**
@@ -319,10 +287,6 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
*/
private final Executor mImageCaptureListenerExecutor;
- private final AtomicReference<EvictionHandler> mEvictionHandler =
- new AtomicReference<EvictionHandler>(DEFAULT_EVICTION_HANDLER);
- private final AtomicBoolean mIsCapturingBurst = new AtomicBoolean(false);
-
/**
* The set of constraints which must be satisfied for a newly acquired image
* to be captured and sent to {@link #mPendingImageCaptureCallback}. null if
@@ -353,12 +317,6 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
mMetadataChangeListeners = new ConcurrentHashMap<Key<?>, Set<MetadataChangeListener>>();
/**
- * The lock for guarding installation and uninstallation of burst eviction
- * handler.
- */
- private final Object mBurstLock = new Object();
-
- /**
* @param maxImages the maximum number of images provided by the
* {@link ImageReader}. This must be greater than 2.
* @param listenerHandler the handler on which to invoke listeners. Note
@@ -440,7 +398,7 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
final TotalCaptureResult result) {
final long timestamp = result.get(TotalCaptureResult.SENSOR_TIMESTAMP);
- updateMetadataChangeListeners(result);
+ updateMetadataChangeListeners(result);
// Detect camera thread stall.
long now = SystemClock.uptimeMillis();
@@ -474,7 +432,7 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
final Object oldValue = (oldEntry != null) ? oldEntry.second : null;
boolean newerValueAlreadyExists = oldEntry != null
- && frameNumber < oldEntry.first;
+ && frameNumber < oldEntry.first;
if (newerValueAlreadyExists) {
continue;
}
@@ -489,12 +447,12 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
}
for (final MetadataChangeListener listener :
- mMetadataChangeListeners.get(key)) {
+ mMetadataChangeListeners.get(key)) {
mListenerHandler.post(new Runnable() {
@Override
public void run() {
listener.onImageMetadataChange(key, oldValue, newValue,
- result);
+ result);
}
});
}
@@ -502,18 +460,6 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
}
private boolean doMetaDataSwap(final TotalCaptureResult newMetadata, final long timestamp) {
- mEvictionHandler.get().onFrameCaptureResultAvailable(timestamp, newMetadata);
-
- if (mIsCapturingBurst.get()) {
- // In case of burst we do not swap metadata in the ring buffer. This
- // is to avoid the following scenario. If image for frame with
- // timestamp A arrives first and the eviction handler decides to
- // evict timestamp A. But when metadata for timestamp A arrives
- // the eviction handler chooses to keep timestamp A. In this case
- // the image for A will never be available.
- return false;
- }
-
return mCapturedImageBuffer.swapLeast(timestamp,
new SwapTask<CapturedImage>() {
@Override
@@ -547,7 +493,6 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
new SwapTask<CapturedImage>() {
@Override
public CapturedImage create() {
- mEvictionHandler.get().onFrameInserted(newImage.getTimestamp());
CapturedImage image = new CapturedImage();
image.addImage(newImage);
return image;
@@ -555,9 +500,6 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
@Override
public CapturedImage swap(CapturedImage oldElement) {
- mEvictionHandler.get().onFrameInserted(newImage.getTimestamp());
- long timestamp = oldElement.tryGetTimestamp();
- mEvictionHandler.get().onFrameDropped(timestamp);
oldElement.reset();
CapturedImage image = new CapturedImage();
image.addImage(newImage);
@@ -566,17 +508,12 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
@Override
public void update(CapturedImage existingElement) {
- mEvictionHandler.get().onFrameInserted(newImage.getTimestamp());
existingElement.addImage(newImage);
}
@Override
public long getSwapKey() {
- final long toDropTimestamp = mEvictionHandler.get().selectFrameToDrop();
- if (toDropTimestamp > 0) {
- mCapturedImageBuffer.releaseIfPinned(toDropTimestamp);
- }
- return toDropTimestamp;
+ return -1;
}
});
}
@@ -605,11 +542,6 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
if (DEBUG_PRINT_OPEN_IMAGE_COUNT) {
Log.v(TAG, "Closed an image. Number of open images = " + numOpenImages);
}
- } else {
- if (mIsCapturingBurst.get()) {
- // In case of burst we pin every image.
- mCapturedImageBuffer.tryPin(timestamp);
- }
}
tryExecutePendingCaptureRequest(timestamp);
@@ -808,57 +740,6 @@ public class ImageCaptureManager extends CameraCaptureSession.CaptureCallback im
}
/**
- * Sets a new burst eviction handler for the internal buffer.
- * <p/>
- * Also clears the buffer. If there was an old burst eviction handler
- * already installed this method will throw an exception.
- *
- * @param evictionHandler the handler to install on the internal image
- * buffer.
- */
- public void setBurstEvictionHandler(EvictionHandler evictionHandler) {
- if (evictionHandler == null) {
- throw new IllegalArgumentException("setBurstEvictionHandler: evictionHandler is null.");
- }
- synchronized (mBurstLock) {
- if (mIsCapturingBurst.compareAndSet(false, true)) {
- if (!mEvictionHandler.compareAndSet(DEFAULT_EVICTION_HANDLER,
- evictionHandler)) {
- throw new IllegalStateException(
- "Trying to set eviction handler before restoring the original.");
- } else {
- clearCapturedImageBuffer(0);
- }
- } else {
- throw new IllegalStateException("Trying to start burst when it was already running.");
- }
- }
- }
-
- /**
- * Removes the burst eviction handler from the buffer.
- */
- public void resetEvictionHandler() {
- synchronized (mBurstLock) {
- mEvictionHandler.set(DEFAULT_EVICTION_HANDLER);
- }
- }
-
- /**
- * Clears the underlying buffer and reset the eviction handler.
- */
- public void resetCaptureState() {
- synchronized (mBurstLock) {
- if (mIsCapturingBurst.compareAndSet(true, false)) {
- // By default the image buffer has 1 slot that is reserved for
- // unpinned elements.
- clearCapturedImageBuffer(1);
- mEvictionHandler.set(DEFAULT_EVICTION_HANDLER);
- }
- }
- }
-
- /**
* Clear the buffer and reserves <code>unpinnedReservedSlots</code> in the buffer.
*
* @param unpinnedReservedSlots the number of unpinned slots that are never
diff --git a/src/com/android/camera/one/v2/OneCameraFactory.java b/src/com/android/camera/one/v2/OneCameraFactory.java
index e7b57e460..1d72dffca 100644
--- a/src/com/android/camera/one/v2/OneCameraFactory.java
+++ b/src/com/android/camera/one/v2/OneCameraFactory.java
@@ -18,6 +18,7 @@ package com.android.camera.one.v2;
import com.android.camera.async.MainThread;
import com.android.camera.async.Observable;
+import com.android.camera.burst.BurstFacade;
import com.android.camera.one.OneCamera;
import com.android.camera.one.OneCameraCharacteristics;
import com.android.camera.one.v2.camera2proxy.CameraDeviceProxy;
@@ -30,5 +31,6 @@ public interface OneCameraFactory {
MainThread mainThread,
Size pictureSize,
ImageSaver.Builder imageSaverBuilder,
- Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting);
+ Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting,
+ BurstFacade burstController);
}
diff --git a/src/com/android/camera/one/v2/OneCameraManagerImpl.java b/src/com/android/camera/one/v2/OneCameraManagerImpl.java
index 6b3754b2b..2879bf763 100644
--- a/src/com/android/camera/one/v2/OneCameraManagerImpl.java
+++ b/src/com/android/camera/one/v2/OneCameraManagerImpl.java
@@ -29,6 +29,7 @@ import com.android.camera.CameraActivity;
import com.android.camera.SoundPlayer;
import com.android.camera.app.AppController;
import com.android.camera.async.MainThread;
+import com.android.camera.burst.BurstFacade;
import com.android.camera.debug.Log;
import com.android.camera.debug.Log.Tag;
import com.android.camera.one.OneCamera;
@@ -97,7 +98,8 @@ public class OneCameraManagerImpl extends OneCameraManager {
public void open(Facing facing, final boolean useHdr, final Size pictureSize,
final OpenCallback openCallback,
Handler handler, final MainThread mainThread,
- final ImageRotationCalculator imageRotationCalculator) {
+ final ImageRotationCalculator imageRotationCalculator,
+ final BurstFacade burstController) {
try {
final String cameraId = getCameraId(facing);
Log.i(TAG, "Opening Camera ID " + cameraId);
@@ -149,7 +151,7 @@ public class OneCameraManagerImpl extends OneCameraManager {
OneCamera oneCamera = OneCameraCreator.create(mAppController, useHdr,
device, characteristics, pictureSize,
mMaxMemoryMB, mDisplayMetrics, mSoundPlayer,
- mainThread, imageRotationCalculator);
+ mainThread, imageRotationCalculator, burstController);
openCallback.onCameraOpened(oneCamera);
} catch (CameraAccessException e) {
Log.d(TAG, "Could not get camera characteristics");
diff --git a/src/com/android/camera/one/v2/OneCameraZslImpl.java b/src/com/android/camera/one/v2/OneCameraZslImpl.java
index 0a57aecde..c326c02ca 100644
--- a/src/com/android/camera/one/v2/OneCameraZslImpl.java
+++ b/src/com/android/camera/one/v2/OneCameraZslImpl.java
@@ -44,8 +44,6 @@ import android.view.Surface;
import com.android.camera.CaptureModuleUtil;
import com.android.camera.app.MediaSaver.OnMediaSavedListener;
-import com.android.camera.burst.BurstImage;
-import com.android.camera.burst.ResultsAccessor;
import com.android.camera.debug.Log;
import com.android.camera.debug.Log.Tag;
import com.android.camera.exif.ExifInterface;
@@ -59,6 +57,7 @@ import com.android.camera.one.Settings3A;
import com.android.camera.one.v2.ImageCaptureManager.ImageCaptureListener;
import com.android.camera.one.v2.ImageCaptureManager.MetadataChangeListener;
import com.android.camera.one.v2.camera2proxy.AndroidImageProxy;
+import com.android.camera.one.v2.camera2proxy.ImageProxy;
import com.android.camera.session.CaptureSession;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.JpegUtilNative;
@@ -196,9 +195,6 @@ public class OneCameraZslImpl extends AbstractOneCamera {
private MediaActionSound mMediaActionSound = new MediaActionSound();
- private final AtomicReference<BurstParameters>
- mBurstParams = new AtomicReference<BurstParameters>();
-
/**
* Ready state (typically displayed by the UI shutter-button) depends on two
* things:<br>
@@ -1098,73 +1094,4 @@ public class OneCameraZslImpl extends AbstractOneCamera {
private Rect cropRegionForZoom(float zoom) {
return AutoFocusHelper.cropRegionForZoom(mCharacteristics, zoom);
}
-
- @Override
- public void startBurst(BurstParameters params, CaptureSession session) {
- if (!mBurstParams.compareAndSet(null, params)) {
- throw new IllegalStateException(
- "Attempting to start burst, when burst is already running.");
- }
- // Overwrite repeating capture request with one specific to capturing Bursts.
- sendRepeatingBurstCaptureRequest();
- mCaptureManager.setBurstEvictionHandler(params.
- burstConfiguration.getEvictionHandler());
- }
-
- private class ImageExtractor implements ResultsAccessor {
- private final int mOrientation;
-
- public ImageExtractor(int orientation) {
- mOrientation = orientation;
- }
-
- @Override
- public Future<BurstImage> extractImage(final long timestampToExtract) {
- final Pair<Image, TotalCaptureResult> pinnedImageData =
- mCaptureManager.tryCapturePinnedImage(timestampToExtract);
- return mImageSaverThreadPool.submit(new Callable<BurstImage>() {
-
- @Override
- public BurstImage call() throws Exception {
- BurstImage burstImage = null;
- Image image = pinnedImageData.first;
- if (image != null) {
- burstImage = new BurstImage();
- int degrees = CameraUtil.getJpegRotation(mOrientation, mCharacteristics);
- Size size = getImageSizeForOrientation(image.getWidth(),
- image.getHeight(),
- degrees);
- burstImage.width = size.getWidth();
- burstImage.height = size.getHeight();
- burstImage.data = acquireJpegBytes(image,
- degrees);
- burstImage.captureResult = pinnedImageData.second;
- burstImage.timestamp = timestampToExtract;
- } else {
- Log.e(TAG, "Failed to extract burst image for timestamp: "
- + timestampToExtract);
- }
- return burstImage;
- }
- });
- }
-
- @Override
- public void close() {
- mCaptureManager.resetCaptureState();
- }
- }
-
- @Override
- public void stopBurst() {
- if (mBurstParams.get() == null) {
- throw new IllegalStateException("Burst parameters should not be null.");
- }
- mCaptureManager.resetEvictionHandler();
- mBurstParams.get().callback.onBurstComplete(
- new ImageExtractor(mBurstParams.get().orientation));
- mBurstParams.set(null);
- // Restore original repeating request associated with taking camera picture.
- sendRepeatingCaptureRequest();
- }
}
diff --git a/src/com/android/camera/one/v2/SimpleOneCameraFactory.java b/src/com/android/camera/one/v2/SimpleOneCameraFactory.java
index 9cf6192ee..f3baa0520 100644
--- a/src/com/android/camera/one/v2/SimpleOneCameraFactory.java
+++ b/src/com/android/camera/one/v2/SimpleOneCameraFactory.java
@@ -29,6 +29,7 @@ import com.android.camera.async.MainThread;
import com.android.camera.async.Observable;
import com.android.camera.async.Observables;
import com.android.camera.async.Updatable;
+import com.android.camera.burst.BurstFacade;
import com.android.camera.debug.Loggers;
import com.android.camera.one.OneCamera;
import com.android.camera.one.OneCameraCharacteristics;
@@ -91,7 +92,8 @@ public class SimpleOneCameraFactory implements OneCameraFactory {
public OneCamera createOneCamera(final CameraDeviceProxy device,
final OneCameraCharacteristics characteristics, final MainThread mainExecutor,
Size pictureSize, final ImageSaver.Builder imageSaverBuilder,
- final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting) {
+ final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting,
+ final BurstFacade burstFacade) {
final Lifetime lifetime = new Lifetime();
final ImageReaderProxy imageReader = new CloseWhenDoneImageReader(new LoggingImageReader(
diff --git a/src/com/android/camera/one/v2/ZslOneCameraFactory.java b/src/com/android/camera/one/v2/ZslOneCameraFactory.java
index 3c13f77df..72a713767 100644
--- a/src/com/android/camera/one/v2/ZslOneCameraFactory.java
+++ b/src/com/android/camera/one/v2/ZslOneCameraFactory.java
@@ -30,6 +30,9 @@ import com.android.camera.async.Updatable;
import com.android.camera.debug.Log.Tag;
import com.android.camera.debug.Logger;
import com.android.camera.debug.Loggers;
+import com.android.camera.burst.BurstFacade;
+import com.android.camera.burst.BurstTaker;
+import com.android.camera.burst.BurstTakerImpl;
import com.android.camera.one.OneCamera;
import com.android.camera.one.OneCameraCharacteristics;
import com.android.camera.one.v2.camera2proxy.AndroidImageReaderProxy;
@@ -101,7 +104,8 @@ public class ZslOneCameraFactory implements OneCameraFactory {
final OneCameraCharacteristics characteristics,
final MainThread mainThread,
Size pictureSize, final ImageSaver.Builder imageSaverBuilder,
- final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting) {
+ final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting,
+ final BurstFacade burstFacade) {
final Lifetime lifetime = new Lifetime();
final ImageReaderProxy imageReader = new CloseWhenDoneImageReader(
@@ -114,6 +118,9 @@ public class ZslOneCameraFactory implements OneCameraFactory {
List<Surface> outputSurfaces = new ArrayList<>();
outputSurfaces.add(imageReader.getSurface());
+ if (burstFacade.getInputSurface() != null) {
+ outputSurfaces.add(burstFacade.getInputSurface());
+ }
/**
* Finishes constructing the camera when prerequisites, e.g. the preview
@@ -183,6 +190,14 @@ public class ZslOneCameraFactory implements OneCameraFactory {
sharedImageReaderFactory.provideSharedImageReader(),
sharedImageReaderFactory.provideZSLStream(),
sharedImageReaderFactory.provideMetadataPool(), flashSetting);
+ BurstTaker burstTaker = new BurstTakerImpl(cameraCommandExecutor, frameServer,
+ rootBuilder, sharedImageReaderFactory.provideSharedImageReader(),
+ burstFacade.getInputSurface(),basicCameraFactory.providePreviewStarter(),
+ // ImageReader#acquireLatestImage() requires two images as the margin so
+ // specify that as the maximum number of images that can be used by burst.
+ mMaxImageCount - 2);
+
+ burstFacade.setBurstTaker(burstTaker);
basicCameraFactory.providePreviewStarter().run();
diff --git a/src/com/android/camera/one/v2/initialization/GenericOneCameraImpl.java b/src/com/android/camera/one/v2/initialization/GenericOneCameraImpl.java
index 32c2cb16e..957ad0e4a 100644
--- a/src/com/android/camera/one/v2/initialization/GenericOneCameraImpl.java
+++ b/src/com/android/camera/one/v2/initialization/GenericOneCameraImpl.java
@@ -95,16 +95,6 @@ class GenericOneCameraImpl implements OneCamera {
}
@Override
- public void startBurst(BurstParameters params, CaptureSession session) {
- // TODO delete from OneCamera interface
- }
-
- @Override
- public void stopBurst() {
- // TODO delete from OneCamera interface
- }
-
- @Override
public void setFocusStateListener(final FocusStateListener listener) {
mAFStateListenable.setCallback(new Callback<Integer>() {
@Override
diff --git a/src/com/android/camera/one/v2/sharedimagereader/ZslSharedImageReaderFactory.java b/src/com/android/camera/one/v2/sharedimagereader/ZslSharedImageReaderFactory.java
index 310eed2ed..d9f4c8aa6 100644
--- a/src/com/android/camera/one/v2/sharedimagereader/ZslSharedImageReaderFactory.java
+++ b/src/com/android/camera/one/v2/sharedimagereader/ZslSharedImageReaderFactory.java
@@ -24,7 +24,6 @@ import com.android.camera.async.Lifetime;
import com.android.camera.async.Observable;
import com.android.camera.async.Updatable;
import com.android.camera.one.v2.camera2proxy.ImageReaderProxy;
-import com.android.camera.one.v2.core.CaptureStream;
import com.android.camera.one.v2.core.ResponseListener;
import com.android.camera.one.v2.core.ResponseListeners;
import com.android.camera.one.v2.sharedimagereader.imagedistributor.ImageDistributor;
diff --git a/src_pd/com/android/camera/burst/BurstControllerImpl.java b/src_pd/com/android/camera/burst/BurstControllerImpl.java
index 0c8156446..dfbc030eb 100644
--- a/src_pd/com/android/camera/burst/BurstControllerImpl.java
+++ b/src_pd/com/android/camera/burst/BurstControllerImpl.java
@@ -15,22 +15,21 @@
package com.android.camera.burst;
import android.content.Context;
+import android.graphics.SurfaceTexture;
-import com.android.camera.gl.FrameDistributor.FrameConsumer;
+import com.android.camera.burst.BurstResultsListener;
+import com.android.camera.burst.EvictionHandler;
+import com.android.camera.burst.BurstController.ImageStreamProperties;
+import com.android.camera.one.v2.camera2proxy.ImageProxy;
+
+import java.util.List;
/**
* Stub implementation for burst controller.
*/
class BurstControllerImpl implements BurstController {
- /**
- * Create a new BurstController.
- *
- * @param context the context of the application.
- * @param resultsListener listener for listening to burst events.
- */
- public BurstControllerImpl(Context context, BurstResultsListener resultsListener) {
- }
+ public BurstControllerImpl(Context context) {}
/**
* Returns true if burst mode is supported by camera.
*/
@@ -39,25 +38,14 @@ class BurstControllerImpl implements BurstController {
}
@Override
- public BurstConfiguration startBurst() {
+ public EvictionHandler startBurst(SurfaceTexture surfaceTexture,
+ ImageStreamProperties imageStreamProperties,
+ BurstResultsListener resultsListener) {
return null;
}
@Override
- public void stopBurst(ResultsAccessor resultsAccessor) {
+ public void processBurstResults(List<ImageProxy> capturedImages) {
// no op
}
-
- @Override
- public void onPreviewSizeChanged(int width, int height) {
- }
-
- @Override
- public void onOrientationChanged(int orientation, boolean isMirrored) {
- }
-
- @Override
- public FrameConsumer getPreviewFrameConsumer() {
- throw new IllegalStateException("Not implemented.");
- }
}
diff --git a/src_pd/com/android/camera/one/v2/OneCameraCreator.java b/src_pd/com/android/camera/one/v2/OneCameraCreator.java
index a1736ec31..7d67e2f8f 100644
--- a/src_pd/com/android/camera/one/v2/OneCameraCreator.java
+++ b/src_pd/com/android/camera/one/v2/OneCameraCreator.java
@@ -23,6 +23,7 @@ import android.util.DisplayMetrics;
import com.android.camera.SoundPlayer;
import com.android.camera.app.AppController;
import com.android.camera.async.MainThread;
+import com.android.camera.burst.BurstFacade;
import com.android.camera.one.OneCamera;
import com.android.camera.one.v2.photo.ImageRotationCalculator;
import com.android.camera.util.Size;
@@ -32,7 +33,8 @@ public class OneCameraCreator {
CameraCharacteristics characteristics, Size pictureSize,
int maxMemoryMB,
DisplayMetrics displayMetrics, SoundPlayer soundPlayer,
- MainThread mainThread, ImageRotationCalculator imageRotationCalculator) {
+ MainThread mainThread, ImageRotationCalculator imageRotationCalculator,
+ BurstFacade burstController) {
// TODO: Might want to switch current camera to vendor HDR.
return new OneCameraImpl(device, characteristics, pictureSize);
}