android_media_ImageWriter.cpp revision 07ad459c84b565ea216854a64e726a16c5824640
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"
36916d8ac650865cd05808d48bad68b69bebbc95abZhijun He#define IMAGE_FORMAT_UNKNOWN          0 // This is the same value as ImageFormat#UNKNOWN.
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,
225916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        jint maxImages, jint userFormat) {
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;
258916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    int32_t width, height, surfaceFormat;
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
273916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    // Query surface format if no valid user format is specified, otherwise, override surface format
274916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    // with user format.
275916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    if (userFormat == IMAGE_FORMAT_UNKNOWN) {
276916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &surfaceFormat)) != OK) {
277916d8ac650865cd05808d48bad68b69bebbc95abZhijun He            ALOGE("%s: Query Surface format failed: %s (%d)", __FUNCTION__, strerror(-res), res);
278916d8ac650865cd05808d48bad68b69bebbc95abZhijun He            jniThrowRuntimeException(env, "Failed to query Surface format");
279916d8ac650865cd05808d48bad68b69bebbc95abZhijun He            return 0;
280916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        }
281916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    } else {
282916d8ac650865cd05808d48bad68b69bebbc95abZhijun He        surfaceFormat = userFormat;
283f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
284916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    ctx->setBufferFormat(surfaceFormat);
285916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    env->SetIntField(thiz,
286916d8ac650865cd05808d48bad68b69bebbc95abZhijun He            gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat));
287f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
288916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    if (!isFormatOpaque(surfaceFormat)) {
289f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        res = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
290f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (res != OK) {
291f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
2921102e21b5dd0f79072e826932d0a3e3cb2f8c285Dan Albert                  __FUNCTION__, static_cast<unsigned int>(GRALLOC_USAGE_SW_WRITE_OFTEN),
293916d8ac650865cd05808d48bad68b69bebbc95abZhijun He                  surfaceFormat, strerror(-res), res);
294f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage");
295f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return 0;
296f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
297f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
298f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
299f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int minUndequeuedBufferCount = 0;
300f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = anw->query(anw.get(),
301f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufferCount);
302f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
303f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGE("%s: Query producer undequeued buffer count failed: %s (%d)",
304f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                __FUNCTION__, strerror(-res), res);
305f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Query producer undequeued buffer count failed");
306f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
307f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     }
308f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
309f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    size_t totalBufferCount = maxImages + minUndequeuedBufferCount;
310f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = native_window_set_buffer_count(anw.get(), totalBufferCount);
311f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
312f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGE("%s: Set buffer count failed: %s (%d)", __FUNCTION__, strerror(-res), res);
313f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Set buffer count failed");
314f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
315f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
316f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
317f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx != 0) {
318f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ctx->incStrong((void*)ImageWriter_init);
319f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
320f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return nativeCtx;
321f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
322f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
323f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void ImageWriter_dequeueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image) {
324f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
325f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
326f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
327f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
328f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "ImageWriterContext is not initialized");
329f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
330f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
331f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
332f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<ANativeWindow> anw = ctx->getProducer();
333f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    android_native_buffer_t *anb = NULL;
334f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int fenceFd = -1;
335f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    status_t res = anw->dequeueBuffer(anw.get(), &anb, &fenceFd);
336f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
337a58271419ee5b4d8d2a6e25c602a0c40719f33e0Zhijun He        ALOGE("%s: Dequeue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res);
338e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        switch (res) {
339e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            case NO_INIT:
340e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowException(env, "java/lang/IllegalStateException",
341e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                    "Surface has been abandoned");
342e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                break;
343e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            default:
344e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                // TODO: handle other error cases here.
345e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowRuntimeException(env, "dequeue buffer failed");
346e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        }
347f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
348f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
349f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // New GraphicBuffer object doesn't own the handle, thus the native buffer
350f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // won't be freed when this object is destroyed.
351845eef05ffea53f4ce7a1e0551896be874c4f302Mathias Agopian    sp<GraphicBuffer> buffer(GraphicBuffer::from(anb));
352f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
353f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Note that:
354f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // 1. No need to lock buffer now, will only lock it when the first getPlanes() is called.
355f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // 2. Fence will be saved to mNativeFenceFd, and will consumed by lock/queue/cancel buffer
356f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    //    later.
357f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // 3. need use lockAsync here, as it will handle the dequeued fence for us automatically.
358f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
359f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Finally, set the native info into image object.
360f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_setNativeContext(env, image, buffer, fenceFd);
361f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
362f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
363f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void ImageWriter_close(JNIEnv* env, jobject thiz, jlong nativeCtx) {
364f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s:", __FUNCTION__);
365f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
366f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
3670375cb042d54a6d7c93795b4d117b138f02bd1e0Chien-Yu Chen        // ImageWriter is already closed.
368f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
369f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
370f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
371f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ANativeWindow* producer = ctx->getProducer();
372f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (producer != NULL) {
373f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        /**
374f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * NATIVE_WINDOW_API_CPU isn't a good choice here, as it makes the bufferQueue not
375f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * connectable after disconnect. MEDIA or CAMERA are treated the same internally.
376f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * The producer listener will be cleared after disconnect call.
377f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         */
378f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        status_t res = native_window_api_disconnect(producer, /*api*/NATIVE_WINDOW_API_CAMERA);
379f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        /**
380f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * This is not an error. if client calling process dies, the window will
381f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * also die and all calls to it will return DEAD_OBJECT, thus it's already
382f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         * "disconnected"
383f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He         */
384f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (res == DEAD_OBJECT) {
385f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            ALOGW("%s: While disconnecting ImageWriter from native window, the"
386f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    " native window died already", __FUNCTION__);
387f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        } else if (res != OK) {
388f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            ALOGE("%s: native window disconnect failed: %s (%d)",
389f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    __FUNCTION__, strerror(-res), res);
390f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            jniThrowRuntimeException(env, "Native window disconnect failed");
391f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return;
392f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
393f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
394f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
395f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ctx->decStrong((void*)ImageWriter_init);
396f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
397f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
398f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void ImageWriter_cancelImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image) {
399f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
400f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
401f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
402dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        ALOGW("ImageWriter#close called before Image#close, consider calling Image#close first");
403f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
404f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
405f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
406f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<ANativeWindow> anw = ctx->getProducer();
407f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
408f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer *buffer = NULL;
409f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int fenceFd = -1;
410f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, image, &buffer, &fenceFd);
411f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
412dc6bb24a3c2c830c909523e8d7d999fb556fb77dZhijun He        // Cancel an already cancelled image is harmless.
413f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
414f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
415f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
416f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Unlock the image if it was locked
417f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_unlockIfLocked(env, image);
418f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
419f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    anw->cancelBuffer(anw.get(), buffer, fenceFd);
420f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
421f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_setNativeContext(env, image, NULL, -1);
422f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
423f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
424f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void ImageWriter_queueImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image,
425f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jlong timestampNs, jint left, jint top, jint right, jint bottom) {
426f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
427f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
428f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
429f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
430f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "ImageWriterContext is not initialized");
431f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
432f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
433f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
434f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    status_t res = OK;
435f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    sp<ANativeWindow> anw = ctx->getProducer();
436f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
437f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer *buffer = NULL;
438f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int fenceFd = -1;
439f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, image, &buffer, &fenceFd);
440f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
441f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
442f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
443f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
444f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
445f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
446f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Unlock image if it was locked.
447f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_unlockIfLocked(env, image);
448f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
449f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Set timestamp
450d1cbc684053986c6c9efc6220bd79d654932b3d0Zhijun He    ALOGV("timestamp to be queued: %" PRId64, timestampNs);
451f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = native_window_set_buffers_timestamp(anw.get(), timestampNs);
452f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
453f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Set timestamp failed");
454f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
455f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
456f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
457f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Set crop
458f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    android_native_rect_t cropRect;
459f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    cropRect.left = left;
460f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    cropRect.top = top;
461f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    cropRect.right = right;
462f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    cropRect.bottom = bottom;
463f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = native_window_set_crop(anw.get(), &cropRect);
464f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
465f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Set crop rect failed");
466f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
467f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
468f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
469f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Finally, queue input buffer
470f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    res = anw->queueBuffer(anw.get(), buffer, fenceFd);
471f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (res != OK) {
472e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res);
473e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        switch (res) {
474e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            case NO_INIT:
475e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowException(env, "java/lang/IllegalStateException",
476e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                    "Surface has been abandoned");
477e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                break;
478e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            default:
479e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                // TODO: handle other error cases here.
480e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowRuntimeException(env, "Queue input buffer failed");
481e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        }
482f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
483f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
484f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
485ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Clear the image native context: end of this image's lifecycle in public API.
486f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_setNativeContext(env, image, NULL, -1);
487f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
488f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
489ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun Hestatic jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nativeCtx,
490ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jlong nativeBuffer, jint imageFormat, jlong timestampNs, jint left, jint top,
491ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jint right, jint bottom) {
492f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
493f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
494f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (ctx == NULL || thiz == NULL) {
495f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
496f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "ImageWriterContext is not initialized");
497ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return -1;
498f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
499f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
500ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    sp<Surface> surface = ctx->getProducer();
501ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    status_t res = OK;
50207ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala    if (isFormatOpaque(imageFormat) != isFormatOpaque(ctx->getBufferFormat())) {
503f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
50407ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala                "Trying to attach an opaque image into a non-opaque ImageWriter, or vice versa");
505ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return -1;
506ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
507ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
508ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Image is guaranteed to be from ImageReader at this point, so it is safe to
509ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // cast to BufferItem pointer.
51007ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala    BufferItem* buffer = reinterpret_cast<BufferItem*>(nativeBuffer);
51107ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala    if (buffer == NULL) {
512ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jniThrowException(env, "java/lang/IllegalStateException",
513ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He                "Image is not initialized or already closed");
514ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return -1;
515ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
516ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
517ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Step 1. Attach Image
51807ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala    res = surface->attachBuffer(buffer->mGraphicBuffer.get());
519ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (res != OK) {
520ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        ALOGE("Attach image failed: %s (%d)", strerror(-res), res);
521e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        switch (res) {
522e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            case NO_INIT:
523e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowException(env, "java/lang/IllegalStateException",
524e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                    "Surface has been abandoned");
525e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                break;
526e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            default:
527e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                // TODO: handle other error cases here.
528e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowRuntimeException(env, "nativeAttachImage failed!!!");
529e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        }
530ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return res;
531f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
532ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    sp < ANativeWindow > anw = surface;
533f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
534ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Step 2. Set timestamp and crop. Note that we do not need unlock the image because
535ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // it was not locked.
536ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    ALOGV("timestamp to be queued: %" PRId64, timestampNs);
537ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    res = native_window_set_buffers_timestamp(anw.get(), timestampNs);
538ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (res != OK) {
539ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jniThrowRuntimeException(env, "Set timestamp failed");
540ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return res;
541ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
542ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
543ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    android_native_rect_t cropRect;
544ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    cropRect.left = left;
545ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    cropRect.top = top;
546ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    cropRect.right = right;
547ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    cropRect.bottom = bottom;
548ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    res = native_window_set_crop(anw.get(), &cropRect);
549ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (res != OK) {
550ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        jniThrowRuntimeException(env, "Set crop rect failed");
551ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return res;
552ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
553ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
554ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Step 3. Queue Image.
55507ad459c84b565ea216854a64e726a16c5824640Eino-Ville Talvala    res = anw->queueBuffer(anw.get(), buffer->mGraphicBuffer.get(), /*fenceFd*/
556ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He            -1);
557ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (res != OK) {
558e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res);
559e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        switch (res) {
560e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            case NO_INIT:
561e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowException(env, "java/lang/IllegalStateException",
562e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                    "Surface has been abandoned");
563e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                break;
564e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen            default:
565e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                // TODO: handle other error cases here.
566e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen                jniThrowRuntimeException(env, "Queue input buffer failed");
567e0ee63046ad062040aafc977585fb461a2acf666Chien-Yu Chen        }
568ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return res;
569ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
570ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
571ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // Do not set the image native context. Since it would overwrite the existing native context
572ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    // of the image that is from ImageReader, the subsequent image close will run into issues.
573ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He
574ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    return res;
575f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
576f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
577f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He// --------------------------Image methods---------------------------------------
578f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
579f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_getNativeContext(JNIEnv* env, jobject thiz,
580f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        GraphicBuffer** buffer, int* fenceFd) {
581f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
582f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer != NULL) {
583f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        GraphicBuffer *gb = reinterpret_cast<GraphicBuffer *>
584f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                  (env->GetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer));
585f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        *buffer = gb;
586f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
587f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
588f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (fenceFd != NULL) {
589f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        *fenceFd = reinterpret_cast<jint>(env->GetIntField(
590f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                thiz, gSurfaceImageClassInfo.mNativeFenceFd));
591f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
592f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
593f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
594f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_setNativeContext(JNIEnv* env, jobject thiz,
595f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        sp<GraphicBuffer> buffer, int fenceFd) {
596f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s:", __FUNCTION__);
597f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* p = NULL;
598f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &p, /*fenceFd*/NULL);
599f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer != 0) {
600f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        buffer->incStrong((void*)Image_setNativeContext);
601f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
602f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (p) {
603f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        p->decStrong((void*)Image_setNativeContext);
604f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
605f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer,
606f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            reinterpret_cast<jlong>(buffer.get()));
607f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
608f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, reinterpret_cast<jint>(fenceFd));
609f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
610f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
611f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_unlockIfLocked(JNIEnv* env, jobject thiz) {
612f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
613f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
614f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, NULL);
615f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
616f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
617f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
618f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
619f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
620f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
621f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Is locked?
622f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    bool isLocked = false;
623ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    jobject planes = NULL;
624ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (!isFormatOpaque(buffer->getPixelFormat())) {
625ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        planes = env->GetObjectField(thiz, gSurfaceImageClassInfo.mPlanes);
626ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
627f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    isLocked = (planes != NULL);
628f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (isLocked) {
629ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        // no need to use fence here, as we it will be consumed by either cancel or queue buffer.
630f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        status_t res = buffer->unlock();
631f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (res != OK) {
632f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            jniThrowRuntimeException(env, "unlock buffer failed");
633f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
634f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ALOGV("Successfully unlocked the image");
635f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
636f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
637f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
638f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic jint Image_getWidth(JNIEnv* env, jobject thiz) {
639f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
640f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
641f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, NULL);
642f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
643f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
644f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
645f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return -1;
646f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
647f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
648f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return buffer->getWidth();
649f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
650f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
651f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic jint Image_getHeight(JNIEnv* env, jobject thiz) {
652f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
653f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
654f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, NULL);
655f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
656f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
657f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
658f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return -1;
659f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
660f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
661f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return buffer->getHeight();
662f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
663f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
664f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic jint Image_getFormat(JNIEnv* env, jobject thiz) {
665f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
666f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
667f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, NULL);
668f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
669f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
670f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
671f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return 0;
672f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
673f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
6740ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    // ImageWriter doesn't support data space yet, assuming it is unknown.
6750ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
6760ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            buffer->getPixelFormat(), HAL_DATASPACE_UNKNOWN);
6770ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    return static_cast<jint>(publicFmt);
678f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
679f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
680f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_setFenceFd(JNIEnv* env, jobject thiz, int fenceFd) {
681f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s:", __FUNCTION__);
682f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, reinterpret_cast<jint>(fenceFd));
683f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
684f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
685f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) {
686f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
687f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    GraphicBuffer* buffer;
688f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int fenceFd = -1;
689f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getNativeContext(env, thiz, &buffer, &fenceFd);
690f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (buffer == NULL) {
691f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalStateException",
692f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                "Image is not initialized");
693f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return;
694f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
695f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
6960ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    // ImageWriter doesn't use crop by itself, app sets it, use the no crop version.
6970ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    const Rect noCrop(buffer->width, buffer->height);
6980ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    status_t res = lockImageFromBuffer(
6990ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, noCrop, fenceFd, image);
7000ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    // Clear the fenceFd as it is already consumed by lock call.
7010ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    Image_setFenceFd(env, thiz, /*fenceFd*/-1);
7020ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    if (res != OK) {
7030ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
7040ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                "lock buffer failed for format 0x%x",
7050ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                buffer->getPixelFormat());
7060ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        return;
707f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
708f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
7090ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    ALOGV("%s: Successfully locked the image", __FUNCTION__);
710f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // crop, transform, scalingMode, timestamp, and frameNumber should be set by producer,
711f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // and we don't set them here.
712f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
713f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
714f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
715f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
716f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s", __FUNCTION__);
717f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
7180ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    status_t res = getLockedImageInfo(buffer, idx, writerFormat, base, size,
7190ab416269a866c8afa8f65d9351afa2407abee4cZhijun He            pixelStride, rowStride);
7200ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    if (res != OK) {
7210ab416269a866c8afa8f65d9351afa2407abee4cZhijun He        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
7220ab416269a866c8afa8f65d9351afa2407abee4cZhijun He                             "Pixel format: 0x%x is unsupported", buffer->flexFormat);
7230ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    }
724f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
725f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
726f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
727f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        int numPlanes, int writerFormat) {
728f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
729f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int rowStride, pixelStride;
730f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    uint8_t *pData;
731f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    uint32_t dataSize;
732f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jobject byteBuffer;
733f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
734f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int format = Image_getFormat(env, thiz);
735ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (isFormatOpaque(format) && numPlanes > 0) {
736f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        String8 msg;
737f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
738f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                " must be 0", format, numPlanes);
739f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowException(env, "java/lang/IllegalArgumentException", msg.string());
740f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return NULL;
741f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
742f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
743f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    jobjectArray surfacePlanes = env->NewObjectArray(numPlanes, gSurfacePlaneClassInfo.clazz,
744f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            /*initial_element*/NULL);
745f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    if (surfacePlanes == NULL) {
746f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jniThrowRuntimeException(env, "Failed to create SurfacePlane arrays,"
747f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                " probably out of memory");
748f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        return NULL;
749f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
750ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    if (isFormatOpaque(format)) {
751ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He        return surfacePlanes;
752ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    }
753f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
754f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Buildup buffer info: rowStride, pixelStride and byteBuffers.
755f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    LockedImage lockedImg = LockedImage();
756f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    Image_getLockedImage(env, thiz, &lockedImg);
757f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
758f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    // Create all SurfacePlanes
7590ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    PublicFormat publicWriterFormat = static_cast<PublicFormat>(writerFormat);
7600ab416269a866c8afa8f65d9351afa2407abee4cZhijun He    writerFormat = android_view_Surface_mapPublicFormatToHalFormat(publicWriterFormat);
761f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    for (int i = 0; i < numPlanes; i++) {
762f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        Image_getLockedImageInfo(env, &lockedImg, i, writerFormat,
763f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                &pData, &dataSize, &pixelStride, &rowStride);
764f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
765f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
766f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            jniThrowException(env, "java/lang/IllegalStateException",
767f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    "Failed to allocate ByteBuffer");
768f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            return NULL;
769f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
770f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
771f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        // Finally, create this SurfacePlane.
772f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        jobject surfacePlane = env->NewObject(gSurfacePlaneClassInfo.clazz,
773f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    gSurfacePlaneClassInfo.ctor, thiz, rowStride, pixelStride, byteBuffer);
774f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        env->SetObjectArrayElement(surfacePlanes, i, surfacePlane);
775f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
776f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
777f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return surfacePlanes;
778f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
779f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
780f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He} // extern "C"
781f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
782f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He// ----------------------------------------------------------------------------
783f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
784f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic JNINativeMethod gImageWriterMethods[] = {
785f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeClassInit",         "()V",                        (void*)ImageWriter_classInit },
786916d8ac650865cd05808d48bad68b69bebbc95abZhijun He    {"nativeInit",              "(Ljava/lang/Object;Landroid/view/Surface;II)J",
787f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                                                              (void*)ImageWriter_init },
788ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    {"nativeClose",              "(J)V",                      (void*)ImageWriter_close },
789ce9d6f9c75e2254f3704996e232e57e0c8f686d8Zhijun He    {"nativeAttachAndQueueImage", "(JJIJIIII)I",          (void*)ImageWriter_attachAndQueueImage },
790f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeDequeueInputImage", "(JLandroid/media/Image;)V",  (void*)ImageWriter_dequeueImage },
791f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeQueueInputImage",   "(JLandroid/media/Image;JIIII)V",  (void*)ImageWriter_queueImage },
792f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"cancelImage",             "(JLandroid/media/Image;)V",   (void*)ImageWriter_cancelImage },
793f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He};
794f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
795f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hestatic JNINativeMethod gImageMethods[] = {
796f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeCreatePlanes",      "(II)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;",
797f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                                                              (void*)Image_createSurfacePlanes },
798f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeGetWidth",         "()I",                         (void*)Image_getWidth },
799f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeGetHeight",        "()I",                         (void*)Image_getHeight },
800f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    {"nativeGetFormat",        "()I",                         (void*)Image_getFormat },
801f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He};
802f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
803f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heint register_android_media_ImageWriter(JNIEnv *env) {
804f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
805f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int ret1 = AndroidRuntime::registerNativeMethods(env,
806f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                   "android/media/ImageWriter", gImageWriterMethods, NELEM(gImageWriterMethods));
807f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
808f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    int ret2 = AndroidRuntime::registerNativeMethods(env,
809f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                   "android/media/ImageWriter$WriterSurfaceImage", gImageMethods, NELEM(gImageMethods));
810f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
811f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    return (ret1 || ret2);
812f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
813