summaryrefslogtreecommitdiffstats
path: root/camera
diff options
context:
space:
mode:
Diffstat (limited to 'camera')
-rw-r--r--camera/Android.mk16
-rw-r--r--camera/CameraMetadata.cpp137
-rw-r--r--camera/CameraParameters.cpp53
-rw-r--r--camera/ICameraService.cpp42
-rw-r--r--camera/ProCamera.cpp9
-rw-r--r--camera/VendorTagDescriptor.cpp319
-rw-r--r--camera/tests/Android.mk17
-rw-r--r--camera/tests/VendorTagDescriptorTests.cpp204
8 files changed, 756 insertions, 41 deletions
diff --git a/camera/Android.mk b/camera/Android.mk
index e633450..369d0c5 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)
@@ -21,6 +35,7 @@ LOCAL_SRC_FILES:= \
camera2/CaptureRequest.cpp \
ProCamera.cpp \
CameraBase.cpp \
+ VendorTagDescriptor.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -34,6 +49,7 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_C_INCLUDES += \
system/media/camera/include \
+ system/media/private/camera/include
LOCAL_MODULE:= libcamera_client
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index 7765914..6b726e0 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;
@@ -431,40 +434,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 +518,79 @@ 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, 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 +602,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 af091f4..99e5df4 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -16,6 +16,7 @@
*/
#define LOG_TAG "CameraParams"
+// #define LOG_NDEBUG 0
#include <utils/Log.h>
#include <string.h>
@@ -198,6 +199,8 @@ String8 CameraParameters::flatten() const
flattened += ";";
}
+ ALOGV("%s: Flattened params = %s", __FUNCTION__, flattened.string());
+
return flattened;
}
@@ -247,7 +250,9 @@ void CameraParameters::set(const char *key, const char *value)
return;
}
- mMap.replaceValueFor(String8(key), String8(value));
+ // Replacing a value updates the key's order to be the new largest order
+ ssize_t res = mMap.replaceValueFor(String8(key), String8(value));
+ LOG_ALWAYS_FATAL_IF(res < 0, "replaceValueFor(%s,%s) failed", key, value);
}
void CameraParameters::set(const char *key, int value)
@@ -266,10 +271,12 @@ void CameraParameters::setFloat(const char *key, float value)
const char *CameraParameters::get(const char *key) const
{
- String8 v = mMap.valueFor(String8(key));
- if (v.length() == 0)
- return 0;
- return v.string();
+ ssize_t idx = mMap.indexOfKey(String8(key));
+ if (idx < 0) {
+ return NULL;
+ } else {
+ return mMap.valueAt(idx).string();
+ }
}
int CameraParameters::getInt(const char *key) const
@@ -287,6 +294,36 @@ float CameraParameters::getFloat(const char *key) const
return strtof(v, 0);
}
+status_t CameraParameters::compareSetOrder(const char *key1, const char *key2,
+ int *order) const {
+ if (key1 == NULL) {
+ ALOGE("%s: key1 must not be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ } else if (key2 == NULL) {
+ ALOGE("%s: key2 must not be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ } else if (order == NULL) {
+ ALOGE("%s: order must not be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ ssize_t index1 = mMap.indexOfKey(String8(key1));
+ ssize_t index2 = mMap.indexOfKey(String8(key2));
+ if (index1 < 0) {
+ ALOGW("%s: Key1 (%s) was not set", __FUNCTION__, key1);
+ return NAME_NOT_FOUND;
+ } else if (index2 < 0) {
+ ALOGW("%s: Key2 (%s) was not set", __FUNCTION__, key2);
+ return NAME_NOT_FOUND;
+ }
+
+ *order = (index1 == index2) ? 0 :
+ (index1 < index2) ? -1 :
+ 1;
+
+ return OK;
+}
+
void CameraParameters::remove(const char *key)
{
mMap.removeItem(String8(key));
@@ -412,6 +449,12 @@ void CameraParameters::getPreviewFpsRange(int *min_fps, int *max_fps) const
parse_pair(p, min_fps, max_fps, ',');
}
+void CameraParameters::setPreviewFpsRange(int min_fps, int max_fps)
+{
+ String8 str = String8::format("%d,%d", min_fps, max_fps);
+ set(KEY_PREVIEW_FPS_RANGE, str.string());
+}
+
void CameraParameters::setPreviewFormat(const char *format)
{
set(KEY_PREVIEW_FORMAT, format);
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 5fc89fb..b86651f 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "BpCameraService"
#include <utils/Log.h>
+#include <utils/Errors.h>
#include <stdint.h>
#include <sys/types.h>
@@ -34,6 +35,7 @@
#include <camera/camera2/ICameraDeviceUser.h>
#include <camera/camera2/ICameraDeviceCallbacks.h>
#include <camera/CameraMetadata.h>
+#include <camera/VendorTagDescriptor.h>
namespace android {
@@ -143,6 +145,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,
@@ -275,6 +295,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 +320,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 +340,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 +360,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) {
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..a0a6a51
--- /dev/null
+++ b/camera/VendorTagDescriptor.cpp
@@ -0,0 +1,319 @@
+/*
+ * 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 "VenderTagDescriptor"
+
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+#include <system/camera_metadata.h>
+#include <camera_metadata_hidden.h>
+
+#include "camera/VendorTagDescriptor.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() {}
+
+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;
+
+ 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;
+ }
+ desc->mTagToSectionMap.add(tag, String8(sectionName));
+ 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);
+ }
+ 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;
+ int32_t tagType;
+ 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;
+ }
+ String8 sectionName = parcel->readString8();
+ if (sectionName.isEmpty()) {
+ ALOGE("%s: parcel section name was NULL for tag %d.", __FUNCTION__, tag);
+ res = NOT_ENOUGH_DATA;
+ break;
+ }
+
+ desc->mTagToNameMap.add(tag, tagName);
+ desc->mTagToSectionMap.add(tag, sectionName);
+ desc->mTagToTypeMap.add(tag, tagType);
+ }
+
+ if (res != OK) {
+ return res;
+ }
+
+ 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 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;
+ int32_t tagType;
+ for (size_t i = 0; i < size; ++i) {
+ tag = mTagToNameMap.keyAt(i);
+ String8 tagName = mTagToNameMap[i];
+ String8 sectionName = 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->writeString8(sectionName)) != OK) break;
+ }
+
+ return res;
+}
+
+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/tests/Android.mk b/camera/tests/Android.mk
index ec13911..61385e5 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_SRC_FILES:= \
main.cpp \
ProCameraTests.cpp \
+ VendorTagDescriptorTests.cpp
LOCAL_SHARED_LIBRARIES := \
libutils \
@@ -26,6 +41,8 @@ LOCAL_C_INCLUDES += \
external/gtest/include \
external/stlport/stlport \
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());
+}
+