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