1f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He/*
2f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Copyright 2015 The Android Open Source Project
3f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He *
4f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Licensed under the Apache License, Version 2.0 (the "License");
5f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * you may not use this file except in compliance with the License.
6f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * You may obtain a copy of the License at
7f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He *
8f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He *      http://www.apache.org/licenses/LICENSE-2.0
9f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He *
10f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Unless required by applicable law or agreed to in writing, software
11f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * distributed under the License is distributed on an "AS IS" BASIS,
12f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * See the License for the specific language governing permissions and
14f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * limitations under the License.
15f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He */
16f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
17f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hepackage android.media;
18f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
19ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun Heimport android.graphics.ImageFormat;
20916d8ac650865cd05808d48bad68b69bebbc95abZhijun Heimport android.graphics.PixelFormat;
21f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport android.graphics.Rect;
22dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun Heimport android.hardware.camera2.utils.SurfaceUtils;
23f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport android.os.Handler;
24f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport android.os.Looper;
25f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport android.os.Message;
26dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun Heimport android.util.Size;
27f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport android.view.Surface;
28f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
29dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun Heimport dalvik.system.VMRuntime;
30dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He
31f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport java.lang.ref.WeakReference;
32f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport java.nio.ByteBuffer;
33f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport java.nio.ByteOrder;
34f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport java.nio.NioUtils;
35f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport java.util.List;
36dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun Heimport java.util.concurrent.CopyOnWriteArrayList;
37f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
38f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He/**
39f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * <p>
40f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * The ImageWriter class allows an application to produce Image data into a
41d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He * {@link android.view.Surface}, and have it be consumed by another component
42d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He * like {@link android.hardware.camera2.CameraDevice CameraDevice}.
43f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * </p>
44f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * <p>
45f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Several Android API classes can provide input {@link android.view.Surface
46f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Surface} objects for ImageWriter to produce data into, including
47f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * {@link MediaCodec MediaCodec} (encoder),
48e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * {@link android.hardware.camera2.CameraCaptureSession CameraCaptureSession}
49e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * (reprocessing input), {@link ImageReader}, etc.
50f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * </p>
51f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * <p>
52f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * The input Image data is encapsulated in {@link Image} objects. To produce
53f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Image data into a destination {@link android.view.Surface Surface}, the
54f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * application can get an input Image via {@link #dequeueInputImage} then write
55f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Image data into it. Multiple such {@link Image} objects can be dequeued at
56f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * the same time and queued back in any order, up to the number specified by the
57f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * {@code maxImages} constructor parameter.
58f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * </p>
59f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * <p>
60f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * If the application already has an Image from {@link ImageReader}, the
61f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * application can directly queue this Image into ImageWriter (via
62d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He * {@link #queueInputImage}), potentially with zero buffer copies. For the
63d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He * {@link ImageFormat#PRIVATE PRIVATE} format Images produced by
64d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He * {@link ImageReader}, this is the only way to send Image data to ImageWriter,
65d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He * as the Image data aren't accessible by the application.
66f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * </p>
67d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He * Once new input Images are queued into an ImageWriter, it's up to the
68d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He * downstream components (e.g. {@link ImageReader} or
69f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the
70f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * downstream components cannot consume the Images at least as fast as the
71d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He * ImageWriter production rate, the {@link #dequeueInputImage} call will
72e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * eventually block and the application will have to drop input frames.
73e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * </p>
74e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * <p>
75e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * If the consumer component that provided the input {@link android.view.Surface Surface}
76e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * abandons the {@link android.view.Surface Surface}, {@link #queueInputImage queueing}
77e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * or {@link #dequeueInputImage dequeueing} an {@link Image} will throw an
78e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * {@link IllegalStateException}.
79e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen * </p>
80f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He */
81f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hepublic class ImageWriter implements AutoCloseable {
82f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private final Object mListenerLock = new Object();
83d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He    private OnImageReleasedListener mListener;
84f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private ListenerHandler mListenerHandler;
85f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private long mNativeContext;
86f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
87f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Field below is used by native code, do not access or modify.
88f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private int mWriterFormat;
89f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
90f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private final int mMaxImages;
91dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He    // Keep track of the currently dequeued Image. This need to be thread safe as the images
92dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He    // could be closed by different threads (e.g., application thread and GC thread).
93916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    private List<Image> mDequeuedImages = new CopyOnWriteArrayList<>();
94dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He    private int mEstimatedNativeAllocBytes;
95f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
96f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
97f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
98f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Create a new ImageWriter.
99f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
100f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
101f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * The {@code maxImages} parameter determines the maximum number of
102f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link Image} objects that can be be dequeued from the
103f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@code ImageWriter} simultaneously. Requesting more buffers will use up
104f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * more memory, so it is important to use only the minimum number necessary.
105f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
106f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
107f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * The input Image size and format depend on the Surface that is provided by
108f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * the downstream consumer end-point.
109f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
110f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
111f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param surface The destination Surface this writer produces Image data
112f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            into.
113f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param maxImages The maximum number of Images the user will want to
114f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            access simultaneously for producing Image data. This should be
115f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            as small as possible to limit memory use. Once maxImages
116f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            Images are dequeued by the user, one of them has to be queued
117f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            back before a new Image can be dequeued for access via
118f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            {@link #dequeueInputImage()}.
119f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @return a new ImageWriter instance.
120f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
121f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    public static ImageWriter newInstance(Surface surface, int maxImages) {
122916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN);
123f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
124f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
125f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
126916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * <p>
127916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * Create a new ImageWriter with given number of max Images and format.
128916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * </p>
129916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * <p>
130916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * The {@code maxImages} parameter determines the maximum number of
131916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * {@link Image} objects that can be be dequeued from the
132916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * {@code ImageWriter} simultaneously. Requesting more buffers will use up
133916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * more memory, so it is important to use only the minimum number necessary.
134916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * </p>
135916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * <p>
136916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * The format specifies the image format of this ImageWriter. The format
137916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * from the {@code surface} will be overridden with this format. For example,
138916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * if the surface is obtained from a {@link android.graphics.SurfaceTexture}, the default
139916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * format may be {@link PixelFormat#RGBA_8888}. If the application creates an ImageWriter
140916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * with this surface and {@link ImageFormat#PRIVATE}, this ImageWriter will be able to operate
141916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * with {@link ImageFormat#PRIVATE} Images.
142916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * </p>
143916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * <p>
144916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * Note that the consumer end-point may or may not be able to support Images with different
145916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * format, for such case, the application should only use this method if the consumer is able
146916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * to consume such images.
147916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * </p>
148916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * <p>
149916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * The input Image size depends on the Surface that is provided by
150916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * the downstream consumer end-point.
151916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * </p>
152916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     *
153916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * @param surface The destination Surface this writer produces Image data
154916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     *            into.
155916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * @param maxImages The maximum number of Images the user will want to
156916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     *            access simultaneously for producing Image data. This should be
157916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     *            as small as possible to limit memory use. Once maxImages
158916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     *            Images are dequeued by the user, one of them has to be queued
159916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     *            back before a new Image can be dequeued for access via
160916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     *            {@link #dequeueInputImage()}.
161916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * @param format The format of this ImageWriter. It can be any valid format specified by
162916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     *            {@link ImageFormat} or {@link PixelFormat}.
163916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     *
164916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * @return a new ImageWriter instance.
165f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @hide
166f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
167916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    public static ImageWriter newInstance(Surface surface, int maxImages, int format) {
168916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
169916d8ac650865cd05808d48bad68b69bebbc95abZhijun He            throw new IllegalArgumentException("Invalid format is specified: " + format);
170916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        }
171916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        return new ImageWriter(surface, maxImages, format);
172916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    }
173916d8ac650865cd05808d48bad68b69bebbc95abZhijun He
174916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    /**
175916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     * @hide
176916d8ac650865cd05808d48bad68b69bebbc95abZhijun He     */
177916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    protected ImageWriter(Surface surface, int maxImages, int format) {
178f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (surface == null || maxImages < 1) {
179f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalArgumentException("Illegal input argument: surface " + surface
180f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    + ", maxImages: " + maxImages);
181f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
182f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
183f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        mMaxImages = maxImages;
184916d8ac650865cd05808d48bad68b69bebbc95abZhijun He
185916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        if (format == ImageFormat.UNKNOWN) {
186916d8ac650865cd05808d48bad68b69bebbc95abZhijun He            format = SurfaceUtils.getSurfaceFormat(surface);
187916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        }
188f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // Note that the underlying BufferQueue is working in synchronous mode
189f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // to avoid dropping any buffers.
190916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format);
191dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He
192dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        // Estimate the native buffer allocation size and register it so it gets accounted for
193dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        // during GC. Note that this doesn't include the buffers required by the buffer queue
194dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        // itself and the buffers requested by the producer.
19504a935162c0af649987108058f81405930408014Eino-Ville Talvala        // Only include memory for 1 buffer, since actually accounting for the memory used is
19604a935162c0af649987108058f81405930408014Eino-Ville Talvala        // complex, and 1 buffer is enough for the VM to treat the ImageWriter as being of some
19704a935162c0af649987108058f81405930408014Eino-Ville Talvala        // size.
198dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        Size surfSize = SurfaceUtils.getSurfaceSize(surface);
199dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        mEstimatedNativeAllocBytes =
200dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He                ImageUtils.getEstimatedNativeAllocBytes(surfSize.getWidth(),surfSize.getHeight(),
20104a935162c0af649987108058f81405930408014Eino-Ville Talvala                        format, /*buffer count*/ 1);
202dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
203f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
204f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
205f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
206f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
207f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Maximum number of Images that can be dequeued from the ImageWriter
208f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * simultaneously (for example, with {@link #dequeueInputImage()}).
209f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
210f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
211f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * An Image is considered dequeued after it's returned by
212f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link #dequeueInputImage()} from ImageWriter, and until the Image is
213f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * sent back to ImageWriter via {@link #queueInputImage}, or
214f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link Image#close()}.
215f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
216f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
217f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Attempting to dequeue more than {@code maxImages} concurrently will
218f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * result in the {@link #dequeueInputImage()} function throwing an
219f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link IllegalStateException}.
220f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
221f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
222f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @return Maximum number of Images that can be dequeued from this
223f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *         ImageWriter.
224f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @see #dequeueInputImage
225f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @see #queueInputImage
226f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @see Image#close
227f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
228f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    public int getMaxImages() {
229f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return mMaxImages;
230f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
231f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
232f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
233f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
234f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Dequeue the next available input Image for the application to produce
235f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * data into.
236f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
237f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
238f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * This method requests a new input Image from ImageWriter. The application
239f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * owns this Image after this call. Once the application fills the Image
240f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * data, it is expected to return this Image back to ImageWriter for
241f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * downstream consumer components (e.g.
242f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link android.hardware.camera2.CameraDevice}) to consume. The Image can
243f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * be returned to ImageWriter via {@link #queueInputImage} or
244f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link Image#close()}.
245f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
246f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
247ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * This call will block if all available input images have been queued by
248f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * the application and the downstream consumer has not yet consumed any.
249ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * When an Image is consumed by the downstream consumer and released, an
250d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link OnImageReleasedListener#onImageReleased} callback will be fired,
251d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * which indicates that there is one input Image available. For non-
252d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link ImageFormat#PRIVATE PRIVATE} formats (
253d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE}), it is
254ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * recommended to dequeue the next Image only after this callback is fired,
255ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * in the steady state.
256ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * </p>
257ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * <p>
258d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} (
259d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the
260d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * image buffer is inaccessible to the application, and calling this method
261d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * will result in an {@link IllegalStateException}. Instead, the application
262d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * should acquire images from some other component (e.g. an
263ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * {@link ImageReader}), and queue them directly to this ImageWriter via the
264ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * {@link ImageWriter#queueInputImage queueInputImage()} method.
265f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
266f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
267f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @return The next available input Image from this ImageWriter.
268f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @throws IllegalStateException if {@code maxImages} Images are currently
269d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     *             dequeued, or the ImageWriter format is
270e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen     *             {@link ImageFormat#PRIVATE PRIVATE}, or the input
271e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen     *             {@link android.view.Surface Surface} has been abandoned by the
272e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen     *             consumer component that provided the {@link android.view.Surface Surface}.
273f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @see #queueInputImage
274f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @see Image#close
275f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
276f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    public Image dequeueInputImage() {
277ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        if (mWriterFormat == ImageFormat.PRIVATE) {
278ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            throw new IllegalStateException(
279d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He                    "PRIVATE format ImageWriter doesn't support this operation since the images are"
280ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                            + " inaccessible to the application!");
281ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        }
282ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
283f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (mDequeuedImages.size() >= mMaxImages) {
284f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalStateException("Already dequeued max number of Images " + mMaxImages);
285f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
286f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        WriterSurfaceImage newImage = new WriterSurfaceImage(this);
287f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        nativeDequeueInputImage(mNativeContext, newImage);
288f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        mDequeuedImages.add(newImage);
289a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He        newImage.mIsImageValid = true;
290f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return newImage;
291f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
292f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
293f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
294f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
295f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Queue an input {@link Image} back to ImageWriter for the downstream
296f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * consumer to access.
297f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
298f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
299f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * The input {@link Image} could be from ImageReader (acquired via
300f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link ImageReader#acquireNextImage} or
301f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link ImageReader#acquireLatestImage}), or from this ImageWriter
302f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * (acquired via {@link #dequeueInputImage}). In the former case, the Image
303f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * data will be moved to this ImageWriter. Note that the Image properties
304f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * (size, format, strides, etc.) must be the same as the properties of the
305f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * images dequeued from this ImageWriter, or this method will throw an
306f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link IllegalArgumentException}. In the latter case, the application has
307f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * filled the input image with data. This method then passes the filled
308f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * buffer to the downstream consumer. In both cases, it's up to the caller
309f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * to ensure that the Image timestamp (in nanoseconds) is correctly set, as
310f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * the downstream component may want to use it to indicate the Image data
311f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * capture time.
312f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
313f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
314ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * After this method is called and the downstream consumer consumes and
315d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * releases the Image, an {@link OnImageReleasedListener#onImageReleased}
316d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * callback will fire. The application can use this callback to avoid
317d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * sending Images faster than the downstream consumer processing rate in
318d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * steady state.
319ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * </p>
320ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * <p>
321ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * Passing in an Image from some other component (e.g. an
322ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * {@link ImageReader}) requires a free input Image from this ImageWriter as
323ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * the destination. In this case, this call will block, as
324ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * {@link #dequeueInputImage} does, if there are no free Images available.
325ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * To avoid blocking, the application should ensure that there is at least
326ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * one free Image available in this ImageWriter before calling this method.
327f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
328f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
329f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * After this call, the input Image is no longer valid for further access,
330f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * as if the Image is {@link Image#close closed}. Attempting to access the
331f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link ByteBuffer ByteBuffers} returned by an earlier
332f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link Image.Plane#getBuffer Plane#getBuffer} call will result in an
333f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link IllegalStateException}.
334f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
335f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
336f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param image The Image to be queued back to ImageWriter for future
337f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            consumption.
338e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen     * @throws IllegalStateException if the image was already queued previously,
339e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen     *            or the image was aborted previously, or the input
340e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen     *            {@link android.view.Surface Surface} has been abandoned by the
341e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen     *            consumer component that provided the
342e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen     *            {@link android.view.Surface Surface}.
343f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @see #dequeueInputImage()
344f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
345f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    public void queueInputImage(Image image) {
346f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (image == null) {
347f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalArgumentException("image shouldn't be null");
348f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
349f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        boolean ownedByMe = isImageOwnedByMe(image);
350a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He        if (ownedByMe && !(((WriterSurfaceImage) image).mIsImageValid)) {
351f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalStateException("Image from ImageWriter is invalid");
352f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
353f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
354f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // For images from other components, need to detach first, then attach.
355f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (!ownedByMe) {
356f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            if (!(image.getOwner() instanceof ImageReader)) {
357f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                throw new IllegalArgumentException("Only images from ImageReader can be queued to"
358f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                        + " ImageWriter, other image source is not supported yet!");
359f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
360f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
361f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            ImageReader prevOwner = (ImageReader) image.getOwner();
36207ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala
36307ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala            prevOwner.detachImage(image);
36407ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala            attachAndQueueInputImage(image);
36507ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala            // This clears the native reference held by the original owner.
36607ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala            // When this Image is detached later by this ImageWriter, the
36707ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala            // native memory won't be leaked.
36807ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala            image.close();
36907ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala            return;
370f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
371f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
372f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        Rect crop = image.getCropRect();
373f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        nativeQueueInputImage(mNativeContext, image, image.getTimestamp(), crop.left, crop.top,
374f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                crop.right, crop.bottom);
375f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
376f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        /**
377f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * Only remove and cleanup the Images that are owned by this
378ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * ImageWriter. Images detached from other owners are only temporarily
379ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * owned by this ImageWriter and will be detached immediately after they
380ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * are released by downstream consumers, so there is no need to keep
381ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * track of them in mDequeuedImages.
382f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         */
383f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (ownedByMe) {
384f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            mDequeuedImages.remove(image);
385ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            // Do not call close here, as close is essentially cancel image.
386f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            WriterSurfaceImage wi = (WriterSurfaceImage) image;
387f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            wi.clearSurfacePlanes();
388a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            wi.mIsImageValid = false;
389f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
390f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
391f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
392f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
393ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * Get the ImageWriter format.
394ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * <p>
395ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * This format may be different than the Image format returned by
396d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link Image#getFormat()}. However, if the ImageWriter format is
397d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link ImageFormat#PRIVATE PRIVATE}, calling {@link #dequeueInputImage()}
398d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * will result in an {@link IllegalStateException}.
399ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * </p>
400ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     *
401ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * @return The ImageWriter format.
402ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     */
403ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    public int getFormat() {
404ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return mWriterFormat;
405ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
406ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
407ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    /**
408f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * ImageWriter callback interface, used to to asynchronously notify the
409f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * application of various ImageWriter events.
410f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
411d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He    public interface OnImageReleasedListener {
412f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        /**
413f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * <p>
414f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * Callback that is called when an input Image is released back to
415f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * ImageWriter after the data consumption.
416f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * </p>
417f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * <p>
418ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * The client can use this callback to be notified that an input Image
419ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * has been consumed and released by the downstream consumer. More
420ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * specifically, this callback will be fired for below cases:
421ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * <li>The application dequeues an input Image via the
422ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * {@link ImageWriter#dequeueInputImage dequeueInputImage()} method,
423ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * uses it, and then queues it back to this ImageWriter via the
424ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * {@link ImageWriter#queueInputImage queueInputImage()} method. After
425ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * the downstream consumer uses and releases this image to this
426ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * ImageWriter, this callback will be fired. This image will be
427ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * available to be dequeued after this callback.</li>
428ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * <li>The application obtains an Image from some other component (e.g.
429ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * an {@link ImageReader}), uses it, and then queues it to this
430ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * ImageWriter via {@link ImageWriter#queueInputImage queueInputImage()}.
431ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * After the downstream consumer uses and releases this image to this
432ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He         * ImageWriter, this callback will be fired.</li>
433f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * </p>
434f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         *
435f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * @param writer the ImageWriter the callback is associated with.
436f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * @see ImageWriter
437f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * @see Image
438f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         */
439d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He        void onImageReleased(ImageWriter writer);
440f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
441f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
442f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
443ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * Register a listener to be invoked when an input Image is returned to the
444ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * ImageWriter.
445f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
446f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param listener The listener that will be run.
447f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param handler The handler on which the listener should be invoked, or
448f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            null if the listener should be invoked on the calling thread's
449f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            looper.
450f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @throws IllegalArgumentException If no handler specified and the calling
451f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *             thread has no looper.
452f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
453d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He    public void setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler) {
454f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        synchronized (mListenerLock) {
455f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            if (listener != null) {
456f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
457f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                if (looper == null) {
458f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    throw new IllegalArgumentException(
459f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                            "handler is null but the current thread is not a looper");
460f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                }
461f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
462f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    mListenerHandler = new ListenerHandler(looper);
463f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                }
464f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mListener = listener;
465f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            } else {
466f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mListener = null;
467f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mListenerHandler = null;
468f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
469f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
470f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
471f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
472f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
473f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Free up all the resources associated with this ImageWriter.
474f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
475f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * After calling this method, this ImageWriter cannot be used. Calling any
476f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * methods on this ImageWriter and Images previously provided by
477f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link #dequeueInputImage()} will result in an
478f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link IllegalStateException}, and attempting to write into
479f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link ByteBuffer ByteBuffers} returned by an earlier
480f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link Image.Plane#getBuffer Plane#getBuffer} call will have undefined
481f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * behavior.
482f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
483f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
484f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    @Override
485f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    public void close() {
486d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He        setOnImageReleasedListener(null, null);
487f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        for (Image image : mDequeuedImages) {
488f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            image.close();
489f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
490f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        mDequeuedImages.clear();
491f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        nativeClose(mNativeContext);
492f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        mNativeContext = 0;
493dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He
494dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        if (mEstimatedNativeAllocBytes > 0) {
495dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            VMRuntime.getRuntime().registerNativeFree(mEstimatedNativeAllocBytes);
496dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            mEstimatedNativeAllocBytes = 0;
497dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        }
498f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
499f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
500f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    @Override
501f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    protected void finalize() throws Throwable {
502f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        try {
503f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            close();
504f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        } finally {
505f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            super.finalize();
506f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
507f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
508f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
509f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
510f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
511ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * Attach and queue input Image to this ImageWriter.
512f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
513f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
514d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * When the format of an Image is {@link ImageFormat#PRIVATE PRIVATE}, or
515d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * the source Image is so large that copying its data is too expensive, this
516d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * method can be used to migrate the source Image into ImageWriter without a
517d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * data copy, and then queue it to this ImageWriter. The source Image must
518d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * be detached from its previous owner already, or this call will throw an
519ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * {@link IllegalStateException}.
520f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
521f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
522ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * After this call, the ImageWriter takes ownership of this Image. This
523ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * ownership will automatically be removed from this writer after the
524f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * consumer releases this Image, that is, after
525d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * {@link OnImageReleasedListener#onImageReleased}. The caller is responsible for
526ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * closing this Image through {@link Image#close()} to free up the resources
527ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He     * held by this Image.
528f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
529f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
530f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param image The source Image to be attached and queued into this
531f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *            ImageWriter for downstream consumer to use.
532f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @throws IllegalStateException if the Image is not detached from its
533f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *             previous owner, or the Image is already attached to this
534f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *             ImageWriter, or the source Image is invalid.
535f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
536ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    private void attachAndQueueInputImage(Image image) {
537f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (image == null) {
538f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalArgumentException("image shouldn't be null");
539f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
540f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (isImageOwnedByMe(image)) {
541f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalArgumentException(
542f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    "Can not attach an image that is owned ImageWriter already");
543f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
544f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        /**
545f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * Throw ISE if the image is not attachable, which means that it is
546f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * either owned by other entity now, or completely non-attachable (some
547f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * stand-alone images are not backed by native gralloc buffer, thus not
548f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * attachable).
549f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         */
550f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (!image.isAttachable()) {
551f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalStateException("Image was not detached from last owner, or image "
552f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    + " is not detachable");
553f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
554f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
555f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // TODO: what if attach failed, throw RTE or detach a slot then attach?
556f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // need do some cleanup to make sure no orphaned
557f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // buffer caused leak.
558ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        Rect crop = image.getCropRect();
559ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(), image.getFormat(),
560ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                image.getTimestamp(), crop.left, crop.top, crop.right, crop.bottom);
561f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
562f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
563f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
564f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * This custom handler runs asynchronously so callbacks don't get queued
565f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * behind UI messages.
566f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
567f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private final class ListenerHandler extends Handler {
568f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public ListenerHandler(Looper looper) {
569f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            super(looper, null, true /* async */);
570f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
571f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
572f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
573f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public void handleMessage(Message msg) {
574d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He            OnImageReleasedListener listener;
575f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            synchronized (mListenerLock) {
576f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                listener = mListener;
577f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
578f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            if (listener != null) {
579d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He                listener.onImageReleased(ImageWriter.this);
580f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
581f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
582f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
583f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
584f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
585f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Called from Native code when an Event happens. This may be called from an
586f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * arbitrary Binder thread, so access to the ImageWriter must be
587f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * synchronized appropriately.
588f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
589f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private static void postEventFromNative(Object selfRef) {
590f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @SuppressWarnings("unchecked")
591f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        WeakReference<ImageWriter> weakSelf = (WeakReference<ImageWriter>) selfRef;
592f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        final ImageWriter iw = weakSelf.get();
593f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (iw == null) {
594f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return;
595f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
596f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
597f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        final Handler handler;
598f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        synchronized (iw.mListenerLock) {
599f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            handler = iw.mListenerHandler;
600f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
601f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (handler != null) {
602f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            handler.sendEmptyMessage(0);
603f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
604f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
605f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
606f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
607f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
608f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Abort the Images that were dequeued from this ImageWriter, and return
609f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * them to this writer for reuse.
610f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
611f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
612f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * This method is used for the cases where the application dequeued the
613f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Image, may have filled the data, but does not want the downstream
614f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * component to consume it. The Image will be returned to this ImageWriter
615f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * for reuse after this call, and the ImageWriter will immediately have an
616f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Image available to be dequeued. This aborted Image will be invisible to
617f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * the downstream consumer, as if nothing happened.
618f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
619f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
620f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param image The Image to be aborted.
621f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @see #dequeueInputImage()
622f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @see Image#close()
623f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
624f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private void abortImage(Image image) {
625f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (image == null) {
626f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalArgumentException("image shouldn't be null");
627f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
628f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
629f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (!mDequeuedImages.contains(image)) {
630f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalStateException("It is illegal to abort some image that is not"
631f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    + " dequeued yet");
632f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
633f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
634f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        WriterSurfaceImage wi = (WriterSurfaceImage) image;
635a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He        if (!wi.mIsImageValid) {
636dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He            return;
637f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
638f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
639f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        /**
640f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * We only need abort Images that are owned and dequeued by ImageWriter.
641f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * For attached Images, no need to abort, as there are only two cases:
642f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * attached + queued successfully, and attach failed. Neither of the
643f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * cases need abort.
644f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         */
645ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        cancelImage(mNativeContext, image);
646f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        mDequeuedImages.remove(image);
647f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        wi.clearSurfacePlanes();
648a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He        wi.mIsImageValid = false;
649f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
650f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
651f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private boolean isImageOwnedByMe(Image image) {
652f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (!(image instanceof WriterSurfaceImage)) {
653f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return false;
654f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
655f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        WriterSurfaceImage wi = (WriterSurfaceImage) image;
656f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (wi.getOwner() != this) {
657f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return false;
658f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
659f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
660f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return true;
661f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
662f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
663f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private static class WriterSurfaceImage extends android.media.Image {
664f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private ImageWriter mOwner;
665f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // This field is used by native code, do not access or modify.
666f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private long mNativeBuffer;
667f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private int mNativeFenceFd = -1;
668f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private SurfacePlane[] mPlanes;
669f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private int mHeight = -1;
670f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private int mWidth = -1;
671f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private int mFormat = -1;
672f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // When this default timestamp is used, timestamp for the input Image
673f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // will be generated automatically when queueInputBuffer is called.
674f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private final long DEFAULT_TIMESTAMP = Long.MIN_VALUE;
675f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private long mTimestamp = DEFAULT_TIMESTAMP;
676f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
677f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public WriterSurfaceImage(ImageWriter writer) {
678f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            mOwner = writer;
679f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
680f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
681f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
682f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public int getFormat() {
683a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            throwISEIfImageIsInvalid();
684a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He
685f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            if (mFormat == -1) {
686f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mFormat = nativeGetFormat();
687f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
688f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return mFormat;
689f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
690f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
691f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
692f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public int getWidth() {
693a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            throwISEIfImageIsInvalid();
694f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
695f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            if (mWidth == -1) {
696f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mWidth = nativeGetWidth();
697f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
698f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
699f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return mWidth;
700f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
701f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
702f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
703f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public int getHeight() {
704a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            throwISEIfImageIsInvalid();
705f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
706f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            if (mHeight == -1) {
707f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mHeight = nativeGetHeight();
708f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
709f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
710f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return mHeight;
711f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
712f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
713f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
714f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public long getTimestamp() {
715a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            throwISEIfImageIsInvalid();
716f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
717f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return mTimestamp;
718f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
719f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
720f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
721f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public void setTimestamp(long timestamp) {
722a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            throwISEIfImageIsInvalid();
723f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
724f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            mTimestamp = timestamp;
725f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
726f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
727f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
728f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public Plane[] getPlanes() {
729a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            throwISEIfImageIsInvalid();
730f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
731f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            if (mPlanes == null) {
732f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                int numPlanes = ImageUtils.getNumPlanesForFormat(getFormat());
733f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mPlanes = nativeCreatePlanes(numPlanes, getOwner().getFormat());
734f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
735f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
736f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return mPlanes.clone();
737f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
738f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
739f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
740f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        boolean isAttachable() {
741a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            throwISEIfImageIsInvalid();
742f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            // Don't allow Image to be detached from ImageWriter for now, as no
743f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            // detach API is exposed.
744f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return false;
745f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
746f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
747f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
748f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ImageWriter getOwner() {
749a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            throwISEIfImageIsInvalid();
750a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He
751f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return mOwner;
752f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
753f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
754f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
755ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        long getNativeContext() {
756a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            throwISEIfImageIsInvalid();
757a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He
758ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            return mNativeBuffer;
759ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        }
760ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
761ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        @Override
762f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        public void close() {
763a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He            if (mIsImageValid) {
764f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                getOwner().abortImage(this);
765f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
766f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
767f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
768f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        @Override
769f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        protected final void finalize() throws Throwable {
770f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            try {
771f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                close();
772f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            } finally {
773f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                super.finalize();
774f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
775f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
776f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
777f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private void clearSurfacePlanes() {
778e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            if (mIsImageValid && mPlanes != null) {
779f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                for (int i = 0; i < mPlanes.length; i++) {
780f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    if (mPlanes[i] != null) {
781f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                        mPlanes[i].clearBuffer();
782f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                        mPlanes[i] = null;
783f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    }
784f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                }
785f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
786f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
787f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
788f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private class SurfacePlane extends android.media.Image.Plane {
789f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            private ByteBuffer mBuffer;
790f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            final private int mPixelStride;
791f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            final private int mRowStride;
792f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
7930ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
7940ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            // called
795f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
796f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mRowStride = rowStride;
797f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mPixelStride = pixelStride;
798f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mBuffer = buffer;
799f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                /**
800f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                 * Set the byteBuffer order according to host endianness (native
801f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                 * order), otherwise, the byteBuffer order defaults to
802f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                 * ByteOrder.BIG_ENDIAN.
803f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                 */
804f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mBuffer.order(ByteOrder.nativeOrder());
805f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
806f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
807f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            @Override
808f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            public int getRowStride() {
809a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He                throwISEIfImageIsInvalid();
810f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                return mRowStride;
811f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
812f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
813f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            @Override
814f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            public int getPixelStride() {
815a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He                throwISEIfImageIsInvalid();
816f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                return mPixelStride;
817f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
818f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
819f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            @Override
820f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            public ByteBuffer getBuffer() {
821a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He                throwISEIfImageIsInvalid();
822f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                return mBuffer;
823f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
824f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
825f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            private void clearBuffer() {
826f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                // Need null check first, as the getBuffer() may not be called
827f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                // before an Image is closed.
828f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                if (mBuffer == null) {
829f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    return;
830f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                }
831f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
832f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                if (mBuffer.isDirect()) {
833f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    NioUtils.freeDirectBuffer(mBuffer);
834f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                }
835f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                mBuffer = null;
836f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            }
837f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
838f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
839f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
8400ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        // Create the SurfacePlane object and fill the information
841f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt);
842f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
843f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private synchronized native int nativeGetWidth();
844f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
845f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private synchronized native int nativeGetHeight();
846f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
847f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        private synchronized native int nativeGetFormat();
848f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
849f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
850f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Native implemented ImageWriter methods.
851916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    private synchronized native long nativeInit(Object weakSelf, Surface surface, int maxImgs,
852916d8ac650865cd05808d48bad68b69bebbc95abZhijun He            int format);
853f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
854f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private synchronized native void nativeClose(long nativeCtx);
855f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
856f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private synchronized native void nativeDequeueInputImage(long nativeCtx, Image wi);
857f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
858f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private synchronized native void nativeQueueInputImage(long nativeCtx, Image image,
859f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            long timestampNs, int left, int top, int right, int bottom);
860f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
861ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    private synchronized native int nativeAttachAndQueueImage(long nativeCtx,
862ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            long imageNativeBuffer, int imageFormat, long timestampNs, int left,
863ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            int top, int right, int bottom);
864ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
865f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private synchronized native void cancelImage(long nativeCtx, Image image);
866f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
867f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
868f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * We use a class initializer to allow the native code to cache some field
869f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * offsets.
870f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
871f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    private static native void nativeClassInit();
872f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
873f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    static {
874f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        System.loadLibrary("media_jni");
875f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        nativeClassInit();
876f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
877f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
878