• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.camera2proxy;
18 
19 import android.graphics.Rect;
20 import android.media.Image;
21 
22 import com.google.common.base.MoreObjects;
23 import com.google.common.base.Objects;
24 import com.google.common.collect.ImmutableList;
25 
26 import java.nio.ByteBuffer;
27 import java.util.ArrayList;
28 import java.util.List;
29 
30 import javax.annotation.concurrent.GuardedBy;
31 import javax.annotation.concurrent.ThreadSafe;
32 
33 /**
34  * An {@link ImageProxy} backed by an {@link android.media.Image}.
35  */
36 @ThreadSafe
37 public class AndroidImageProxy implements ImageProxy {
38 
39     /**
40      * An {@link ImageProxy.Plane} backed by an
41      * {@link android.media.Image.Plane}.
42      */
43     public class Plane implements ImageProxy.Plane {
44         private final int mPixelStride;
45         private final int mRowStride;
46         private final ByteBuffer mBuffer;
47 
Plane(Image.Plane imagePlane)48         public Plane(Image.Plane imagePlane) {
49             // Copying out the contents of the Image.Plane means that this Plane
50             // implementation can be thread-safe (without requiring any locking)
51             // and can have getters which do not throw a RuntimeException if
52             // the underlying Image is closed.
53             mPixelStride = imagePlane.getPixelStride();
54             mRowStride = imagePlane.getRowStride();
55             mBuffer = imagePlane.getBuffer();
56         }
57 
58         /**
59          * @see {@link android.media.Image.Plane#getRowStride}
60          */
61         @Override
getRowStride()62         public int getRowStride() {
63             return mRowStride;
64         }
65 
66         /**
67          * @see {@link android.media.Image.Plane#getPixelStride}
68          */
69         @Override
getPixelStride()70         public int getPixelStride() {
71             return mPixelStride;
72         }
73 
74         /**
75          * @see {@link android.media.Image.Plane#getBuffer}
76          */
77         @Override
getBuffer()78         public ByteBuffer getBuffer() {
79             return mBuffer;
80         }
81     }
82 
83     private final Object mLock;
84     /**
85      * {@link android.media.Image} is not thread-safe, so all interactions must
86      * be guarded by {@link #mLock}.
87      */
88     @GuardedBy("mLock")
89     private final android.media.Image mImage;
90     private final int mFormat;
91     private final int mWidth;
92     private final int mHeight;
93     private final long mTimestamp;
94     private final ImmutableList<ImageProxy.Plane> mPlanes;
95     @GuardedBy("mLock")
96     private Rect mCropRect;
97 
AndroidImageProxy(android.media.Image image)98     public AndroidImageProxy(android.media.Image image) {
99         mLock = new Object();
100 
101         mImage = image;
102         // Copying out the contents of the Image means that this Image
103         // implementation can be thread-safe (without requiring any locking)
104         // and can have getters which do not throw a RuntimeException if
105         // the underlying Image is closed.
106         mFormat = mImage.getFormat();
107         mWidth = mImage.getWidth();
108         mHeight = mImage.getHeight();
109         mTimestamp = mImage.getTimestamp();
110 
111         Image.Plane[] planes;
112         planes = mImage.getPlanes();
113         if (planes == null) {
114             mPlanes = ImmutableList.of();
115         } else {
116             List<ImageProxy.Plane> wrappedPlanes = new ArrayList<>(planes.length);
117             for (int i = 0; i < planes.length; i++) {
118                 wrappedPlanes.add(new Plane(planes[i]));
119             }
120             mPlanes = ImmutableList.copyOf(wrappedPlanes);
121         }
122     }
123 
124     /**
125      * @see {@link android.media.Image#getCropRect}
126      */
127     @Override
getCropRect()128     public Rect getCropRect() {
129         synchronized (mLock) {
130             try {
131                 mCropRect = mImage.getCropRect();
132             } catch (IllegalStateException imageClosedException) {
133                 // If the image is closed, then just return the cached CropRect.
134                 return mCropRect;
135             }
136             return mCropRect;
137         }
138     }
139 
140     /**
141      * @see {@link android.media.Image#setCropRect}
142      */
143     @Override
setCropRect(Rect cropRect)144     public void setCropRect(Rect cropRect) {
145         synchronized (mLock) {
146             mCropRect = cropRect;
147             try {
148                 mImage.setCropRect(cropRect);
149             } catch (IllegalStateException imageClosedException) {
150                 // Ignore.
151             }
152         }
153     }
154 
155     /**
156      * @see {@link android.media.Image#getFormat}
157      */
158     @Override
getFormat()159     public int getFormat() {
160         return mFormat;
161     }
162 
163     /**
164      * @see {@link android.media.Image#getHeight}
165      */
166     @Override
getHeight()167     public int getHeight() {
168         return mHeight;
169     }
170 
171     /**
172      * @see {@link android.media.Image#getPlanes}
173      */
174     @Override
getPlanes()175     public List<ImageProxy.Plane> getPlanes() {
176         return mPlanes;
177     }
178 
179     /**
180      * @see {@link android.media.Image#getTimestamp}
181      */
182     @Override
getTimestamp()183     public long getTimestamp() {
184         return mTimestamp;
185     }
186 
187     /**
188      * @see {@link android.media.Image#getWidth}
189      */
190     @Override
getWidth()191     public int getWidth() {
192         return mWidth;
193     }
194 
195     /**
196      * @see {@link android.media.Image#close}
197      */
198     @Override
close()199     public void close() {
200         synchronized (mLock) {
201             mImage.close();
202         }
203     }
204 
205     @Override
toString()206     public String toString() {
207         return MoreObjects.toStringHelper(this)
208                 .add("format", getFormat())
209                 .add("timestamp", getTimestamp())
210                 .add("width", getWidth())
211                 .add("height", getHeight())
212                 .toString();
213     }
214 
215     @Override
equals(Object other)216     public boolean equals(Object other) {
217         if (other == null) {
218             return false;
219         }
220         if (!(other instanceof ImageProxy)) {
221             return false;
222         }
223         ImageProxy otherImage = (ImageProxy) other;
224         return otherImage.getFormat() == getFormat() &&
225                 otherImage.getWidth() == getWidth() &&
226                 otherImage.getHeight() == getHeight() &&
227                 otherImage.getTimestamp() == getTimestamp();
228     }
229 
230     @Override
hashCode()231     public int hashCode() {
232         return Objects.hashCode(getFormat(), getWidth(), getHeight(), getTimestamp());
233     }
234 }
235