android_hardware_camera2_legacy_LegacyCameraDevice.cpp revision 3c8fa3b356fa8f24b55d3dc42d4313297542e9f2
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
23#include "jni.h"
24#include "JNIHelp.h"
25#include "android_runtime/AndroidRuntime.h"
26#include "android_runtime/android_view_Surface.h"
27
28#include <gui/Surface.h>
29#include <gui/IGraphicBufferProducer.h>
30#include <ui/GraphicBuffer.h>
31#include <system/window.h>
32#include <hardware/camera3.h>
33
34#include <stdint.h>
35#include <inttypes.h>
36
37using namespace android;
38
39// fully-qualified class name
40#define CAMERA_DEVICE_CLASS_NAME "android/hardware/camera2/legacy/LegacyCameraDevice"
41#define CAMERA_DEVICE_BUFFER_SLACK  3
42#define DONT_CARE 0
43
44#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
45
46#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
47
48/**
49 * Convert from RGB 888 to Y'CbCr using the conversion specified in ITU-R BT.601 for
50 * digital RGB with K_b = 0.114, and K_r = 0.299.
51 */
52static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, uint8_t* yPlane,
53        uint8_t* uPlane, uint8_t* vPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
54    uint8_t R, G, B;
55    size_t index = 0;
56
57    int32_t cStrideDiff = chromaStride - width;
58
59    for (int32_t j = 0; j < height; j++) {
60        for (int32_t i = 0; i < width; i++) {
61            R = rgbBuf[index++];
62            G = rgbBuf[index++];
63            B = rgbBuf[index++];
64            *(yPlane + i) = ((66 * R + 129 * G +  25 * B + 128) >> 8) +  16;
65
66            if (j % 2 == 0 && i % 2 == 0){
67                *uPlane = (( -38 * R -  74 * G + 112 * B + 128) >> 8) + 128;
68                *vPlane = (( 112 * R -  94 * G -  18 * B + 128) >> 8) + 128;
69                uPlane += chromaStep;
70                vPlane += chromaStep;
71            }
72            // Skip alpha
73            index++;
74        }
75        yPlane += yStride;
76        if (j % 2 == 0) {
77            uPlane += cStrideDiff;
78            vPlane += cStrideDiff;
79        }
80    }
81}
82
83static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, android_ycbcr* ycbcr) {
84    size_t cStep = ycbcr->chroma_step;
85    size_t cStride = ycbcr->cstride;
86    size_t yStride = ycbcr->ystride;
87    rgbToYuv420(rgbBuf, width, height, reinterpret_cast<uint8_t*>(ycbcr->y),
88            reinterpret_cast<uint8_t*>(ycbcr->cb), reinterpret_cast<uint8_t*>(ycbcr->cr),
89            cStep, yStride, cStride);
90}
91
92static status_t configureSurface(const sp<ANativeWindow>& anw,
93                                 int32_t width,
94                                 int32_t height,
95                                 int32_t pixelFmt,
96                                 int32_t maxBufferSlack) {
97    status_t err = NO_ERROR;
98    err = native_window_set_buffers_dimensions(anw.get(), width, height);
99    if (err != NO_ERROR) {
100        ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__,
101                strerror(-err), err);
102        return err;
103    }
104
105    err = native_window_set_buffers_format(anw.get(), pixelFmt);
106    if (err != NO_ERROR) {
107        ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__,
108                strerror(-err), err);
109        return err;
110    }
111
112    err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
113    if (err != NO_ERROR) {
114        ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__,
115                strerror(-err), err);
116        return err;
117    }
118
119    int minUndequeuedBuffers;
120    err = anw.get()->query(anw.get(),
121            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
122            &minUndequeuedBuffers);
123    if (err != NO_ERROR) {
124        ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).",
125                __FUNCTION__, strerror(-err), err);
126        return err;
127    }
128
129    ALOGV("%s: Setting buffer count to %d, size to (%dx%d), fmt (0x%x)", __FUNCTION__,
130          maxBufferSlack + 1 + minUndequeuedBuffers,
131          width, height, pixelFmt);
132    err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
133    if (err != NO_ERROR) {
134        ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__,
135                strerror(-err), err);
136        return err;
137    }
138    return NO_ERROR;
139}
140
141/**
142 * Produce a frame in the given surface.
143 *
144 * Args:
145 *    anw - a surface to produce a frame in.
146 *    pixelBuffer - image buffer to generate a frame from.
147 *    width - width of the pixelBuffer in pixels.
148 *    height - height of the pixelBuffer in pixels.
149 *    pixelFmt - format of the pixelBuffer, one of:
150 *               HAL_PIXEL_FORMAT_YCrCb_420_SP,
151 *               HAL_PIXEL_FORMAT_YCbCr_420_888,
152 *               HAL_PIXEL_FORMAT_BLOB
153 *    bufSize - the size of the pixelBuffer in bytes.
154 */
155static status_t produceFrame(const sp<ANativeWindow>& anw,
156                             uint8_t* pixelBuffer,
157                             int32_t width, // Width of the pixelBuffer
158                             int32_t height, // Height of the pixelBuffer
159                             int32_t pixelFmt, // Format of the pixelBuffer
160                             int32_t bufSize) {
161    ATRACE_CALL();
162    status_t err = NO_ERROR;
163    ANativeWindowBuffer* anb;
164    ALOGV("%s: Dequeue buffer from %p %dx%d (fmt=%x, size=%x)",
165            __FUNCTION__, anw.get(), width, height, pixelFmt, bufSize);
166
167    if (anw == 0) {
168        ALOGE("%s: anw must not be NULL", __FUNCTION__);
169        return BAD_VALUE;
170    } else if (pixelBuffer == NULL) {
171        ALOGE("%s: pixelBuffer must not be NULL", __FUNCTION__);
172        return BAD_VALUE;
173    } else if (width < 0) {
174        ALOGE("%s: width must be non-negative", __FUNCTION__);
175        return BAD_VALUE;
176    } else if (height < 0) {
177        ALOGE("%s: height must be non-negative", __FUNCTION__);
178        return BAD_VALUE;
179    } else if (bufSize < 0) {
180        ALOGE("%s: bufSize must be non-negative", __FUNCTION__);
181        return BAD_VALUE;
182    }
183
184    if (width < 0 || height < 0 || bufSize < 0) {
185        ALOGE("%s: Illegal argument, negative dimension passed to produceFrame", __FUNCTION__);
186        return BAD_VALUE;
187    }
188
189    // TODO: Switch to using Surface::lock and Surface::unlockAndPost
190    err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
191    if (err != NO_ERROR) return err;
192
193    // TODO: check anb is large enough to store the results
194
195    sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false));
196
197    switch(pixelFmt) {
198        case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
199            if (bufSize < width * height * 4) {
200                ALOGE("%s: PixelBuffer size %" PRId32 " to small for given dimensions",
201                        __FUNCTION__, bufSize);
202                return BAD_VALUE;
203            }
204            uint8_t* img = NULL;
205            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
206            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
207            if (err != NO_ERROR) return err;
208
209            uint8_t* yPlane = img;
210            uint8_t* uPlane = img + height * width;
211            uint8_t* vPlane = uPlane + 1;
212            size_t chromaStep = 2;
213            size_t yStride = width;
214            size_t chromaStride = width;
215
216            rgbToYuv420(pixelBuffer, width, height, yPlane,
217                    uPlane, vPlane, chromaStep, yStride, chromaStride);
218            break;
219        }
220        case HAL_PIXEL_FORMAT_YV12: {
221            if (bufSize < width * height * 4) {
222                ALOGE("%s: PixelBuffer size %" PRId32 " to small for given dimensions",
223                        __FUNCTION__, bufSize);
224                return BAD_VALUE;
225            }
226
227            if ((width & 1) || (height & 1)) {
228                ALOGE("%s: Dimens %dx%d are not divisible by 2.", __FUNCTION__, width, height);
229                return BAD_VALUE;
230            }
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) {
236                ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__,
237                        strerror(-err), err);
238                return err;
239            }
240
241            uint32_t stride = buf->getStride();
242            LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride);
243
244            uint32_t cStride = ALIGN(stride / 2, 16);
245            size_t chromaStep = 1;
246
247            uint8_t* yPlane = img;
248            uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride;
249            uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2;
250
251            rgbToYuv420(pixelBuffer, width, height, yPlane,
252                    crPlane, cbPlane, chromaStep, stride, cStride);
253            break;
254        }
255        case HAL_PIXEL_FORMAT_YCbCr_420_888: {
256            // Software writes with YCbCr_420_888 format are unsupported
257            // by the gralloc module for now
258            if (bufSize < width * height * 4) {
259                ALOGE("%s: PixelBuffer size %" PRId32 " to small for given dimensions",
260                        __FUNCTION__, bufSize);
261                return BAD_VALUE;
262            }
263            android_ycbcr ycbcr = android_ycbcr();
264            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
265
266            err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr);
267            if (err != NO_ERROR) {
268                ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__,
269                        strerror(-err), err);
270                return err;
271            }
272            rgbToYuv420(pixelBuffer, width, height, &ycbcr);
273            break;
274        }
275        case HAL_PIXEL_FORMAT_BLOB: {
276            if (bufSize != width || height != 1) {
277                ALOGE("%s: Incorrect pixelBuffer size: %" PRId32, __FUNCTION__, bufSize);
278                return BAD_VALUE;
279            }
280            int8_t* img = NULL;
281
282            ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
283            err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
284            if (err != NO_ERROR) {
285                ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err),
286                        err);
287                return err;
288            }
289            struct camera3_jpeg_blob footer = {
290                jpeg_blob_id: CAMERA3_JPEG_BLOB_ID,
291                jpeg_size: (uint32_t)width
292            };
293            memcpy(img, pixelBuffer, width);
294            memcpy(img + anb->width - sizeof(footer), &footer, sizeof(footer));
295            break;
296        }
297        default: {
298            ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt);
299            return BAD_VALUE;
300        }
301    }
302
303    ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get());
304    err = buf->unlock();
305    if (err != NO_ERROR) {
306        ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
307        return err;
308    }
309
310    ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get());
311    err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1);
312    if (err != NO_ERROR) {
313        ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
314        return err;
315    }
316    return NO_ERROR;
317}
318
319static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
320    sp<ANativeWindow> anw;
321    if (surface) {
322        anw = android_view_Surface_getNativeWindow(env, surface);
323        if (env->ExceptionCheck()) {
324            return NULL;
325        }
326    } else {
327        jniThrowNullPointerException(env, "surface");
328        return NULL;
329    }
330    if (anw == NULL) {
331        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
332                "Surface had no valid native window.");
333        return NULL;
334    }
335    return anw;
336}
337
338static sp<Surface> getSurface(JNIEnv* env, jobject surface) {
339    sp<Surface> s;
340    if (surface) {
341        s = android_view_Surface_getSurface(env, surface);
342        if (env->ExceptionCheck()) {
343            return NULL;
344        }
345    } else {
346        jniThrowNullPointerException(env, "surface");
347        return NULL;
348    }
349    if (s == NULL) {
350        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
351                "Surface had no valid native Surface.");
352        return NULL;
353    }
354    return s;
355}
356
357extern "C" {
358
359static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) {
360    ALOGV("nativeDetectSurfaceType");
361    sp<ANativeWindow> anw;
362    if ((anw = getNativeWindow(env, surface)) == NULL) {
363        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
364        return BAD_VALUE;
365    }
366    int32_t fmt = 0;
367    status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt);
368    if(err != NO_ERROR) {
369        ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__, strerror(-err),
370                err);
371        return err;
372    }
373    return fmt;
374}
375
376static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz,
377          jobject surface, jintArray dimens) {
378    ALOGV("nativeGetSurfaceDimens");
379    sp<ANativeWindow> anw;
380    if ((anw = getNativeWindow(env, surface)) == NULL) {
381        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
382        return BAD_VALUE;
383    }
384    int32_t dimenBuf[2];
385    status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
386    if(err != NO_ERROR) {
387        ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err),
388                err);
389        return err;
390    }
391    err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
392    if(err != NO_ERROR) {
393        ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
394                err);
395        return err;
396    }
397    env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
398    return NO_ERROR;
399}
400
401static jint LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface,
402        jint width, jint height, jint pixelFormat) {
403    ALOGV("nativeConfigureSurface");
404    sp<ANativeWindow> anw;
405    if ((anw = getNativeWindow(env, surface)) == NULL) {
406        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
407        return BAD_VALUE;
408    }
409    status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK);
410    if (err != NO_ERROR) {
411        ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
412        return err;
413    }
414    return NO_ERROR;
415}
416
417static jint LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface,
418        jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) {
419    ALOGV("nativeProduceFrame");
420    sp<ANativeWindow> anw;
421
422    if ((anw = getNativeWindow(env, surface)) == NULL) {
423        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
424        return BAD_VALUE;
425    }
426
427    if (pixelBuffer == NULL) {
428        jniThrowNullPointerException(env, "pixelBuffer");
429        return DONT_CARE;
430    }
431
432    int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer));
433    jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL);
434
435    if (pixels == NULL) {
436        jniThrowNullPointerException(env, "pixels");
437        return DONT_CARE;
438    }
439
440    status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height,
441            pixelFormat, bufSize);
442    env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT);
443
444    if (err != NO_ERROR) {
445        ALOGE("%s: Error while producing frame %s (%d).", __FUNCTION__, strerror(-err), err);
446        return err;
447    }
448    return NO_ERROR;
449}
450
451static jint LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface,
452        jint pixelFormat) {
453    ALOGV("nativeSetSurfaceType");
454    sp<ANativeWindow> anw;
455    if ((anw = getNativeWindow(env, surface)) == NULL) {
456        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
457        return BAD_VALUE;
458    }
459    status_t err = native_window_set_buffers_format(anw.get(), pixelFormat);
460    if (err != NO_ERROR) {
461        ALOGE("%s: Error while setting surface format %s (%d).", __FUNCTION__, strerror(-err), err);
462        return err;
463    }
464    return NO_ERROR;
465}
466
467static jint LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface,
468        jint width, jint height) {
469    ALOGV("nativeSetSurfaceDimens");
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    status_t err = native_window_set_buffers_dimensions(anw.get(), width, height);
476    if (err != NO_ERROR) {
477        ALOGE("%s: Error while setting surface dimens %s (%d).", __FUNCTION__, strerror(-err), err);
478        return err;
479    }
480    return NO_ERROR;
481}
482
483static jlong LegacyCameraDevice_nativeGetSurfaceId(JNIEnv* env, jobject thiz, jobject surface) {
484    ALOGV("nativeGetSurfaceId");
485    sp<Surface> s;
486    if ((s = getSurface(env, surface)) == NULL) {
487        ALOGE("%s: Could not retrieve native Surface from surface.", __FUNCTION__);
488        return 0;
489    }
490    sp<IGraphicBufferProducer> gbp = s->getIGraphicBufferProducer();
491    if (gbp == NULL) {
492        ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__);
493        return 0;
494    }
495    sp<IBinder> b = gbp->asBinder();
496    if (b == NULL) {
497        ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__);
498        return 0;
499    }
500    /*
501     * FIXME: Use better unique ID for surfaces than native IBinder pointer.  Fix also in the camera
502     * service (CameraDeviceClient.h).
503     */
504    return reinterpret_cast<jlong>(b.get());
505}
506
507} // extern "C"
508
509static JNINativeMethod gCameraDeviceMethods[] = {
510    { "nativeDetectSurfaceType",
511    "(Landroid/view/Surface;)I",
512    (void *)LegacyCameraDevice_nativeDetectSurfaceType },
513    { "nativeDetectSurfaceDimens",
514    "(Landroid/view/Surface;[I)I",
515    (void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
516    { "nativeConfigureSurface",
517    "(Landroid/view/Surface;III)I",
518    (void *)LegacyCameraDevice_nativeConfigureSurface },
519    { "nativeProduceFrame",
520    "(Landroid/view/Surface;[BIII)I",
521    (void *)LegacyCameraDevice_nativeProduceFrame },
522    { "nativeSetSurfaceFormat",
523    "(Landroid/view/Surface;I)I",
524    (void *)LegacyCameraDevice_nativeSetSurfaceFormat },
525    { "nativeSetSurfaceDimens",
526    "(Landroid/view/Surface;II)I",
527    (void *)LegacyCameraDevice_nativeSetSurfaceDimens },
528    { "nativeGetSurfaceId",
529    "(Landroid/view/Surface;)J",
530    (void *)LegacyCameraDevice_nativeGetSurfaceId },
531};
532
533// Get all the required offsets in java class and register native functions
534int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env)
535{
536    // Register native functions
537    return AndroidRuntime::registerNativeMethods(env,
538            CAMERA_DEVICE_CLASS_NAME,
539            gCameraDeviceMethods,
540            NELEM(gCameraDeviceMethods));
541}
542
543