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