android_media_ImageWriter.cpp revision 0ab416269a866c8afa8f65d9351afa2407abee4c
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 He//#define LOG_NDEBUG 0
18f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#define LOG_TAG "ImageWriter_JNI"
190ab416269a866c8afa8f65d9351afa2407abee4cZhijun He#include "android_media_Utils.h"
200ab416269a866c8afa8f65d9351afa2407abee4cZhijun He
21f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <utils/Log.h>
22f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <utils/String8.h>
23f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
24f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <gui/IProducerListener.h>
25f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <gui/Surface.h>
26f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <android_runtime/AndroidRuntime.h>
27f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <android_runtime/android_view_Surface.h>
28f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <camera3.h>
29f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <jni.h>
30f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <JNIHelp.h>
31f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
32f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <stdint.h>
33f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#include <inttypes.h>
34f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
35f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He#define IMAGE_BUFFER_JNI_ID           "mNativeBuffer"
36f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
37f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He// ----------------------------------------------------------------------------
38f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
39f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heusing namespace android;
40f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
41f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic struct {
42f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jmethodID postEventFromNative;
43f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jfieldID mWriterFormat;
44f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He} gImageWriterClassInfo;
45f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
46f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic struct {
47f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jfieldID mNativeBuffer;
48f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jfieldID mNativeFenceFd;
49f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jfieldID mPlanes;
50f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He} gSurfaceImageClassInfo;
51f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
52f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic struct {
53f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jclass clazz;
54f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jmethodID ctor;
55f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He} gSurfacePlaneClassInfo;
56f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
57f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He// ----------------------------------------------------------------------------
58f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
59f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heclass JNIImageWriterContext : public BnProducerListener {
60f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hepublic:
61f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext(JNIEnv* env, jobject weakThiz, jclass clazz);
62f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
63f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    virtual ~JNIImageWriterContext();
64f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
65f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Implementation of IProducerListener, used to notify the ImageWriter that the consumer
66f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // has returned a buffer and it is ready for ImageWriter to dequeue.
67f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    virtual void onBufferReleased();
68f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
69ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    void setProducer(const sp<Surface>& producer) { mProducer = producer; }
70ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    Surface* getProducer() { return mProducer.get(); }
71f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
72f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    void setBufferFormat(int format) { mFormat = format; }
73f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int getBufferFormat() { return mFormat; }
74f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
75f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    void setBufferWidth(int width) { mWidth = width; }
76f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int getBufferWidth() { return mWidth; }
77f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
78f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    void setBufferHeight(int height) { mHeight = height; }
79f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int getBufferHeight() { return mHeight; }
80f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
81f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heprivate:
82f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    static JNIEnv* getJNIEnv(bool* needsDetach);
83f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    static void detachJNI();
84f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
85ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    sp<Surface> mProducer;
86f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jobject mWeakThiz;
87f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jclass mClazz;
88f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int mFormat;
89f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int mWidth;
90f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int mHeight;
91f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He};
92f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
93f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun HeJNIImageWriterContext::JNIImageWriterContext(JNIEnv* env, jobject weakThiz, jclass clazz) :
94f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    mWeakThiz(env->NewGlobalRef(weakThiz)),
95f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    mClazz((jclass)env->NewGlobalRef(clazz)),
96f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    mFormat(0),
97f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    mWidth(-1),
98f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    mHeight(-1) {
99f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
100f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
101f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun HeJNIImageWriterContext::~JNIImageWriterContext() {
102f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
103f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    bool needsDetach = false;
104f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIEnv* env = getJNIEnv(&needsDetach);
105f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (env != NULL) {
106f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        env->DeleteGlobalRef(mWeakThiz);
107f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        env->DeleteGlobalRef(mClazz);
108f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    } else {
109f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGW("leaking JNI object references");
110f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
111f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (needsDetach) {
112f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        detachJNI();
113f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
114f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
115f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    mProducer.clear();
116f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
117f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
118f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun HeJNIEnv* JNIImageWriterContext::getJNIEnv(bool* needsDetach) {
119f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
120f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LOG_ALWAYS_FATAL_IF(needsDetach == NULL, "needsDetach is null!!!");
121f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    *needsDetach = false;
122f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIEnv* env = AndroidRuntime::getJNIEnv();
123f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (env == NULL) {
124f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
125f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        JavaVM* vm = AndroidRuntime::getJavaVM();
126f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        int result = vm->AttachCurrentThread(&env, (void*) &args);
127f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (result != JNI_OK) {
128f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            ALOGE("thread attach failed: %#x", result);
129f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return NULL;
130f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
131f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        *needsDetach = true;
132f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
133f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return env;
134f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
135f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
136f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hevoid JNIImageWriterContext::detachJNI() {
137f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
138f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JavaVM* vm = AndroidRuntime::getJavaVM();
139f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int result = vm->DetachCurrentThread();
140f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (result != JNI_OK) {
141f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGE("thread detach failed: %#x", result);
142f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
143f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
144f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
145f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hevoid JNIImageWriterContext::onBufferReleased() {
146f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s: buffer released", __FUNCTION__);
147f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    bool needsDetach = false;
148f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIEnv* env = getJNIEnv(&needsDetach);
149f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (env != NULL) {
150ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        // Detach the buffer every time when a buffer consumption is done,
151ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        // need let this callback give a BufferItem, then only detach if it was attached to this
152ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        // Writer. Do the detach unconditionally for opaque format now. see b/19977520
153ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        if (mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
154ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            sp<Fence> fence;
1553316452ffa74ea9a44d157c4d0cacdca3ad99fc9Dan Stoza            sp<GraphicBuffer> buffer;
156ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            ALOGV("%s: One buffer is detached", __FUNCTION__);
157ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            mProducer->detachNextBuffer(&buffer, &fence);
158ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        }
159ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
160f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        env->CallStaticVoidMethod(mClazz, gImageWriterClassInfo.postEventFromNative, mWeakThiz);
161f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    } else {
162f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGW("onBufferReleased event will not posted");
163f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
164ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
165f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (needsDetach) {
166f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        detachJNI();
167f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
168f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
169f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
170f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He// ----------------------------------------------------------------------------
171f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
172f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heextern "C" {
173f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
174f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He// -------------------------------Private method declarations--------------
175f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
176f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_setNativeContext(JNIEnv* env, jobject thiz,
177f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        sp<GraphicBuffer> buffer, int fenceFd);
178f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_getNativeContext(JNIEnv* env, jobject thiz,
179f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        GraphicBuffer** buffer, int* fenceFd);
180f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_unlockIfLocked(JNIEnv* env, jobject thiz);
181f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
182f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He// --------------------------ImageWriter methods---------------------------------------
183f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
184f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void ImageWriter_classInit(JNIEnv* env, jclass clazz) {
185f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s:", __FUNCTION__);
186f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jclass imageClazz = env->FindClass("android/media/ImageWriter$WriterSurfaceImage");
187f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LOG_ALWAYS_FATAL_IF(imageClazz == NULL,
188f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            "can't find android/media/ImageWriter$WriterSurfaceImage");
189f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    gSurfaceImageClassInfo.mNativeBuffer = env->GetFieldID(
190f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            imageClazz, IMAGE_BUFFER_JNI_ID, "J");
191f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mNativeBuffer == NULL,
192f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            "can't find android/media/ImageWriter$WriterSurfaceImage.%s", IMAGE_BUFFER_JNI_ID);
193f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
194f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    gSurfaceImageClassInfo.mNativeFenceFd = env->GetFieldID(
195f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            imageClazz, "mNativeFenceFd", "I");
196f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mNativeFenceFd == NULL,
197f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            "can't find android/media/ImageWriter$WriterSurfaceImage.mNativeFenceFd");
198f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
199f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    gSurfaceImageClassInfo.mPlanes = env->GetFieldID(
200f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            imageClazz, "mPlanes", "[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;");
201f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mPlanes == NULL,
202f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            "can't find android/media/ImageWriter$WriterSurfaceImage.mPlanes");
203f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
204f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    gImageWriterClassInfo.postEventFromNative = env->GetStaticMethodID(
205f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            clazz, "postEventFromNative", "(Ljava/lang/Object;)V");
206f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LOG_ALWAYS_FATAL_IF(gImageWriterClassInfo.postEventFromNative == NULL,
207f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                        "can't find android/media/ImageWriter.postEventFromNative");
208f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
209f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    gImageWriterClassInfo.mWriterFormat = env->GetFieldID(
210f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            clazz, "mWriterFormat", "I");
211f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LOG_ALWAYS_FATAL_IF(gImageWriterClassInfo.mWriterFormat == NULL,
212f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                        "can't find android/media/ImageWriter.mWriterFormat");
213f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
214f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jclass planeClazz = env->FindClass("android/media/ImageWriter$WriterSurfaceImage$SurfacePlane");
215f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LOG_ALWAYS_FATAL_IF(planeClazz == NULL, "Can not find SurfacePlane class");
216f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // FindClass only gives a local reference of jclass object.
217f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    gSurfacePlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz);
218f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    gSurfacePlaneClassInfo.ctor = env->GetMethodID(gSurfacePlaneClassInfo.clazz, "<init>",
219f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            "(Landroid/media/ImageWriter$WriterSurfaceImage;IILjava/nio/ByteBuffer;)V");
220f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LOG_ALWAYS_FATAL_IF(gSurfacePlaneClassInfo.ctor == NULL,
221f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            "Can not find SurfacePlane constructor");
222f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
223f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
224f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobject jsurface,
225f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jint maxImages) {
226f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    status_t res;
227f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
228f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s: maxImages:%d", __FUNCTION__, maxImages);
229f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
230f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
231f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (surface == NULL) {
232f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env,
233f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "java/lang/IllegalArgumentException",
234f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "The surface has been released");
235f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
236f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     }
237f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<IGraphicBufferProducer> bufferProducer = surface->getIGraphicBufferProducer();
238f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
239f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jclass clazz = env->GetObjectClass(thiz);
240f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (clazz == NULL) {
241f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Can't find android/graphics/ImageWriter");
242f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
243f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
244f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<JNIImageWriterContext> ctx(new JNIImageWriterContext(env, weakThiz, clazz));
245f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
246f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<Surface> producer = new Surface(bufferProducer, /*controlledByApp*/false);
247f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ctx->setProducer(producer);
248f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
249f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * NATIVE_WINDOW_API_CPU isn't a good choice here, as it makes the bufferQueue not connectable
250f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * after disconnect. MEDIA or CAMERA are treated the same internally. The producer listener
251f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * will be cleared after disconnect call.
252f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
253f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    producer->connect(/*api*/NATIVE_WINDOW_API_CAMERA, /*listener*/ctx);
254f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jlong nativeCtx = reinterpret_cast<jlong>(ctx.get());
255f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
256f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Get the dimension and format of the producer.
257f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<ANativeWindow> anw = producer;
258f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int32_t width, height, format;
259f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
260f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGE("%s: Query Surface width failed: %s (%d)", __FUNCTION__, strerror(-res), res);
261f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Failed to query Surface width");
262f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
263f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
264f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ctx->setBufferWidth(width);
265f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
266f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if ((res = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, &height)) != OK) {
267f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGE("%s: Query Surface height failed: %s (%d)", __FUNCTION__, strerror(-res), res);
268f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Failed to query Surface height");
269f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
270f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
271f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ctx->setBufferHeight(height);
272f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
273f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &format)) != OK) {
274f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGE("%s: Query Surface format failed: %s (%d)", __FUNCTION__, strerror(-res), res);
275f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Failed to query Surface format");
276f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
277f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
278f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ctx->setBufferFormat(format);
279f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    env->SetIntField(thiz, gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(format));
280f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
281f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
282ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (!isFormatOpaque(format)) {
283f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        res = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
284f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (res != OK) {
285f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
2861102e21b5dd0f79072e826932d0a3e3cb2f8c285Dan Albert                  __FUNCTION__, static_cast<unsigned int>(GRALLOC_USAGE_SW_WRITE_OFTEN),
2871102e21b5dd0f79072e826932d0a3e3cb2f8c285Dan Albert                  format, strerror(-res), res);
288f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage");
289f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return 0;
290f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
291f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
292f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
293f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int minUndequeuedBufferCount = 0;
294f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = anw->query(anw.get(),
295f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufferCount);
296f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
297f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGE("%s: Query producer undequeued buffer count failed: %s (%d)",
298f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                __FUNCTION__, strerror(-res), res);
299f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Query producer undequeued buffer count failed");
300f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
301f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     }
302f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
303f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    size_t totalBufferCount = maxImages + minUndequeuedBufferCount;
304f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = native_window_set_buffer_count(anw.get(), totalBufferCount);
305f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
306f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGE("%s: Set buffer count failed: %s (%d)", __FUNCTION__, strerror(-res), res);
307f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Set buffer count failed");
308f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
309f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
310f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
311f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx != 0) {
312f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ctx->incStrong((void*)ImageWriter_init);
313f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
314f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return nativeCtx;
315f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
316f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
317f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void ImageWriter_dequeueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image) {
318f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
319f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
320f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
321f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
322f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "ImageWriterContext is not initialized");
323f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
324f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
325f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
326f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<ANativeWindow> anw = ctx->getProducer();
327f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    android_native_buffer_t *anb = NULL;
328f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int fenceFd = -1;
329f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    status_t res = anw->dequeueBuffer(anw.get(), &anb, &fenceFd);
330f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
331a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He        ALOGE("%s: Dequeue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res);
332e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        switch (res) {
333e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            case NO_INIT:
334e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowException(env, "java/lang/IllegalStateException",
335e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                    "Surface has been abandoned");
336e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                break;
337e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            default:
338e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                // TODO: handle other error cases here.
339e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowRuntimeException(env, "dequeue buffer failed");
340e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        }
341f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
342f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
343f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // New GraphicBuffer object doesn't own the handle, thus the native buffer
344f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // won't be freed when this object is destroyed.
345f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<GraphicBuffer> buffer(new GraphicBuffer(anb, /*keepOwnership*/false));
346f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
347f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Note that:
348f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // 1. No need to lock buffer now, will only lock it when the first getPlanes() is called.
349f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // 2. Fence will be saved to mNativeFenceFd, and will consumed by lock/queue/cancel buffer
350f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    //    later.
351f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // 3. need use lockAsync here, as it will handle the dequeued fence for us automatically.
352f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
353f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Finally, set the native info into image object.
354f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_setNativeContext(env, image, buffer, fenceFd);
355f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
356f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
357f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void ImageWriter_close(JNIEnv* env, jobject thiz, jlong nativeCtx) {
358f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s:", __FUNCTION__);
359f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
360f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
3610375cb042d54a6d7c93795b4d117b138f02bd1e0Chien-Yu Chen        // ImageWriter is already closed.
362f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
363f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
364f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
365f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ANativeWindow* producer = ctx->getProducer();
366f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (producer != NULL) {
367f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        /**
368f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * NATIVE_WINDOW_API_CPU isn't a good choice here, as it makes the bufferQueue not
369f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * connectable after disconnect. MEDIA or CAMERA are treated the same internally.
370f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * The producer listener will be cleared after disconnect call.
371f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         */
372f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        status_t res = native_window_api_disconnect(producer, /*api*/NATIVE_WINDOW_API_CAMERA);
373f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        /**
374f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * This is not an error. if client calling process dies, the window will
375f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * also die and all calls to it will return DEAD_OBJECT, thus it's already
376f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * "disconnected"
377f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         */
378f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (res == DEAD_OBJECT) {
379f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            ALOGW("%s: While disconnecting ImageWriter from native window, the"
380f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    " native window died already", __FUNCTION__);
381f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        } else if (res != OK) {
382f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            ALOGE("%s: native window disconnect failed: %s (%d)",
383f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    __FUNCTION__, strerror(-res), res);
384f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            jniThrowRuntimeException(env, "Native window disconnect failed");
385f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return;
386f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
387f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
388f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
389f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ctx->decStrong((void*)ImageWriter_init);
390f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
391f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
392f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void ImageWriter_cancelImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image) {
393f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
394f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
395f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
396dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        ALOGW("ImageWriter#close called before Image#close, consider calling Image#close first");
397f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
398f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
399f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
400f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<ANativeWindow> anw = ctx->getProducer();
401f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
402f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer *buffer = NULL;
403f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int fenceFd = -1;
404f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, image, &buffer, &fenceFd);
405f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
406dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        // Cancel an already cancelled image is harmless.
407f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
408f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
409f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
410f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Unlock the image if it was locked
411f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_unlockIfLocked(env, image);
412f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
413f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    anw->cancelBuffer(anw.get(), buffer, fenceFd);
414f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
415f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_setNativeContext(env, image, NULL, -1);
416f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
417f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
418f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image,
419f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jlong timestampNs, jint left, jint top, jint right, jint bottom) {
420f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
421f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
422f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
423f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
424f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "ImageWriterContext is not initialized");
425f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
426f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
427f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
428f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    status_t res = OK;
429f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<ANativeWindow> anw = ctx->getProducer();
430f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
431f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer *buffer = NULL;
432f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int fenceFd = -1;
433f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, image, &buffer, &fenceFd);
434f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
435f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
436f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
437f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
438f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
439f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
440f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Unlock image if it was locked.
441f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_unlockIfLocked(env, image);
442f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
443f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Set timestamp
444d1cbc684053986c6c9efc6220bd79d654932b3d0Zhijun He    ALOGV("timestamp to be queued: %" PRId64, timestampNs);
445f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = native_window_set_buffers_timestamp(anw.get(), timestampNs);
446f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
447f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Set timestamp failed");
448f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
449f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
450f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
451f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Set crop
452f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    android_native_rect_t cropRect;
453f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    cropRect.left = left;
454f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    cropRect.top = top;
455f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    cropRect.right = right;
456f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    cropRect.bottom = bottom;
457f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = native_window_set_crop(anw.get(), &cropRect);
458f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
459f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Set crop rect failed");
460f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
461f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
462f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
463f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Finally, queue input buffer
464f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = anw->queueBuffer(anw.get(), buffer, fenceFd);
465f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
466e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res);
467e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        switch (res) {
468e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            case NO_INIT:
469e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowException(env, "java/lang/IllegalStateException",
470e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                    "Surface has been abandoned");
471e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                break;
472e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            default:
473e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                // TODO: handle other error cases here.
474e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowRuntimeException(env, "Queue input buffer failed");
475e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        }
476f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
477f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
478f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
479ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Clear the image native context: end of this image's lifecycle in public API.
480f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_setNativeContext(env, image, NULL, -1);
481f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
482f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
483ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun Hestatic jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nativeCtx,
484ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jlong nativeBuffer, jint imageFormat, jlong timestampNs, jint left, jint top,
485ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jint right, jint bottom) {
486f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
487f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
488f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
489f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
490f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "ImageWriterContext is not initialized");
491ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return -1;
492f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
493f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
494ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    sp<Surface> surface = ctx->getProducer();
495ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    status_t res = OK;
496ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (!isFormatOpaque(imageFormat)) {
497ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        // TODO: need implement, see b/19962027
498ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jniThrowRuntimeException(env,
499ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                "nativeAttachImage for non-opaque image is not implement yet!!!");
500ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return -1;
501ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
502f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
503ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (!isFormatOpaque(ctx->getBufferFormat())) {
504f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
505ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                "Trying to attach an opaque image into a non-opaque ImageWriter");
506ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return -1;
507ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
508ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
509ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Image is guaranteed to be from ImageReader at this point, so it is safe to
510ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // cast to BufferItem pointer.
511ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    BufferItem* opaqueBuffer = reinterpret_cast<BufferItem*>(nativeBuffer);
512ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (opaqueBuffer == NULL) {
513ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jniThrowException(env, "java/lang/IllegalStateException",
514ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                "Image is not initialized or already closed");
515ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return -1;
516ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
517ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
518ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Step 1. Attach Image
519ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    res = surface->attachBuffer(opaqueBuffer->mGraphicBuffer.get());
520ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (res != OK) {
521ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        ALOGE("Attach image failed: %s (%d)", strerror(-res), res);
522e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        switch (res) {
523e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            case NO_INIT:
524e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowException(env, "java/lang/IllegalStateException",
525e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                    "Surface has been abandoned");
526e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                break;
527e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            default:
528e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                // TODO: handle other error cases here.
529e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowRuntimeException(env, "nativeAttachImage failed!!!");
530e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        }
531ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return res;
532f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
533ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    sp < ANativeWindow > anw = surface;
534f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
535ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Step 2. Set timestamp and crop. Note that we do not need unlock the image because
536ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // it was not locked.
537ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    ALOGV("timestamp to be queued: %" PRId64, timestampNs);
538ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    res = native_window_set_buffers_timestamp(anw.get(), timestampNs);
539ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (res != OK) {
540ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jniThrowRuntimeException(env, "Set timestamp failed");
541ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return res;
542ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
543ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
544ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    android_native_rect_t cropRect;
545ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    cropRect.left = left;
546ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    cropRect.top = top;
547ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    cropRect.right = right;
548ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    cropRect.bottom = bottom;
549ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    res = native_window_set_crop(anw.get(), &cropRect);
550ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (res != OK) {
551ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jniThrowRuntimeException(env, "Set crop rect failed");
552ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return res;
553ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
554ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
555ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Step 3. Queue Image.
556ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    res = anw->queueBuffer(anw.get(), opaqueBuffer->mGraphicBuffer.get(), /*fenceFd*/
557ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            -1);
558ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (res != OK) {
559e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res);
560e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        switch (res) {
561e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            case NO_INIT:
562e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowException(env, "java/lang/IllegalStateException",
563e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                    "Surface has been abandoned");
564e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                break;
565e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            default:
566e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                // TODO: handle other error cases here.
567e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowRuntimeException(env, "Queue input buffer failed");
568e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        }
569ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return res;
570ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
571ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
572ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Do not set the image native context. Since it would overwrite the existing native context
573ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // of the image that is from ImageReader, the subsequent image close will run into issues.
574ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
575ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    return res;
576f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
577f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
578f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He// --------------------------Image methods---------------------------------------
579f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
580f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_getNativeContext(JNIEnv* env, jobject thiz,
581f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        GraphicBuffer** buffer, int* fenceFd) {
582f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
583f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer != NULL) {
584f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        GraphicBuffer *gb = reinterpret_cast<GraphicBuffer *>
585f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                  (env->GetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer));
586f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        *buffer = gb;
587f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
588f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
589f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (fenceFd != NULL) {
590f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        *fenceFd = reinterpret_cast<jint>(env->GetIntField(
591f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                thiz, gSurfaceImageClassInfo.mNativeFenceFd));
592f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
593f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
594f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
595f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_setNativeContext(JNIEnv* env, jobject thiz,
596f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        sp<GraphicBuffer> buffer, int fenceFd) {
597f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s:", __FUNCTION__);
598f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* p = NULL;
599f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &p, /*fenceFd*/NULL);
600f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer != 0) {
601f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        buffer->incStrong((void*)Image_setNativeContext);
602f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
603f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (p) {
604f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        p->decStrong((void*)Image_setNativeContext);
605f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
606f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer,
607f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            reinterpret_cast<jlong>(buffer.get()));
608f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
609f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, reinterpret_cast<jint>(fenceFd));
610f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
611f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
612f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_unlockIfLocked(JNIEnv* env, jobject thiz) {
613f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
614f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
615f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, NULL);
616f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
617f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
618f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
619f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
620f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
621f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
622f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Is locked?
623f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    bool isLocked = false;
624ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    jobject planes = NULL;
625ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (!isFormatOpaque(buffer->getPixelFormat())) {
626ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        planes = env->GetObjectField(thiz, gSurfaceImageClassInfo.mPlanes);
627ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
628f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    isLocked = (planes != NULL);
629f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (isLocked) {
630ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        // no need to use fence here, as we it will be consumed by either cancel or queue buffer.
631f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        status_t res = buffer->unlock();
632f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (res != OK) {
633f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            jniThrowRuntimeException(env, "unlock buffer failed");
634f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
635f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGV("Successfully unlocked the image");
636f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
637f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
638f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
639f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic jint Image_getWidth(JNIEnv* env, jobject thiz) {
640f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
641f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
642f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, NULL);
643f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
644f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
645f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
646f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return -1;
647f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
648f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
649f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return buffer->getWidth();
650f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
651f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
652f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic jint Image_getHeight(JNIEnv* env, jobject thiz) {
653f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
654f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
655f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, NULL);
656f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
657f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
658f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
659f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return -1;
660f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
661f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
662f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return buffer->getHeight();
663f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
664f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
665f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic jint Image_getFormat(JNIEnv* env, jobject thiz) {
666f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
667f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
668f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, NULL);
669f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
670f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
671f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
672f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
673f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
674f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
6750ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    // ImageWriter doesn't support data space yet, assuming it is unknown.
6760ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
6770ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            buffer->getPixelFormat(), HAL_DATASPACE_UNKNOWN);
6780ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    return static_cast<jint>(publicFmt);
679f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
680f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
681f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_setFenceFd(JNIEnv* env, jobject thiz, int fenceFd) {
682f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s:", __FUNCTION__);
683f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, reinterpret_cast<jint>(fenceFd));
684f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
685f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
686f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) {
687f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
688f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
689f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int fenceFd = -1;
690f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, &fenceFd);
691f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
692f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
693f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
694f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
695f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
696f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
6970ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    // ImageWriter doesn't use crop by itself, app sets it, use the no crop version.
6980ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    const Rect noCrop(buffer->width, buffer->height);
6990ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    status_t res = lockImageFromBuffer(
7000ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, noCrop, fenceFd, image);
7010ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    // Clear the fenceFd as it is already consumed by lock call.
7020ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    Image_setFenceFd(env, thiz, /*fenceFd*/-1);
7030ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    if (res != OK) {
7040ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
7050ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                "lock buffer failed for format 0x%x",
7060ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                buffer->getPixelFormat());
7070ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        return;
708f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
709f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
7100ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    ALOGV("%s: Successfully locked the image", __FUNCTION__);
711f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // crop, transform, scalingMode, timestamp, and frameNumber should be set by producer,
712f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // and we don't set them here.
713f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
714f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
715f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
716f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
717f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
718f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
7190ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    status_t res = getLockedImageInfo(buffer, idx, writerFormat, base, size,
7200ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            pixelStride, rowStride);
7210ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    if (res != OK) {
7220ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
7230ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                             "Pixel format: 0x%x is unsupported", buffer->flexFormat);
7240ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    }
725f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
726f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
727f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
728f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        int numPlanes, int writerFormat) {
729f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
730f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int rowStride, pixelStride;
731f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    uint8_t *pData;
732f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    uint32_t dataSize;
733f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jobject byteBuffer;
734f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
735f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int format = Image_getFormat(env, thiz);
736ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (isFormatOpaque(format) && numPlanes > 0) {
737f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        String8 msg;
738f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
739f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                " must be 0", format, numPlanes);
740f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalArgumentException", msg.string());
741f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return NULL;
742f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
743f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
744f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jobjectArray surfacePlanes = env->NewObjectArray(numPlanes, gSurfacePlaneClassInfo.clazz,
745f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            /*initial_element*/NULL);
746f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (surfacePlanes == NULL) {
747f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Failed to create SurfacePlane arrays,"
748f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                " probably out of memory");
749f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return NULL;
750f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
751ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (isFormatOpaque(format)) {
752ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return surfacePlanes;
753ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
754f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
755f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Buildup buffer info: rowStride, pixelStride and byteBuffers.
756f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LockedImage lockedImg = LockedImage();
757f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getLockedImage(env, thiz, &lockedImg);
758f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
759f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Create all SurfacePlanes
7600ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    PublicFormat publicWriterFormat = static_cast<PublicFormat>(writerFormat);
7610ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    writerFormat = android_view_Surface_mapPublicFormatToHalFormat(publicWriterFormat);
762f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    for (int i = 0; i < numPlanes; i++) {
763f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        Image_getLockedImageInfo(env, &lockedImg, i, writerFormat,
764f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                &pData, &dataSize, &pixelStride, &rowStride);
765f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
766f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
767f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            jniThrowException(env, "java/lang/IllegalStateException",
768f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    "Failed to allocate ByteBuffer");
769f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return NULL;
770f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
771f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
772f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // Finally, create this SurfacePlane.
773f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jobject surfacePlane = env->NewObject(gSurfacePlaneClassInfo.clazz,
774f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    gSurfacePlaneClassInfo.ctor, thiz, rowStride, pixelStride, byteBuffer);
775f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        env->SetObjectArrayElement(surfacePlanes, i, surfacePlane);
776f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
777f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
778f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return surfacePlanes;
779f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
780f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
781f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He} // extern "C"
782f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
783f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He// ----------------------------------------------------------------------------
784f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
785f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic JNINativeMethod gImageWriterMethods[] = {
786f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeClassInit",         "()V",                        (void*)ImageWriter_classInit },
787f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeInit",              "(Ljava/lang/Object;Landroid/view/Surface;I)J",
788f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                                                              (void*)ImageWriter_init },
789ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    {"nativeClose",              "(J)V",                      (void*)ImageWriter_close },
790ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    {"nativeAttachAndQueueImage", "(JJIJIIII)I",          (void*)ImageWriter_attachAndQueueImage },
791f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeDequeueInputImage", "(JLandroid/media/Image;)V",  (void*)ImageWriter_dequeueImage },
792f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeQueueInputImage",   "(JLandroid/media/Image;JIIII)V",  (void*)ImageWriter_queueImage },
793f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"cancelImage",             "(JLandroid/media/Image;)V",   (void*)ImageWriter_cancelImage },
794f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He};
795f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
796f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic JNINativeMethod gImageMethods[] = {
797f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeCreatePlanes",      "(II)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;",
798f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                                                              (void*)Image_createSurfacePlanes },
799f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeGetWidth",         "()I",                         (void*)Image_getWidth },
800f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeGetHeight",        "()I",                         (void*)Image_getHeight },
801f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeGetFormat",        "()I",                         (void*)Image_getFormat },
802f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He};
803f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
804f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heint register_android_media_ImageWriter(JNIEnv *env) {
805f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
806f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int ret1 = AndroidRuntime::registerNativeMethods(env,
807f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                   "android/media/ImageWriter", gImageWriterMethods, NELEM(gImageWriterMethods));
808f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
809f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int ret2 = AndroidRuntime::registerNativeMethods(env,
810f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                   "android/media/ImageWriter$WriterSurfaceImage", gImageMethods, NELEM(gImageMethods));
811f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
812f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return (ret1 || ret2);
813f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
814f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
815