diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2014-11-06 17:49:48 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2014-11-06 17:49:48 -0800 |
commit | e1a2df553a6d151807a5da738a3cd853bef908d9 (patch) | |
tree | 9015c1c9ad9ec69f1962657f70fe3df386fbb05a /camera | |
parent | bcf093bfef277a8ec0119da9e84e5abac58ad0b1 (diff) | |
parent | 841daebc75fbf5e7fb4dd71cab559b8f4d7150ae (diff) | |
download | frameworks_av-e1a2df553a6d151807a5da738a3cd853bef908d9.zip frameworks_av-e1a2df553a6d151807a5da738a3cd853bef908d9.tar.gz frameworks_av-e1a2df553a6d151807a5da738a3cd853bef908d9.tar.bz2 |
Resolve conflict
Diffstat (limited to 'camera')
-rw-r--r-- | camera/Android.mk | 18 | ||||
-rw-r--r-- | camera/Camera.cpp | 26 | ||||
-rw-r--r-- | camera/CameraMetadata.cpp | 141 | ||||
-rw-r--r-- | camera/CameraParameters.cpp | 42 | ||||
-rw-r--r-- | camera/CameraParameters2.cpp | 1 | ||||
-rw-r--r-- | camera/CameraUtils.cpp | 125 | ||||
-rw-r--r-- | camera/CaptureResult.cpp | 129 | ||||
-rw-r--r-- | camera/ICameraService.cpp | 145 | ||||
-rw-r--r-- | camera/ProCamera.cpp | 9 | ||||
-rw-r--r-- | camera/VendorTagDescriptor.cpp | 460 | ||||
-rw-r--r-- | camera/camera2/ICameraDeviceCallbacks.cpp | 48 | ||||
-rw-r--r-- | camera/camera2/ICameraDeviceUser.cpp | 168 | ||||
-rw-r--r-- | camera/tests/Android.mk | 17 | ||||
-rw-r--r-- | camera/tests/VendorTagDescriptorTests.cpp | 204 |
14 files changed, 1473 insertions, 60 deletions
diff --git a/camera/Android.mk b/camera/Android.mk index 5cedab0..da5ac59 100644 --- a/camera/Android.mk +++ b/camera/Android.mk @@ -1,3 +1,17 @@ +# Copyright 2010 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + CAMERA_CLIENT_LOCAL_PATH:= $(call my-dir) include $(call all-subdir-makefiles) include $(CLEAR_VARS) @@ -8,6 +22,7 @@ LOCAL_SRC_FILES:= \ Camera.cpp \ CameraMetadata.cpp \ CameraParameters.cpp \ + CaptureResult.cpp \ CameraParameters2.cpp \ ICamera.cpp \ ICameraClient.cpp \ @@ -22,6 +37,8 @@ LOCAL_SRC_FILES:= \ camera2/CaptureRequest.cpp \ ProCamera.cpp \ CameraBase.cpp \ + CameraUtils.cpp \ + VendorTagDescriptor.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -35,6 +52,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES += \ system/media/camera/include \ + system/media/private/camera/include \ LOCAL_MODULE:= libcamera_client diff --git a/camera/Camera.cpp b/camera/Camera.cpp index 22199fa..85f44f0 100644 --- a/camera/Camera.cpp +++ b/camera/Camera.cpp @@ -77,6 +77,32 @@ sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName, return CameraBaseT::connect(cameraId, clientPackageName, clientUid); } +status_t Camera::connectLegacy(int cameraId, int halVersion, + const String16& clientPackageName, + int clientUid, + sp<Camera>& camera) +{ + ALOGV("%s: connect legacy camera device", __FUNCTION__); + sp<Camera> c = new Camera(cameraId); + sp<ICameraClient> cl = c; + status_t status = NO_ERROR; + const sp<ICameraService>& cs = CameraBaseT::getCameraService(); + + if (cs != 0) { + status = cs.get()->connectLegacy(cl, cameraId, halVersion, clientPackageName, + clientUid, /*out*/c->mCamera); + } + if (status == OK && c->mCamera != 0) { + c->mCamera->asBinder()->linkToDeath(c); + c->mStatus = NO_ERROR; + camera = c; + } else { + ALOGW("An error occurred while connecting to camera: %d", cameraId); + c.clear(); + } + return status; +} + status_t Camera::reconnect() { ALOGV("reconnect"); diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp index 7765914..043437f 100644 --- a/camera/CameraMetadata.cpp +++ b/camera/CameraMetadata.cpp @@ -25,6 +25,9 @@ namespace android { +#define ALIGN_TO(val, alignment) \ + (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1)) + typedef Parcel::WritableBlob WritableBlob; typedef Parcel::ReadableBlob ReadableBlob; @@ -270,7 +273,8 @@ status_t CameraMetadata::update(uint32_t tag, if ( (res = checkType(tag, TYPE_BYTE)) != OK) { return res; } - return updateImpl(tag, (const void*)string.string(), string.size()); + // string.size() doesn't count the null termination character. + return updateImpl(tag, (const void*)string.string(), string.size() + 1); } status_t CameraMetadata::updateImpl(uint32_t tag, const void *data, @@ -431,40 +435,70 @@ status_t CameraMetadata::readFromParcel(const Parcel& data, *out = NULL; } - // arg0 = metadataSize (int32) - int32_t metadataSizeTmp = -1; - if ((err = data.readInt32(&metadataSizeTmp)) != OK) { + // See CameraMetadata::writeToParcel for parcel data layout diagram and explanation. + // arg0 = blobSize (int32) + int32_t blobSizeTmp = -1; + if ((err = data.readInt32(&blobSizeTmp)) != OK) { ALOGE("%s: Failed to read metadata size (error %d %s)", __FUNCTION__, err, strerror(-err)); return err; } - const size_t metadataSize = static_cast<size_t>(metadataSizeTmp); + const size_t blobSize = static_cast<size_t>(blobSizeTmp); + const size_t alignment = get_camera_metadata_alignment(); - if (metadataSize == 0) { + // Special case: zero blob size means zero sized (NULL) metadata. + if (blobSize == 0) { ALOGV("%s: Read 0-sized metadata", __FUNCTION__); return OK; } - // NOTE: this doesn't make sense to me. shouldnt the blob + if (blobSize <= alignment) { + ALOGE("%s: metadata blob is malformed, blobSize(%zu) should be larger than alignment(%zu)", + __FUNCTION__, blobSize, alignment); + return BAD_VALUE; + } + + const size_t metadataSize = blobSize - alignment; + + // NOTE: this doesn't make sense to me. shouldn't the blob // know how big it is? why do we have to specify the size // to Parcel::readBlob ? - ReadableBlob blob; // arg1 = metadata (blob) do { - if ((err = data.readBlob(metadataSize, &blob)) != OK) { - ALOGE("%s: Failed to read metadata blob (sized %d). Possible " + if ((err = data.readBlob(blobSize, &blob)) != OK) { + ALOGE("%s: Failed to read metadata blob (sized %zu). Possible " " serialization bug. Error %d %s", - __FUNCTION__, metadataSize, err, strerror(-err)); + __FUNCTION__, blobSize, err, strerror(-err)); break; } - const camera_metadata_t* tmp = - reinterpret_cast<const camera_metadata_t*>(blob.data()); + // arg2 = offset (blob) + // Must be after blob since we don't know offset until after writeBlob. + int32_t offsetTmp; + if ((err = data.readInt32(&offsetTmp)) != OK) { + ALOGE("%s: Failed to read metadata offsetTmp (error %d %s)", + __FUNCTION__, err, strerror(-err)); + break; + } + const size_t offset = static_cast<size_t>(offsetTmp); + if (offset >= alignment) { + ALOGE("%s: metadata offset(%zu) should be less than alignment(%zu)", + __FUNCTION__, blobSize, alignment); + err = BAD_VALUE; + break; + } + + const uintptr_t metadataStart = reinterpret_cast<uintptr_t>(blob.data()) + offset; + const camera_metadata_t* tmp = + reinterpret_cast<const camera_metadata_t*>(metadataStart); + ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu", + __FUNCTION__, alignment, tmp, offset); metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize); if (metadata == NULL) { // We consider that allocation only fails if the validation // also failed, therefore the readFromParcel was a failure. + ALOGE("%s: metadata allocation and copy failed", __FUNCTION__); err = BAD_VALUE; } } while(0); @@ -485,38 +519,80 @@ status_t CameraMetadata::writeToParcel(Parcel& data, const camera_metadata_t* metadata) { status_t res = OK; - // arg0 = metadataSize (int32) - + /** + * Below is the camera metadata parcel layout: + * + * |--------------------------------------------| + * | arg0: blobSize | + * | (length = 4) | + * |--------------------------------------------|<--Skip the rest if blobSize == 0. + * | | + * | | + * | arg1: blob | + * | (length = variable, see arg1 layout below) | + * | | + * | | + * |--------------------------------------------| + * | arg2: offset | + * | (length = 4) | + * |--------------------------------------------| + */ + + // arg0 = blobSize (int32) if (metadata == NULL) { + // Write zero blobSize for null metadata. return data.writeInt32(0); } + /** + * Always make the blob size sufficiently larger, as we need put alignment + * padding and metadata into the blob. Since we don't know the alignment + * offset before writeBlob. Then write the metadata to aligned offset. + */ const size_t metadataSize = get_camera_metadata_compact_size(metadata); - res = data.writeInt32(static_cast<int32_t>(metadataSize)); + const size_t alignment = get_camera_metadata_alignment(); + const size_t blobSize = metadataSize + alignment; + res = data.writeInt32(static_cast<int32_t>(blobSize)); if (res != OK) { return res; } - // arg1 = metadata (blob) + size_t offset = 0; + /** + * arg1 = metadata (blob). + * + * The blob size is the sum of front padding size, metadata size and back padding + * size, which is equal to metadataSize + alignment. + * + * The blob layout is: + * |------------------------------------|<----Start address of the blob (unaligned). + * | front padding | + * | (size = offset) | + * |------------------------------------|<----Aligned start address of metadata. + * | | + * | | + * | metadata | + * | (size = metadataSize) | + * | | + * | | + * |------------------------------------| + * | back padding | + * | (size = alignment - offset) | + * |------------------------------------|<----End address of blob. + * (Blob start address + blob size). + */ WritableBlob blob; do { - res = data.writeBlob(metadataSize, &blob); + res = data.writeBlob(blobSize, &blob); if (res != OK) { break; } - copy_camera_metadata(blob.data(), metadataSize, metadata); - - IF_ALOGV() { - if (validate_camera_metadata_structure( - (const camera_metadata_t*)blob.data(), - &metadataSize) != OK) { - ALOGV("%s: Failed to validate metadata %p after writing blob", - __FUNCTION__, blob.data()); - } else { - ALOGV("%s: Metadata written to blob. Validation success", - __FUNCTION__); - } - } + const uintptr_t metadataStart = ALIGN_TO(blob.data(), alignment); + offset = metadataStart - reinterpret_cast<uintptr_t>(blob.data()); + ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu", + __FUNCTION__, alignment, + reinterpret_cast<const void *>(metadataStart), offset); + copy_camera_metadata(reinterpret_cast<void*>(metadataStart), metadataSize, metadata); // Not too big of a problem since receiving side does hard validation // Don't check the size since the compact size could be larger @@ -528,6 +604,9 @@ status_t CameraMetadata::writeToParcel(Parcel& data, } while(false); blob.release(); + // arg2 = offset (int32) + res = data.writeInt32(static_cast<int32_t>(offset)); + return res; } diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index 78eb4d6..25d632d 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -21,6 +21,7 @@ #include <string.h> #include <stdlib.h> #include <camera/CameraParameters.h> +#include <system/graphics.h> namespace android { // Parameter keys to communicate between camera application and driver. @@ -483,4 +484,45 @@ status_t CameraParameters::dump(int fd, const Vector<String16>& /*args*/) const return NO_ERROR; } +void CameraParameters::getSupportedPreviewFormats(Vector<int>& formats) const { + const char* supportedPreviewFormats = + get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS); + + String8 fmtStr(supportedPreviewFormats); + char* prevFmts = fmtStr.lockBuffer(fmtStr.size()); + + char* savePtr; + char* fmt = strtok_r(prevFmts, ",", &savePtr); + while (fmt) { + int actual = previewFormatToEnum(fmt); + if (actual != -1) { + formats.add(actual); + } + fmt = strtok_r(NULL, ",", &savePtr); + } + fmtStr.unlockBuffer(fmtStr.size()); +} + + +int CameraParameters::previewFormatToEnum(const char* format) { + return + !format ? + HAL_PIXEL_FORMAT_YCrCb_420_SP : + !strcmp(format, PIXEL_FORMAT_YUV422SP) ? + HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16 + !strcmp(format, PIXEL_FORMAT_YUV420SP) ? + HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21 + !strcmp(format, PIXEL_FORMAT_YUV422I) ? + HAL_PIXEL_FORMAT_YCbCr_422_I : // YUY2 + !strcmp(format, PIXEL_FORMAT_YUV420P) ? + HAL_PIXEL_FORMAT_YV12 : // YV12 + !strcmp(format, PIXEL_FORMAT_RGB565) ? + HAL_PIXEL_FORMAT_RGB_565 : // RGB565 + !strcmp(format, PIXEL_FORMAT_RGBA8888) ? + HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888 + !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ? + HAL_PIXEL_FORMAT_RAW_SENSOR : // Raw sensor data + -1; +} + }; // namespace android diff --git a/camera/CameraParameters2.cpp b/camera/CameraParameters2.cpp index eac79e1..378afeb 100644 --- a/camera/CameraParameters2.cpp +++ b/camera/CameraParameters2.cpp @@ -362,6 +362,7 @@ void CameraParameters2::dump() const status_t CameraParameters2::dump(int fd, const Vector<String16>& args) const { + (void)args; const size_t SIZE = 256; char buffer[SIZE]; String8 result; diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp new file mode 100644 index 0000000..04244ac --- /dev/null +++ b/camera/CameraUtils.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "CameraUtils" +//#define LOG_NDEBUG 0 + +#include <camera/CameraUtils.h> + +#include <system/window.h> +#include <system/graphics.h> + +#include <utils/Log.h> + +namespace android { + +status_t CameraUtils::getRotationTransform(const CameraMetadata& staticInfo, + /*out*/int32_t* transform) { + ALOGV("%s", __FUNCTION__); + + if (transform == NULL) { + ALOGW("%s: null transform", __FUNCTION__); + return BAD_VALUE; + } + + *transform = 0; + + camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_SENSOR_ORIENTATION); + if (entry.count == 0) { + ALOGE("%s: Can't find android.sensor.orientation in static metadata!", __FUNCTION__); + return INVALID_OPERATION; + } + + camera_metadata_ro_entry_t entryFacing = staticInfo.find(ANDROID_LENS_FACING); + if (entry.count == 0) { + ALOGE("%s: Can't find android.lens.facing in static metadata!", __FUNCTION__); + return INVALID_OPERATION; + } + + int32_t& flags = *transform; + + bool mirror = (entryFacing.data.u8[0] == ANDROID_LENS_FACING_FRONT); + int orientation = entry.data.i32[0]; + if (!mirror) { + switch (orientation) { + case 0: + flags = 0; + break; + case 90: + flags = NATIVE_WINDOW_TRANSFORM_ROT_90; + break; + case 180: + flags = NATIVE_WINDOW_TRANSFORM_ROT_180; + break; + case 270: + flags = NATIVE_WINDOW_TRANSFORM_ROT_270; + break; + default: + ALOGE("%s: Invalid HAL android.sensor.orientation value: %d", + __FUNCTION__, orientation); + return INVALID_OPERATION; + } + } else { + // Front camera needs to be horizontally flipped for mirror-like behavior. + // Note: Flips are applied before rotates; using XOR here as some of these flags are + // composed in terms of other flip/rotation flags, and are not bitwise-ORable. + switch (orientation) { + case 0: + flags = NATIVE_WINDOW_TRANSFORM_FLIP_H; + break; + case 90: + flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^ + NATIVE_WINDOW_TRANSFORM_ROT_270; + break; + case 180: + flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^ + NATIVE_WINDOW_TRANSFORM_ROT_180; + break; + case 270: + flags = NATIVE_WINDOW_TRANSFORM_FLIP_H ^ + NATIVE_WINDOW_TRANSFORM_ROT_90; + + break; + default: + ALOGE("%s: Invalid HAL android.sensor.orientation value: %d", + __FUNCTION__, orientation); + return INVALID_OPERATION; + } + + } + + /** + * This magic flag makes surfaceflinger un-rotate the buffers + * to counter the extra global device UI rotation whenever the user + * physically rotates the device. + * + * By doing this, the camera buffer always ends up aligned + * with the physical camera for a "see through" effect. + * + * In essence, the buffer only gets rotated during preview use-cases. + * The user is still responsible to re-create streams of the proper + * aspect ratio, or the preview will end up looking non-uniformly + * stretched. + */ + flags |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; + + ALOGV("%s: final transform = 0x%x", __FUNCTION__, flags); + + return OK; +} + + +} /* namespace android */ diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp new file mode 100644 index 0000000..4e36160 --- /dev/null +++ b/camera/CaptureResult.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Camera-CaptureResult" +#include <utils/Log.h> + +#include <camera/CaptureResult.h> +#include <binder/Parcel.h> + +namespace android { + +bool CaptureResultExtras::isValid() { + return requestId >= 0; +} + +status_t CaptureResultExtras::readFromParcel(Parcel *parcel) { + if (parcel == NULL) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->readInt32(&requestId); + parcel->readInt32(&burstId); + parcel->readInt32(&afTriggerId); + parcel->readInt32(&precaptureTriggerId); + parcel->readInt64(&frameNumber); + parcel->readInt32(&partialResultCount); + + return OK; +} + +status_t CaptureResultExtras::writeToParcel(Parcel *parcel) const { + if (parcel == NULL) { + ALOGE("%s: Null parcel", __FUNCTION__); + return BAD_VALUE; + } + + parcel->writeInt32(requestId); + parcel->writeInt32(burstId); + parcel->writeInt32(afTriggerId); + parcel->writeInt32(precaptureTriggerId); + parcel->writeInt64(frameNumber); + parcel->writeInt32(partialResultCount); + + return OK; +} + +CaptureResult::CaptureResult() : + mMetadata(), mResultExtras() { +} + +CaptureResult::CaptureResult(const CaptureResult &otherResult) { + mResultExtras = otherResult.mResultExtras; + mMetadata = otherResult.mMetadata; +} + +status_t CaptureResult::readFromParcel(Parcel *parcel) { + + ALOGV("%s: parcel = %p", __FUNCTION__, parcel); + + if (parcel == NULL) { + ALOGE("%s: parcel is null", __FUNCTION__); + return BAD_VALUE; + } + + mMetadata.clear(); + + status_t res = OK; + res = mMetadata.readFromParcel(parcel); + if (res != OK) { + ALOGE("%s: Failed to read metadata from parcel.", + __FUNCTION__); + return res; + } + ALOGV("%s: Read metadata from parcel", __FUNCTION__); + + res = mResultExtras.readFromParcel(parcel); + if (res != OK) { + ALOGE("%s: Failed to read result extras from parcel.", + __FUNCTION__); + return res; + } + ALOGV("%s: Read result extras from parcel", __FUNCTION__); + + return OK; +} + +status_t CaptureResult::writeToParcel(Parcel *parcel) const { + + ALOGV("%s: parcel = %p", __FUNCTION__, parcel); + + if (parcel == NULL) { + ALOGE("%s: parcel is null", __FUNCTION__); + return BAD_VALUE; + } + + status_t res; + + res = mMetadata.writeToParcel(parcel); + if (res != OK) { + ALOGE("%s: Failed to write metadata to parcel", __FUNCTION__); + return res; + } + ALOGV("%s: Wrote metadata to parcel", __FUNCTION__); + + res = mResultExtras.writeToParcel(parcel); + if (res != OK) { + ALOGE("%s: Failed to write result extras to parcel", __FUNCTION__); + return res; + } + ALOGV("%s: Wrote result extras to parcel", __FUNCTION__); + + return OK; +} + +} diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index 5fc89fb..5485205 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -17,6 +17,8 @@ #define LOG_TAG "BpCameraService" #include <utils/Log.h> +#include <utils/Errors.h> +#include <utils/String16.h> #include <stdint.h> #include <sys/types.h> @@ -34,6 +36,7 @@ #include <camera/camera2/ICameraDeviceUser.h> #include <camera/camera2/ICameraDeviceCallbacks.h> #include <camera/CameraMetadata.h> +#include <camera/VendorTagDescriptor.h> namespace android { @@ -143,6 +146,24 @@ public: return result; } + // Get enumeration and description of vendor tags for camera + virtual status_t getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescriptor>& desc) { + Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); + remote()->transact(BnCameraService::GET_CAMERA_VENDOR_TAG_DESCRIPTOR, data, &reply); + + if (readExceptionCode(reply)) return -EPROTO; + status_t result = reply.readInt32(); + + if (reply.readInt32() != 0) { + sp<VendorTagDescriptor> d; + if (VendorTagDescriptor::createFromParcel(&reply, /*out*/d) == OK) { + desc = d; + } + } + return result; + } + // connect to camera service (android.hardware.Camera) virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId, const String16 &clientPackageName, int clientUid, @@ -165,6 +186,29 @@ public: return status; } + // connect to camera service (android.hardware.Camera) + virtual status_t connectLegacy(const sp<ICameraClient>& cameraClient, int cameraId, + int halVersion, + const String16 &clientPackageName, int clientUid, + /*out*/sp<ICamera>& device) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); + data.writeStrongBinder(cameraClient->asBinder()); + data.writeInt32(cameraId); + data.writeInt32(halVersion); + data.writeString16(clientPackageName); + data.writeInt32(clientUid); + remote()->transact(BnCameraService::CONNECT_LEGACY, data, &reply); + + if (readExceptionCode(reply)) return -EPROTO; + status_t status = reply.readInt32(); + if (reply.readInt32() != 0) { + device = interface_cast<ICamera>(reply.readStrongBinder()); + } + return status; + } + // connect to camera service (pro client) virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb, int cameraId, const String16 &clientPackageName, int clientUid, @@ -233,6 +277,41 @@ public: if (readExceptionCode(reply)) return -EPROTO; return reply.readInt32(); } + + virtual status_t getLegacyParameters(int cameraId, String16* parameters) { + if (parameters == NULL) { + ALOGE("%s: parameters must not be null", __FUNCTION__); + return BAD_VALUE; + } + + Parcel data, reply; + + data.writeInt32(cameraId); + remote()->transact(BnCameraService::GET_LEGACY_PARAMETERS, data, &reply); + if (readExceptionCode(reply)) return -EPROTO; + + status_t res = data.readInt32(); + int32_t length = data.readInt32(); // -1 means null + if (length > 0) { + *parameters = data.readString16(); + } else { + *parameters = String16(); + } + + return res; + } + + virtual status_t supportsCameraApi(int cameraId, int apiVersion) { + Parcel data, reply; + + data.writeInt32(cameraId); + data.writeInt32(apiVersion); + remote()->transact(BnCameraService::SUPPORTS_CAMERA_API, data, &reply); + if (readExceptionCode(reply)) return -EPROTO; + + status_t res = data.readInt32(); + return res; + } }; IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService"); @@ -275,6 +354,22 @@ status_t BnCameraService::onTransact( info.writeToParcel(reply); return NO_ERROR; } break; + case GET_CAMERA_VENDOR_TAG_DESCRIPTOR: { + CHECK_INTERFACE(ICameraService, data, reply); + sp<VendorTagDescriptor> d; + status_t result = getCameraVendorTagDescriptor(d); + reply->writeNoException(); + reply->writeInt32(result); + + // out-variables are after exception and return value + if (d == NULL) { + reply->writeInt32(0); + } else { + reply->writeInt32(1); // means the parcelable is included + d->writeToParcel(reply); + } + return NO_ERROR; + } break; case CONNECT: { CHECK_INTERFACE(ICameraService, data, reply); sp<ICameraClient> cameraClient = @@ -284,7 +379,7 @@ status_t BnCameraService::onTransact( int32_t clientUid = data.readInt32(); sp<ICamera> camera; status_t status = connect(cameraClient, cameraId, - clientName, clientUid, /*out*/ camera); + clientName, clientUid, /*out*/camera); reply->writeNoException(); reply->writeInt32(status); if (camera != NULL) { @@ -304,7 +399,7 @@ status_t BnCameraService::onTransact( int32_t clientUid = data.readInt32(); sp<IProCameraUser> camera; status_t status = connectPro(cameraClient, cameraId, - clientName, clientUid, /*out*/ camera); + clientName, clientUid, /*out*/camera); reply->writeNoException(); reply->writeInt32(status); if (camera != NULL) { @@ -324,7 +419,7 @@ status_t BnCameraService::onTransact( int32_t clientUid = data.readInt32(); sp<ICameraDeviceUser> camera; status_t status = connectDevice(cameraClient, cameraId, - clientName, clientUid, /*out*/ camera); + clientName, clientUid, /*out*/camera); reply->writeNoException(); reply->writeInt32(status); if (camera != NULL) { @@ -351,6 +446,50 @@ status_t BnCameraService::onTransact( reply->writeInt32(removeListener(listener)); return NO_ERROR; } break; + case GET_LEGACY_PARAMETERS: { + CHECK_INTERFACE(ICameraService, data, reply); + int cameraId = data.readInt32(); + String16 parameters; + + reply->writeNoException(); + // return value + reply->writeInt32(getLegacyParameters(cameraId, ¶meters)); + // out parameters + reply->writeInt32(1); // parameters is always available + reply->writeString16(parameters); + return NO_ERROR; + } break; + case SUPPORTS_CAMERA_API: { + CHECK_INTERFACE(ICameraService, data, reply); + int cameraId = data.readInt32(); + int apiVersion = data.readInt32(); + + reply->writeNoException(); + // return value + reply->writeInt32(supportsCameraApi(cameraId, apiVersion)); + return NO_ERROR; + } break; + case CONNECT_LEGACY: { + CHECK_INTERFACE(ICameraService, data, reply); + sp<ICameraClient> cameraClient = + interface_cast<ICameraClient>(data.readStrongBinder()); + int32_t cameraId = data.readInt32(); + int32_t halVersion = data.readInt32(); + const String16 clientName = data.readString16(); + int32_t clientUid = data.readInt32(); + sp<ICamera> camera; + status_t status = connectLegacy(cameraClient, cameraId, halVersion, + clientName, clientUid, /*out*/camera); + reply->writeNoException(); + reply->writeInt32(status); + if (camera != NULL) { + reply->writeInt32(1); + reply->writeStrongBinder(camera->asBinder()); + } else { + reply->writeInt32(0); + } + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp index ba5a48c..48f8e8e 100644 --- a/camera/ProCamera.cpp +++ b/camera/ProCamera.cpp @@ -249,11 +249,14 @@ status_t ProCamera::createStreamCpu(int width, int height, int format, sp <IProCameraUser> c = mCamera; if (c == 0) return NO_INIT; - sp<BufferQueue> bq = new BufferQueue(); - sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount/*, synchronousMode*/); + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + sp<CpuConsumer> cc = new CpuConsumer(consumer, heapCount + /*, synchronousMode*/); cc->setName(String8("ProCamera::mCpuConsumer")); - sp<Surface> stc = new Surface(bq); + sp<Surface> stc = new Surface(producer); status_t s = createStream(width, height, format, stc->getIGraphicBufferProducer(), diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp new file mode 100644 index 0000000..0dda6b6 --- /dev/null +++ b/camera/VendorTagDescriptor.cpp @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VendorTagDescriptor" + +#include <binder/Parcel.h> +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/Mutex.h> +#include <utils/Vector.h> +#include <utils/SortedVector.h> +#include <system/camera_metadata.h> +#include <camera_metadata_hidden.h> + +#include "camera/VendorTagDescriptor.h" + +#include <stdio.h> +#include <string.h> + +namespace android { + +extern "C" { + +static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v); +static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray); +static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag); +static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag); +static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag); + +} /* extern "C" */ + + +static Mutex sLock; +static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor; + +VendorTagDescriptor::VendorTagDescriptor() {} + +VendorTagDescriptor::~VendorTagDescriptor() { + size_t len = mReverseMapping.size(); + for (size_t i = 0; i < len; ++i) { + delete mReverseMapping[i]; + } +} + +status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps, + /*out*/ + sp<VendorTagDescriptor>& descriptor) { + if (vOps == NULL) { + ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__); + return BAD_VALUE; + } + + int tagCount = vOps->get_tag_count(vOps); + if (tagCount < 0 || tagCount > INT32_MAX) { + ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount); + return BAD_VALUE; + } + + Vector<uint32_t> tagArray; + LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount, + "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount); + + vOps->get_all_tags(vOps, /*out*/tagArray.editArray()); + + sp<VendorTagDescriptor> desc = new VendorTagDescriptor(); + desc->mTagCount = tagCount; + + SortedVector<String8> sections; + KeyedVector<uint32_t, String8> tagToSectionMap; + + for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) { + uint32_t tag = tagArray[i]; + if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) { + ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag); + return BAD_VALUE; + } + const char *tagName = vOps->get_tag_name(vOps, tag); + if (tagName == NULL) { + ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag); + return BAD_VALUE; + } + desc->mTagToNameMap.add(tag, String8(tagName)); + const char *sectionName = vOps->get_section_name(vOps, tag); + if (sectionName == NULL) { + ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag); + return BAD_VALUE; + } + + String8 sectionString(sectionName); + + sections.add(sectionString); + tagToSectionMap.add(tag, sectionString); + + int tagType = vOps->get_tag_type(vOps, tag); + if (tagType < 0 || tagType >= NUM_TYPES) { + ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType); + return BAD_VALUE; + } + desc->mTagToTypeMap.add(tag, tagType); + } + + desc->mSections = sections; + + for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) { + uint32_t tag = tagArray[i]; + String8 sectionString = tagToSectionMap.valueFor(tag); + + // Set up tag to section index map + ssize_t index = sections.indexOf(sectionString); + LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index); + desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index)); + + // Set up reverse mapping + ssize_t reverseIndex = -1; + if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) { + KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>(); + reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper); + } + desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag); + } + + descriptor = desc; + return OK; +} + +status_t VendorTagDescriptor::createFromParcel(const Parcel* parcel, + /*out*/ + sp<VendorTagDescriptor>& descriptor) { + status_t res = OK; + if (parcel == NULL) { + ALOGE("%s: parcel argument was NULL.", __FUNCTION__); + return BAD_VALUE; + } + + int32_t tagCount = 0; + if ((res = parcel->readInt32(&tagCount)) != OK) { + ALOGE("%s: could not read tag count from parcel", __FUNCTION__); + return res; + } + + if (tagCount < 0 || tagCount > INT32_MAX) { + ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount); + return BAD_VALUE; + } + + sp<VendorTagDescriptor> desc = new VendorTagDescriptor(); + desc->mTagCount = tagCount; + + uint32_t tag, sectionIndex; + uint32_t maxSectionIndex = 0; + int32_t tagType; + Vector<uint32_t> allTags; + for (int32_t i = 0; i < tagCount; ++i) { + if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(&tag))) != OK) { + ALOGE("%s: could not read tag id from parcel for index %d", __FUNCTION__, i); + break; + } + if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) { + ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag); + res = BAD_VALUE; + break; + } + if ((res = parcel->readInt32(&tagType)) != OK) { + ALOGE("%s: could not read tag type from parcel for tag %d", __FUNCTION__, tag); + break; + } + if (tagType < 0 || tagType >= NUM_TYPES) { + ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType); + res = BAD_VALUE; + break; + } + String8 tagName = parcel->readString8(); + if (tagName.isEmpty()) { + ALOGE("%s: parcel tag name was NULL for tag %d.", __FUNCTION__, tag); + res = NOT_ENOUGH_DATA; + break; + } + + if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(§ionIndex))) != OK) { + ALOGE("%s: could not read section index for tag %d.", __FUNCTION__, tag); + break; + } + + maxSectionIndex = (maxSectionIndex >= sectionIndex) ? maxSectionIndex : sectionIndex; + + allTags.add(tag); + desc->mTagToNameMap.add(tag, tagName); + desc->mTagToSectionMap.add(tag, sectionIndex); + desc->mTagToTypeMap.add(tag, tagType); + } + + if (res != OK) { + return res; + } + + size_t sectionCount; + if (tagCount > 0) { + if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(§ionCount))) != OK) { + ALOGE("%s: could not read section count for.", __FUNCTION__); + return res; + } + if (sectionCount < (maxSectionIndex + 1)) { + ALOGE("%s: Incorrect number of sections defined, received %zu, needs %d.", + __FUNCTION__, sectionCount, (maxSectionIndex + 1)); + return BAD_VALUE; + } + LOG_ALWAYS_FATAL_IF(desc->mSections.setCapacity(sectionCount) <= 0, + "Vector capacity must be positive"); + for (size_t i = 0; i < sectionCount; ++i) { + String8 sectionName = parcel->readString8(); + if (sectionName.isEmpty()) { + ALOGE("%s: parcel section name was NULL for section %zu.", + __FUNCTION__, i); + return NOT_ENOUGH_DATA; + } + desc->mSections.add(sectionName); + } + } + + LOG_ALWAYS_FATAL_IF(static_cast<size_t>(tagCount) != allTags.size(), + "tagCount must be the same as allTags size"); + // Set up reverse mapping + for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) { + uint32_t tag = allTags[i]; + String8 sectionString = desc->mSections[desc->mTagToSectionMap.valueFor(tag)]; + + ssize_t reverseIndex = -1; + if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) { + KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>(); + reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper); + } + desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag); + } + + descriptor = desc; + return res; +} + +int VendorTagDescriptor::getTagCount() const { + size_t size = mTagToNameMap.size(); + if (size == 0) { + return VENDOR_TAG_COUNT_ERR; + } + return size; +} + +void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const { + size_t size = mTagToNameMap.size(); + for (size_t i = 0; i < size; ++i) { + tagArray[i] = mTagToNameMap.keyAt(i); + } +} + +const char* VendorTagDescriptor::getSectionName(uint32_t tag) const { + ssize_t index = mTagToSectionMap.indexOfKey(tag); + if (index < 0) { + return VENDOR_SECTION_NAME_ERR; + } + return mSections[mTagToSectionMap.valueAt(index)].string(); +} + +const char* VendorTagDescriptor::getTagName(uint32_t tag) const { + ssize_t index = mTagToNameMap.indexOfKey(tag); + if (index < 0) { + return VENDOR_TAG_NAME_ERR; + } + return mTagToNameMap.valueAt(index).string(); +} + +int VendorTagDescriptor::getTagType(uint32_t tag) const { + ssize_t index = mTagToNameMap.indexOfKey(tag); + if (index < 0) { + return VENDOR_TAG_TYPE_ERR; + } + return mTagToTypeMap.valueFor(tag); +} + +status_t VendorTagDescriptor::writeToParcel(Parcel* parcel) const { + status_t res = OK; + if (parcel == NULL) { + ALOGE("%s: parcel argument was NULL.", __FUNCTION__); + return BAD_VALUE; + } + + if ((res = parcel->writeInt32(mTagCount)) != OK) { + return res; + } + + size_t size = mTagToNameMap.size(); + uint32_t tag, sectionIndex; + int32_t tagType; + for (size_t i = 0; i < size; ++i) { + tag = mTagToNameMap.keyAt(i); + String8 tagName = mTagToNameMap[i]; + sectionIndex = mTagToSectionMap.valueFor(tag); + tagType = mTagToTypeMap.valueFor(tag); + if ((res = parcel->writeInt32(tag)) != OK) break; + if ((res = parcel->writeInt32(tagType)) != OK) break; + if ((res = parcel->writeString8(tagName)) != OK) break; + if ((res = parcel->writeInt32(sectionIndex)) != OK) break; + } + + size_t numSections = mSections.size(); + if (numSections > 0) { + if ((res = parcel->writeInt32(numSections)) != OK) return res; + for (size_t i = 0; i < numSections; ++i) { + if ((res = parcel->writeString8(mSections[i])) != OK) return res; + } + } + + return res; +} + +SortedVector<String8> VendorTagDescriptor::getAllSectionNames() const { + return mSections; +} + +status_t VendorTagDescriptor::lookupTag(String8 name, String8 section, /*out*/uint32_t* tag) const { + ssize_t index = mReverseMapping.indexOfKey(section); + if (index < 0) { + ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string()); + return BAD_VALUE; + } + + ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name); + if (nameIndex < 0) { + ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string()); + return BAD_VALUE; + } + + if (tag != NULL) { + *tag = mReverseMapping[index]->valueAt(nameIndex); + } + return OK; +} + +void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const { + + size_t size = mTagToNameMap.size(); + if (size == 0) { + dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n", + indentation, ""); + return; + } + + dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n", + indentation, "", size); + for (size_t i = 0; i < size; ++i) { + uint32_t tag = mTagToNameMap.keyAt(i); + + if (verbosity < 1) { + dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag); + continue; + } + String8 name = mTagToNameMap.valueAt(i); + uint32_t sectionId = mTagToSectionMap.valueFor(tag); + String8 sectionName = mSections[sectionId]; + int type = mTagToTypeMap.valueFor(tag); + const char* typeName = (type >= 0 && type < NUM_TYPES) ? + camera_metadata_type_names[type] : "UNKNOWN"; + dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2, + "", tag, name.string(), type, typeName, sectionName.string()); + } + +} + +status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc) { + status_t res = OK; + Mutex::Autolock al(sLock); + sGlobalVendorTagDescriptor = desc; + + vendor_tag_ops_t* opsPtr = NULL; + if (desc != NULL) { + opsPtr = &(desc->mVendorOps); + opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count; + opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags; + opsPtr->get_section_name = vendor_tag_descriptor_get_section_name; + opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name; + opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type; + } + if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) { + ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)." + , __FUNCTION__, strerror(-res), res); + } + return res; +} + +void VendorTagDescriptor::clearGlobalVendorTagDescriptor() { + Mutex::Autolock al(sLock); + set_camera_metadata_vendor_ops(NULL); + sGlobalVendorTagDescriptor.clear(); +} + +sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() { + Mutex::Autolock al(sLock); + return sGlobalVendorTagDescriptor; +} + +extern "C" { + +int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* /*v*/) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_TAG_COUNT_ERR; + } + return sGlobalVendorTagDescriptor->getTagCount(); +} + +void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* /*v*/, uint32_t* tagArray) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return; + } + sGlobalVendorTagDescriptor->getTagArray(tagArray); +} + +const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_SECTION_NAME_ERR; + } + return sGlobalVendorTagDescriptor->getSectionName(tag); +} + +const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_TAG_NAME_ERR; + } + return sGlobalVendorTagDescriptor->getTagName(tag); +} + +int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* /*v*/, uint32_t tag) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_TAG_TYPE_ERR; + } + return sGlobalVendorTagDescriptor->getTagType(tag); +} + +} /* extern "C" */ +} /* namespace android */ diff --git a/camera/camera2/ICameraDeviceCallbacks.cpp b/camera/camera2/ICameraDeviceCallbacks.cpp index 613358a..4cc7b5d 100644 --- a/camera/camera2/ICameraDeviceCallbacks.cpp +++ b/camera/camera2/ICameraDeviceCallbacks.cpp @@ -28,6 +28,7 @@ #include <camera/camera2/ICameraDeviceCallbacks.h> #include "camera/CameraMetadata.h" +#include "camera/CaptureResult.h" namespace android { @@ -46,12 +47,14 @@ public: { } - void onDeviceError(CameraErrorCode errorCode) + void onDeviceError(CameraErrorCode errorCode, const CaptureResultExtras& resultExtras) { ALOGV("onDeviceError"); Parcel data, reply; data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor()); data.writeInt32(static_cast<int32_t>(errorCode)); + data.writeInt32(1); // to mark presence of CaptureResultExtras object + resultExtras.writeToParcel(&data); remote()->transact(CAMERA_ERROR, data, &reply, IBinder::FLAG_ONEWAY); data.writeNoException(); } @@ -65,25 +68,28 @@ public: data.writeNoException(); } - void onCaptureStarted(int32_t requestId, int64_t timestamp) + void onCaptureStarted(const CaptureResultExtras& result, int64_t timestamp) { ALOGV("onCaptureStarted"); Parcel data, reply; data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor()); - data.writeInt32(requestId); + data.writeInt32(1); // to mark presence of CaptureResultExtras object + result.writeToParcel(&data); data.writeInt64(timestamp); remote()->transact(CAPTURE_STARTED, data, &reply, IBinder::FLAG_ONEWAY); data.writeNoException(); } - void onResultReceived(int32_t requestId, const CameraMetadata& result) { + void onResultReceived(const CameraMetadata& metadata, + const CaptureResultExtras& resultExtras) { ALOGV("onResultReceived"); Parcel data, reply; data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor()); - data.writeInt32(requestId); data.writeInt32(1); // to mark presence of metadata object - result.writeToParcel(&data); + metadata.writeToParcel(&data); + data.writeInt32(1); // to mark presence of CaptureResult object + resultExtras.writeToParcel(&data); remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY); data.writeNoException(); } @@ -104,7 +110,13 @@ status_t BnCameraDeviceCallbacks::onTransact( CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply); CameraErrorCode errorCode = static_cast<CameraErrorCode>(data.readInt32()); - onDeviceError(errorCode); + CaptureResultExtras resultExtras; + if (data.readInt32() != 0) { + resultExtras.readFromParcel(const_cast<Parcel*>(&data)); + } else { + ALOGE("No CaptureResultExtras object is present!"); + } + onDeviceError(errorCode, resultExtras); data.readExceptionCode(); return NO_ERROR; } break; @@ -118,23 +130,33 @@ status_t BnCameraDeviceCallbacks::onTransact( case CAPTURE_STARTED: { ALOGV("onCaptureStarted"); CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply); - int32_t requestId = data.readInt32(); + CaptureResultExtras result; + if (data.readInt32() != 0) { + result.readFromParcel(const_cast<Parcel*>(&data)); + } else { + ALOGE("No CaptureResultExtras object is present in result!"); + } int64_t timestamp = data.readInt64(); - onCaptureStarted(requestId, timestamp); + onCaptureStarted(result, timestamp); data.readExceptionCode(); return NO_ERROR; } break; case RESULT_RECEIVED: { ALOGV("onResultReceived"); CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply); - int32_t requestId = data.readInt32(); - CameraMetadata result; + CameraMetadata metadata; if (data.readInt32() != 0) { - result.readFromParcel(const_cast<Parcel*>(&data)); + metadata.readFromParcel(const_cast<Parcel*>(&data)); } else { ALOGW("No metadata object is present in result"); } - onResultReceived(requestId, result); + CaptureResultExtras resultExtras; + if (data.readInt32() != 0) { + resultExtras.readFromParcel(const_cast<Parcel*>(&data)); + } else { + ALOGW("No capture result extras object is present in result"); + } + onResultReceived(metadata, resultExtras); data.readExceptionCode(); return NO_ERROR; } break; diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp index 1e5822f..ff4a0c2 100644 --- a/camera/camera2/ICameraDeviceUser.cpp +++ b/camera/camera2/ICameraDeviceUser.cpp @@ -35,7 +35,10 @@ typedef Parcel::ReadableBlob ReadableBlob; enum { DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, SUBMIT_REQUEST, + SUBMIT_REQUEST_LIST, CANCEL_REQUEST, + BEGIN_CONFIGURE, + END_CONFIGURE, DELETE_STREAM, CREATE_STREAM, CREATE_DEFAULT_REQUEST, @@ -75,7 +78,8 @@ public: reply.readExceptionCode(); } - virtual int submitRequest(sp<CaptureRequest> request, bool streaming) + virtual status_t submitRequest(sp<CaptureRequest> request, bool repeating, + int64_t *lastFrameNumber) { Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); @@ -89,15 +93,67 @@ public: } // arg1 = streaming (bool) - data.writeInt32(streaming); + data.writeInt32(repeating); remote()->transact(SUBMIT_REQUEST, data, &reply); reply.readExceptionCode(); - return reply.readInt32(); + status_t res = reply.readInt32(); + + status_t resFrameNumber = BAD_VALUE; + if (reply.readInt32() != 0) { + if (lastFrameNumber != NULL) { + resFrameNumber = reply.readInt64(lastFrameNumber); + } + } + + if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + res = FAILED_TRANSACTION; + } + return res; + } + + virtual status_t submitRequestList(List<sp<CaptureRequest> > requestList, bool repeating, + int64_t *lastFrameNumber) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + + data.writeInt32(requestList.size()); + + for (List<sp<CaptureRequest> >::iterator it = requestList.begin(); + it != requestList.end(); ++it) { + sp<CaptureRequest> request = *it; + if (request != 0) { + data.writeInt32(1); + if (request->writeToParcel(&data) != OK) { + return BAD_VALUE; + } + } else { + data.writeInt32(0); + } + } + + data.writeInt32(repeating); + + remote()->transact(SUBMIT_REQUEST_LIST, data, &reply); + + reply.readExceptionCode(); + status_t res = reply.readInt32(); + + status_t resFrameNumber = BAD_VALUE; + if (reply.readInt32() != 0) { + if (lastFrameNumber != NULL) { + resFrameNumber = reply.readInt64(lastFrameNumber); + } + } + if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + res = FAILED_TRANSACTION; + } + return res; } - virtual status_t cancelRequest(int requestId) + virtual status_t cancelRequest(int requestId, int64_t *lastFrameNumber) { Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); @@ -106,6 +162,37 @@ public: remote()->transact(CANCEL_REQUEST, data, &reply); reply.readExceptionCode(); + status_t res = reply.readInt32(); + + status_t resFrameNumber = BAD_VALUE; + if (reply.readInt32() != 0) { + if (lastFrameNumber != NULL) { + res = reply.readInt64(lastFrameNumber); + } + } + if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + res = FAILED_TRANSACTION; + } + return res; + } + + virtual status_t beginConfigure() + { + ALOGV("beginConfigure"); + Parcel data, reply; + data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + remote()->transact(BEGIN_CONFIGURE, data, &reply); + reply.readExceptionCode(); + return reply.readInt32(); + } + + virtual status_t endConfigure() + { + ALOGV("endConfigure"); + Parcel data, reply; + data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + remote()->transact(END_CONFIGURE, data, &reply); + reply.readExceptionCode(); return reply.readInt32(); } @@ -197,14 +284,25 @@ public: return reply.readInt32(); } - virtual status_t flush() + virtual status_t flush(int64_t *lastFrameNumber) { ALOGV("flush"); Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); remote()->transact(FLUSH, data, &reply); reply.readExceptionCode(); - return reply.readInt32(); + status_t res = reply.readInt32(); + + status_t resFrameNumber = BAD_VALUE; + if (reply.readInt32() != 0) { + if (lastFrameNumber != NULL) { + res = reply.readInt64(lastFrameNumber); + } + } + if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + res = FAILED_TRANSACTION; + } + return res; } private: @@ -239,11 +337,43 @@ status_t BnCameraDeviceUser::onTransact( } // arg1 = streaming (bool) - bool streaming = data.readInt32(); + bool repeating = data.readInt32(); // return code: requestId (int32) reply->writeNoException(); - reply->writeInt32(submitRequest(request, streaming)); + int64_t lastFrameNumber = -1; + reply->writeInt32(submitRequest(request, repeating, &lastFrameNumber)); + reply->writeInt32(1); + reply->writeInt64(lastFrameNumber); + + return NO_ERROR; + } break; + case SUBMIT_REQUEST_LIST: { + CHECK_INTERFACE(ICameraDeviceUser, data, reply); + + List<sp<CaptureRequest> > requestList; + int requestListSize = data.readInt32(); + for (int i = 0; i < requestListSize; i++) { + if (data.readInt32() != 0) { + sp<CaptureRequest> request = new CaptureRequest(); + if (request->readFromParcel(const_cast<Parcel*>(&data)) != OK) { + return BAD_VALUE; + } + requestList.push_back(request); + } else { + sp<CaptureRequest> request = 0; + requestList.push_back(request); + ALOGE("A request is missing. Sending in null request."); + } + } + + bool repeating = data.readInt32(); + + reply->writeNoException(); + int64_t lastFrameNumber = -1; + reply->writeInt32(submitRequestList(requestList, repeating, &lastFrameNumber)); + reply->writeInt32(1); + reply->writeInt64(lastFrameNumber); return NO_ERROR; } break; @@ -251,7 +381,10 @@ status_t BnCameraDeviceUser::onTransact( CHECK_INTERFACE(ICameraDeviceUser, data, reply); int requestId = data.readInt32(); reply->writeNoException(); - reply->writeInt32(cancelRequest(requestId)); + int64_t lastFrameNumber = -1; + reply->writeInt32(cancelRequest(requestId, &lastFrameNumber)); + reply->writeInt32(1); + reply->writeInt64(lastFrameNumber); return NO_ERROR; } break; case DELETE_STREAM: { @@ -339,9 +472,24 @@ status_t BnCameraDeviceUser::onTransact( case FLUSH: { CHECK_INTERFACE(ICameraDeviceUser, data, reply); reply->writeNoException(); - reply->writeInt32(flush()); + int64_t lastFrameNumber = -1; + reply->writeInt32(flush(&lastFrameNumber)); + reply->writeInt32(1); + reply->writeInt64(lastFrameNumber); return NO_ERROR; } + case BEGIN_CONFIGURE: { + CHECK_INTERFACE(ICameraDeviceUser, data, reply); + reply->writeNoException(); + reply->writeInt32(beginConfigure()); + return NO_ERROR; + } break; + case END_CONFIGURE: { + CHECK_INTERFACE(ICameraDeviceUser, data, reply); + reply->writeNoException(); + reply->writeInt32(endConfigure()); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk index a806e31..2db4c14 100644 --- a/camera/tests/Android.mk +++ b/camera/tests/Android.mk @@ -1,9 +1,24 @@ +# Copyright 2013 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES:= \ ProCameraTests.cpp \ + VendorTagDescriptorTests.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ @@ -18,6 +33,8 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES += \ system/media/camera/include \ + system/media/private/camera/include \ + system/media/camera/tests \ frameworks/av/services/camera/libcameraservice \ frameworks/av/include/camera \ frameworks/native/include \ diff --git a/camera/tests/VendorTagDescriptorTests.cpp b/camera/tests/VendorTagDescriptorTests.cpp new file mode 100644 index 0000000..6624e79 --- /dev/null +++ b/camera/tests/VendorTagDescriptorTests.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "VendorTagDescriptorTests" + +#include <binder/Parcel.h> +#include <camera/VendorTagDescriptor.h> +#include <camera_metadata_tests_fake_vendor.h> +#include <camera_metadata_hidden.h> +#include <system/camera_vendor_tags.h> +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/RefBase.h> + +#include <gtest/gtest.h> +#include <stdint.h> + +using namespace android; + +enum { + BAD_TAG_ARRAY = 0xDEADBEEFu, + BAD_TAG = 0x8DEADBADu, +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static bool ContainsTag(uint32_t* tagArray, size_t size, uint32_t tag) { + for (size_t i = 0; i < size; ++i) { + if (tag == tagArray[i]) return true; + } + return false; +} + +#define EXPECT_CONTAINS_TAG(t, a) \ + EXPECT_TRUE(ContainsTag(a, ARRAY_SIZE(a), t)) + +#define ASSERT_NOT_NULL(x) \ + ASSERT_TRUE((x) != NULL) + +extern "C" { + +static int default_get_tag_count(const vendor_tag_ops_t* vOps) { + return VENDOR_TAG_COUNT_ERR; +} + +static void default_get_all_tags(const vendor_tag_ops_t* vOps, uint32_t* tagArray) { + //Noop +} + +static const char* default_get_section_name(const vendor_tag_ops_t* vOps, uint32_t tag) { + return VENDOR_SECTION_NAME_ERR; +} + +static const char* default_get_tag_name(const vendor_tag_ops_t* vOps, uint32_t tag) { + return VENDOR_TAG_NAME_ERR; +} + +static int default_get_tag_type(const vendor_tag_ops_t* vOps, uint32_t tag) { + return VENDOR_TAG_TYPE_ERR; +} + +} /*extern "C"*/ + +// Set default vendor operations for a vendor_tag_ops struct +static void FillWithDefaults(vendor_tag_ops_t* vOps) { + ASSERT_NOT_NULL(vOps); + vOps->get_tag_count = default_get_tag_count; + vOps->get_all_tags = default_get_all_tags; + vOps->get_section_name = default_get_section_name; + vOps->get_tag_name = default_get_tag_name; + vOps->get_tag_type = default_get_tag_type; +} + +/** + * Test if values from VendorTagDescriptor methods match corresponding values + * from vendor_tag_ops functions. + */ +TEST(VendorTagDescriptorTest, ConsistentWithVendorTags) { + sp<VendorTagDescriptor> vDesc; + const vendor_tag_ops_t *vOps = &fakevendor_ops; + EXPECT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(vOps, /*out*/vDesc)); + + ASSERT_NOT_NULL(vDesc); + + // Ensure reasonable tag count + int tagCount = vDesc->getTagCount(); + EXPECT_EQ(tagCount, vOps->get_tag_count(vOps)); + + uint32_t descTagArray[tagCount]; + uint32_t opsTagArray[tagCount]; + + // Get all tag ids + vDesc->getTagArray(descTagArray); + vOps->get_all_tags(vOps, opsTagArray); + + ASSERT_NOT_NULL(descTagArray); + ASSERT_NOT_NULL(opsTagArray); + + uint32_t tag; + for (int i = 0; i < tagCount; ++i) { + // For each tag id, check whether type, section name, tag name match + tag = descTagArray[i]; + EXPECT_CONTAINS_TAG(tag, opsTagArray); + EXPECT_EQ(vDesc->getTagType(tag), vOps->get_tag_type(vOps, tag)); + EXPECT_STREQ(vDesc->getSectionName(tag), vOps->get_section_name(vOps, tag)); + EXPECT_STREQ(vDesc->getTagName(tag), vOps->get_tag_name(vOps, tag)); + } +} + +/** + * Test if values from VendorTagDescriptor methods stay consistent after being + * parcelled/unparcelled. + */ +TEST(VendorTagDescriptorTest, ConsistentAcrossParcel) { + sp<VendorTagDescriptor> vDescOriginal, vDescParceled; + const vendor_tag_ops_t *vOps = &fakevendor_ops; + EXPECT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(vOps, /*out*/vDescOriginal)); + + ASSERT_TRUE(vDescOriginal != NULL); + + Parcel p; + + // Check whether parcel read/write succeed + EXPECT_EQ(OK, vDescOriginal->writeToParcel(&p)); + p.setDataPosition(0); + ASSERT_EQ(OK, VendorTagDescriptor::createFromParcel(&p, vDescParceled)); + + // Ensure consistent tag count + int tagCount = vDescOriginal->getTagCount(); + ASSERT_EQ(tagCount, vDescParceled->getTagCount()); + + uint32_t descTagArray[tagCount]; + uint32_t desc2TagArray[tagCount]; + + // Get all tag ids + vDescOriginal->getTagArray(descTagArray); + vDescParceled->getTagArray(desc2TagArray); + + ASSERT_NOT_NULL(descTagArray); + ASSERT_NOT_NULL(desc2TagArray); + + uint32_t tag; + for (int i = 0; i < tagCount; ++i) { + // For each tag id, check consistency between the two vendor tag + // descriptors for each type, section name, tag name + tag = descTagArray[i]; + EXPECT_CONTAINS_TAG(tag, desc2TagArray); + EXPECT_EQ(vDescOriginal->getTagType(tag), vDescParceled->getTagType(tag)); + EXPECT_STREQ(vDescOriginal->getSectionName(tag), vDescParceled->getSectionName(tag)); + EXPECT_STREQ(vDescOriginal->getTagName(tag), vDescParceled->getTagName(tag)); + } +} + +/** + * Test defaults and error conditions. + */ +TEST(VendorTagDescriptorTest, ErrorConditions) { + sp<VendorTagDescriptor> vDesc; + vendor_tag_ops_t vOps; + FillWithDefaults(&vOps); + + // Ensure create fails when using null vOps + EXPECT_EQ(BAD_VALUE, VendorTagDescriptor::createDescriptorFromOps(/*vOps*/NULL, vDesc)); + + // Ensure create works when there are no vtags defined in a well-formed vOps + ASSERT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(&vOps, vDesc)); + + // Ensure defaults are returned when no vtags are defined, or tag is unknown + EXPECT_EQ(VENDOR_TAG_COUNT_ERR, vDesc->getTagCount()); + uint32_t* tagArray = reinterpret_cast<uint32_t*>(BAD_TAG_ARRAY); + uint32_t* testArray = tagArray; + vDesc->getTagArray(tagArray); + EXPECT_EQ(testArray, tagArray); + EXPECT_EQ(VENDOR_SECTION_NAME_ERR, vDesc->getSectionName(BAD_TAG)); + EXPECT_EQ(VENDOR_TAG_NAME_ERR, vDesc->getTagName(BAD_TAG)); + EXPECT_EQ(VENDOR_TAG_TYPE_ERR, vDesc->getTagType(BAD_TAG)); + + // Make sure global can be set/cleared + const vendor_tag_ops_t *fakeOps = &fakevendor_ops; + sp<VendorTagDescriptor> prevGlobal = VendorTagDescriptor::getGlobalVendorTagDescriptor(); + VendorTagDescriptor::clearGlobalVendorTagDescriptor(); + + EXPECT_TRUE(VendorTagDescriptor::getGlobalVendorTagDescriptor() == NULL); + EXPECT_EQ(OK, VendorTagDescriptor::setAsGlobalVendorTagDescriptor(vDesc)); + EXPECT_TRUE(VendorTagDescriptor::getGlobalVendorTagDescriptor() != NULL); + EXPECT_EQ(VENDOR_SECTION_NAME_ERR, vDesc->getSectionName(BAD_TAG)); + EXPECT_EQ(OK, VendorTagDescriptor::setAsGlobalVendorTagDescriptor(prevGlobal)); + EXPECT_EQ(prevGlobal, VendorTagDescriptor::getGlobalVendorTagDescriptor()); +} + |