android_hardware_camera2_legacy_LegacyCameraDevice.cpp revision ef14da32804b06bac872c9e0e14ce0e52120a0bd
15460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao/*
25460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * Copyright (C) 2014 The Android Open Source Project
35460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao *
45460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * Licensed under the Apache License, Version 2.0 (the "License");
55460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * you may not use this file except in compliance with the License.
65460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * You may obtain a copy of the License at
75460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao *
85460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao *      http://www.apache.org/licenses/LICENSE-2.0
95460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao *
105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * Unless required by applicable law or agreed to in writing, software
115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * distributed under the License is distributed on an "AS IS" BASIS,
125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * See the License for the specific language governing permissions and
1487f34658dec9097d987d254a990ea7f311bfc95fStephen Hines * limitations under the License.
1587f34658dec9097d987d254a990ea7f311bfc95fStephen Hines */
165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
175460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#define LOG_TAG "Legacy-CameraDevice-JNI"
18affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// #define LOG_NDEBUG 0
195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <utils/Log.h>
205460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <utils/Errors.h>
215460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <utils/Trace.h>
225460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
235460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "jni.h"
245460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "JNIHelp.h"
25affc150dc44fab1911775a49636d0ce85333b634Zonr Chang#include "android_runtime/AndroidRuntime.h"
265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "android_runtime/android_view_Surface.h"
275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <ui/GraphicBuffer.h>
295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <system/window.h>
305460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <hardware/camera3.h>
315460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
325460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaousing namespace android;
335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
345460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao// fully-qualified class name
355460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#define CAMERA_DEVICE_CLASS_NAME "android/hardware/camera2/legacy/LegacyCameraDevice"
365460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#define CAMERA_DEVICE_BUFFER_SLACK  3
375460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#define DONT_CARE 0
385460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
395460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
405460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
415460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
425460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
435460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao/**
445460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * Convert from RGB 888 to Y'CbCr using the conversion specified in ITU-R BT.601 for
455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao * digital RGB with K_b = 0.114, and K_r = 0.299.
465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao */
475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, uint8_t* yPlane,
485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        uint8_t* uPlane, uint8_t* vPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    uint8_t R, G, B;
505460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    size_t index = 0;
515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
525460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    int32_t cStrideDiff = chromaStride - width;
535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    for (int32_t j = 0; j < height; j++) {
555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        for (int32_t i = 0; i < width; i++) {
565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            R = rgbBuf[index++];
575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            G = rgbBuf[index++];
585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            B = rgbBuf[index++];
595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            *(yPlane + i) = ((66 * R + 129 * G +  25 * B + 128) >> 8) +  16;
605460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
615460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            if (j % 2 == 0 && i % 2 == 0){
625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                *uPlane = (( -38 * R -  74 * G + 112 * B + 128) >> 8) + 128;
635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                *vPlane = (( 112 * R -  94 * G -  18 * B + 128) >> 8) + 128;
645460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                uPlane += chromaStep;
655460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                vPlane += chromaStep;
665460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            }
675460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            // Skip alpha
685460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            index++;
695460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        }
705460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        yPlane += yStride;
715460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        if (j % 2 == 0) {
725460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            uPlane += cStrideDiff;
735460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            vPlane += cStrideDiff;
745460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        }
755460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
785460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaostatic void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, android_ycbcr* ycbcr) {
795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    size_t cStep = ycbcr->chroma_step;
80f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    size_t cStride = ycbcr->cstride;
815460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    size_t yStride = ycbcr->ystride;
82f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    rgbToYuv420(rgbBuf, width, height, reinterpret_cast<uint8_t*>(ycbcr->y),
83f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines            reinterpret_cast<uint8_t*>(ycbcr->cb), reinterpret_cast<uint8_t*>(ycbcr->cr),
84f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines            cStep, yStride, cStride);
85f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
86f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
87f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesstatic status_t configureSurface(const sp<ANativeWindow>& anw,
885460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                 int32_t width,
89f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                                 int32_t height,
905460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                 int32_t pixelFmt,
915460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                 int32_t maxBufferSlack) {
925460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    status_t err = NO_ERROR;
935460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    err = native_window_set_buffers_dimensions(anw.get(), width, height);
945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (err != NO_ERROR) {
955460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__,
96f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                strerror(-err), err);
97affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        return err;
98affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    }
99affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
100f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    err = native_window_set_buffers_format(anw.get(), pixelFmt);
101f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (err != NO_ERROR) {
102affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__,
103f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                strerror(-err), err);
104f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        return err;
105f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
1065460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1075460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
1085460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (err != NO_ERROR) {
1095460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__,
1105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                strerror(-err), err);
1115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        return err;
1125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
1135460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
114    int minUndequeuedBuffers;
115    err = anw.get()->query(anw.get(),
116            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
117            &minUndequeuedBuffers);
118    if (err != NO_ERROR) {
119        ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).",
120                __FUNCTION__, strerror(-err), err);
121        return err;
122    }
123
124    ALOGV("%s: Setting buffer count to %d, size to (%dx%d), fmt (0x%x)", __FUNCTION__,
125          maxBufferSlack + 1 + minUndequeuedBuffers,
126          width, height, pixelFmt);
127    err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
128    if (err != NO_ERROR) {
129        ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__,
130                strerror(-err), err);
131        return err;
132    }
133    return NO_ERROR;
134}
135
136/**
137 * Produce a frame in the given surface.
138 *
139 * Args:
140 *    anw - a surface to produce a frame in.
141 *    pixelBuffer - image buffer to generate a frame from.
142 *    width - width of the pixelBuffer in pixels.
143 *    height - height of the pixelBuffer in pixels.
144 *    pixelFmt - format of the pixelBuffer, one of:
145 *               HAL_PIXEL_FORMAT_YCrCb_420_SP,
146 *               HAL_PIXEL_FORMAT_YCbCr_420_888,
147 *               HAL_PIXEL_FORMAT_BLOB
148 *    bufSize - the size of the pixelBuffer in bytes.
149 */
150static status_t produceFrame(const sp<ANativeWindow>& anw,
151                             uint8_t* pixelBuffer,
152                             int32_t width, // Width of the pixelBuffer
153                             int32_t height, // Height of the pixelBuffer
154                             int32_t pixelFmt, // Format of the pixelBuffer
155                             int32_t bufSize) {
156    ATRACE_CALL();
157    status_t err = NO_ERROR;
158    ANativeWindowBuffer* anb;
159    ALOGV("%s: Dequeue buffer from %p %dx%d (fmt=%x, size=%x)",
160            __FUNCTION__, anw.get(), width, height, pixelFmt, bufSize);
161
162    if (anw == 0) {
163        ALOGE("%s: anw must not be NULL", __FUNCTION__);
164        return BAD_VALUE;
165    } else if (pixelBuffer == NULL) {
166        ALOGE("%s: pixelBuffer must not be NULL", __FUNCTION__);
167        return BAD_VALUE;
168    } else if (width < 0) {
169        ALOGE("%s: width must be non-negative", __FUNCTION__);
170        return BAD_VALUE;
171    } else if (height < 0) {
172        ALOGE("%s: height must be non-negative", __FUNCTION__);
173        return BAD_VALUE;
174    } else if (bufSize < 0) {
175        ALOGE("%s: bufSize must be non-negative", __FUNCTION__);
176        return BAD_VALUE;
177    }
178
179    if (width < 0 || height < 0 || bufSize < 0) {
180        ALOGE("%s: Illegal argument, negative dimension passed to produceFrame", __FUNCTION__);
181        return BAD_VALUE;
182    }
183
184    // TODO: Switch to using Surface::lock and Surface::unlockAndPost
185    err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
186    if (err != NO_ERROR) return err;
187
188    // TODO: check anb is large enough to store the results
189
190    sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false));
191
192    switch(pixelFmt) {
193        case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
194            if (bufSize < width * height * 4) {
195                ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__,
196                        bufSize);
197                return BAD_VALUE;
198            }
199            uint8_t* img = NULL;
200            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
201            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
202            if (err != NO_ERROR) return err;
203
204            uint8_t* yPlane = img;
205            uint8_t* uPlane = img + height * width;
206            uint8_t* vPlane = uPlane + 1;
207            size_t chromaStep = 2;
208            size_t yStride = width;
209            size_t chromaStride = width;
210
211            rgbToYuv420(pixelBuffer, width, height, yPlane,
212                    uPlane, vPlane, chromaStep, yStride, chromaStride);
213            break;
214        }
215        case HAL_PIXEL_FORMAT_YV12: {
216            if (bufSize < width * height * 4) {
217                ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__,
218                        bufSize);
219                return BAD_VALUE;
220            }
221
222            if ((width & 1) || (height & 1)) {
223                ALOGE("%s: Dimens %dx%d are not divisible by 2.", __FUNCTION__, width, height);
224                return BAD_VALUE;
225            }
226
227            uint8_t* img = NULL;
228            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
229            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
230            if (err != NO_ERROR) {
231                ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__,
232                        strerror(-err), err);
233                return err;
234            }
235
236            uint32_t stride = buf->getStride();
237            LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride);
238
239            uint32_t cStride = ALIGN(stride / 2, 16);
240            size_t chromaStep = 1;
241
242            uint8_t* yPlane = img;
243            uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride;
244            uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2;
245
246            rgbToYuv420(pixelBuffer, width, height, yPlane,
247                    crPlane, cbPlane, chromaStep, stride, cStride);
248            break;
249        }
250        case HAL_PIXEL_FORMAT_YCbCr_420_888: {
251            // Software writes with YCbCr_420_888 format are unsupported
252            // by the gralloc module for now
253            if (bufSize < width * height * 4) {
254                ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__,
255                      bufSize);
256                return BAD_VALUE;
257            }
258            android_ycbcr ycbcr = android_ycbcr();
259            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
260
261            err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr);
262            if (err != NO_ERROR) {
263                ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__,
264                        strerror(-err), err);
265                return err;
266            }
267            rgbToYuv420(pixelBuffer, width, height, &ycbcr);
268            break;
269        }
270        case HAL_PIXEL_FORMAT_BLOB: {
271            if (bufSize != width || height != 1) {
272                ALOGE("%s: Incorrect pixelBuffer size: %lld", __FUNCTION__, bufSize);
273                return BAD_VALUE;
274            }
275            int8_t* img = NULL;
276
277            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
278            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
279            if (err != NO_ERROR) {
280                ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err),
281                        err);
282                return err;
283            }
284            struct camera3_jpeg_blob footer = {
285                jpeg_blob_id: CAMERA3_JPEG_BLOB_ID,
286                jpeg_size: (uint32_t)width
287            };
288            memcpy(img, pixelBuffer, width);
289            memcpy(img + anb->width - sizeof(footer), &footer, sizeof(footer));
290            break;
291        }
292        default: {
293            ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt);
294            return BAD_VALUE;
295        }
296    }
297
298    ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get());
299    err = buf->unlock();
300    if (err != NO_ERROR) {
301        ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
302        return err;
303    }
304
305    ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get());
306    err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1);
307    if (err != NO_ERROR) {
308        ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
309        return err;
310    }
311    return NO_ERROR;
312}
313
314static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
315    sp<ANativeWindow> anw;
316    if (surface) {
317        anw = android_view_Surface_getNativeWindow(env, surface);
318        if (env->ExceptionCheck()) {
319            return anw;
320        }
321    } else {
322        jniThrowNullPointerException(env, "surface");
323        return anw;
324    }
325    if (anw == NULL) {
326        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
327                "Surface had no valid native window.");
328        return anw;
329    }
330    return anw;
331}
332
333extern "C" {
334
335static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) {
336    ALOGV("nativeDetectSurfaceType");
337    sp<ANativeWindow> anw;
338    if ((anw = getNativeWindow(env, surface)) == NULL) {
339        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
340        return BAD_VALUE;
341    }
342    int32_t fmt = 0;
343    status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt);
344    if(err != NO_ERROR) {
345        ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__, strerror(-err),
346                err);
347        return err;
348    }
349    return fmt;
350}
351
352static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz,
353          jobject surface, jintArray dimens) {
354    ALOGV("nativeGetSurfaceDimens");
355    sp<ANativeWindow> anw;
356    if ((anw = getNativeWindow(env, surface)) == NULL) {
357        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
358        return BAD_VALUE;
359    }
360    int32_t dimenBuf[2];
361    status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
362    if(err != NO_ERROR) {
363        ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err),
364                err);
365        return err;
366    }
367    err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
368    if(err != NO_ERROR) {
369        ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
370                err);
371        return err;
372    }
373    env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
374    return NO_ERROR;
375}
376
377static jint LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface,
378        jint width, jint height, jint pixelFormat) {
379    ALOGV("nativeConfigureSurface");
380    sp<ANativeWindow> anw;
381    if ((anw = getNativeWindow(env, surface)) == NULL) {
382        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
383        return BAD_VALUE;
384    }
385    status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK);
386    if (err != NO_ERROR) {
387        ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
388        return err;
389    }
390    return NO_ERROR;
391}
392
393static jint LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface,
394        jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) {
395    ALOGV("nativeProduceFrame");
396    sp<ANativeWindow> anw;
397
398    if ((anw = getNativeWindow(env, surface)) == NULL) {
399        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
400        return BAD_VALUE;
401    }
402
403    if (pixelBuffer == NULL) {
404        jniThrowNullPointerException(env, "pixelBuffer");
405        return DONT_CARE;
406    }
407
408    int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer));
409    jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL);
410
411    if (pixels == NULL) {
412        jniThrowNullPointerException(env, "pixels");
413        return DONT_CARE;
414    }
415
416    status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height,
417            pixelFormat, bufSize);
418    env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT);
419
420    if (err != NO_ERROR) {
421        ALOGE("%s: Error while producing frame %s (%d).", __FUNCTION__, strerror(-err), err);
422        return err;
423    }
424    return NO_ERROR;
425}
426
427static jint LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface,
428        jint pixelFormat) {
429    ALOGV("nativeSetSurfaceType");
430    sp<ANativeWindow> anw;
431    if ((anw = getNativeWindow(env, surface)) == NULL) {
432        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
433        return BAD_VALUE;
434    }
435    status_t err = native_window_set_buffers_format(anw.get(), pixelFormat);
436    if (err != NO_ERROR) {
437        ALOGE("%s: Error while setting surface format %s (%d).", __FUNCTION__, strerror(-err), err);
438        return err;
439    }
440    return NO_ERROR;
441}
442
443static jint LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface,
444        jint width, jint height) {
445    ALOGV("nativeSetSurfaceDimens");
446    sp<ANativeWindow> anw;
447    if ((anw = getNativeWindow(env, surface)) == NULL) {
448        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
449        return BAD_VALUE;
450    }
451    status_t err = native_window_set_buffers_dimensions(anw.get(), width, height);
452    if (err != NO_ERROR) {
453        ALOGE("%s: Error while setting surface dimens %s (%d).", __FUNCTION__, strerror(-err), err);
454        return err;
455    }
456    return NO_ERROR;
457}
458
459} // extern "C"
460
461static JNINativeMethod gCameraDeviceMethods[] = {
462    { "nativeDetectSurfaceType",
463    "(Landroid/view/Surface;)I",
464    (void *)LegacyCameraDevice_nativeDetectSurfaceType },
465    { "nativeDetectSurfaceDimens",
466    "(Landroid/view/Surface;[I)I",
467    (void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
468    { "nativeConfigureSurface",
469    "(Landroid/view/Surface;III)I",
470    (void *)LegacyCameraDevice_nativeConfigureSurface },
471    { "nativeProduceFrame",
472    "(Landroid/view/Surface;[BIII)I",
473    (void *)LegacyCameraDevice_nativeProduceFrame },
474    { "nativeSetSurfaceFormat",
475    "(Landroid/view/Surface;I)I",
476    (void *)LegacyCameraDevice_nativeSetSurfaceFormat },
477    { "nativeSetSurfaceDimens",
478    "(Landroid/view/Surface;II)I",
479    (void *)LegacyCameraDevice_nativeSetSurfaceDimens },
480};
481
482// Get all the required offsets in java class and register native functions
483int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env)
484{
485    // Register native functions
486    return AndroidRuntime::registerNativeMethods(env,
487            CAMERA_DEVICE_CLASS_NAME,
488            gCameraDeviceMethods,
489            NELEM(gCameraDeviceMethods));
490}
491
492