Home | History | Annotate | Download | only in sharedimagereader
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera.one.v2.sharedimagereader;
     18 
     19 import android.media.ImageReader;
     20 import android.view.Surface;
     21 
     22 import com.android.camera.async.BufferQueue;
     23 import com.android.camera.async.BufferQueueController;
     24 import com.android.camera.async.ConcurrentBufferQueue;
     25 import com.android.camera.async.Lifetime;
     26 import com.android.camera.one.v2.camera2proxy.ImageProxy;
     27 import com.android.camera.one.v2.core.CaptureStream;
     28 import com.android.camera.one.v2.core.FrameServer;
     29 import com.android.camera.one.v2.core.RequestBuilder;
     30 import com.android.camera.one.v2.core.ResourceAcquisitionFailedException;
     31 import com.android.camera.one.v2.sharedimagereader.imagedistributor.ImageDistributor;
     32 import com.android.camera.one.v2.sharedimagereader.imagedistributor.ImageStream;
     33 import com.android.camera.one.v2.sharedimagereader.ticketpool.ReservableTicketPool;
     34 import com.android.camera.one.v2.sharedimagereader.ticketpool.TicketPool;
     35 import com.android.camera.one.v2.sharedimagereader.util.ImageCloser;
     36 
     37 /**
     38  * Builds {@link CaptureStream}s which can share the same underlying
     39  * {@link ImageReader}.
     40  * <p>
     41  * Example usage:
     42  *
     43  * <pre>
     44  * RequestBuilder builder = ...;
     45  *
     46  * // Create a stream which holds 3 images.
     47  * ImageStream stream = managedImageReader.createStream(3);
     48  *
     49  * builder.addStream(stream);
     50  * builder.setParam(...);
     51  *
     52  * frameServer.sendRequest(builder.build());
     53  * frameServer.sendRequest(builder.build());
     54  * frameServer.sendRequest(builder.build());
     55  *
     56  * // Synchronously receive the images as they arrive...
     57  * ImageProxy image1 = stream.getNext();
     58  * ImageProxy image2 = stream.getNext();
     59  * ImageProxy image3 = stream.getNext();
     60  *
     61  * // Close the stream when no more images are expected.
     62  * stream.close();
     63  *
     64  * // Process the Images...
     65  *
     66  * // Close the images.
     67  * image1.close();
     68  * image2.close();
     69  * image3.close();
     70  * </pre>
     71  */
     72 public class ManagedImageReader {
     73     private final Lifetime mLifetime;
     74     private final TicketPool mTicketPool;
     75     /**
     76      * The {@link ImageReader} surface.
     77      */
     78     private final Surface mSurface;
     79 
     80     private final ImageDistributor mImageDistributor;
     81 
     82     /**
     83      * @param lifetime
     84      * @param ticketPool
     85      * @param surface
     86      * @param imageDistributor
     87      */
     88     public ManagedImageReader(Lifetime lifetime, TicketPool ticketPool, Surface surface,
     89                               ImageDistributor imageDistributor) {
     90         mLifetime = lifetime;
     91         mTicketPool = ticketPool;
     92         mSurface = surface;
     93         mImageDistributor = imageDistributor;
     94     }
     95 
     96     private AllocatingImageStream createUnallocatedStream(int capacity) {
     97         ReservableTicketPool ticketPool = new ReservableTicketPool(mTicketPool);
     98         mLifetime.add(ticketPool);
     99 
    100         ConcurrentBufferQueue<ImageProxy> imageStream = new ConcurrentBufferQueue<>(new
    101                 ImageCloser());
    102         mLifetime.add(imageStream);
    103 
    104         BufferQueueController<ImageProxy> imageStreamController = new
    105                 TicketRequiredFilter(ticketPool, imageStream);
    106         mLifetime.add(imageStreamController);
    107 
    108         AllocatingImageStream stream = new AllocatingImageStream(capacity,
    109                 ticketPool, imageStream, imageStreamController, mImageDistributor, mSurface);
    110         mLifetime.add(stream);
    111 
    112         return stream;
    113     }
    114 
    115     /**
    116      * Creates a logical bounded stream of images with the specified capacity.
    117      * Note that the required image space will be allocated/acquired the first
    118      * time {@link CaptureStream#bind(BufferQueue)} is called, but it will be
    119      * reused on subsequent invocations. So, for example, the stream provider
    120      * may be attached to multiple {@link RequestBuilder}s and the images for
    121      * those requests will share the same ticket pool with size specified by the
    122      * given capacity.
    123      *
    124      * @param capacity The maximum number of images which can be simultaneously
    125      *            held from the resulting image queue before images are dropped.
    126      */
    127     public ImageStream createStream(int capacity) {
    128         return createUnallocatedStream(capacity);
    129     }
    130 
    131     /**
    132      * Creates a logical bounded stream of images with the specified capacity,
    133      * blocking until the required capacity can be reserved.
    134      * <p>
    135      * Note: Unlike using {@link #createStream} with a {@link FrameServer}, this
    136      * method cannot guarantee non-circular-wait to eliminate the possibility of
    137      * deadlock. FrameServer's session lock has already been acquired. Thus,
    138      * there is a possibility of deadlock if callers have not already acquired
    139      * an exclusive session before calling this method.
    140      * <p>
    141      * TODO Use a CycleDetectingLockFactory to detect deadlock-prone misuse of
    142      * this method, and document the required order of resource acquisition at a
    143      * higher-level.
    144      *
    145      * @param capacity The maximum number of images which can be simultaneously
    146      *            held from the resulting image queue before images are dropped.
    147      */
    148     public ImageStream createPreallocatedStream(int capacity) throws InterruptedException,
    149             ResourceAcquisitionFailedException {
    150         AllocatingImageStream stream = createUnallocatedStream(capacity);
    151         try {
    152             stream.allocate();
    153             return stream;
    154         } catch (Exception e) {
    155             // If allocation failed, close the stream before returning.
    156             stream.close();
    157             throw e;
    158         }
    159     }
    160 }
    161