android_hardware_camera2_legacy_LegacyCameraDevice.cpp revision 0fd198ad89ec9c600bb1761b10d938146c28bb98
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, int32_t width, int32_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    int32_t cStrideDiff = chromaStride - width;
61
62    for (int32_t j = 0; j < height; j++) {
63        for (int32_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, int32_t width, int32_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 width, // Width of the pixelBuffer
161                             int32_t height, // 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(), width, height, 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 (width < 0) {
177        ALOGE("%s: width must be non-negative", __FUNCTION__);
178        return BAD_VALUE;
179    } else if (height < 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    if (width < 0 || height < 0 || bufSize < 0) {
188        ALOGE("%s: Illegal argument, negative dimension passed to produceFrame", __FUNCTION__);
189        return BAD_VALUE;
190    }
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    // TODO: check anb is large enough to store the results
197
198    sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false));
199
200    switch(pixelFmt) {
201        case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
202            if (bufSize < width * height * 4) {
203                ALOGE("%s: PixelBuffer size %" PRId32 " too small for given dimensions",
204                        __FUNCTION__, bufSize);
205                return BAD_VALUE;
206            }
207            uint8_t* img = NULL;
208            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
209            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
210            if (err != NO_ERROR) return err;
211
212            uint8_t* yPlane = img;
213            uint8_t* uPlane = img + height * width;
214            uint8_t* vPlane = uPlane + 1;
215            size_t chromaStep = 2;
216            size_t yStride = width;
217            size_t chromaStride = width;
218
219            rgbToYuv420(pixelBuffer, width, height, yPlane,
220                    uPlane, vPlane, chromaStep, yStride, chromaStride);
221            break;
222        }
223        case HAL_PIXEL_FORMAT_YV12: {
224            if (bufSize < width * height * 4) {
225                ALOGE("%s: PixelBuffer size %" PRId32 " too small for given dimensions",
226                        __FUNCTION__, bufSize);
227                return BAD_VALUE;
228            }
229
230            if ((width & 1) || (height & 1)) {
231                ALOGE("%s: Dimens %dx%d are not divisible by 2.", __FUNCTION__, width, height);
232                return BAD_VALUE;
233            }
234
235            uint8_t* img = NULL;
236            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
237            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
238            if (err != NO_ERROR) {
239                ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__,
240                        strerror(-err), err);
241                return err;
242            }
243
244            uint32_t stride = buf->getStride();
245            LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride);
246
247            uint32_t cStride = ALIGN(stride / 2, 16);
248            size_t chromaStep = 1;
249
250            uint8_t* yPlane = img;
251            uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride;
252            uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2;
253
254            rgbToYuv420(pixelBuffer, width, height, yPlane,
255                    crPlane, cbPlane, chromaStep, stride, cStride);
256            break;
257        }
258        case HAL_PIXEL_FORMAT_YCbCr_420_888: {
259            // Software writes with YCbCr_420_888 format are unsupported
260            // by the gralloc module for now
261            if (bufSize < width * height * 4) {
262                ALOGE("%s: PixelBuffer size %" PRId32 " too small for given dimensions",
263                        __FUNCTION__, bufSize);
264                return BAD_VALUE;
265            }
266            android_ycbcr ycbcr = android_ycbcr();
267            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
268
269            err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr);
270            if (err != NO_ERROR) {
271                ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__,
272                        strerror(-err), err);
273                return err;
274            }
275            rgbToYuv420(pixelBuffer, width, height, &ycbcr);
276            break;
277        }
278        case HAL_PIXEL_FORMAT_BLOB: {
279            if (bufSize != width || height != 1) {
280                ALOGE("%s: Incorrect pixelBuffer size: %" PRId32, __FUNCTION__, bufSize);
281                return BAD_VALUE;
282            }
283            int8_t* img = NULL;
284            struct camera3_jpeg_blob footer = {
285                jpeg_blob_id: CAMERA3_JPEG_BLOB_ID,
286                jpeg_size: (uint32_t)width
287            };
288
289            size_t totalSize = static_cast<size_t>(width) + sizeof(footer);
290            size_t padding = ((totalSize - 1) & ~0x3) + 4; // align to next octonibble
291            totalSize += padding;
292            if (anb->width != totalSize) {
293                ALOGE("%s: gralloc buffer wrong size to hold jpeg, failed to produce buffer.");
294                return BAD_VALUE;
295            }
296
297            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
298            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
299            if (err != NO_ERROR) {
300                ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err),
301                        err);
302                return err;
303            }
304            memcpy(img, pixelBuffer, width);
305            memset(img + width, 0, padding);
306            memcpy(img + totalSize - sizeof(footer), &footer, sizeof(footer));
307            break;
308        }
309        default: {
310            ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt);
311            return BAD_VALUE;
312        }
313    }
314
315    ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get());
316    err = buf->unlock();
317    if (err != NO_ERROR) {
318        ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
319        return err;
320    }
321
322    ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get());
323    err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1);
324    if (err != NO_ERROR) {
325        ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
326        return err;
327    }
328    return NO_ERROR;
329}
330
331static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
332    sp<ANativeWindow> anw;
333    if (surface) {
334        anw = android_view_Surface_getNativeWindow(env, surface);
335        if (env->ExceptionCheck()) {
336            return NULL;
337        }
338    } else {
339        jniThrowNullPointerException(env, "surface");
340        return NULL;
341    }
342    if (anw == NULL) {
343        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
344                "Surface had no valid native window.");
345        return NULL;
346    }
347    return anw;
348}
349
350static sp<ANativeWindow> getNativeWindowFromTexture(JNIEnv* env, jobject surfaceTexture) {
351    sp<ANativeWindow> anw;
352    if (surfaceTexture) {
353        anw = android_SurfaceTexture_getNativeWindow(env, surfaceTexture);
354        if (env->ExceptionCheck()) {
355            return NULL;
356        }
357    } else {
358        jniThrowNullPointerException(env, "surfaceTexture");
359        return NULL;
360    }
361    if (anw == NULL) {
362        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
363                "SurfaceTexture had no valid native window.");
364        return NULL;
365    }
366    return anw;
367}
368
369static sp<Surface> getSurface(JNIEnv* env, jobject surface) {
370    sp<Surface> s;
371    if (surface) {
372        s = android_view_Surface_getSurface(env, surface);
373        if (env->ExceptionCheck()) {
374            return NULL;
375        }
376    } else {
377        jniThrowNullPointerException(env, "surface");
378        return NULL;
379    }
380    if (s == NULL) {
381        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
382                "Surface had no valid native Surface.");
383        return NULL;
384    }
385    return s;
386}
387
388extern "C" {
389
390static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) {
391    ALOGV("nativeDetectSurfaceType");
392    sp<ANativeWindow> anw;
393    if ((anw = getNativeWindow(env, surface)) == NULL) {
394        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
395        return BAD_VALUE;
396    }
397    int32_t fmt = 0;
398    status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt);
399    if(err != NO_ERROR) {
400        ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__, strerror(-err),
401                err);
402        return err;
403    }
404    return fmt;
405}
406
407static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz,
408          jobject surface, jintArray dimens) {
409    ALOGV("nativeGetSurfaceDimens");
410
411    if (dimens == NULL) {
412        ALOGE("%s: Null dimens argument passed to nativeDetectSurfaceDimens", __FUNCTION__);
413        return BAD_VALUE;
414    }
415
416    if (env->GetArrayLength(dimens) < 2) {
417        ALOGE("%s: Invalid length of dimens argument in nativeDetectSurfaceDimens", __FUNCTION__);
418        return BAD_VALUE;
419    }
420
421    sp<ANativeWindow> anw;
422    if ((anw = getNativeWindow(env, surface)) == NULL) {
423        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
424        return BAD_VALUE;
425    }
426    int32_t dimenBuf[2];
427    status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
428    if(err != NO_ERROR) {
429        ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err),
430                err);
431        return err;
432    }
433    err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
434    if(err != NO_ERROR) {
435        ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
436                err);
437        return err;
438    }
439    env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
440    return NO_ERROR;
441}
442
443static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz,
444        jobject surfaceTexture, jintArray dimens) {
445    ALOGV("nativeDetectTextureDimens");
446    sp<ANativeWindow> anw;
447    if ((anw = getNativeWindowFromTexture(env, surfaceTexture)) == NULL) {
448        ALOGE("%s: Could not retrieve native window from SurfaceTexture.", __FUNCTION__);
449        return BAD_VALUE;
450    }
451
452    int32_t dimenBuf[2];
453    status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
454    if(err != NO_ERROR) {
455        ALOGE("%s: Error while querying SurfaceTexture width %s (%d)", __FUNCTION__,
456                strerror(-err), err);
457        return err;
458    }
459
460    err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
461    if(err != NO_ERROR) {
462        ALOGE("%s: Error while querying SurfaceTexture height %s (%d)", __FUNCTION__,
463                strerror(-err), err);
464        return err;
465    }
466
467    env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
468    if (env->ExceptionCheck()) {
469        return BAD_VALUE;
470    }
471    return NO_ERROR;
472}
473
474static jint LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface,
475        jint width, jint height, jint pixelFormat) {
476    ALOGV("nativeConfigureSurface");
477    sp<ANativeWindow> anw;
478    if ((anw = getNativeWindow(env, surface)) == NULL) {
479        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
480        return BAD_VALUE;
481    }
482    status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK);
483    if (err != NO_ERROR) {
484        ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
485        return err;
486    }
487    return NO_ERROR;
488}
489
490static jint LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface,
491        jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) {
492    ALOGV("nativeProduceFrame");
493    sp<ANativeWindow> anw;
494
495    if ((anw = getNativeWindow(env, surface)) == NULL) {
496        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
497        return BAD_VALUE;
498    }
499
500    if (pixelBuffer == NULL) {
501        jniThrowNullPointerException(env, "pixelBuffer");
502        return DONT_CARE;
503    }
504
505    int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer));
506    jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL);
507
508    if (pixels == NULL) {
509        jniThrowNullPointerException(env, "pixels");
510        return DONT_CARE;
511    }
512
513    status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height,
514            pixelFormat, bufSize);
515    env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT);
516
517    if (err != NO_ERROR) {
518        ALOGE("%s: Error while producing frame %s (%d).", __FUNCTION__, strerror(-err), err);
519        return err;
520    }
521    return NO_ERROR;
522}
523
524static jint LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface,
525        jint pixelFormat) {
526    ALOGV("nativeSetSurfaceType");
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 = native_window_set_buffers_format(anw.get(), pixelFormat);
533    if (err != NO_ERROR) {
534        ALOGE("%s: Error while setting surface format %s (%d).", __FUNCTION__, strerror(-err), err);
535        return err;
536    }
537    return NO_ERROR;
538}
539
540static jint LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface,
541        jint width, jint height) {
542    ALOGV("nativeSetSurfaceDimens");
543    sp<ANativeWindow> anw;
544    if ((anw = getNativeWindow(env, surface)) == NULL) {
545        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
546        return BAD_VALUE;
547    }
548    status_t err = native_window_set_buffers_dimensions(anw.get(), width, height);
549    if (err != NO_ERROR) {
550        ALOGE("%s: Error while setting surface dimens %s (%d).", __FUNCTION__, strerror(-err), err);
551        return err;
552    }
553
554    // WAR - Set user dimensions also to avoid incorrect scaling after TextureView orientation
555    // change.
556    err = native_window_set_buffers_user_dimensions(anw.get(), width, height);
557    if (err != NO_ERROR) {
558        ALOGE("%s: Error while setting surface user dimens %s (%d).", __FUNCTION__, strerror(-err),
559                err);
560        return err;
561    }
562    return NO_ERROR;
563}
564
565static jlong LegacyCameraDevice_nativeGetSurfaceId(JNIEnv* env, jobject thiz, jobject surface) {
566    ALOGV("nativeGetSurfaceId");
567    sp<Surface> s;
568    if ((s = getSurface(env, surface)) == NULL) {
569        ALOGE("%s: Could not retrieve native Surface from surface.", __FUNCTION__);
570        return 0;
571    }
572    sp<IGraphicBufferProducer> gbp = s->getIGraphicBufferProducer();
573    if (gbp == NULL) {
574        ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__);
575        return 0;
576    }
577    sp<IBinder> b = gbp->asBinder();
578    if (b == NULL) {
579        ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__);
580        return 0;
581    }
582    /*
583     * FIXME: Use better unique ID for surfaces than native IBinder pointer.  Fix also in the camera
584     * service (CameraDeviceClient.h).
585     */
586    return reinterpret_cast<jlong>(b.get());
587}
588
589static jint LegacyCameraDevice_nativeSetSurfaceOrientation(JNIEnv* env, jobject thiz,
590        jobject surface, jint facing, jint orientation) {
591    ALOGV("nativeSetSurfaceOrientation");
592    sp<ANativeWindow> anw;
593    if ((anw = getNativeWindow(env, surface)) == NULL) {
594        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
595        return BAD_VALUE;
596    }
597
598    status_t err = NO_ERROR;
599    CameraMetadata staticMetadata;
600
601    int32_t orientVal = static_cast<int32_t>(orientation);
602    uint8_t facingVal = static_cast<uint8_t>(facing);
603    staticMetadata.update(ANDROID_SENSOR_ORIENTATION, &orientVal, 1);
604    staticMetadata.update(ANDROID_LENS_FACING, &facingVal, 1);
605
606    int32_t transform = 0;
607
608    if ((err = CameraUtils::getRotationTransform(staticMetadata, /*out*/&transform)) != NO_ERROR) {
609        ALOGE("%s: Invalid rotation transform %s (%d)", __FUNCTION__, strerror(-err),
610                err);
611        return err;
612    }
613
614    ALOGV("%s: Setting buffer sticky transform to %d", __FUNCTION__, transform);
615
616    if ((err = native_window_set_buffers_sticky_transform(anw.get(), transform)) != NO_ERROR) {
617        ALOGE("%s: Unable to configure surface transform, error %s (%d)", __FUNCTION__,
618                strerror(-err), err);
619        return err;
620    }
621
622    return NO_ERROR;
623}
624
625static jint LegacyCameraDevice_nativeSetNextTimestamp(JNIEnv* env, jobject thiz, jobject surface,
626        jlong timestamp) {
627    ALOGV("nativeSetNextTimestamp");
628    sp<ANativeWindow> anw;
629    if ((anw = getNativeWindow(env, surface)) == NULL) {
630        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
631        return BAD_VALUE;
632    }
633
634    status_t err = NO_ERROR;
635
636    if ((err = native_window_set_buffers_timestamp(anw.get(), static_cast<int64_t>(timestamp))) !=
637            NO_ERROR) {
638        ALOGE("%s: Unable to set surface timestamp, error %s (%d)", __FUNCTION__, strerror(-err),
639                err);
640        return err;
641    }
642    return NO_ERROR;
643}
644
645static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz) {
646    ALOGV("nativeGetJpegFooterSize");
647    return static_cast<jint>(sizeof(struct camera3_jpeg_blob));
648}
649
650} // extern "C"
651
652static JNINativeMethod gCameraDeviceMethods[] = {
653    { "nativeDetectSurfaceType",
654    "(Landroid/view/Surface;)I",
655    (void *)LegacyCameraDevice_nativeDetectSurfaceType },
656    { "nativeDetectSurfaceDimens",
657    "(Landroid/view/Surface;[I)I",
658    (void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
659    { "nativeConfigureSurface",
660    "(Landroid/view/Surface;III)I",
661    (void *)LegacyCameraDevice_nativeConfigureSurface },
662    { "nativeProduceFrame",
663    "(Landroid/view/Surface;[BIII)I",
664    (void *)LegacyCameraDevice_nativeProduceFrame },
665    { "nativeSetSurfaceFormat",
666    "(Landroid/view/Surface;I)I",
667    (void *)LegacyCameraDevice_nativeSetSurfaceFormat },
668    { "nativeSetSurfaceDimens",
669    "(Landroid/view/Surface;II)I",
670    (void *)LegacyCameraDevice_nativeSetSurfaceDimens },
671    { "nativeGetSurfaceId",
672    "(Landroid/view/Surface;)J",
673    (void *)LegacyCameraDevice_nativeGetSurfaceId },
674    { "nativeDetectTextureDimens",
675    "(Landroid/graphics/SurfaceTexture;[I)I",
676    (void *)LegacyCameraDevice_nativeDetectTextureDimens },
677    { "nativeSetSurfaceOrientation",
678    "(Landroid/view/Surface;II)I",
679    (void *)LegacyCameraDevice_nativeSetSurfaceOrientation },
680    { "nativeSetNextTimestamp",
681    "(Landroid/view/Surface;J)I",
682    (void *)LegacyCameraDevice_nativeSetNextTimestamp },
683    { "nativeGetJpegFooterSize",
684    "()I",
685    (void *)LegacyCameraDevice_nativeGetJpegFooterSize },
686};
687
688// Get all the required offsets in java class and register native functions
689int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env)
690{
691    // Register native functions
692    return AndroidRuntime::registerNativeMethods(env,
693            CAMERA_DEVICE_CLASS_NAME,
694            gCameraDeviceMethods,
695            NELEM(gCameraDeviceMethods));
696}
697
698