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