ImageBackend.java revision abac2a23443f13b58951d88bf4b972f31a562e3d
1ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin/* 2ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Copyright (C) 2014 The Android Open Source Project 3ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 4ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * you may not use this file except in compliance with the License. 6ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * You may obtain a copy of the License at 7ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 8ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * http://www.apache.org/licenses/LICENSE-2.0 9ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 10ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Unless required by applicable law or agreed to in writing, software 11ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * distributed under the License is distributed on an "AS IS" BASIS, 12ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * See the License for the specific language governing permissions and 14ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * limitations under the License. 15ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 16ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 173830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberlingpackage com.android.camera.processing.imagebackend; 18ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 19ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport com.android.camera.debug.Log; 20abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Linimport com.android.camera.processing.ProcessingService; 21abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Linimport com.android.camera.processing.ProcessingServiceManager; 22abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Linimport com.android.camera.processing.ProcessingTaskConsumer; 2330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Linimport com.android.camera.session.CaptureSession; 2430ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Linimport com.android.camera.util.Size; 2530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin 26ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.HashMap; 27ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.HashSet; 28ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.Map; 29ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.Set; 30ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.Executor; 31ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.ExecutorService; 32ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.Executors; 33ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.ThreadFactory; 34ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.locks.Condition; 35ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.locks.ReentrantLock; 36ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 37ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin/** 3830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * This ImageBackend is created for the purpose of creating a task-running 3930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * infrastructure that has two-level of priority and doing the book-keeping to 4030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * keep track of tasks that use Android Images. Android.media.images are 4130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * critical system resources that MUST be properly managed in order to maintain 4230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * camera application performance. Android.media.images are merely Java handles 4330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * to regions of physically contiguous memory used by the camera hardware as a 4430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * destination for imaging data. In general, this physically contiguous memory 4530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is not counted as an application resource, but as a system resources held by 4630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * the application and does NOT count against the limits of application memory. 4730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * The performance pressures of both computing and memory resources must often 4830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * be prioritized in releasing Android.media.images in a timely manner. In order 4930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * to properly balance these concerns, most image processing requested should be 5030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * routed through this object. This object is also responsible for releasing 5130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Android.media image as soon as possible, so as not to stall the camera 5230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * hardware subsystem. Image that reserve these images are a subclass of the 5330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * basic Java Runnable with a few conditions placed upon their run() 5430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * implementation: 55ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * <ol> 5630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * <li>The task will try to release the image as early as possible by calling 5730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * the releaseSemaphoreReference as soon as a reference to the original image is 5830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * no longer required.</li> 5930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * <li>A set of tasks that require ImageData must only happen on the first 6030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * receiveImage call. receiveImage must only be called once per image.</li> 6130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * <li>However, the submitted tasks may spawn new tasks via the appendTask with 6230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * any image that have had a task submitted, but NOT released via 6330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * releaseSemaphoreReference.</li> 6430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * <li>Computation that is dependent on multiple images should be written into 6530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * this task framework in a distributed manner where image task can be computed 6630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * independently and join their results to a common shared object.This style of 6730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * implementation allows for the earliest release of Android Images while 6830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * honoring the resources priorities set by this class. See the Lucky shot 6930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * implementation for a concrete example for this shared object and its 7030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * respective task {@link TaskLuckyShotSession} {@link LuckyShotSession}</li> 71ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * </ol> 72abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * To integrate with the ProcessingServiceManager, ImageBackend also signals to 73abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * the ProcessingServiceManager its processing state by enqueuing 74abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * ImageShadowTasks on each ImageBackend::receiveIamge call. These ImageShadow 75abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * tasks have no implementation, but emulate the processing delay by blocking 76abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * until all tasks submitted and spawned by a particular receiveImage call have 77abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * completed their processing. This emulated functionality ensures that other 78abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * ProcessingTasks associated with Lens Blur and Panorama are not processing 79abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * while the ImageBackend is running. Unfairly, the ImageBackend proceeds with 80abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * its own processing regardless of the state of ImageShadowTask. 81abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * ImageShadowTasks that are associated with ImageBackend tasks that have 82abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * already been completed should return immediately on its process call. 83ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 843c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Linpublic class ImageBackend implements ImageConsumer, ImageTaskManager { 85ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 86ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected static final int FAST_THREAD_PRIORITY = Thread.MAX_PRIORITY; 87ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 88ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected static final int SLOW_THREAD_PRIORITY = Thread.NORM_PRIORITY; 89ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 90ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected static final int NUM_THREADS_FAST = 2; 91ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 92ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected static final int NUM_THREADS_SLOW = 2; 93ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 94abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protected final ProcessingTaskConsumer mProcessingTaskConsumer; 95abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 96abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 97abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Map for TaskImageContainer and the release of ImageProxy Book-keeping 98abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 993830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling protected final Map<ImageToProcess, ImageReleaseProtocol> mImageSemaphoreMap; 100abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 101abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Map for ImageShadowTask and release of blocking on 102abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * ImageShadowTask::process 103abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 104abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protected final Map<CaptureSession, ImageShadowTask> mShadowTaskMap; 105ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 106ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected final ExecutorService mThreadPoolFast; 107ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 108ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected final ExecutorService mThreadPoolSlow; 109ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 110ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private final static Log.Tag TAG = new Log.Tag("ImageBackend"); 111ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 11230ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin /** 11330ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * Approximate viewable size (in pixels) for the fast thumbnail in the 11430ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * current UX definition of the product. Note that these values will be the 115abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * minimum size of FAST_THUMBNAIL target for the CONVERT_TO_RGB_PREVIEW 116abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * task. 11730ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin */ 11830ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin private final static Size FAST_THUMBNAIL_TARGET_SIZE = new Size(160, 100); 11930ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin 12030ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin /** 12130ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * A standard viewable size (in pixels) for the filmstrip thumbnail in the 12230ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * current UX definition of the product. Note that this size is the minimum 12330ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * size for the Preview on the filmstrip associated with 1244dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin * COMPRESS_TO_JPEG_AND_WRITE_TO_DISK task. 12530ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin */ 12630ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin private final static Size FILMSTRIP_THUMBNAIL_TARGET_SIZE = new Size(512, 384); 12730ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin 128ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Some invariants to know that we're keeping track of everything 129ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // that reflect the state of mImageSemaphoreMap 130ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private int mOutstandingImageRefs = 0; 131ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 132ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private int mOutstandingImageOpened = 0; 133ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 134ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private int mOutstandingImageClosed = 0; 135ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 136ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Objects that may be registered to this objects events. 137ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private ImageProcessorProxyListener mProxyListener = null; 138ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 139ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Default constructor, values are conservatively targeted to the Nexus 6 140abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public ImageBackend(ProcessingTaskConsumer processingTaskConsumer) { 141ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolFast = Executors.newFixedThreadPool(NUM_THREADS_FAST, new FastThreadFactory()); 142ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolSlow = Executors.newFixedThreadPool(NUM_THREADS_SLOW, new SlowThreadFactory()); 143ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mProxyListener = new ImageProcessorProxyListener(); 1443830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling mImageSemaphoreMap = new HashMap<>(); 145abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mShadowTaskMap = new HashMap<>(); 146abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mProcessingTaskConsumer = processingTaskConsumer; 147ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 148ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 149ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 150ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Direct Injection Constructor for Testing purposes. 151ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 152ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param fastService Service where Tasks of FAST Priority are placed. 153ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param slowService Service where Tasks of SLOW Priority are placed. 154ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param imageProcessorProxyListener iamge proxy listener to be used 155ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 156ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public ImageBackend(ExecutorService fastService, ExecutorService slowService, 157abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ImageProcessorProxyListener imageProcessorProxyListener, 158abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ProcessingTaskConsumer processingTaskConsumer) { 159ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolFast = fastService; 160ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolSlow = slowService; 161ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mProxyListener = imageProcessorProxyListener; 1623830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling mImageSemaphoreMap = new HashMap<>(); 163abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mShadowTaskMap = new HashMap<>(); 164abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mProcessingTaskConsumer = processingTaskConsumer; 165ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 166ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 167ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 1683c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * Simple getter for the associated listener object associated with this 16930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * instantiation that handles registration of events listeners. 170ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 171ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @return listener proxy that handles events messaging for this object. 172ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 173ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public ImageProcessorProxyListener getProxyListener() { 174ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return mProxyListener; 175ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 176ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 177abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 178abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Sets a listener that receive events from all tasks, regardless of image 179abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 180abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param listener Listener to receive all events 181abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 182ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void setCameraImageProcessorListener(ImageProcessorListener listener) { 183ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin this.mProxyListener.registerListener(listener, null); 184ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 185ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 186ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 18730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Wrapper function for all log messages created by this object. Default 18830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * implementation is to send messages to the Android logger. For test 18930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * purposes, this method can be overridden to avoid "Stub!" Runtime 19030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * exceptions in Unit Tests. 191ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 192ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void logWrapper(String message) { 1930745f6eb1a8cbed85761e02839367ed8b2ff6ef6I-Jong Lin Log.v(TAG, message); 194ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 195ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 196ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 197ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @return Number of Image references currently held by this instance 198ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 199ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 200abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public int getNumberOfReservedOpenImages() { 201ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin synchronized (mImageSemaphoreMap) { 202ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // since mOutstandingImageOpened, mOutstandingImageClosed reflect 203ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // the historical state of mImageSemaphoreMap, we need to lock on 204ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // before we return a value. 205ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return mOutstandingImageOpened - mOutstandingImageClosed; 206ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 207ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 208ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 209ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 210abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Returns of the number of receiveImage calls that are currently enqueued 211abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * and/or being processed. 212abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 213abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @return The number of receiveImage calls that are currently enqueued 214abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * and/or being processed 215abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 216abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin @Override 217abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public int getNumberOfOutstandingCalls() { 218abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 219abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin return mShadowTaskMap.size(); 220abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 221abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 222abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 223abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 22430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Signals the ImageBackend that a tasks has released a reference to the 22530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * image. Imagebackend determines whether all references have been released 22630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * and applies its specified release protocol of closing image and/or 22730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * unblocking the caller. Should ONLY be called by the tasks running on this 22830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * class. 229ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 230ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img the image to be released by the task. 23130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param executor the executor on which the image close is run. if null, 23230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * image close is run by the calling thread (usually the main 23330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * task thread). 234ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 2353c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin @Override 2363830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public void releaseSemaphoreReference(final ImageToProcess img, Executor executor) { 237ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin synchronized (mImageSemaphoreMap) { 238ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin ImageReleaseProtocol protocol = mImageSemaphoreMap.get(img); 239ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol == null || protocol.getCount() <= 0) { 240ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // That means task implementation has allowed an unbalanced 241ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // semaphore release. 242ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException( 243ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin "ERROR: Task implementation did NOT balance its release."); 244ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 245ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 246ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Normal operation from here. 247ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protocol.addCount(-1); 248ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageRefs--; 249ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin logWrapper("Ref release. Total refs = " + mOutstandingImageRefs); 250ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol.getCount() == 0) { 251ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Image is ready to be released 252ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Remove the image from the map so that it may be submitted 253ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // again. 254ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mImageSemaphoreMap.remove(img); 255ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 256ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Conditionally close the image, specified by initial 257ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // receiveImage call 258ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol.closeOnRelease) { 259ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin closeImageExecutorSafe(img, executor); 26030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin logWrapper("Ref release close."); 261ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 262ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 263ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Conditionally signal the blocking thread to go. 264ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol.blockUntilRelease) { 265ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protocol.signal(); 266ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 267ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } else { 268ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Image is still being held by other tasks. 269ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Otherwise, update the semaphore 270ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mImageSemaphoreMap.put(img, protocol); 271ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 272ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 273ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 274ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 275ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 2763c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * Spawns dependent tasks from internal implementation of a set of tasks. If 2773c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * a dependent task does NOT require the image reference, it should be 2783c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * passed a null pointer as an image reference. In general, this method 2793c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * should be called after the task has completed its own computations, but 2803c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * before it has released its own image reference (via the 2813c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * releaseSemaphoreReference call). 282ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 283ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param tasks The set of tasks to be run 284ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @return whether tasks are successfully submitted. 285ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 2863c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin @Override 2873830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean appendTasks(ImageToProcess img, Set<TaskImageContainer> tasks) { 288ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Make sure that referred images are all the same, if it exists. 289ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // And count how image references need to be kept track of. 290ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin int countImageRefs = numPropagatedImageReferences(img, tasks); 291ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 292ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (img != null) { 293ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // If you're still holding onto the reference, make sure you keep 294ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // count 295ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin incrementSemaphoreReferenceCount(img, countImageRefs); 296ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 297ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 298abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Update the done count on the new tasks. 299abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin incrementTaskDone(tasks); 300abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 301ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin scheduleTasks(tasks); 302ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return true; 303ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 304ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 305ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 306ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Spawns a single dependent task from internal implementation of a task. 307ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 308ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param task The task to be run 309ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @return whether tasks are successfully submitted. 310ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 3113c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin @Override 3123830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean appendTasks(ImageToProcess img, TaskImageContainer task) { 313ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Set<TaskImageContainer> tasks = new HashSet<TaskImageContainer>(1); 314ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin tasks.add(task); 315ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return appendTasks(img, tasks); 316ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 317ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 318ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 31930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Implements that top-level image single task submission that is defined by 32030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * the ImageConsumer interface. 321ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 322ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img Image required by the task 323ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param task Task to be run 32430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param blockUntilImageRelease If true, call blocks until the object img 32530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is no longer referred by any task. If false, call is 32630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * non-blocking 32730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param closeOnImageRelease If true, images is closed when the object img 32830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is is no longer referred by any task. If false, After an image 32930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is submitted, it should never be submitted again to the 33030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * interface until all tasks and their spawned tasks are 331ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * finished. 332ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 333ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 3343830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean receiveImage(ImageToProcess img, TaskImageContainer task, 3353c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin boolean blockUntilImageRelease, boolean closeOnImageRelease) 336ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throws InterruptedException { 337ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Set<TaskImageContainer> passTasks = new HashSet<TaskImageContainer>(1); 338ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin passTasks.add(task); 3393c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin return receiveImage(img, passTasks, blockUntilImageRelease, closeOnImageRelease); 340ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 341ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 342ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 34330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Implements that top-level image single task submission that is defined by 34430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * the ImageConsumer interface. 345ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 346ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img Image required by the task 347ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param tasks A set of Tasks to be run 34830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param blockUntilImageRelease If true, call blocks until the object img 34930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is no longer referred by any task. If false, call is 35030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * non-blocking 35130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param closeOnImageRelease If true, images is closed when the object img 35230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is is no longer referred by any task. If false, After an image 35330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is submitted, it should never be submitted again to the 35430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * interface until all tasks and their spawned tasks are 355ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * finished. 356ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @return whether the blocking completed properly 357ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 358ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 3593830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean receiveImage(ImageToProcess img, Set<TaskImageContainer> tasks, 3603c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin boolean blockUntilImageRelease, boolean closeOnImageRelease) 361ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throws InterruptedException { 362ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 363ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Short circuit if no tasks submitted. 364ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (tasks == null || tasks.size() <= 0) { 365ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return false; 366ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 367ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 368ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (img == null) { 369ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // TODO: Determine whether you need to be so strict at the top level 370ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException("ERROR: Initial call must reference valid Image!"); 371ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 372ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 373ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Make sure that referred images are all the same, if it exists. 374ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // And count how image references need to be kept track of. 375ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin int countImageRefs = numPropagatedImageReferences(img, tasks); 376ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 377abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Initialize the counters for process-level tasks 378abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin initializeTaskDone(tasks); 379abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 380ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Set the semaphore, given that the number of tasks that need to be 381ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // scheduled 382ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // and the boolean flags for imaging closing and thread blocking 383ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin ImageReleaseProtocol protocol = setSemaphoreReferenceCount(img, countImageRefs, 384ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin blockUntilImageRelease, closeOnImageRelease); 385ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 386ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Put the tasks on their respective queues. 387ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin scheduleTasks(tasks); 388ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 389ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Implement blocking if required 390ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol.blockUntilRelease) { 391ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protocol.block(); 392ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 393ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 394ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return true; 395ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 396ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 397ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 39830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Implements that top-level image task submission short-cut that is defined 39930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * by the ImageConsumer interface. 400ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 401ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img Image required by the task 40230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param executor Executor to run events and image closes, in case of 40330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * control leakage 40430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param processingFlags Magical bit vector that specifies jobs to be run 40530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * After an image is submitted, it should never be submitted 40630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * again to the interface until all tasks and their spawned tasks 40730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * are finished. 408ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 409ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 4103830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean receiveImage(ImageToProcess img, Executor executor, 41130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin Set<ImageTaskFlags> processingFlags, CaptureSession session) 41230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin throws InterruptedException { 413ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 414ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Set<TaskImageContainer> tasksToExecute = new HashSet<TaskImageContainer>(); 415ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 416ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (img == null) { 417ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // No data to process, just pure message. 418ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return true; 419ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 420ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 421ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Now add the pre-mixed versions of the tasks. 422ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 4234dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin if (processingFlags.contains(ImageTaskFlags.COMPRESS_TO_JPEG_AND_WRITE_TO_DISK)) { 4244dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin if (processingFlags.contains(ImageTaskFlags.CREATE_EARLY_FILMSTRIP_PREVIEW)) { 4254dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin // Request job that creates both filmstrip thumbnail from YUV, 426abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // JPEG compression of the YUV Image, and writes the result to 427abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // disk 4284dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin tasksToExecute.add(new TaskPreviewChainedJpeg(img, executor, this, session, 4294dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin FILMSTRIP_THUMBNAIL_TARGET_SIZE)); 4304dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin } else { 431abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Request job that only does JPEG compression and writes the 432abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // result to disk 4334dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin tasksToExecute.add(new TaskCompressImageToJpeg(img, executor, this, session)); 4344dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin } 435ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 436ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 4374dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin if (processingFlags.contains(ImageTaskFlags.CONVERT_TO_RGB_PREVIEW)) { 4384dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin // Add an additional type of task to the appropriate queue. 43930ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin tasksToExecute.add(new TaskConvertImageToRGBPreview(img, executor, 44030ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin this, TaskImageContainer.ProcessingPriority.FAST, session, 44130ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin FAST_THUMBNAIL_TARGET_SIZE, 44230ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin TaskConvertImageToRGBPreview.ThumbnailShape.SQUARE_ASPECT_CIRCULAR_INSET)); 443ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 444ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 445ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin receiveImage(img, tasksToExecute, 4464dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin processingFlags.contains(ImageTaskFlags.BLOCK_UNTIL_ALL_TASKS_RELEASE), 4474dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin processingFlags.contains(ImageTaskFlags.CLOSE_ON_ALL_TASKS_RELEASE)); 448ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 449ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return true; 450ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 451ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 452ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 453ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Factory functions, in case, you want some shake and bake functionality. 454ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 4553830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public TaskConvertImageToRGBPreview createTaskConvertImageToRGBPreview( 4563830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling ImageToProcess image, Executor executor, ImageBackend imageBackend, 45730ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin CaptureSession session, Size targetSize, 45830ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin TaskConvertImageToRGBPreview.ThumbnailShape thumbnailShape) { 45930ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin return new TaskConvertImageToRGBPreview(image, executor, imageBackend, 46030ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin TaskImageContainer.ProcessingPriority.FAST, session, 46130ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin FAST_THUMBNAIL_TARGET_SIZE, thumbnailShape); 462ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 463ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 4643830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public TaskCompressImageToJpeg createTaskCompressImageToJpeg(ImageToProcess image, 46530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin Executor executor, ImageBackend imageBackend, CaptureSession session) { 4663830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling return new TaskCompressImageToJpeg(image, executor, imageBackend, session); 467ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 468ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 469ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 470ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Blocks and waits for all tasks to complete. 471ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 472ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 473ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void shutdown() { 474ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolSlow.shutdown(); 475ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolFast.shutdown(); 476ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 477ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 478ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 479abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * For a given set of starting tasks, initialize the associated sessions 480abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * with a proper blocking semaphore and value of number of tasks to be run. 481abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * For each semaphore, a ImageShadowTask will be instantiated and enqueued 482abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * onto the selected ProcessingSerivceManager. 483abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 484abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param tasks The set of ImageContainer tasks to be run on ImageBackend 485abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 486abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protected void initializeTaskDone(Set<TaskImageContainer> tasks) { 487abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin Set<CaptureSession> sessionSet = new HashSet<>(); 488abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin Map<CaptureSession, Integer> sessionTaskCount = new HashMap<>(); 489abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 490abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Create a set w/ no session duplicates and count them 491abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin for (TaskImageContainer task : tasks) { 492abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin sessionSet.add(task.mSession); 493abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin Integer currentCount = sessionTaskCount.get(task.mSession); 494abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin if (currentCount == null) { 495abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin sessionTaskCount.put(task.mSession, 1); 496abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } else { 497abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin sessionTaskCount.put(task.mSession, currentCount + 1); 498abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 499abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 500abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 501abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Create a new blocking semaphore for each set of tasks on a given 502abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // session. 503abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 504abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin for (CaptureSession captureSession : sessionSet) { 505abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin BlockSignalProtocol protocol = new BlockSignalProtocol(); 506abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protocol.setCount(sessionTaskCount.get(captureSession)); 507abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ImageShadowTask shadowTask = new ImageShadowTask(protocol, captureSession); 508abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mShadowTaskMap.put(captureSession, shadowTask); 509abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mProcessingTaskConsumer.enqueueTask(shadowTask); 510abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 511abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 512abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 513abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 514abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 515abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * For ImageBackend tasks that spawn their own tasks, increase the semaphore 516abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * count to take into account the new tasks being spawned. 517abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 518abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param tasks The set of tasks to be spawned. 519abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 520abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protected void incrementTaskDone(Set<TaskImageContainer> tasks) throws RuntimeException { 521abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // TODO: Add invariant test so that all sessions are the same. 522abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 523abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin for (TaskImageContainer task : tasks) { 524abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ImageShadowTask shadowTask = mShadowTaskMap.get(task.mSession); 525abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin if (shadowTask == null) { 526abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin throw new RuntimeException( 527abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin "Session NOT previously registered." 528abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin + " ImageShadowTask booking-keeping is incorrect."); 529abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 530abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin shadowTask.getProtocol().addCount(1); 531abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 532abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 533abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 534abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 535abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 536abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Decrement the semaphore count of the ImageShadowTask. Should be called 537abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * when a task completes its processing in ImageBackend. 538abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 539abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param imageShadowTask The ImageShadow task that contains the blocking 540abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * semaphore. 541abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 542abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protected void decrementTaskDone(ImageShadowTask imageShadowTask) { 543abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 544abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin int remainingTasks = imageShadowTask.getProtocol().addCount(-1); 545abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin if (remainingTasks == 0) { 546abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mShadowTaskMap.remove(imageShadowTask.getSession()); 547abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin imageShadowTask.getProtocol().signal(); 548abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 549abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 550abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 551abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 552abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 553abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 55430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Puts the tasks on the specified queue. May be more complicated in the 55530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * future. 556ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 557ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param tasks The set of tasks to be run 558ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 559ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected void scheduleTasks(Set<TaskImageContainer> tasks) { 560abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 561abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin for (TaskImageContainer task : tasks) { 562abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ImageShadowTask shadowTask = mShadowTaskMap.get(task.mSession); 563abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin if (shadowTask == null) { 564abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin throw new IllegalStateException("Scheduling a task with a unknown session."); 565abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 566abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Before scheduling, wrap TaskImageContainer inside of the 567abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // TaskDoneWrapper to add 568abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // instrumentation for managing ImageShadowTasks 569abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin if (task.getProcessingPriority() == TaskImageContainer.ProcessingPriority.FAST) { 570abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mThreadPoolFast.execute(new TaskDoneWrapper(this, shadowTask, task)); 571abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } else { 572abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mThreadPoolSlow.execute(new TaskDoneWrapper(this, shadowTask, task)); 573abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 574ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 575ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 576ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 577ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 578ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 579ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Initializes the semaphore count for the image 580ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 58130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @return The protocol object that keeps tracks of the image reference 58230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * count and actions to be taken on release. 583ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 5843830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling protected ImageReleaseProtocol setSemaphoreReferenceCount(ImageToProcess img, int count, 585ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin boolean blockUntilRelease, boolean closeOnRelease) throws RuntimeException { 586ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin synchronized (mImageSemaphoreMap) { 587ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (mImageSemaphoreMap.get(img) != null) { 588ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException( 589abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin "ERROR: Rewriting of Semaphore Lock." 590abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin + " Image references may not freed properly"); 591ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 592ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 593ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Create the new booking-keeping object. 594ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin ImageReleaseProtocol protocol = new ImageReleaseProtocol(blockUntilRelease, 595ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin closeOnRelease); 596abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protocol.setCount(count); 597ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 598ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mImageSemaphoreMap.put(img, protocol); 599ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageRefs += count; 600ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageOpened++; 601ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin logWrapper("Received an opened image: " + mOutstandingImageOpened + "/" 602ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin + mOutstandingImageClosed); 603ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin logWrapper("Setting an image reference count of " + count + " Total refs = " 604ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin + mOutstandingImageRefs); 605ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return protocol; 606ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 607ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 608ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 609ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 61030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Increments the semaphore count for the image. Should ONLY be internally 61130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * via appendTasks by internal tasks. Otherwise, image references could get 61230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * out of whack. 613abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 614abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param img The Image associated with the set of tasks running on it. 615abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param count The number of tasks to be added 616abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @throws RuntimeException Indicates image Closing Bookkeeping is screwed 617abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * up. 618ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 6193830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling protected void incrementSemaphoreReferenceCount(ImageToProcess img, int count) 620ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throws RuntimeException { 621ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin synchronized (mImageSemaphoreMap) { 622ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin ImageReleaseProtocol protocol = mImageSemaphoreMap.get(img); 623ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (mImageSemaphoreMap.get(img) == null) { 624ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException( 625ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin "Image Reference has already been released or has never been held."); 626ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 627ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 628ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protocol.addCount(count); 629ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mImageSemaphoreMap.put(img, protocol); 630ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 631ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageRefs += count; 632ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 633ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 634ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 635ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 63630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Close an Image with a executor if it's available and does the proper 63730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * booking keeping on the object. 638ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 639ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img Image to be closed 64030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param executor Executor to be used, if executor is null, the close is 64130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * run on the task thread 642ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 6433830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling private void closeImageExecutorSafe(final ImageToProcess img, Executor executor) { 644ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Runnable closeTask = new Runnable() { 645ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 646ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void run() { 6473830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling img.proxy.close(); 648ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageClosed++; 649ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin logWrapper("Release of image occurred. Good fun. " + "Total Images Open/Closed = " 650ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin + mOutstandingImageOpened + "/" + mOutstandingImageClosed); 651ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 652ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin }; 653ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (executor == null) { 654ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Just run it on the main thread. 655ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin closeTask.run(); 656ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } else { 657ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin executor.execute(closeTask); 658ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 659ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 660ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 661ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 66230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Calculates the number of new Image references in a set of dependent 66330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * tasks. Checks to make sure no new image references are being introduced. 664ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 665ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param tasks The set of dependent tasks to be run 666ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 6673830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling private int numPropagatedImageReferences(ImageToProcess img, Set<TaskImageContainer> tasks) 668ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throws RuntimeException { 669ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin int countImageRefs = 0; 670ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin for (TaskImageContainer task : tasks) { 6713830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling if (task.mImage != null && task.mImage != img) { 672ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException("ERROR: Spawned tasks cannot reference new images!"); 673ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 674ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 6753830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling if (task.mImage != null) { 676ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin countImageRefs++; 677ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 678ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 679ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 680ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return countImageRefs; 681ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 682ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 683ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 684abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Simple wrapper task to instrument when tasks ends so that ImageBackend 685abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * can fire events when set of tasks created by a ReceiveImage call have all 686abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * completed. 687ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 688abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin private class TaskDoneWrapper implements Runnable { 689abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin private final ImageBackend mImageBackend; 690abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin private final ImageShadowTask mImageShadowTask; 691abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin private final Runnable mTaskToRun; 692abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 693abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 694abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Constructor 695abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 696abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param imageBackend ImageBackend that the task is running on 697abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param imageShadowTask ImageShadowTask that is blocking on the 698abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * completion of the task 699abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param taskToRun The task to be run w/o instrumentation 700abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 701abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public TaskDoneWrapper(ImageBackend imageBackend, ImageShadowTask imageShadowTask, 702abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin Runnable taskToRun) { 703abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mImageBackend = imageBackend; 704abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mImageShadowTask = imageShadowTask; 705abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mTaskToRun = taskToRun; 706abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 707ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 708abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 709abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Adds instrumentation that runs when a Runnable completes. 710abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 711abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin @Override 712abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public void run() { 713abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mTaskToRun.run(); 714abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Decrement count 715abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mImageBackend.decrementTaskDone(mImageShadowTask); 716abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 717abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 718ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 719abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 720abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Encapsulates all synchronization for semaphore signaling and blocking. 721abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 722abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin static public class BlockSignalProtocol { 723ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private int count; 724ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 725ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private final ReentrantLock mLock = new ReentrantLock(); 726ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 727ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private Condition mSignal; 728ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 729ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void setCount(int value) { 730ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 731ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin count = value; 732ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.unlock(); 733ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 734ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 735ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public int getCount() { 736ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin int value; 737ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 738ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin value = count; 739ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.unlock(); 740ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return value; 741ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 742ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 743abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public int addCount(int value) { 744ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 745abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin try { 746abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin count += value; 747abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin return count; 748abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } finally { 749abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mLock.unlock(); 750abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 751ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 752ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 753abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin BlockSignalProtocol() { 754ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin count = 0; 755ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mSignal = mLock.newCondition(); 756ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 757ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 758ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void block() throws InterruptedException { 759ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 760ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin try { 761ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin while (count != 0) { 762ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Spin to deal with spurious signals. 763ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mSignal.await(); 764ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 765ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } catch (InterruptedException e) { 766ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // TODO: on interruption, figure out what to do. 767ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw (e); 7683c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin } finally { 7693c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin mLock.unlock(); 770ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 771ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 772ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 773ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void signal() { 774ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 775ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mSignal.signal(); 776ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.unlock(); 777ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 778ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 779ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 780ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 781abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 782abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * A simple tuple class to keep track of image reference, and whether to 783abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * block and/or close on final image release. Instantiated on every task 784abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * submission call. 785abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 786abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin static public class ImageReleaseProtocol extends BlockSignalProtocol { 787abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 788abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public final boolean blockUntilRelease; 789abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 790abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public final boolean closeOnRelease; 791abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 792abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ImageReleaseProtocol(boolean block, boolean close) { 793abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin super(); 794abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin blockUntilRelease = block; 795abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin closeOnRelease = close; 796abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 797abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 798abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 799abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 800ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Thread factories for a default constructor 801ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private class FastThreadFactory implements ThreadFactory { 802ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 803ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public Thread newThread(Runnable r) { 804ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Thread t = new Thread(r); 805ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin t.setPriority(FAST_THREAD_PRIORITY); 806ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return t; 807ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 808ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 809ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 810ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private class SlowThreadFactory implements ThreadFactory { 811ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 812ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public Thread newThread(Runnable r) { 813ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Thread t = new Thread(r); 814ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin t.setPriority(SLOW_THREAD_PRIORITY); 815ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return t; 816ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 817ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 818ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 819ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin} 820