1b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala/*
2b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * Copyright (C) 2013 The Android Open Source Project
3b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala *
4b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License");
5b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * you may not use this file except in compliance with the License.
6b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * You may obtain a copy of the License at
7b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala *
8b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala *      http://www.apache.org/licenses/LICENSE-2.0
9b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala *
10b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * Unless required by applicable law or agreed to in writing, software
11b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS,
12b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * See the License for the specific language governing permissions and
14b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * limitations under the License.
15b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */
16b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
17b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvalapackage android.media;
18b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
19212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun Heimport android.graphics.ImageFormat;
20212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun Heimport android.os.Handler;
21212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun Heimport android.os.Looper;
22c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hallimport android.os.Message;
23dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun Heimport android.util.Log;
24b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvalaimport android.view.Surface;
25212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
2611c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chenimport dalvik.system.VMRuntime;
2711c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen
28212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun Heimport java.lang.ref.WeakReference;
29212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun Heimport java.nio.ByteBuffer;
30212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun Heimport java.nio.ByteOrder;
31e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun Heimport java.nio.NioUtils;
32dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun Heimport java.util.List;
33dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun Heimport java.util.concurrent.CopyOnWriteArrayList;
34f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport java.util.concurrent.atomic.AtomicBoolean;
35b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
36b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala/**
37b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <p>The ImageReader class allows direct application access to image data
38b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * rendered into a {@link android.view.Surface}</p>
39b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala *
40b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <p>Several Android media API classes accept Surface objects as targets to
41b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * render to, including {@link MediaPlayer}, {@link MediaCodec},
42f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * {@link android.hardware.camera2.CameraDevice}, {@link ImageWriter} and
43b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * {@link android.renderscript.Allocation RenderScript Allocations}. The image
44b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * sizes and formats that can be used with each source vary, and should be
45b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * checked in the documentation for the specific API.</p>
46b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala *
47b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * <p>The image data is encapsulated in {@link Image} objects, and multiple such
48b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * objects can be accessed at the same time, up to the number specified by the
49b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * {@code maxImages} constructor parameter. New images sent to an ImageReader
505e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin * through its {@link Surface} are queued until accessed through the {@link #acquireLatestImage}
515e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin * or {@link #acquireNextImage} call. Due to memory limits, an image source will
52b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * eventually stall or drop Images in trying to render to the Surface if the
53b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * ImageReader does not obtain and release Images at a rate equal to the
54b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala * production rate.</p>
55b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala */
565e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkinpublic class ImageReader implements AutoCloseable {
575e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin
585e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    /**
59e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * Returned by nativeImageSetup when acquiring the image was successful.
605e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     */
61e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    private static final int ACQUIRE_SUCCESS = 0;
62e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    /**
63e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * Returned by nativeImageSetup when we couldn't acquire the buffer,
64e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * because there were no buffers available to acquire.
65e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     */
66e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    private static final int ACQUIRE_NO_BUFS = 1;
67e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    /**
68e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * Returned by nativeImageSetup when we couldn't acquire the buffer
69e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * because the consumer has already acquired {@maxImages} and cannot
70e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * acquire more than that.
71e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     */
72e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    private static final int ACQUIRE_MAX_IMAGES = 2;
73b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
74b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
75f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
76d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * Create a new reader for images of the desired size and format.
77f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
78f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
79f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * The {@code maxImages} parameter determines the maximum number of
80f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link Image} objects that can be be acquired from the
81f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@code ImageReader} simultaneously. Requesting more buffers will use up
82d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * more memory, so it is important to use only the minimum number necessary
83d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * for the use case.
84f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
85f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
86f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * The valid sizes and formats depend on the source of the image data.
87f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
88f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
89d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * If the {@code format} is {@link ImageFormat#PRIVATE PRIVATE}, the created
90d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link ImageReader} will produce images that are not directly accessible
91d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * by the application. The application can still acquire images from this
92d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link ImageReader}, and send them to the
93d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link android.hardware.camera2.CameraDevice camera} for reprocessing via
94d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link ImageWriter} interface. However, the {@link Image#getPlanes()
95d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * getPlanes()} will return an empty array for {@link ImageFormat#PRIVATE
96d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * PRIVATE} format images. The application can check if an existing reader's
97d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * format by calling {@link #getImageFormat()}.
98d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * </p>
99d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * <p>
100d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link ImageFormat#PRIVATE PRIVATE} format {@link ImageReader
101d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * ImageReaders} are more efficient to use when application access to image
102d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * data is not necessary, compared to ImageReaders using other format such
103d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * as {@link ImageFormat#YUV_420_888 YUV_420_888}.
104f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
105f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
106f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param width The default width in pixels of the Images that this reader
107f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            will produce.
108f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param height The default height in pixels of the Images that this reader
109f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            will produce.
110d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * @param format The format of the Image that this reader will produce. This
111d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     *            must be one of the {@link android.graphics.ImageFormat} or
112d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     *            {@link android.graphics.PixelFormat} constants. Note that not
113d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     *            all formats are supported, like ImageFormat.NV21.
114f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param maxImages The maximum number of images the user will want to
115f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            access simultaneously. This should be as small as possible to
116f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            limit memory use. Once maxImages Images are obtained by the
117f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            user, one of them has to be released before a new Image will
118f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            become available for access through
119f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
120f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            Must be greater than 0.
121f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @see Image
122f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
123d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He    public static ImageReader newInstance(int width, int height, int format, int maxImages) {
124d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He        return new ImageReader(width, height, format, maxImages);
125f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
126f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
127f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
1285e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @hide
1295e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     */
1305e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    protected ImageReader(int width, int height, int format, int maxImages) {
131b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        mWidth = width;
132b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        mHeight = height;
133b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        mFormat = format;
134b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        mMaxImages = maxImages;
135b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
136b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        if (width < 1 || height < 1) {
137b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala            throw new IllegalArgumentException(
138b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala                "The image dimensions must be positive");
139b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        }
140b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        if (mMaxImages < 1) {
141b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala            throw new IllegalArgumentException(
142b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala                "Maximum outstanding image count must be at least 1");
143b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        }
144212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
1454eda9f5359347c11914e47f477535c9533674d32Zhijun He        if (format == ImageFormat.NV21) {
1464eda9f5359347c11914e47f477535c9533674d32Zhijun He            throw new IllegalArgumentException(
1474eda9f5359347c11914e47f477535c9533674d32Zhijun He                    "NV21 format is not supported");
1484eda9f5359347c11914e47f477535c9533674d32Zhijun He        }
1494eda9f5359347c11914e47f477535c9533674d32Zhijun He
150dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
151212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
152212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        nativeInit(new WeakReference<ImageReader>(this), width, height, format, maxImages);
153212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
154212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        mSurface = nativeGetSurface();
15511c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen
1568e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He        mIsReaderValid = true;
15711c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        // Estimate the native buffer allocation size and register it so it gets accounted for
15811c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        // during GC. Note that this doesn't include the buffers required by the buffer queue
15911c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        // itself and the buffers requested by the producer.
16004a935162c0af649987108058f81405930408014Eino-Ville Talvala        // Only include memory for 1 buffer, since actually accounting for the memory used is
16104a935162c0af649987108058f81405930408014Eino-Ville Talvala        // complex, and 1 buffer is enough for the VM to treat the ImageReader as being of some
16204a935162c0af649987108058f81405930408014Eino-Ville Talvala        // size.
16304a935162c0af649987108058f81405930408014Eino-Ville Talvala        mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
16404a935162c0af649987108058f81405930408014Eino-Ville Talvala                width, height, format, /*buffer count*/ 1);
16511c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
166b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
167b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
1685e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    /**
1698d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * The default width of {@link Image Images}, in pixels.
1705e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
1718d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * <p>The width may be overridden by the producer sending buffers to this
1728d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * ImageReader's Surface. If so, the actual width of the images can be
1738d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * found using {@link Image#getWidth}.</p>
1745e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
1758d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * @return the expected width of an Image
1765e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     */
177b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    public int getWidth() {
178b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        return mWidth;
179b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
180b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
1815e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    /**
1828d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * The default height of {@link Image Images}, in pixels.
1835e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
1848d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * <p>The height may be overridden by the producer sending buffers to this
1858d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * ImageReader's Surface. If so, the actual height of the images can be
1868d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * found using {@link Image#getHeight}.</p>
1875e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
1888d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * @return the expected height of an Image
1895e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     */
190b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    public int getHeight() {
191b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        return mHeight;
192b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
193b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
1945e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    /**
1958d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * The default {@link ImageFormat image format} of {@link Image Images}.
1965e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
1978d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * <p>Some color formats may be overridden by the producer sending buffers to
1988d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * this ImageReader's Surface if the default color format allows. ImageReader
1998d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * guarantees that all {@link Image Images} acquired from ImageReader
2008d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * (for example, with {@link #acquireNextImage}) will have a "compatible"
2018d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * format to what was specified in {@link #newInstance}.
2028d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * As of now, each format is only compatible to itself.
2038d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * The actual format of the images can be found using {@link Image#getFormat}.</p>
2045e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
2058d563a20776b476df77f2a4f3de1feebcf7c255fLajos Molnar     * @return the expected format of an Image
2065e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
2075e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @see ImageFormat
2085e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     */
209b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    public int getImageFormat() {
210b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        return mFormat;
211b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
212b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
2135e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    /**
2145e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * Maximum number of images that can be acquired from the ImageReader by any time (for example,
2155e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * with {@link #acquireNextImage}).
2165e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
2175e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>An image is considered acquired after it's returned by a function from ImageReader, and
2185e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * until the Image is {@link Image#close closed} to release the image back to the ImageReader.
2195e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * </p>
2205e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
2215e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>Attempting to acquire more than {@code maxImages} concurrently will result in the
222e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * acquire function throwing a {@link IllegalStateException}. Furthermore,
2235e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * while the max number of images have been acquired by the ImageReader user, the producer
2245e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * enqueueing additional images may stall until at least one image has been released. </p>
2255e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
2265e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @return Maximum number of images for this ImageReader.
2275e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
2285e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @see Image#close
2295e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     */
230b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    public int getMaxImages() {
231b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        return mMaxImages;
232b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
233b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
234b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
2355e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
2365e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@code ImageReader}.</p>
237b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
2385e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>Until valid image data is rendered into this {@link Surface}, the
2395e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link #acquireNextImage} method will return {@code null}. Only one source
240b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * can be producing data into this Surface at the same time, although the
2415e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * same {@link Surface} can be reused with a different API once the first source is
2425e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * disconnected from the {@link Surface}.</p>
243b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
2445e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @return A {@link Surface} to use for a drawing target for various APIs.
245b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
246b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    public Surface getSurface() {
247212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        return mSurface;
248b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
249b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
250b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
251dd0643202de80cc4ced37d1844e722c8a5e89154Igor Murashkin     * <p>
2525e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * Acquire the latest {@link Image} from the ImageReader's queue, dropping older
2535e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link Image images}. Returns {@code null} if no new image is available.
2545e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * </p>
2555e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>
2565e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * This operation will acquire all the images possible from the ImageReader,
2575e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * but {@link #close} all images that aren't the latest. This function is
2585e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * recommended to use over {@link #acquireNextImage} for most use-cases, as it's
2595e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * more suited for real-time processing.
2605e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * </p>
2615e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>
2625e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * Note that {@link #getMaxImages maxImages} should be at least 2 for
2635e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link #acquireLatestImage} to be any different than {@link #acquireNextImage} -
2645e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * discarding all-but-the-newest {@link Image} requires temporarily acquiring two
2655e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link Image Images} at once. Or more generally, calling {@link #acquireLatestImage}
2665e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * with less than two images of margin, that is
2675e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@code (maxImages - currentAcquiredImages < 2)} will not discard as expected.
2685e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * </p>
2695e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>
270e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * This operation will fail by throwing an {@link IllegalStateException} if
2715e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@code maxImages} have been acquired with {@link #acquireLatestImage} or
2725e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link #acquireNextImage}. In particular a sequence of {@link #acquireLatestImage}
2735e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * calls greater than {@link #getMaxImages} without calling {@link Image#close} in-between
274e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * will exhaust the underlying queue. At such a time, {@link IllegalStateException}
2755e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * will be thrown until more images are
2765e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * released with {@link Image#close}.
2775e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * </p>
2785e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
2795e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @return latest frame of image data, or {@code null} if no image data is available.
280e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @throws IllegalStateException if too many images are currently acquired
2815e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     */
282e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    public Image acquireLatestImage() {
2835e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin        Image image = acquireNextImage();
2845e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin        if (image == null) {
2855e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin            return null;
2865e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin        }
2875e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin        try {
2885e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin            for (;;) {
289e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin                Image next = acquireNextImageNoThrowISE();
2905e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin                if (next == null) {
2915e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin                    Image result = image;
2925e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin                    image = null;
2935e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin                    return result;
2945e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin                }
2955e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin                image.close();
2965e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin                image = next;
2975e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin            }
2985e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin        } finally {
2995e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin            if (image != null) {
3005e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin                image.close();
3015e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin            }
3025e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin        }
3035e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    }
3045e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin
305e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    /**
306e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * Don't throw IllegalStateException if there are too many images acquired.
307e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     *
308e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @return Image if acquiring succeeded, or null otherwise.
309e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     *
310e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @hide
311e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     */
312e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    public Image acquireNextImageNoThrowISE() {
313ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        SurfaceImage si = new SurfaceImage(mFormat);
314e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin        return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
315e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    }
316e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin
317e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    /**
318e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * Attempts to acquire the next image from the underlying native implementation.
319e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     *
320e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * <p>
321e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * Note that unexpected failures will throw at the JNI level.
322e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * </p>
323e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     *
324e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @param si A blank SurfaceImage.
325e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @return One of the {@code ACQUIRE_*} codes that determine success or failure.
326e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     *
327e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @see #ACQUIRE_MAX_IMAGES
328e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @see #ACQUIRE_NO_BUFS
329e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @see #ACQUIRE_SUCCESS
330e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     */
331e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    private int acquireNextSurfaceImage(SurfaceImage si) {
332dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        synchronized (mCloseLock) {
3338e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            // A null image will eventually be returned if ImageReader is already closed.
3348e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            int status = ACQUIRE_NO_BUFS;
3358e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            if (mIsReaderValid) {
3368e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He                status = nativeImageSetup(si);
3378e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            }
338dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He
339dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            switch (status) {
340dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                case ACQUIRE_SUCCESS:
341dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                    si.mIsImageValid = true;
342dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                case ACQUIRE_NO_BUFS:
343dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                case ACQUIRE_MAX_IMAGES:
344dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                    break;
345dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                default:
346dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                    throw new AssertionError("Unknown nativeImageSetup return code " + status);
347dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            }
348e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin
349dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            // Only keep track the successfully acquired image, as the native buffer is only mapped
350dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            // for such case.
351dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            if (status == ACQUIRE_SUCCESS) {
352dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                mAcquiredImages.add(si);
353dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            }
354dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            return status;
3555e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin        }
3565e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    }
3575e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin
3585e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    /**
3595e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>
3605e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * Acquire the next Image from the ImageReader's queue. Returns {@code null} if
361dd0643202de80cc4ced37d1844e722c8a5e89154Igor Murashkin     * no new image is available.
362dd0643202de80cc4ced37d1844e722c8a5e89154Igor Murashkin     * </p>
3635e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
3645e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p><i>Warning:</i> Consider using {@link #acquireLatestImage()} instead, as it will
3655e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * automatically release older images, and allow slower-running processing routines to catch
3665e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * up to the newest frame. Usage of {@link #acquireNextImage} is recommended for
3675e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * batch/background processing. Incorrectly using this function can cause images to appear
3685e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * with an ever-increasing delay, followed by a complete stall where no new images seem to
3695e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * appear.
3705e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * </p>
3715e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
372dd0643202de80cc4ced37d1844e722c8a5e89154Igor Murashkin     * <p>
373e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * This operation will fail by throwing an {@link IllegalStateException} if
3745e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@code maxImages} have been acquired with {@link #acquireNextImage} or
3755e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link #acquireLatestImage}. In particular a sequence of {@link #acquireNextImage} or
3765e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link #acquireLatestImage} calls greater than {@link #getMaxImages maxImages} without
3775e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * calling {@link Image#close} in-between will exhaust the underlying queue. At such a time,
378e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * {@link IllegalStateException} will be thrown until more images are released with
3795e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link Image#close}.
380dd0643202de80cc4ced37d1844e722c8a5e89154Igor Murashkin     * </p>
381b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     *
3825e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @return a new frame of image data, or {@code null} if no image data is available.
383e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @throws IllegalStateException if {@code maxImages} images are currently acquired
3845e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @see #acquireLatestImage
385b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
386e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    public Image acquireNextImage() {
387ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        // Initialize with reader format, but can be overwritten by native if the image
388ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        // format is different from the reader format.
389ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        SurfaceImage si = new SurfaceImage(mFormat);
390e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin        int status = acquireNextSurfaceImage(si);
391e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin
392e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin        switch (status) {
393e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin            case ACQUIRE_SUCCESS:
394e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin                return si;
395e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin            case ACQUIRE_NO_BUFS:
396e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin                return null;
397e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin            case ACQUIRE_MAX_IMAGES:
398e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin                throw new IllegalStateException(
399e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin                        String.format(
400e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin                                "maxImages (%d) has already been acquired, " +
401e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin                                "call #close before acquiring more.", mMaxImages));
402e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin            default:
403e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin                throw new AssertionError("Unknown nativeImageSetup return code " + status);
404212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
405b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
406b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
407b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    /**
408b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     * <p>Return the frame to the ImageReader for reuse.</p>
409b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala     */
4105e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    private void releaseImage(Image i) {
411b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        if (! (i instanceof SurfaceImage) ) {
412b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala            throw new IllegalArgumentException(
413b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala                "This image was not produced by an ImageReader");
414b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        }
415b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        SurfaceImage si = (SurfaceImage) i;
416dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        if (si.mIsImageValid == false) {
417dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            return;
418dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        }
419dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He
420dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        if (si.getReader() != this || !mAcquiredImages.contains(i)) {
421b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala            throw new IllegalArgumentException(
422b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala                "This image was not produced by this ImageReader");
423b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        }
424212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
425212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        si.clearSurfacePlanes();
426212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        nativeReleaseImage(i);
427a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He        si.mIsImageValid = false;
428dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        mAcquiredImages.remove(i);
429b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
430b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
431212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    /**
432212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * Register a listener to be invoked when a new image becomes available
433212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * from the ImageReader.
434dd0643202de80cc4ced37d1844e722c8a5e89154Igor Murashkin     *
4355e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @param listener
4365e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *            The listener that will be run.
4375e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @param handler
4385e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *            The handler on which the listener should be invoked, or null
4395e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *            if the listener should be invoked on the calling thread's looper.
4405e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * @throws IllegalArgumentException
4415e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *            If no handler specified and the calling thread has no looper.
442212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     */
443c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall    public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
444c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        synchronized (mListenerLock) {
445c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall            if (listener != null) {
446c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
447c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                if (looper == null) {
448c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                    throw new IllegalArgumentException(
449c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                            "handler is null but the current thread is not a looper");
450c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                }
451c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
452c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                    mListenerHandler = new ListenerHandler(looper);
453c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                }
454c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                mListener = listener;
455212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            } else {
456c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                mListener = null;
457c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                mListenerHandler = null;
458212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            }
459212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
460b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
461b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
462212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    /**
463212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * Callback interface for being notified that a new image is available.
4645e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
4655e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>
466212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * The onImageAvailable is called per image basis, that is, callback fires for every new frame
467212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * available from ImageReader.
4685e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * </p>
469212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     */
470b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    public interface OnImageAvailableListener {
471212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        /**
472212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         * Callback that is called when a new image is available from ImageReader.
4735e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin         *
474212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         * @param reader the ImageReader the callback is associated with.
475212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         * @see ImageReader
476212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         * @see Image
477212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         */
478b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        void onImageAvailable(ImageReader reader);
479b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
480b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
481212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    /**
4825e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * Free up all the resources associated with this ImageReader.
4835e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     *
4845e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * <p>
4855e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * After calling this method, this ImageReader can not be used. Calling
4865e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * any methods on this ImageReader and Images previously provided by
4875e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link #acquireNextImage} or {@link #acquireLatestImage}
4885e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * will result in an {@link IllegalStateException}, and attempting to read from
4895e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link ByteBuffer ByteBuffers} returned by an earlier
4905e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * {@link Image.Plane#getBuffer Plane#getBuffer} call will
491212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * have undefined behavior.
4925e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin     * </p>
493212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     */
494212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    @Override
495212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    public void close() {
496c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        setOnImageAvailableListener(null, null);
497443ab2c7dbe2a3a482892f3171882572f10eab9aRuben Brunk        if (mSurface != null) mSurface.release();
498dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He
499dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        /**
500dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He         * Close all outstanding acquired images before closing the ImageReader. It is a good
501dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He         * practice to close all the images as soon as it is not used to reduce system instantaneous
502dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He         * memory pressure. CopyOnWrite list will use a copy of current list content. For the images
503dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He         * being closed by other thread (e.g., GC thread), doubling the close call is harmless. For
504dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He         * the image being acquired by other threads, mCloseLock is used to synchronize close and
505dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He         * acquire operations.
506dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He         */
507dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        synchronized (mCloseLock) {
5088e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            mIsReaderValid = false;
509dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            for (Image image : mAcquiredImages) {
510dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                image.close();
511dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            }
512dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            mAcquiredImages.clear();
513dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He
514dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            nativeClose();
515dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        }
516dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He
51711c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        if (mEstimatedNativeAllocBytes > 0) {
51811c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            VMRuntime.getRuntime().registerNativeFree(mEstimatedNativeAllocBytes);
51911c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            mEstimatedNativeAllocBytes = 0;
52011c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        }
521212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    }
522212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
523212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    @Override
524212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    protected void finalize() throws Throwable {
525212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        try {
526212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            close();
527212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        } finally {
528212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            super.finalize();
529212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
530212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    }
531212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
532708e3595031fa15f4ac26c5675a53c1ed495b895Zhijun He    /**
533f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
534f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Remove the ownership of this image from the ImageReader.
535f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
536f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
537f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * After this call, the ImageReader no longer owns this image, and the image
538f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * ownership can be transfered to another entity like {@link ImageWriter}
539f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * via {@link ImageWriter#queueInputImage}. It's up to the new owner to
540f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * release the resources held by this image. For example, if the ownership
541f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * of this image is transfered to an {@link ImageWriter}, the image will be
542f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * freed by the ImageWriter after the image data consumption is done.
543f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
544f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
545f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * This method can be used to achieve zero buffer copy for use cases like
546d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link android.hardware.camera2.CameraDevice Camera2 API} PRIVATE and YUV
547f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * reprocessing, where the application can select an output image from
548f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link ImageReader} and transfer this image directly to
549f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link ImageWriter}, where this image can be consumed by camera directly.
550d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * For PRIVATE reprocessing, this is the only way to send input buffers to
551f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * the {@link android.hardware.camera2.CameraDevice camera} for
552f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * reprocessing.
553f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
554f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
555f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * This is a package private method that is only used internally.
556f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
557f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
558f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param image The image to be detached from this ImageReader.
559f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @throws IllegalStateException If the ImageReader or image have been
560f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *             closed, or the has been detached, or has not yet been
561f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *             acquired.
562f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
563f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     void detachImage(Image image) {
564f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He       if (image == null) {
565f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He           throw new IllegalArgumentException("input image must not be null");
566f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He       }
567f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He       if (!isImageOwnedbyMe(image)) {
568f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He           throw new IllegalArgumentException("Trying to detach an image that is not owned by"
569f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                   + " this ImageReader");
570f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He       }
571f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
572f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        SurfaceImage si = (SurfaceImage) image;
573ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        si.throwISEIfImageIsInvalid();
574ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
575f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (si.isAttachable()) {
576f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalStateException("Image was already detached from this ImageReader");
577f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
578f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
579f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        nativeDetachImage(image);
580f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        si.setDetached(true);
58144581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh    }
582f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
583f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private boolean isImageOwnedbyMe(Image image) {
584f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (!(image instanceof SurfaceImage)) {
585f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return false;
586f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
587f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        SurfaceImage si = (SurfaceImage) image;
588f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return si.getReader() == this;
589f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
590f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
591212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    /**
592212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * Called from Native code when an Event happens.
593c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall     *
594c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall     * This may be called from an arbitrary Binder thread, so access to the ImageReader must be
595c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall     * synchronized appropriately.
596212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     */
597212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    private static void postEventFromNative(Object selfRef) {
598dd0643202de80cc4ced37d1844e722c8a5e89154Igor Murashkin        @SuppressWarnings("unchecked")
599dd0643202de80cc4ced37d1844e722c8a5e89154Igor Murashkin        WeakReference<ImageReader> weakSelf = (WeakReference<ImageReader>)selfRef;
600dd0643202de80cc4ced37d1844e722c8a5e89154Igor Murashkin        final ImageReader ir = weakSelf.get();
601212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        if (ir == null) {
602212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            return;
603212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
604212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
605c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        final Handler handler;
606c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        synchronized (ir.mListenerLock) {
607c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall            handler = ir.mListenerHandler;
608c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        }
609c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        if (handler != null) {
610c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall            handler.sendEmptyMessage(0);
611212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
612212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    }
613212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
614b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    private final int mWidth;
615b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    private final int mHeight;
616b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    private final int mFormat;
617b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    private final int mMaxImages;
618212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    private final int mNumPlanes;
619212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    private final Surface mSurface;
62011c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen    private int mEstimatedNativeAllocBytes;
621b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
622c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall    private final Object mListenerLock = new Object();
623dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He    private final Object mCloseLock = new Object();
6248e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He    private boolean mIsReaderValid = false;
625c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall    private OnImageAvailableListener mListener;
626c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall    private ListenerHandler mListenerHandler;
627dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He    // Keep track of the successfully acquired Images. This need to be thread safe as the images
628dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He    // could be closed by different threads (e.g., application thread and GC thread).
629dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He    private List<Image> mAcquiredImages = new CopyOnWriteArrayList<Image>();
630b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
631212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    /**
632212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * This field is used by native code, do not access or modify.
633212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     */
634212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    private long mNativeContext;
635212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
636c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall    /**
637c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall     * This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
638c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall     */
639c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall    private final class ListenerHandler extends Handler {
640c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        public ListenerHandler(Looper looper) {
641c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall            super(looper, null, true /*async*/);
642c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        }
643c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall
644c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        @Override
645c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        public void handleMessage(Message msg) {
646c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall            OnImageAvailableListener listener;
647c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall            synchronized (mListenerLock) {
648c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                listener = mListener;
649c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall            }
6508e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He
6518e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            // It's dangerous to fire onImageAvailable() callback when the ImageReader is being
6528e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            // closed, as application could acquire next image in the onImageAvailable() callback.
6538e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            boolean isReaderValid = false;
6548e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            synchronized (mCloseLock) {
6558e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He                isReaderValid = mIsReaderValid;
6568e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            }
6578e694e3b494b0fc857dcd981c57687ecea543c02Zhijun He            if (listener != null && isReaderValid) {
658c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall                listener.onImageAvailable(ImageReader.this);
659c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall            }
660c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall        }
661c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall    }
662c395fffd901f5670bc2cb41a91af7ad87c39790eJesse Hall
6635e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    private class SurfaceImage extends android.media.Image {
664ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        public SurfaceImage(int format) {
665ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            mFormat = format;
666b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        }
667b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
668b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        @Override
669b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        public void close() {
670dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            ImageReader.this.releaseImage(this);
671b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        }
672b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala
673b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        public ImageReader getReader() {
674b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala            return ImageReader.this;
675b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala        }
676212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
677212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        @Override
678212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        public int getFormat() {
679ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
6807c3997d96a2571295a97457264832d54b05ee966Zhijun He            int readerFormat = ImageReader.this.getImageFormat();
6817c3997d96a2571295a97457264832d54b05ee966Zhijun He            // Assume opaque reader always produce opaque images.
6827c3997d96a2571295a97457264832d54b05ee966Zhijun He            mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
6837c3997d96a2571295a97457264832d54b05ee966Zhijun He                nativeGetFormat(readerFormat);
684ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            return mFormat;
685212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
686212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
687212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        @Override
688212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        public int getWidth() {
689ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
69072064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala            int width;
69172064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala            switch(getFormat()) {
69272064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                case ImageFormat.JPEG:
69372064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                case ImageFormat.DEPTH_POINT_CLOUD:
69444581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                case ImageFormat.RAW_PRIVATE:
69572064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                    width = ImageReader.this.getWidth();
69672064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                    break;
69772064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                default:
6980ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                    width = nativeGetWidth();
69972064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala            }
70072064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala            return width;
701212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
702212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
703212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        @Override
704212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        public int getHeight() {
705ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
70672064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala            int height;
70772064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala            switch(getFormat()) {
70872064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                case ImageFormat.JPEG:
70972064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                case ImageFormat.DEPTH_POINT_CLOUD:
71044581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                case ImageFormat.RAW_PRIVATE:
71172064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                    height = ImageReader.this.getHeight();
71272064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                    break;
71372064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala                default:
7140ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                    height = nativeGetHeight();
71572064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala            }
71672064af7e75f7e3b2eb2e58a3af408861eb8c4e9Eino-Ville Talvala            return height;
717212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
718212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
719212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        @Override
720212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        public long getTimestamp() {
721ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
722ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            return mTimestamp;
723212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
724212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
725212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        @Override
726f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public void setTimestamp(long timestampNs) {
727ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
728ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            mTimestamp = timestampNs;
729f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
730f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
731f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
732212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        public Plane[] getPlanes() {
733ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
7340ab416269a866c8afa8f65d9351afa2407abee4cZhijun He
7350ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            if (mPlanes == null) {
7360ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
7370ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            }
738ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            // Shallow copy is fine.
739ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            return mPlanes.clone();
740212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
741212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
742212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        @Override
743212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        protected final void finalize() throws Throwable {
744212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            try {
745212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                close();
746212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            } finally {
747212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                super.finalize();
748212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            }
749212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
750212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
751f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
752f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        boolean isAttachable() {
753ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
754f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return mIsDetached.get();
755f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
756f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
757f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
758f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ImageReader getOwner() {
759ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
760f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return ImageReader.this;
761f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
762f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
763ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        @Override
764ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        long getNativeContext() {
765ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
766ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            return mNativeBuffer;
767ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        }
768ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
769f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private void setDetached(boolean detached) {
770ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throwISEIfImageIsInvalid();
771f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            mIsDetached.getAndSet(detached);
772f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
773f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
774212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        private void clearSurfacePlanes() {
7750ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            // Image#getPlanes may not be called before the image is closed.
7760ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            if (mIsImageValid && mPlanes != null) {
777212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                for (int i = 0; i < mPlanes.length; i++) {
778212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                    if (mPlanes[i] != null) {
779212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                        mPlanes[i].clearBuffer();
780212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                        mPlanes[i] = null;
781212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                    }
782212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                }
783212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            }
784212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
785212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
7865e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin        private class SurfacePlane extends android.media.Image.Plane {
7870ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
7880ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            // called
7890ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
790212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                mRowStride = rowStride;
791212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                mPixelStride = pixelStride;
7920ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                mBuffer = buffer;
7930ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                /**
7940ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                 * Set the byteBuffer order according to host endianness (native
7950ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                 * order), otherwise, the byteBuffer order defaults to
7960ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                 * ByteOrder.BIG_ENDIAN.
7970ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                 */
7980ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                mBuffer.order(ByteOrder.nativeOrder());
799212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            }
800212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
801212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            @Override
802212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            public ByteBuffer getBuffer() {
8030ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                throwISEIfImageIsInvalid();
8040ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                return mBuffer;
805212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            }
806212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
807212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            @Override
808212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            public int getPixelStride() {
809ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                SurfaceImage.this.throwISEIfImageIsInvalid();
81044581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                if (ImageReader.this.mFormat == ImageFormat.RAW_PRIVATE) {
81144581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                    throw new UnsupportedOperationException(
81244581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                            "getPixelStride is not supported for RAW_PRIVATE plane");
81344581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                }
814ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                return mPixelStride;
815212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            }
816212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
817212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            @Override
818212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            public int getRowStride() {
819ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                SurfaceImage.this.throwISEIfImageIsInvalid();
82044581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                if (ImageReader.this.mFormat == ImageFormat.RAW_PRIVATE) {
82144581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                    throw new UnsupportedOperationException(
82244581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                            "getRowStride is not supported for RAW_PRIVATE plane");
82344581ff4db54bbaa30365ed210e67a0369576100Yin-Chia Yeh                }
824ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                return mRowStride;
825212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            }
826212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
827212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            private void clearBuffer() {
828e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun He                // Need null check first, as the getBuffer() may not be called before an image
829e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun He                // is closed.
830e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun He                if (mBuffer == null) {
831e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun He                    return;
832e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun He                }
833e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun He
834e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun He                if (mBuffer.isDirect()) {
835e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun He                    NioUtils.freeDirectBuffer(mBuffer);
836e09dcdba7161170a6b052dffe2a5608d1f07548bZhijun He                }
837212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                mBuffer = null;
838212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            }
839212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
840212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            final private int mPixelStride;
841212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            final private int mRowStride;
842212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
843212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He            private ByteBuffer mBuffer;
844212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        }
845212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
846212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        /**
847212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         * This field is used to keep track of native object and used by native code only.
848212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         * Don't modify.
849212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         */
850ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        private long mNativeBuffer;
851212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
852212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        /**
853212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         * This field is set by native code during nativeImageSetup().
854212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He         */
855212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        private long mTimestamp;
856212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
857212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        private SurfacePlane[] mPlanes;
858ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        private int mFormat = ImageFormat.UNKNOWN;
859f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // If this image is detached from the ImageReader.
860f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private AtomicBoolean mIsDetached = new AtomicBoolean(false);
861212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
8620ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
8630ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                int readerFormat);
8640ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        private synchronized native int nativeGetWidth();
8650ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        private synchronized native int nativeGetHeight();
8667c3997d96a2571295a97457264832d54b05ee966Zhijun He        private synchronized native int nativeGetFormat(int readerFormat);
867212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    }
868212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
869212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    private synchronized native void nativeInit(Object weakSelf, int w, int h,
870212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He                                                    int fmt, int maxImgs);
871212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    private synchronized native void nativeClose();
872212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    private synchronized native void nativeReleaseImage(Image i);
873212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    private synchronized native Surface nativeGetSurface();
874ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    private synchronized native int nativeDetachImage(Image i);
875e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin
876e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    /**
877e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @return A return code {@code ACQUIRE_*}
878e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     *
879e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @see #ACQUIRE_SUCCESS
880e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @see #ACQUIRE_NO_BUFS
881e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     * @see #ACQUIRE_MAX_IMAGES
882e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin     */
883e3351f1942bfe86682389b278e7ff128a72ea671Igor Murashkin    private synchronized native int nativeImageSetup(Image i);
884212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He
8855e712064dfe48992f8f732208fa4fc13f3455b30Igor Murashkin    /**
886212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * We use a class initializer to allow the native code to cache some
887212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     * field offsets.
888212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He     */
889212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    private static native void nativeClassInit();
890212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He    static {
891212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        System.loadLibrary("media_jni");
892212e78df9eb3bfff069de01aa7820cf4201c5f82Zhijun He        nativeClassInit();
893b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala    }
894b2675542c2f414154125b534767ae0903fba581eEino-Ville Talvala}
895