Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8ce89d9e authored by Eino-Ville Talvala's avatar Eino-Ville Talvala
Browse files

Camera2: Skeleton for output frame processing, plus face detect

- Plumbing for processing output metadata frames from the HAL
- Support for passing face detection metadata from said frames
  to the application.
- Switch calls on ICameraClient interface to use separate mutex to
  avoid deadlock scenarios with messages being communicated from the
  HAL to the camera user while calls from the user to the service are
  active.

Bug: 6243944

Change-Id: Id4cf821d9c5c3c0069be4c0f669874b6ff0d1ecd
parent 93b68548
Loading
Loading
Loading
Loading
+354 −67
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
        Client(cameraService, cameraClient,
                cameraId, cameraFacing, clientPid),
        mState(DISCONNECTED),
        mDeviceInfo(NULL),
        mPreviewStreamId(NO_STREAM),
        mPreviewRequest(NULL),
        mCaptureStreamId(NO_STREAM),
@@ -89,7 +90,9 @@ status_t Camera2Client::initialize(camera_module_t *module)
    }

    res = mDevice->setNotifyCallback(this);
    res = mDevice->setFrameListener(this);

    res = buildDeviceInfo();
    res = buildDefaultParameters();
    if (res != OK) {
        ALOGE("%s: Camera %d: unable to build defaults: %s (%d)",
@@ -377,6 +380,11 @@ void Camera2Client::disconnect() {
    mDevice.clear();
    mState = DISCONNECTED;

    if (mDeviceInfo != NULL) {
        delete mDeviceInfo;
        mDeviceInfo = NULL;
    }

    CameraService::Client::disconnect();
}

@@ -393,6 +401,8 @@ status_t Camera2Client::connect(const sp<ICameraClient>& client) {
    }

    mClientPid = getCallingPid();

    Mutex::Autolock iccl(mICameraClientLock);
    mCameraClient = client;

    return OK;
@@ -429,6 +439,8 @@ status_t Camera2Client::unlock() {
    // TODO: Check for uninterruptable conditions

    if (mClientPid == getCallingPid()) {
        Mutex::Autolock iccl(mICameraClientLock);

        mClientPid = 0;
        mCameraClient.clear();
        return OK;
@@ -637,6 +649,7 @@ void Camera2Client::stopPreviewL() {
            mDevice->waitUntilDrained();
        case WAITING_FOR_PREVIEW_WINDOW:
            mState = STOPPED;
            commandStopFaceDetectionL();
            break;
        default:
            ALOGE("%s: Camera %d: Unknown state %d", __FUNCTION__, mCameraId,
@@ -901,6 +914,10 @@ status_t Camera2Client::takePicture(int msgType) {
            return INVALID_OPERATION;
    }


    ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId);

    {
        LockedParameters::Key k(mParameters);

        res = updateCaptureStream(k.mParameters);
@@ -918,6 +935,7 @@ status_t Camera2Client::takePicture(int msgType) {
                return res;
            }
        }
    }

    camera_metadata_entry_t outputStreams;
    if (mState == PREVIEW) {
@@ -972,6 +990,12 @@ status_t Camera2Client::takePicture(int msgType) {
    switch (mState) {
        case PREVIEW:
            mState = STILL_CAPTURE;
            res = commandStopFaceDetectionL();
            if (res != OK) {
                ALOGE("%s: Camera %d: Unable to stop face detection for still capture",
                        __FUNCTION__, mCameraId);
                return res;
            }
            break;
        case RECORD:
            mState = VIDEO_SNAPSHOT;
@@ -1490,46 +1514,12 @@ status_t Camera2Client::setParameters(const String8& params) {
    k.mParameters.recordingHint = recordingHint;
    k.mParameters.videoStabilization = videoStabilization;

    res = updatePreviewRequest(k.mParameters);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }
    res = updateCaptureRequest(k.mParameters);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to update capture request: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }
    k.mParameters.paramsFlattened = params;

    res = updateRecordingRequest(k.mParameters);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }
    res = updateRequests(k.mParameters);

    if (mState == PREVIEW) {
        res = mDevice->setStreamingRequest(mPreviewRequest);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error streaming new preview request: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
    return res;
}
    } else if (mState == RECORD || mState == VIDEO_SNAPSHOT) {
        res = mDevice->setStreamingRequest(mRecordingRequest);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error streaming new record request: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
    }

    k.mParameters.paramsFlattened = params;

    return OK;
}

String8 Camera2Client::getParameters() const {
    ATRACE_CALL();
@@ -1637,13 +1627,55 @@ status_t Camera2Client::commandPlayRecordingSoundL() {
}

status_t Camera2Client::commandStartFaceDetectionL(int type) {
    ALOGE("%s: Unimplemented!", __FUNCTION__);
    return OK;
    ALOGV("%s: Camera %d: Starting face detection",
          __FUNCTION__, mCameraId);
    status_t res;
    switch (mState) {
        case DISCONNECTED:
        case STOPPED:
        case WAITING_FOR_PREVIEW_WINDOW:
        case STILL_CAPTURE:
            ALOGE("%s: Camera %d: Cannot start face detection without preview active",
                    __FUNCTION__, mCameraId);
            return INVALID_OPERATION;
        case PREVIEW:
        case RECORD:
        case VIDEO_SNAPSHOT:
            // Good to go for starting face detect
            break;
    }
    // Ignoring type
    if (mDeviceInfo->bestFaceDetectMode == ANDROID_STATS_FACE_DETECTION_OFF) {
        ALOGE("%s: Camera %d: Face detection not supported",
                __FUNCTION__, mCameraId);
        return INVALID_OPERATION;
    }

    LockedParameters::Key k(mParameters);
    if (k.mParameters.enableFaceDetect) return OK;

    k.mParameters.enableFaceDetect = true;

    res = updateRequests(k.mParameters);

    return res;
}

status_t Camera2Client::commandStopFaceDetectionL() {
    ALOGE("%s: Unimplemented!", __FUNCTION__);
    return OK;
    status_t res = OK;
    ALOGV("%s: Camera %d: Stopping face detection",
          __FUNCTION__, mCameraId);

    LockedParameters::Key k(mParameters);
    if (!k.mParameters.enableFaceDetect) return OK;

    k.mParameters.enableFaceDetect = false;

    if (mState == PREVIEW || mState == RECORD || mState == VIDEO_SNAPSHOT) {
        res = updateRequests(k.mParameters);
    }

    return res;
}

status_t Camera2Client::commandEnableFocusMoveMsgL(bool enable) {
@@ -1791,13 +1823,19 @@ void Camera2Client::notifyAutoFocus(uint8_t newState, int triggerId) {
        }
    }
    if (sendMovingMessage) {
        Mutex::Autolock iccl(mICameraClientLock);
        if (mCameraClient != 0) {
            mCameraClient->notifyCallback(CAMERA_MSG_FOCUS_MOVE,
                    afInMotion ? 1 : 0, 0);
        }
    }
    if (sendCompletedMessage) {
        Mutex::Autolock iccl(mICameraClientLock);
        if (mCameraClient != 0) {
            mCameraClient->notifyCallback(CAMERA_MSG_FOCUS, success ? 1 : 0, 0);
        }
    }
}

void Camera2Client::notifyAutoExposure(uint8_t newState, int triggerId) {
    ALOGV("%s: Autoexposure state now %d, last trigger %d",
@@ -1809,6 +1847,149 @@ void Camera2Client::notifyAutoWhitebalance(uint8_t newState, int triggerId) {
            __FUNCTION__, newState, triggerId);
}

void Camera2Client::onNewFrameAvailable() {
    status_t res;
    camera_metadata_t *frame = NULL;
    do {
        res = mDevice->getNextFrame(&frame);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return;
        }
        if (frame != NULL) {
            camera_metadata_entry_t entry;
            res = find_camera_metadata_entry(frame, ANDROID_REQUEST_FRAME_COUNT,
                    &entry);
            if (res != OK) {
                ALOGE("%s: Camera %d: Error reading frame number: %s (%d)",
                        __FUNCTION__, mCameraId, strerror(-res), res);
                break;
            }

            res = processFrameFaceDetect(frame);
            if (res != OK) break;

            free_camera_metadata(frame);
        }
    } while (frame != NULL);

    if (frame != NULL) {
        free_camera_metadata(frame);
    }
    return;
}

status_t Camera2Client::processFrameFaceDetect(camera_metadata_t *frame) {
    status_t res;
    camera_metadata_entry_t entry;
    bool enableFaceDetect;
    {
        LockedParameters::Key k(mParameters);
        enableFaceDetect = k.mParameters.enableFaceDetect;
    }
    res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_DETECT_MODE,
            &entry);
    if (res != OK) {
        ALOGE("%s: Camera %d: Error reading face mode: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }
    uint8_t faceDetectMode = entry.data.u8[0];

    if (enableFaceDetect && faceDetectMode != ANDROID_STATS_FACE_DETECTION_OFF) {
        res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_RECTANGLES,
                &entry);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error reading face rectangles: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
        camera_frame_metadata metadata;
        metadata.number_of_faces = entry.count / 4;
        if (metadata.number_of_faces >
                mDeviceInfo->maxFaces) {
            ALOGE("%s: Camera %d: More faces than expected! (Got %d, max %d)",
                    __FUNCTION__, mCameraId,
                    metadata.number_of_faces, mDeviceInfo->maxFaces);
            return res;
        }
        int32_t *faceRects = entry.data.i32;

        res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_SCORES,
                &entry);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error reading face scores: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
        uint8_t *faceScores = entry.data.u8;

        int32_t *faceLandmarks = NULL;
        int32_t *faceIds = NULL;

        if (faceDetectMode == ANDROID_STATS_FACE_DETECTION_FULL) {
            res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_LANDMARKS,
                    &entry);
            if (res != OK) {
                ALOGE("%s: Camera %d: Error reading face landmarks: %s (%d)",
                        __FUNCTION__, mCameraId, strerror(-res), res);
                return res;
            }
            faceLandmarks = entry.data.i32;

            res = find_camera_metadata_entry(frame, ANDROID_STATS_FACE_IDS,
                    &entry);
            if (res != OK) {
                ALOGE("%s: Camera %d: Error reading face IDs: %s (%d)",
                        __FUNCTION__, mCameraId, strerror(-res), res);
                return res;
            }
            faceIds = entry.data.i32;
        }

        Vector<camera_face_t> faces;
        faces.setCapacity(metadata.number_of_faces);

        for (int i = 0; i < metadata.number_of_faces; i++) {
            camera_face_t face;

            face.rect[0] = arrayXToNormalized(faceRects[i*4 + 0]);
            face.rect[1] = arrayYToNormalized(faceRects[i*4 + 1]);
            face.rect[2] = arrayXToNormalized(faceRects[i*4 + 2]);
            face.rect[3] = arrayYToNormalized(faceRects[i*4 + 3]);

            face.score = faceScores[i];
            if (faceDetectMode == ANDROID_STATS_FACE_DETECTION_FULL) {
                face.id = faceIds[i];
                face.left_eye[0] = arrayXToNormalized(faceLandmarks[i*6 + 0]);
                face.left_eye[1] = arrayYToNormalized(faceLandmarks[i*6 + 1]);
                face.right_eye[0] = arrayXToNormalized(faceLandmarks[i*6 + 2]);
                face.right_eye[1] = arrayYToNormalized(faceLandmarks[i*6 + 3]);
                face.mouth[0] = arrayXToNormalized(faceLandmarks[i*6 + 4]);
                face.mouth[1] = arrayYToNormalized(faceLandmarks[i*6 + 5]);
            } else {
                face.id = 0;
                face.left_eye[0] = face.left_eye[1] = -2000;
                face.right_eye[0] = face.right_eye[1] = -2000;
                face.mouth[0] = face.mouth[1] = -2000;
            }
            faces.push_back(face);
        }

        metadata.faces = faces.editArray();
        {
            Mutex::Autolock iccl(mICameraClientLock);
            if (mCameraClient != NULL) {
                mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_METADATA,
                        NULL, &metadata);
            }
        }
    }
    return OK;
}


void Camera2Client::onCaptureAvailable() {
    ATRACE_CALL();
    status_t res;
@@ -1849,7 +2030,6 @@ void Camera2Client::onCaptureAvailable() {

        mCaptureConsumer->unlockBuffer(imgBuffer);

        currentClient = mCameraClient;
        switch (mState) {
            case STILL_CAPTURE:
                mState = STOPPED;
@@ -1862,6 +2042,9 @@ void Camera2Client::onCaptureAvailable() {
                        mCameraId, mState);
                break;
        }

        Mutex::Autolock iccl(mICameraClientLock);
        currentClient = mCameraClient;
    }
    // Call outside mICameraLock to allow re-entrancy from notification
    if (currentClient != 0) {
@@ -1951,6 +2134,7 @@ void Camera2Client::onRecordingFrameAvailable() {
        memcpy(data + 4, &imgBuffer, sizeof(buffer_handle_t));
        ALOGV("%s: Camera %d: Sending out buffer_handle_t %p",
                __FUNCTION__, mCameraId, imgBuffer);
        Mutex::Autolock iccl(mICameraClientLock);
        currentClient = mCameraClient;
    }
    // Call outside mICameraLock to allow re-entrancy from notification
@@ -1997,6 +2181,56 @@ camera_metadata_entry_t Camera2Client::staticInfo(uint32_t tag,

/** Utility methods */

status_t Camera2Client::buildDeviceInfo() {
    if (mDeviceInfo != NULL) {
        delete mDeviceInfo;
    }
    DeviceInfo *deviceInfo = new DeviceInfo;
    mDeviceInfo = deviceInfo;

    camera_metadata_entry_t activeArraySize =
        staticInfo(ANDROID_SENSOR_ACTIVE_ARRAY_SIZE, 2, 2);
    if (!activeArraySize.count) return NO_INIT;
    deviceInfo->arrayWidth = activeArraySize.data.i32[0];
    deviceInfo->arrayHeight = activeArraySize.data.i32[1];

    camera_metadata_entry_t availableFaceDetectModes =
        staticInfo(ANDROID_STATS_AVAILABLE_FACE_DETECT_MODES);
    if (!availableFaceDetectModes.count) return NO_INIT;

    deviceInfo->bestFaceDetectMode =
        ANDROID_STATS_FACE_DETECTION_OFF;
    for (size_t i = 0 ; i < availableFaceDetectModes.count; i++) {
        switch (availableFaceDetectModes.data.u8[i]) {
            case ANDROID_STATS_FACE_DETECTION_OFF:
                break;
            case ANDROID_STATS_FACE_DETECTION_SIMPLE:
                if (deviceInfo->bestFaceDetectMode !=
                        ANDROID_STATS_FACE_DETECTION_FULL) {
                    deviceInfo->bestFaceDetectMode =
                        ANDROID_STATS_FACE_DETECTION_SIMPLE;
                }
                break;
            case ANDROID_STATS_FACE_DETECTION_FULL:
                deviceInfo->bestFaceDetectMode =
                    ANDROID_STATS_FACE_DETECTION_FULL;
                break;
            default:
                ALOGE("%s: Camera %d: Unknown face detect mode %d:",
                        __FUNCTION__, mCameraId,
                        availableFaceDetectModes.data.u8[i]);
                return NO_INIT;
        }
    }

    camera_metadata_entry_t maxFacesDetected =
        staticInfo(ANDROID_STATS_MAX_FACE_COUNT, 1, 1);
    if (!maxFacesDetected.count) return NO_INIT;

    deviceInfo->maxFaces = maxFacesDetected.data.i32[0];

    return OK;
}

status_t Camera2Client::buildDefaultParameters() {
    ATRACE_CALL();
@@ -2655,10 +2889,8 @@ status_t Camera2Client::buildDefaultParameters() {
    params.set(CameraParameters::KEY_FOCUS_DISTANCES,
            "Infinity,Infinity,Infinity");

    camera_metadata_entry_t maxFacesDetected =
        staticInfo(ANDROID_STATS_MAX_FACE_COUNT, 1, 1);
    params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW,
            maxFacesDetected.data.i32[0]);
            mDeviceInfo->maxFaces);
    params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW,
            0);

@@ -2690,6 +2922,7 @@ status_t Camera2Client::buildDefaultParameters() {

    k.mParameters.storeMetadataInBuffers = true;
    k.mParameters.playShutterSound = true;
    k.mParameters.enableFaceDetect = false;
    k.mParameters.afTriggerCounter = 0;
    k.mParameters.currentAfTriggerId = -1;

@@ -2698,6 +2931,47 @@ status_t Camera2Client::buildDefaultParameters() {
    return OK;
}

status_t Camera2Client::updateRequests(const Parameters &params) {
    status_t res;

    res = updatePreviewRequest(params);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }
    res = updateCaptureRequest(params);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to update capture request: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }

    res = updateRecordingRequest(params);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }

    if (mState == PREVIEW) {
        res = mDevice->setStreamingRequest(mPreviewRequest);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error streaming new preview request: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
    } else if (mState == RECORD || mState == VIDEO_SNAPSHOT) {
        res = mDevice->setStreamingRequest(mRecordingRequest);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error streaming new record request: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
    }
    return res;
}

status_t Camera2Client::updatePreviewStream(const Parameters &params) {
    ATRACE_CALL();
    status_t res;
@@ -3126,22 +3400,18 @@ status_t Camera2Client::updateRequestCommon(camera_metadata_t *request,
            (NUM_ZOOM_STEPS-1);
    float zoomRatio = 1 + zoomIncrement * params.zoom;

    camera_metadata_entry_t activePixelArraySize =
            staticInfo(ANDROID_SENSOR_ACTIVE_ARRAY_SIZE, 2, 2);
    int32_t arrayWidth = activePixelArraySize.data.i32[0];
    int32_t arrayHeight = activePixelArraySize.data.i32[1];
    float zoomLeft, zoomTop, zoomWidth, zoomHeight;
    if (params.previewWidth >= params.previewHeight) {
        zoomWidth =  arrayWidth / zoomRatio;
        zoomWidth =  mDeviceInfo->arrayWidth / zoomRatio;
        zoomHeight = zoomWidth *
                params.previewHeight / params.previewWidth;
    } else {
        zoomHeight = arrayHeight / zoomRatio;
        zoomHeight = mDeviceInfo->arrayHeight / zoomRatio;
        zoomWidth = zoomHeight *
                params.previewWidth / params.previewHeight;
    }
    zoomLeft = (arrayWidth - zoomWidth) / 2;
    zoomTop = (arrayHeight - zoomHeight) / 2;
    zoomLeft = (mDeviceInfo->arrayWidth - zoomWidth) / 2;
    zoomTop = (mDeviceInfo->arrayHeight - zoomHeight) / 2;

    int32_t cropRegion[3] = { zoomLeft, zoomTop, zoomWidth };
    res = updateEntry(request,
@@ -3158,9 +3428,25 @@ status_t Camera2Client::updateRequestCommon(camera_metadata_t *request,
            &vstabMode, 1);
    if (res != OK) return res;

    uint8_t faceDetectMode = params.enableFaceDetect ?
            mDeviceInfo->bestFaceDetectMode :
            (uint8_t)ANDROID_STATS_FACE_DETECTION_OFF;
    res = updateEntry(request,
            ANDROID_STATS_FACE_DETECT_MODE,
            &faceDetectMode, 1);
    if (res != OK) return res;

    return OK;
}

int Camera2Client::arrayXToNormalized(int width) const {
    return width * 2000 / (mDeviceInfo->arrayWidth - 1) - 1000;
}

int Camera2Client::arrayYToNormalized(int height) const {
    return height * 2000 / (mDeviceInfo->arrayHeight - 1) - 1000;
}

status_t Camera2Client::updateEntry(camera_metadata_t *buffer,
        uint32_t tag, const void *data, size_t data_count) {
    camera_metadata_entry_t entry;
@@ -3477,4 +3763,5 @@ int Camera2Client::degToTransform(int degrees, bool mirror) {
    return -1;
}


} // namespace android
+39 −3
Original line number Diff line number Diff line
@@ -31,8 +31,10 @@ namespace android {
 * Implements the android.hardware.camera API on top of
 * camera device HAL version 2.
 */
class Camera2Client : public CameraService::Client,
                      public Camera2Device::NotificationListener
class Camera2Client :
        public CameraService::Client,
        public Camera2Device::NotificationListener,
        public Camera2Device::FrameListener
{
public:
    // ICamera interface (see ICamera for details)
@@ -81,6 +83,7 @@ public:
    virtual void notifyAutoExposure(uint8_t newState, int triggerId);
    virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId);

    virtual void onNewFrameAvailable();
private:
    enum State {
        DISCONNECTED,
@@ -102,6 +105,11 @@ private:
    // they're called
    mutable Mutex mICameraLock;

    // Mutex that must be locked by methods accessing the base Client's
    // mCameraClient ICameraClient interface member, for sending notifications
    // up to the camera user
    mutable Mutex mICameraClientLock;

    status_t setPreviewWindowL(const sp<IBinder>& binder,
            sp<ANativeWindow> window);

@@ -200,13 +208,16 @@ private:
        // listed in Camera.Parameters
        bool storeMetadataInBuffers;
        bool playShutterSound;
        bool enableFocusMoveMessages;
        bool enableFaceDetect;

        bool enableFocusMoveMessages;
        int afTriggerCounter;
        int currentAfTriggerId;
        bool afInMotion;
    };

    // This class encapsulates the Parameters class so that it can only be accessed
    // by constructing a Key object, which locks the LockedParameter's mutex.
    class LockedParameters {
      public:
        class Key {
@@ -258,15 +269,32 @@ private:

    } mParameters;

    // Static device information; this is a subset of the information
    // available through the staticInfo() method, used for frequently-accessed
    // values or values that have to be calculated from the static information.
    struct DeviceInfo {
        int32_t arrayWidth;
        int32_t arrayHeight;
        uint8_t bestFaceDetectMode;
        int32_t maxFaces;
    };
    const DeviceInfo *mDeviceInfo;

    /** Camera device-related private members */

    class Camera2Heap;

    status_t updateRequests(const Parameters &params);

    // Number of zoom steps to simulate
    static const unsigned int NUM_ZOOM_STEPS = 10;
    // Used with stream IDs
    static const int NO_STREAM = -1;

    /* Output frame metadata processing methods */

    status_t processFrameFaceDetect(camera_metadata_t *frame);

    /* Preview related members */

    int mPreviewStreamId;
@@ -373,6 +401,8 @@ private:
    camera_metadata_entry_t staticInfo(uint32_t tag,
            size_t minCount=0, size_t maxCount=0);

    // Extract frequently-used camera static information into mDeviceInfo
    status_t buildDeviceInfo();
    // Convert static camera info from a camera2 device to the
    // old API parameter map.
    status_t buildDefaultParameters();
@@ -380,6 +410,12 @@ private:
    // Update parameters all requests use, based on mParameters
    status_t updateRequestCommon(camera_metadata_t *request, const Parameters &params);

    // Map from sensor active array pixel coordinates to normalized camera parameter coordinates
    // The former are (0,0)-(array width - 1, array height - 1), the latter from
    // (-1000,-1000)-(1000,1000)
    int arrayXToNormalized(int width) const;
    int arrayYToNormalized(int height) const;

    // Update specific metadata entry with new values. Adds entry if it does not
    // exist, which will invalidate sorting
    static status_t updateEntry(camera_metadata_t *buffer,
+30 −1
Original line number Diff line number Diff line
@@ -340,6 +340,14 @@ void Camera2Device::notificationCallback(int32_t msg_type,
    }
}

status_t Camera2Device::setFrameListener(FrameListener *listener) {
    return mFrameQueue.setListener(listener);
}

status_t Camera2Device::getNextFrame(camera_metadata_t **frame) {
    return mFrameQueue.dequeue(frame);
}

status_t Camera2Device::triggerAutofocus(uint32_t id) {
    status_t res;
    ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id);
@@ -383,6 +391,13 @@ status_t Camera2Device::triggerPrecaptureMetering(uint32_t id) {
Camera2Device::NotificationListener::~NotificationListener() {
}

/**
 * Camera2Device::FrameListener
 */

Camera2Device::FrameListener::~FrameListener() {
}

/**
 * Camera2Device::MetadataQueue
 */
@@ -392,7 +407,8 @@ Camera2Device::MetadataQueue::MetadataQueue():
            mFrameCount(0),
            mCount(0),
            mStreamSlotCount(0),
            mSignalConsumer(true)
            mSignalConsumer(true),
            mListener(NULL)
{
    camera2_request_queue_src_ops::dequeue_request = consumer_dequeue;
    camera2_request_queue_src_ops::request_count = consumer_buffer_count;
@@ -510,6 +526,12 @@ status_t Camera2Device::MetadataQueue::waitForBuffer(nsecs_t timeout)
    return OK;
}

status_t Camera2Device::MetadataQueue::setListener(FrameListener *listener) {
    Mutex::Autolock l(mMutex);
    mListener = listener;
    return OK;
}

status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
{
    ALOGV("%s: E", __FUNCTION__);
@@ -622,6 +644,13 @@ status_t Camera2Device::MetadataQueue::signalConsumerLocked() {
        res = mDevice->ops->notify_request_queue_not_empty(mDevice);
        mMutex.lock();
    }
    if (mListener != NULL) {
        FrameListener *listener = mListener;
        mMutex.unlock();
        ALOGVV("%s: Signaling listener", __FUNCTION__);
        listener->onNewFrameAvailable();
        mMutex.lock();
    }
    return res;
}

+23 −0
Original line number Diff line number Diff line
@@ -123,6 +123,27 @@ class Camera2Device : public virtual RefBase {
     */
    status_t setNotifyCallback(NotificationListener *listener);

    /**
     * Abstract class for HAL frame available notifications
     */
    class FrameListener {
      public:
        virtual void onNewFrameAvailable() = 0;
      protected:
        virtual ~FrameListener();
    };

    /**
     * Set a frame listener to be notified about new frames.
     */
    status_t setFrameListener(FrameListener *listener);

    /**
     * Get next metadata frame from the frame queue. Returns NULL if the queue
     * is empty; caller takes ownership of the metadata buffer.
     */
    status_t getNextFrame(camera_metadata_t **frame);

    /**
     * Trigger auto-focus. The latest ID used in a trigger autofocus or cancel
     * autofocus call will be returned by the HAL in all subsequent AF
@@ -180,6 +201,7 @@ class Camera2Device : public virtual RefBase {
        status_t dequeue(camera_metadata_t **buf, bool incrementCount = true);
        int      getBufferCount();
        status_t waitForBuffer(nsecs_t timeout);
        status_t setListener(FrameListener *listener);

        // Set repeating buffer(s); if the queue is empty on a dequeue call, the
        // queue copies the contents of the stream slot into the queue, and then
@@ -208,6 +230,7 @@ class Camera2Device : public virtual RefBase {
        List<camera_metadata_t*> mStreamSlot;

        bool mSignalConsumer;
        FrameListener *mListener;

        static MetadataQueue* getInstance(
            const camera2_frame_queue_dst_ops_t *q);