summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/imageprocessor/ZSLQueue.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/imageprocessor/ZSLQueue.java')
-rw-r--r--src/com/android/camera/imageprocessor/ZSLQueue.java348
1 files changed, 348 insertions, 0 deletions
diff --git a/src/com/android/camera/imageprocessor/ZSLQueue.java b/src/com/android/camera/imageprocessor/ZSLQueue.java
new file mode 100644
index 000000000..ce2da1c6b
--- /dev/null
+++ b/src/com/android/camera/imageprocessor/ZSLQueue.java
@@ -0,0 +1,348 @@
+/*
+Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.camera.imageprocessor;
+
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.media.Image;
+import android.util.Log;
+
+import com.android.camera.CaptureModule;
+import android.os.SystemProperties;
+
+import java.util.LinkedList;
+
+public class ZSLQueue {
+ private static final String CIRCULAR_BUFFER_SIZE_PERSIST = "persist.camera.zsl.buffer.size";
+ private static final int CIRCULAR_BUFFER_SIZE_DEFAULT = 5;
+ private int mCircularBufferSize = CIRCULAR_BUFFER_SIZE_DEFAULT;
+ private ImageItem[] mBuffer;
+ private int mImageHead;
+ private int mMetaHead;
+ private Object mLock = new Object();
+ private LinkedList<PendingRequest> mPendingRequestList = new LinkedList<PendingRequest>();
+ private CaptureModule mModule;
+ private static final boolean DEBUG = false;
+ private static final boolean DEBUG_QUEUE = false;
+ private static final String TAG = "ZSLQueue";
+ private static final int REQUEST_LIFESPAN = 5; //This is in frame count.
+
+ class PendingRequest {
+ private int mLifeTimeInFrame;
+
+ public PendingRequest(){
+ mLifeTimeInFrame = 0;
+ }
+
+ public int getLifeTime() {
+ return mLifeTimeInFrame;
+ }
+
+ public void incLifeTime() {
+ mLifeTimeInFrame++;
+ }
+ }
+
+ public ZSLQueue(CaptureModule module) {
+ mCircularBufferSize = SystemProperties.getInt(CIRCULAR_BUFFER_SIZE_PERSIST, CIRCULAR_BUFFER_SIZE_DEFAULT);
+ synchronized (mLock) {
+ mBuffer = new ImageItem[mCircularBufferSize];
+ mImageHead = 0;
+ mMetaHead = 0;
+ mPendingRequestList.clear();
+ mModule = module;
+ }
+ }
+
+ private int findMeta(long timestamp, int index) {
+ int startIndex = index;
+ do {
+ if(mBuffer[index] != null && mBuffer[index].getMetadata() != null &&
+ mBuffer[index].getMetadata().get(CaptureResult.SENSOR_TIMESTAMP).longValue() == timestamp) {
+ return index;
+ }
+ index = (index + 1) % mBuffer.length;
+ } while(index != startIndex);
+ return -1;
+ }
+
+ private int findImage(long timestamp, int index) {
+ int startIndex = index;
+ do {
+ if(mBuffer[index] != null && mBuffer[index].getImage() != null &&
+ mBuffer[index].getImage().getTimestamp() == timestamp) {
+ return index;
+ }
+ index = (index + 1) % mBuffer.length;
+ } while(index != startIndex);
+ return -1;
+ }
+
+ public void add(Image image) {
+ int lastIndex = -1;
+ synchronized (mLock) {
+ if(mBuffer == null)
+ return;
+ if(mBuffer[mImageHead] != null) {
+ mBuffer[mImageHead].closeImage();
+ } else {
+ mBuffer[mImageHead] = new ImageItem();
+ }
+ if(mBuffer[mImageHead].getMetadata() != null) {
+ if((mBuffer[mImageHead].getMetadata().get(CaptureResult.SENSOR_TIMESTAMP)).longValue() == image.getTimestamp()) {
+ mBuffer[mImageHead].setImage(image);
+ lastIndex = mImageHead;
+ mImageHead = (mImageHead + 1) % mBuffer.length;
+ } else if((mBuffer[mImageHead].getMetadata().get(CaptureResult.SENSOR_TIMESTAMP)).longValue() > image.getTimestamp()) {
+ image.close();
+ } else {
+ int i = findMeta(image.getTimestamp(), mImageHead);
+ if(i == -1) {
+ mBuffer[mImageHead].setImage(image);
+ mBuffer[mImageHead].setMetadata(null);
+ mImageHead = (mImageHead + 1) % mBuffer.length;
+ } else {
+ lastIndex = mImageHead = i;
+ mBuffer[mImageHead].setImage(image);
+ mImageHead = (mImageHead + 1) % mBuffer.length;
+ }
+ }
+ } else {
+ mBuffer[mImageHead].setImage(image);
+ lastIndex = mImageHead;
+ mImageHead = (mImageHead + 1) % mBuffer.length;
+ }
+ }
+
+ if(DEBUG_QUEUE) Log.d(TAG, "imageIndex: " + lastIndex + " " + image.getTimestamp());
+
+ if(mPendingRequestList.size() != 0) {
+ if(lastIndex != -1) {
+ processPendingRequest(lastIndex);
+ }
+ for(int i=0; i < mPendingRequestList.size(); i++) {
+ mPendingRequestList.get(i).incLifeTime();
+ }
+ }
+ }
+
+ private void processPendingRequest(int index) {
+ ImageItem item;
+ synchronized (mLock) {
+ if(mBuffer == null)
+ return;
+ item = mBuffer[index];
+ if (item != null && item.isValid() && checkImageRequirement(item.getMetadata())) {
+ if(DEBUG && (mBuffer[index].getMetadata().get(CaptureResult.SENSOR_TIMESTAMP)).longValue() !=
+ mBuffer[index].getImage().getTimestamp()) {
+ Log.e(TAG,"Not matching image coming through");
+ }
+ mBuffer[index] = null;
+ mPendingRequestList.removeFirst();
+ for(PendingRequest request : mPendingRequestList) {
+ if(request.getLifeTime() >= REQUEST_LIFESPAN) {
+ mPendingRequestList.remove(request);
+ }
+ }
+ } else {
+ return;
+ }
+ }
+ mModule.getPostProcessor().onMatchingZSLPictureAvailable(item);
+ }
+
+ public void add(TotalCaptureResult metadata) {
+ int lastIndex = -1;
+ synchronized (mLock) {
+ if(mBuffer == null)
+ return;
+ long timestamp = -1;
+ try {
+ timestamp = metadata.get(CaptureResult.SENSOR_TIMESTAMP).longValue();
+ } catch(IllegalStateException e) {
+ //This happens when corresponding image to this metadata is closed and discarded.
+ return;
+ }
+ if(timestamp == -1) {
+ return;
+ }
+ if(mBuffer[mMetaHead] == null) {
+ mBuffer[mMetaHead] = new ImageItem();
+ } else {
+ mBuffer[mMetaHead].closeMeta();
+ }
+ if(mBuffer[mMetaHead].getImage() != null) {
+ if(mBuffer[mMetaHead].getImage().getTimestamp() == timestamp) {
+ mBuffer[mMetaHead].setMetadata(metadata);
+ lastIndex = mMetaHead;
+ mMetaHead = (mMetaHead + 1) % mBuffer.length;
+ } else if(mBuffer[mMetaHead].getImage().getTimestamp() > timestamp) {
+ //Disard
+ } else {
+ int i = findImage(timestamp, mMetaHead);
+ if(i == -1) {
+ mBuffer[mMetaHead].setImage(null);
+ mBuffer[mMetaHead].setMetadata(metadata);
+ mMetaHead = (mMetaHead + 1) % mBuffer.length;
+ } else {
+ lastIndex = mMetaHead = i;
+ mBuffer[mMetaHead].setMetadata(metadata);
+ mMetaHead = (mMetaHead + 1) % mBuffer.length;
+ }
+ }
+ } else {
+ mBuffer[mMetaHead].setMetadata(metadata);
+ lastIndex = mImageHead;
+ mMetaHead = (mMetaHead + 1) % mBuffer.length;
+ }
+ }
+
+ if(DEBUG_QUEUE) Log.d(TAG, "Meta: " + lastIndex + " " + metadata.get(CaptureResult.SENSOR_TIMESTAMP));
+
+ if(mPendingRequestList.size() != 0) {
+ if(lastIndex != -1) {
+ processPendingRequest(lastIndex);
+ }
+ for(int i=0; i < mPendingRequestList.size(); i++) {
+ mPendingRequestList.get(i).incLifeTime();
+ }
+ }
+ }
+
+ public ImageItem tryToGetMatchingItem() {
+ synchronized (mLock) {
+ int index = mImageHead;
+ ImageItem item;
+ do {
+ item = mBuffer[index];
+ if (item != null && item.isValid() && checkImageRequirement(item.getMetadata())) {
+ mBuffer[index] = null;
+ return item;
+ }
+ index--;
+ if (index < 0) index = mBuffer.length - 1;
+ } while (index != mImageHead);
+ }
+ return null;
+ }
+
+ public void addPictureRequest() {
+ if(DEBUG) Log.d(TAG, "RequsetPendingCount: "+mPendingRequestList.size());
+ synchronized (mLock) {
+ mPendingRequestList.addLast(new PendingRequest());
+ }
+ }
+
+ public void onClose() {
+ synchronized (mLock) {
+ for (int i = 0; i < mBuffer.length; i++) {
+ if (mBuffer[i] != null) {
+ mBuffer[i].closeImage();
+ mBuffer[i].closeMeta();
+ mBuffer[i] = null;
+ }
+ }
+ mBuffer = null;
+ mImageHead = 0;
+ mMetaHead = 0;
+ mPendingRequestList.clear();
+ }
+ }
+
+ private boolean checkImageRequirement(TotalCaptureResult captureResult) {
+ if( (captureResult.get(CaptureResult.LENS_STATE) != null &&
+ captureResult.get(CaptureResult.LENS_STATE).intValue() == CaptureResult.LENS_STATE_MOVING)
+ ||
+ (captureResult.get(CaptureResult.CONTROL_AE_STATE) != null &&
+ (captureResult.get(CaptureResult.CONTROL_AE_STATE).intValue() == CaptureResult.CONTROL_AE_STATE_SEARCHING ||
+ captureResult.get(CaptureResult.CONTROL_AE_STATE).intValue() == CaptureResult.CONTROL_AE_STATE_PRECAPTURE))
+ ||
+ (captureResult.get(CaptureResult.CONTROL_AF_STATE) != null) &&
+ (captureResult.get(CaptureResult.CONTROL_AF_STATE) == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN ||
+ captureResult.get(CaptureResult.CONTROL_AF_STATE) == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN)) {
+ return false;
+ }
+
+ if( captureResult.get(CaptureResult.CONTROL_AE_STATE) != null &&
+ captureResult.get(CaptureResult.CONTROL_AF_STATE) != null &&
+ captureResult.get(CaptureResult.CONTROL_AE_STATE).intValue() == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED &&
+ captureResult.get(CaptureResult.CONTROL_AF_STATE).intValue() != CaptureResult.FLASH_MODE_OFF) {
+ return true;
+ }
+
+ if( captureResult.get(CaptureResult.CONTROL_AWB_STATE) != null &&
+ captureResult.get(CaptureResult.CONTROL_AWB_STATE).intValue() == CaptureResult.CONTROL_AWB_STATE_SEARCHING ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ class ImageItem {
+ private Image mImage = null;
+ private TotalCaptureResult mMetadata = null;
+
+ public Image getImage() {
+ return mImage;
+ }
+
+ public void setImage(Image image) {
+ if(mImage != null) {
+ mImage.close();
+ }
+ mImage = image;
+ }
+
+ public TotalCaptureResult getMetadata() {
+ return mMetadata;
+ }
+
+ public void setMetadata(TotalCaptureResult metadata) {
+ mMetadata = metadata;
+ }
+
+ public void closeImage() {
+ if(mImage != null) {
+ mImage.close();
+ }
+ mImage = null;
+ }
+
+ public void closeMeta() {
+ mMetadata = null;
+ }
+
+ public boolean isValid() {
+ if(mImage != null && mMetadata != null) {
+ return true;
+ }
+ return false;
+ }
+ }
+}