1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Legacy-CameraDevice-JNI"
18// #define LOG_NDEBUG 0
19#include <utils/Log.h>
20#include <utils/Errors.h>
21#include <utils/Trace.h>
22#include <camera/CameraUtils.h>
23
24#include "jni.h"
25#include "JNIHelp.h"
26#include "core_jni_helpers.h"
27#include "android_runtime/android_view_Surface.h"
28#include "android_runtime/android_graphics_SurfaceTexture.h"
29
30#include <gui/Surface.h>
31#include <gui/IGraphicBufferProducer.h>
32#include <ui/GraphicBuffer.h>
33#include <system/window.h>
34#include <hardware/camera3.h>
35#include <system/camera_metadata.h>
36
37#include <stdint.h>
38#include <inttypes.h>
39
40using namespace android;
41
42// fully-qualified class name
43#define CAMERA_DEVICE_CLASS_NAME "android/hardware/camera2/legacy/LegacyCameraDevice"
44#define CAMERA_DEVICE_BUFFER_SLACK  3
45#define DONT_CARE 0
46
47#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
48
49#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
50
51/**
52 * Convert from RGB 888 to Y'CbCr using the conversion specified in JFIF v1.02
53 */
54static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, uint8_t* yPlane,
55        uint8_t* crPlane, uint8_t* cbPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
56    uint8_t R, G, B;
57    size_t index = 0;
58    for (size_t j = 0; j < height; j++) {
59        uint8_t* cr = crPlane;
60        uint8_t* cb = cbPlane;
61        uint8_t* y = yPlane;
62        bool jEven = (j & 1) == 0;
63        for (size_t i = 0; i < width; i++) {
64            R = rgbBuf[index++];
65            G = rgbBuf[index++];
66            B = rgbBuf[index++];
67            *y++ = (77 * R + 150 * G +  29 * B) >> 8;
68            if (jEven && (i & 1) == 0) {
69                *cb = (( -43 * R - 85 * G + 128 * B) >> 8) + 128;
70                *cr = (( 128 * R - 107 * G - 21 * B) >> 8) + 128;
71                cr += chromaStep;
72                cb += chromaStep;
73            }
74            // Skip alpha
75            index++;
76        }
77        yPlane += yStride;
78        if (jEven) {
79            crPlane += chromaStride;
80            cbPlane += chromaStride;
81        }
82    }
83}
84
85static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, android_ycbcr* ycbcr) {
86    size_t cStep = ycbcr->chroma_step;
87    size_t cStride = ycbcr->cstride;
88    size_t yStride = ycbcr->ystride;
89    ALOGV("%s: yStride is: %zu, cStride is: %zu, cStep is: %zu", __FUNCTION__, yStride, cStride,
90            cStep);
91    rgbToYuv420(rgbBuf, width, height, reinterpret_cast<uint8_t*>(ycbcr->y),
92            reinterpret_cast<uint8_t*>(ycbcr->cr), reinterpret_cast<uint8_t*>(ycbcr->cb),
93            cStep, yStride, cStride);
94}
95
96static status_t configureSurface(const sp<ANativeWindow>& anw,
97                                 int32_t width,
98                                 int32_t height,
99                                 int32_t pixelFmt,
100                                 int32_t maxBufferSlack) {
101    status_t err = NO_ERROR;
102    err = native_window_set_buffers_dimensions(anw.get(), width, height);
103    if (err != NO_ERROR) {
104        ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__,
105                strerror(-err), err);
106        return err;
107    }
108
109    err = native_window_set_buffers_format(anw.get(), pixelFmt);
110    if (err != NO_ERROR) {
111        ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__,
112                strerror(-err), err);
113        return err;
114    }
115
116    err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
117    if (err != NO_ERROR) {
118        ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__,
119                strerror(-err), err);
120        return err;
121    }
122
123    int minUndequeuedBuffers;
124    err = anw.get()->query(anw.get(),
125            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
126            &minUndequeuedBuffers);
127    if (err != NO_ERROR) {
128        ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).",
129                __FUNCTION__, strerror(-err), err);
130        return err;
131    }
132
133    ALOGV("%s: Setting buffer count to %d, size to (%dx%d), fmt (0x%x)", __FUNCTION__,
134          maxBufferSlack + 1 + minUndequeuedBuffers,
135          width, height, pixelFmt);
136    err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
137    if (err != NO_ERROR) {
138        ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__,
139                strerror(-err), err);
140        return err;
141    }
142    return NO_ERROR;
143}
144
145/**
146 * Produce a frame in the given surface.
147 *
148 * Args:
149 *    anw - a surface to produce a frame in.
150 *    pixelBuffer - image buffer to generate a frame from.
151 *    width - width of the pixelBuffer in pixels.
152 *    height - height of the pixelBuffer in pixels.
153 *    pixelFmt - format of the pixelBuffer, one of:
154 *               HAL_PIXEL_FORMAT_YCrCb_420_SP,
155 *               HAL_PIXEL_FORMAT_YCbCr_420_888,
156 *               HAL_PIXEL_FORMAT_BLOB
157 *    bufSize - the size of the pixelBuffer in bytes.
158 */
159static status_t produceFrame(const sp<ANativeWindow>& anw,
160                             uint8_t* pixelBuffer,
161                             int32_t bufWidth, // Width of the pixelBuffer
162                             int32_t bufHeight, // Height of the pixelBuffer
163                             int32_t pixelFmt, // Format of the pixelBuffer
164                             int32_t bufSize) {
165    ATRACE_CALL();
166    status_t err = NO_ERROR;
167    ANativeWindowBuffer* anb;
168    ALOGV("%s: Dequeue buffer from %p %dx%d (fmt=%x, size=%x)",
169            __FUNCTION__, anw.get(), bufWidth, bufHeight, pixelFmt, bufSize);
170
171    if (anw == 0) {
172        ALOGE("%s: anw must not be NULL", __FUNCTION__);
173        return BAD_VALUE;
174    } else if (pixelBuffer == NULL) {
175        ALOGE("%s: pixelBuffer must not be NULL", __FUNCTION__);
176        return BAD_VALUE;
177    } else if (bufWidth < 0) {
178        ALOGE("%s: width must be non-negative", __FUNCTION__);
179        return BAD_VALUE;
180    } else if (bufHeight < 0) {
181        ALOGE("%s: height must be non-negative", __FUNCTION__);
182        return BAD_VALUE;
183    } else if (bufSize < 0) {
184        ALOGE("%s: bufSize must be non-negative", __FUNCTION__);
185        return BAD_VALUE;
186    }
187
188    size_t width = static_cast<size_t>(bufWidth);
189    size_t height = static_cast<size_t>(bufHeight);
190    size_t bufferLength = static_cast<size_t>(bufSize);
191
192    // TODO: Switch to using Surface::lock and Surface::unlockAndPost
193    err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
194    if (err != NO_ERROR) return err;
195
196    sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false));
197    uint32_t grallocBufWidth = buf->getWidth();
198    uint32_t grallocBufHeight = buf->getHeight();
199    uint32_t grallocBufStride = buf->getStride();
200    if (grallocBufWidth != width || grallocBufHeight != height) {
201        ALOGE("%s: Received gralloc buffer with bad dimensions %" PRIu32 "x%" PRIu32
202                ", expecting dimensions %zu x %zu",  __FUNCTION__, grallocBufWidth,
203                grallocBufHeight, width, height);
204        return BAD_VALUE;
205    }
206
207    int32_t bufFmt = 0;
208    err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &bufFmt);
209    if (err != NO_ERROR) {
210        ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__,
211                strerror(-err), err);
212        return err;
213    }
214
215    uint64_t tmpSize = (pixelFmt == HAL_PIXEL_FORMAT_BLOB) ? grallocBufWidth :
216            4 * grallocBufHeight * grallocBufWidth;
217    if (bufFmt != pixelFmt) {
218        if (bufFmt == HAL_PIXEL_FORMAT_RGBA_8888 && pixelFmt == HAL_PIXEL_FORMAT_BLOB) {
219            ALOGV("%s: Using BLOB to RGBA format override.", __FUNCTION__);
220            tmpSize = 4 * (grallocBufWidth + grallocBufStride * (grallocBufHeight - 1));
221        } else {
222            ALOGW("%s: Format mismatch in produceFrame: expecting format %#" PRIx32
223                    ", but received buffer with format %#" PRIx32, __FUNCTION__, pixelFmt, bufFmt);
224        }
225    }
226
227    if (tmpSize > SIZE_MAX) {
228        ALOGE("%s: Overflow calculating size, buffer with dimens %zu x %zu is absurdly large...",
229                __FUNCTION__, width, height);
230        return BAD_VALUE;
231    }
232
233    size_t totalSizeBytes = tmpSize;
234
235    ALOGV("%s: Pixel format chosen: %x", __FUNCTION__, pixelFmt);
236    switch(pixelFmt) {
237        case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
238            if (bufferLength < totalSizeBytes) {
239                ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
240                        __FUNCTION__, bufferLength);
241                return BAD_VALUE;
242            }
243            uint8_t* img = NULL;
244            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
245            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
246            if (err != NO_ERROR) return err;
247
248            uint8_t* yPlane = img;
249            uint8_t* uPlane = img + height * width;
250            uint8_t* vPlane = uPlane + 1;
251            size_t chromaStep = 2;
252            size_t yStride = width;
253            size_t chromaStride = width;
254
255            rgbToYuv420(pixelBuffer, width, height, yPlane,
256                    uPlane, vPlane, chromaStep, yStride, chromaStride);
257            break;
258        }
259        case HAL_PIXEL_FORMAT_YV12: {
260            if (bufferLength < totalSizeBytes) {
261                ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
262                        __FUNCTION__, bufferLength);
263                return BAD_VALUE;
264            }
265
266            if ((width & 1) || (height & 1)) {
267                ALOGE("%s: Dimens %zu x %zu are not divisible by 2.", __FUNCTION__, width, height);
268                return BAD_VALUE;
269            }
270
271            uint8_t* img = NULL;
272            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
273            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
274            if (err != NO_ERROR) {
275                ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__,
276                        strerror(-err), err);
277                return err;
278            }
279
280            uint32_t stride = buf->getStride();
281            ALOGV("%s: stride is: %" PRIu32, __FUNCTION__, stride);
282            LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride);
283
284            uint32_t cStride = ALIGN(stride / 2, 16);
285            size_t chromaStep = 1;
286
287            uint8_t* yPlane = img;
288            uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride;
289            uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2;
290
291            rgbToYuv420(pixelBuffer, width, height, yPlane,
292                    crPlane, cbPlane, chromaStep, stride, cStride);
293            break;
294        }
295        case HAL_PIXEL_FORMAT_YCbCr_420_888: {
296            // Software writes with YCbCr_420_888 format are unsupported
297            // by the gralloc module for now
298            if (bufferLength < totalSizeBytes) {
299                ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
300                        __FUNCTION__, bufferLength);
301                return BAD_VALUE;
302            }
303            android_ycbcr ycbcr = android_ycbcr();
304            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
305
306            err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr);
307            if (err != NO_ERROR) {
308                ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__,
309                        strerror(-err), err);
310                return err;
311            }
312            rgbToYuv420(pixelBuffer, width, height, &ycbcr);
313            break;
314        }
315        case HAL_PIXEL_FORMAT_BLOB: {
316            int8_t* img = NULL;
317            struct camera3_jpeg_blob footer = {
318                .jpeg_blob_id = CAMERA3_JPEG_BLOB_ID,
319                .jpeg_size = (uint32_t)bufferLength
320            };
321
322            size_t totalJpegSize = bufferLength + sizeof(footer);
323            totalJpegSize = (totalJpegSize + 3) & ~0x3; // round up to nearest octonibble
324
325            if (totalJpegSize > totalSizeBytes) {
326                ALOGE("%s: Pixel buffer needs size %zu, cannot fit in gralloc buffer of size %zu",
327                        __FUNCTION__, totalJpegSize, totalSizeBytes);
328                return BAD_VALUE;
329            }
330
331            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
332            if (err != NO_ERROR) {
333                ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err),
334                        err);
335                return err;
336            }
337
338            memcpy(img, pixelBuffer, bufferLength);
339            memcpy(img + totalSizeBytes - sizeof(footer), &footer, sizeof(footer));
340            break;
341        }
342        default: {
343            ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt);
344            return BAD_VALUE;
345        }
346    }
347
348    ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get());
349    err = buf->unlock();
350    if (err != NO_ERROR) {
351        ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
352        return err;
353    }
354
355    ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get());
356    err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1);
357    if (err != NO_ERROR) {
358        ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
359        return err;
360    }
361    return NO_ERROR;
362}
363
364static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
365    sp<ANativeWindow> anw;
366    if (surface) {
367        anw = android_view_Surface_getNativeWindow(env, surface);
368        if (env->ExceptionCheck()) {
369            return NULL;
370        }
371    } else {
372        jniThrowNullPointerException(env, "surface");
373        return NULL;
374    }
375    if (anw == NULL) {
376        ALOGE("%s: Surface had no valid native window.", __FUNCTION__);
377        return NULL;
378    }
379    return anw;
380}
381
382static sp<ANativeWindow> getNativeWindowFromTexture(JNIEnv* env, jobject surfaceTexture) {
383    sp<ANativeWindow> anw;
384    if (surfaceTexture) {
385        anw = android_SurfaceTexture_getNativeWindow(env, surfaceTexture);
386        if (env->ExceptionCheck()) {
387            return NULL;
388        }
389    } else {
390        jniThrowNullPointerException(env, "surfaceTexture");
391        return NULL;
392    }
393    if (anw == NULL) {
394        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
395                "SurfaceTexture had no valid native window.");
396        return NULL;
397    }
398    return anw;
399}
400
401static sp<Surface> getSurface(JNIEnv* env, jobject surface) {
402    sp<Surface> s;
403    if (surface) {
404        s = android_view_Surface_getSurface(env, surface);
405        if (env->ExceptionCheck()) {
406            return NULL;
407        }
408    } else {
409        jniThrowNullPointerException(env, "surface");
410        return NULL;
411    }
412    if (s == NULL) {
413        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
414                "Surface had no valid native Surface.");
415        return NULL;
416    }
417    return s;
418}
419
420extern "C" {
421
422static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) {
423    ALOGV("nativeDetectSurfaceType");
424    sp<ANativeWindow> anw;
425    if ((anw = getNativeWindow(env, surface)) == NULL) {
426        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
427        return BAD_VALUE;
428    }
429    int32_t fmt = 0;
430    status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt);
431    if(err != NO_ERROR) {
432        ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__, strerror(-err),
433                err);
434        return err;
435    }
436    return fmt;
437}
438
439static jint LegacyCameraDevice_nativeDetectSurfaceDataspace(JNIEnv* env, jobject thiz, jobject surface) {
440    ALOGV("nativeDetectSurfaceDataspace");
441    sp<ANativeWindow> anw;
442    if ((anw = getNativeWindow(env, surface)) == NULL) {
443        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
444        return BAD_VALUE;
445    }
446    int32_t fmt = 0;
447    status_t err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, &fmt);
448    if(err != NO_ERROR) {
449        ALOGE("%s: Error while querying surface dataspace  %s (%d).", __FUNCTION__, strerror(-err),
450                err);
451        return err;
452    }
453    return fmt;
454}
455
456static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz,
457          jobject surface, jintArray dimens) {
458    ALOGV("nativeGetSurfaceDimens");
459
460    if (dimens == NULL) {
461        ALOGE("%s: Null dimens argument passed to nativeDetectSurfaceDimens", __FUNCTION__);
462        return BAD_VALUE;
463    }
464
465    if (env->GetArrayLength(dimens) < 2) {
466        ALOGE("%s: Invalid length of dimens argument in nativeDetectSurfaceDimens", __FUNCTION__);
467        return BAD_VALUE;
468    }
469
470    sp<ANativeWindow> anw;
471    if ((anw = getNativeWindow(env, surface)) == NULL) {
472        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
473        return BAD_VALUE;
474    }
475    int32_t dimenBuf[2];
476    status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
477    if(err != NO_ERROR) {
478        ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err),
479                err);
480        return err;
481    }
482    err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
483    if(err != NO_ERROR) {
484        ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
485                err);
486        return err;
487    }
488    env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
489    return NO_ERROR;
490}
491
492static jint LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobject thiz,
493          jobject surface) {
494    ALOGV("nativeDetectSurfaceUsageFlags");
495
496    sp<ANativeWindow> anw;
497    if ((anw = getNativeWindow(env, surface)) == NULL) {
498        jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
499            "Could not retrieve native window from surface.");
500        return BAD_VALUE;
501    }
502    int32_t usage = 0;
503    status_t err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage);
504    if(err != NO_ERROR) {
505        jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
506            "Error while querying surface usage bits");
507        return err;
508    }
509    return usage;
510}
511
512static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz,
513        jobject surfaceTexture, jintArray dimens) {
514    ALOGV("nativeDetectTextureDimens");
515    sp<ANativeWindow> anw;
516    if ((anw = getNativeWindowFromTexture(env, surfaceTexture)) == NULL) {
517        ALOGE("%s: Could not retrieve native window from SurfaceTexture.", __FUNCTION__);
518        return BAD_VALUE;
519    }
520
521    int32_t dimenBuf[2];
522    status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
523    if(err != NO_ERROR) {
524        ALOGE("%s: Error while querying SurfaceTexture width %s (%d)", __FUNCTION__,
525                strerror(-err), err);
526        return err;
527    }
528
529    err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
530    if(err != NO_ERROR) {
531        ALOGE("%s: Error while querying SurfaceTexture height %s (%d)", __FUNCTION__,
532                strerror(-err), err);
533        return err;
534    }
535
536    env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
537    if (env->ExceptionCheck()) {
538        return BAD_VALUE;
539    }
540    return NO_ERROR;
541}
542
543static jint LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface,
544        jint width, jint height, jint pixelFormat) {
545    ALOGV("nativeConfigureSurface");
546    sp<ANativeWindow> anw;
547    if ((anw = getNativeWindow(env, surface)) == NULL) {
548        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
549        return BAD_VALUE;
550    }
551    status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK);
552    if (err != NO_ERROR) {
553        ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
554        return err;
555    }
556    return NO_ERROR;
557}
558
559static jint LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface,
560        jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) {
561    ALOGV("nativeProduceFrame");
562    sp<ANativeWindow> anw;
563
564    if ((anw = getNativeWindow(env, surface)) == NULL) {
565        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
566        return BAD_VALUE;
567    }
568
569    if (pixelBuffer == NULL) {
570        jniThrowNullPointerException(env, "pixelBuffer");
571        return DONT_CARE;
572    }
573
574    int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer));
575    jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL);
576
577    if (pixels == NULL) {
578        jniThrowNullPointerException(env, "pixels");
579        return DONT_CARE;
580    }
581
582    status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height,
583            pixelFormat, bufSize);
584    env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT);
585
586    if (err != NO_ERROR) {
587        ALOGE("%s: Error while producing frame %s (%d).", __FUNCTION__, strerror(-err), err);
588        return err;
589    }
590    return NO_ERROR;
591}
592
593static jint LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface,
594        jint pixelFormat) {
595    ALOGV("nativeSetSurfaceType");
596    sp<ANativeWindow> anw;
597    if ((anw = getNativeWindow(env, surface)) == NULL) {
598        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
599        return BAD_VALUE;
600    }
601    status_t err = native_window_set_buffers_format(anw.get(), pixelFormat);
602    if (err != NO_ERROR) {
603        ALOGE("%s: Error while setting surface format %s (%d).", __FUNCTION__, strerror(-err), err);
604        return err;
605    }
606    return NO_ERROR;
607}
608
609static jint LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface,
610        jint width, jint height) {
611    ALOGV("nativeSetSurfaceDimens");
612    sp<ANativeWindow> anw;
613    if ((anw = getNativeWindow(env, surface)) == NULL) {
614        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
615        return BAD_VALUE;
616    }
617
618    // Set user dimensions only
619    // The producer dimensions are owned by GL
620    status_t err = native_window_set_buffers_user_dimensions(anw.get(), width, height);
621    if (err != NO_ERROR) {
622        ALOGE("%s: Error while setting surface user dimens %s (%d).", __FUNCTION__, strerror(-err),
623                err);
624        return err;
625    }
626    return NO_ERROR;
627}
628
629static jlong LegacyCameraDevice_nativeGetSurfaceId(JNIEnv* env, jobject thiz, jobject surface) {
630    ALOGV("nativeGetSurfaceId");
631    sp<Surface> s;
632    if ((s = getSurface(env, surface)) == NULL) {
633        ALOGE("%s: Could not retrieve native Surface from surface.", __FUNCTION__);
634        return 0;
635    }
636    sp<IGraphicBufferProducer> gbp = s->getIGraphicBufferProducer();
637    if (gbp == NULL) {
638        ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__);
639        return 0;
640    }
641    sp<IBinder> b = IInterface::asBinder(gbp);
642    if (b == NULL) {
643        ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__);
644        return 0;
645    }
646    /*
647     * FIXME: Use better unique ID for surfaces than native IBinder pointer.  Fix also in the camera
648     * service (CameraDeviceClient.h).
649     */
650    return reinterpret_cast<jlong>(b.get());
651}
652
653static jint LegacyCameraDevice_nativeSetSurfaceOrientation(JNIEnv* env, jobject thiz,
654        jobject surface, jint facing, jint orientation) {
655    ALOGV("nativeSetSurfaceOrientation");
656    sp<ANativeWindow> anw;
657    if ((anw = getNativeWindow(env, surface)) == NULL) {
658        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
659        return BAD_VALUE;
660    }
661
662    status_t err = NO_ERROR;
663    CameraMetadata staticMetadata;
664
665    int32_t orientVal = static_cast<int32_t>(orientation);
666    uint8_t facingVal = static_cast<uint8_t>(facing);
667    staticMetadata.update(ANDROID_SENSOR_ORIENTATION, &orientVal, 1);
668    staticMetadata.update(ANDROID_LENS_FACING, &facingVal, 1);
669
670    int32_t transform = 0;
671
672    if ((err = CameraUtils::getRotationTransform(staticMetadata, /*out*/&transform)) != NO_ERROR) {
673        ALOGE("%s: Invalid rotation transform %s (%d)", __FUNCTION__, strerror(-err),
674                err);
675        return err;
676    }
677
678    ALOGV("%s: Setting buffer sticky transform to %d", __FUNCTION__, transform);
679
680    if ((err = native_window_set_buffers_sticky_transform(anw.get(), transform)) != NO_ERROR) {
681        ALOGE("%s: Unable to configure surface transform, error %s (%d)", __FUNCTION__,
682                strerror(-err), err);
683        return err;
684    }
685
686    return NO_ERROR;
687}
688
689static jint LegacyCameraDevice_nativeSetNextTimestamp(JNIEnv* env, jobject thiz, jobject surface,
690        jlong timestamp) {
691    ALOGV("nativeSetNextTimestamp");
692    sp<ANativeWindow> anw;
693    if ((anw = getNativeWindow(env, surface)) == NULL) {
694        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
695        return BAD_VALUE;
696    }
697
698    status_t err = NO_ERROR;
699
700    if ((err = native_window_set_buffers_timestamp(anw.get(), static_cast<int64_t>(timestamp))) !=
701            NO_ERROR) {
702        ALOGE("%s: Unable to set surface timestamp, error %s (%d)", __FUNCTION__, strerror(-err),
703                err);
704        return err;
705    }
706    return NO_ERROR;
707}
708
709static jint LegacyCameraDevice_nativeSetScalingMode(JNIEnv* env, jobject thiz, jobject surface,
710        jint mode) {
711    ALOGV("nativeSetScalingMode");
712    sp<ANativeWindow> anw;
713    if ((anw = getNativeWindow(env, surface)) == NULL) {
714        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
715        return BAD_VALUE;
716    }
717    status_t err = NO_ERROR;
718    if ((err = native_window_set_scaling_mode(anw.get(), static_cast<int>(mode))) != NO_ERROR) {
719        ALOGE("%s: Unable to set surface scaling mode, error %s (%d)", __FUNCTION__,
720                strerror(-err), err);
721        return err;
722    }
723    return NO_ERROR;
724}
725
726static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz) {
727    ALOGV("nativeGetJpegFooterSize");
728    return static_cast<jint>(sizeof(struct camera3_jpeg_blob));
729}
730
731} // extern "C"
732
733static JNINativeMethod gCameraDeviceMethods[] = {
734    { "nativeDetectSurfaceType",
735    "(Landroid/view/Surface;)I",
736    (void *)LegacyCameraDevice_nativeDetectSurfaceType },
737    { "nativeDetectSurfaceDataspace",
738    "(Landroid/view/Surface;)I",
739    (void *)LegacyCameraDevice_nativeDetectSurfaceDataspace },
740    { "nativeDetectSurfaceDimens",
741    "(Landroid/view/Surface;[I)I",
742    (void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
743    { "nativeConfigureSurface",
744    "(Landroid/view/Surface;III)I",
745    (void *)LegacyCameraDevice_nativeConfigureSurface },
746    { "nativeProduceFrame",
747    "(Landroid/view/Surface;[BIII)I",
748    (void *)LegacyCameraDevice_nativeProduceFrame },
749    { "nativeSetSurfaceFormat",
750    "(Landroid/view/Surface;I)I",
751    (void *)LegacyCameraDevice_nativeSetSurfaceFormat },
752    { "nativeSetSurfaceDimens",
753    "(Landroid/view/Surface;II)I",
754    (void *)LegacyCameraDevice_nativeSetSurfaceDimens },
755    { "nativeGetSurfaceId",
756    "(Landroid/view/Surface;)J",
757    (void *)LegacyCameraDevice_nativeGetSurfaceId },
758    { "nativeDetectTextureDimens",
759    "(Landroid/graphics/SurfaceTexture;[I)I",
760    (void *)LegacyCameraDevice_nativeDetectTextureDimens },
761    { "nativeSetSurfaceOrientation",
762    "(Landroid/view/Surface;II)I",
763    (void *)LegacyCameraDevice_nativeSetSurfaceOrientation },
764    { "nativeSetNextTimestamp",
765    "(Landroid/view/Surface;J)I",
766    (void *)LegacyCameraDevice_nativeSetNextTimestamp },
767    { "nativeGetJpegFooterSize",
768    "()I",
769    (void *)LegacyCameraDevice_nativeGetJpegFooterSize },
770    { "nativeDetectSurfaceUsageFlags",
771    "(Landroid/view/Surface;)I",
772    (void *)LegacyCameraDevice_nativeDetectSurfaceUsageFlags },
773    { "nativeSetScalingMode",
774    "(Landroid/view/Surface;I)I",
775    (void *)LegacyCameraDevice_nativeSetScalingMode },
776};
777
778// Get all the required offsets in java class and register native functions
779int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env)
780{
781    // Register native functions
782    return RegisterMethodsOrDie(env,
783            CAMERA_DEVICE_CLASS_NAME,
784            gCameraDeviceMethods,
785            NELEM(gCameraDeviceMethods));
786}
787