summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorZhijun He <zhijunhe@google.com>2013-08-19 21:03:22 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-08-19 21:03:22 +0000
commita7ff78d4edb046cfc106e450ad0733775aa22e22 (patch)
treeb717c5442d15449e1bca1a72e0378f954f6d7690 /tests
parentaaf337dccb23f04ed4a59f2f371326c93cb5c96f (diff)
parent8ef0144a52df7edfb754efce597e078bc185c57d (diff)
downloadhardware_libhardware-a7ff78d4edb046cfc106e450ad0733775aa22e22.zip
hardware_libhardware-a7ff78d4edb046cfc106e450ad0733775aa22e22.tar.gz
hardware_libhardware-a7ff78d4edb046cfc106e450ad0733775aa22e22.tar.bz2
Merge "Camera2 Tests: Add multiple stream tests" into klp-dev
Diffstat (limited to 'tests')
-rw-r--r--tests/camera2/Android.mk1
-rw-r--r--tests/camera2/CameraMultiStreamTests.cpp651
-rw-r--r--tests/camera2/CameraStreamFixture.h1
-rw-r--r--tests/camera2/camera2.cpp4
-rw-r--r--tests/camera2/camera2_utils.cpp1
5 files changed, 655 insertions, 3 deletions
diff --git a/tests/camera2/Android.mk b/tests/camera2/Android.mk
index 8f2278a..9efac0f 100644
--- a/tests/camera2/Android.mk
+++ b/tests/camera2/Android.mk
@@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \
CameraStreamTests.cpp \
CameraFrameTests.cpp \
CameraBurstTests.cpp \
+ CameraMultiStreamTests.cpp\
ForkedTests.cpp \
TestForkerEventListener.cpp \
TestSettings.cpp \
diff --git a/tests/camera2/CameraMultiStreamTests.cpp b/tests/camera2/CameraMultiStreamTests.cpp
new file mode 100644
index 0000000..679ff4e
--- /dev/null
+++ b/tests/camera2/CameraMultiStreamTests.cpp
@@ -0,0 +1,651 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "CameraMultiStreamTest"
+//#define LOG_NDEBUG 0
+#include "CameraStreamFixture.h"
+#include "TestExtensions.h"
+
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <common/CameraDeviceBase.h>
+#include <hardware/hardware.h>
+#include <hardware/camera2.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/Surface.h>
+
+#define DEFAULT_FRAME_DURATION 33000000LL // 33ms
+#define CAMERA_HEAP_COUNT 1
+#define CAMERA_EXPOSURE_FORMAT CAMERA_STREAM_AUTO_CPU_FORMAT
+#define CAMERA_DISPLAY_FORMAT HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
+#define CAMERA_MULTI_STREAM_DEBUGGING 0
+#define CAMERA_FRAME_TIMEOUT 1000000000LL // nsecs (1 secs)
+#define PREVIEW_RENDERING_TIME_INTERVAL 200000 // in unit of us, 200ms
+/* constants for display */
+#define DISPLAY_BUFFER_HEIGHT 1024
+#define DISPLAY_BUFFER_WIDTH 1024
+#define DISPLAY_BUFFER_FORMAT PIXEL_FORMAT_RGB_888
+
+// This test intends to test large preview size but less than 1080p.
+#define PREVIEW_WIDTH_CAP 1920
+#define PREVIEW_HEIGHT_CAP 1080
+// This test intends to test small metering burst size that is less than 640x480
+#define METERING_WIDTH_CAP 640
+#define METERING_HEIGHT_CAP 480
+
+#define EXP_WAIT_MULTIPLIER 2
+
+namespace android {
+namespace camera2 {
+namespace tests {
+
+static const CameraStreamParams DEFAULT_STREAM_PARAMETERS = {
+ /*mFormat*/ CAMERA_EXPOSURE_FORMAT,
+ /*mHeapCount*/ CAMERA_HEAP_COUNT
+};
+
+static const CameraStreamParams DISPLAY_STREAM_PARAMETERS = {
+ /*mFormat*/ CAMERA_DISPLAY_FORMAT,
+ /*mHeapCount*/ CAMERA_HEAP_COUNT
+};
+
+class CameraMultiStreamTest
+ : public ::testing::Test,
+ public CameraStreamFixture {
+
+public:
+ CameraMultiStreamTest() : CameraStreamFixture(DEFAULT_STREAM_PARAMETERS) {
+ TEST_EXTENSION_FORKING_CONSTRUCTOR;
+
+ if (HasFatalFailure()) {
+ return;
+ }
+ /**
+ * Don't create default stream, each test is in charge of creating
+ * its own streams.
+ */
+ }
+
+ ~CameraMultiStreamTest() {
+ TEST_EXTENSION_FORKING_DESTRUCTOR;
+ }
+
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<SurfaceControl> mSurfaceControl;
+
+ void CreateOnScreenSurface(sp<ANativeWindow>& surface) {
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ mSurfaceControl = mComposerClient->createSurface(
+ String8("CameraMultiStreamTest StreamingImage Surface"),
+ DISPLAY_BUFFER_HEIGHT, DISPLAY_BUFFER_WIDTH,
+ DISPLAY_BUFFER_FORMAT, 0);
+
+ ASSERT_NE((void*)NULL, mSurfaceControl.get());
+ ASSERT_TRUE(mSurfaceControl->isValid());
+
+ SurfaceComposerClient::openGlobalTransaction();
+ ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
+ ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
+ SurfaceComposerClient::closeGlobalTransaction();
+
+ surface = mSurfaceControl->getSurface();
+
+ ASSERT_NE((void*)NULL, surface.get());
+ }
+
+ struct Size {
+ int32_t width;
+ int32_t height;
+ };
+
+ // Select minimal size by number of pixels.
+ void GetMinSize(const int32_t* data, size_t count,
+ Size* min, int32_t* idx) {
+ ASSERT_NE((int32_t*)NULL, data);
+ int32_t minIdx = 0;
+ int32_t minSize = INT_MAX, tempSize;
+ for (size_t i = 0; i < count; i+=2) {
+ tempSize = data[i] * data[i+1];
+ if (minSize > tempSize) {
+ minSize = tempSize;
+ minIdx = i;
+ }
+ }
+ min->width = data[minIdx];
+ min->height = data[minIdx + 1];
+ *idx = minIdx;
+ }
+
+ // Select maximal size by number of pixels.
+ void GetMaxSize(const int32_t* data, size_t count,
+ Size* max, int32_t* idx) {
+ ASSERT_NE((int32_t*)NULL, data);
+ int32_t maxIdx = 0;
+ int32_t maxSize = INT_MIN, tempSize;
+ for (size_t i = 0; i < count; i+=2) {
+ tempSize = data[i] * data[i+1];
+ if (maxSize < tempSize) {
+ maxSize = tempSize;
+ maxIdx = i;
+ }
+ }
+ max->width = data[maxIdx];
+ max->height = data[maxIdx + 1];
+ *idx = maxIdx;
+ }
+
+ // Cap size by number of pixels.
+ Size CapSize(Size cap, Size input) {
+ if (input.width * input.height > cap.width * cap.height) {
+ return cap;
+ }
+ return input;
+ }
+
+ struct CameraStream : public RefBase {
+
+ public:
+ /**
+ * Only initialize the variables here, do the ASSERT check in
+ * SetUp function. To make this stream useful, the SetUp must
+ * be called before using it.
+ */
+ CameraStream(
+ int width,
+ int height,
+ const sp<CameraDeviceBase>& device,
+ CameraStreamParams param, sp<ANativeWindow> surface,
+ bool useCpuConsumer)
+ : mDevice(device),
+ mWidth(width),
+ mHeight(height) {
+ mFormat = param.mFormat;
+ if (useCpuConsumer) {
+ sp<BufferQueue> bq = new BufferQueue();
+ mCpuConsumer = new CpuConsumer(bq, param.mHeapCount);
+ mCpuConsumer->setName(String8(
+ "CameraMultiStreamTest::mCpuConsumer"));
+ mNativeWindow = new Surface(bq);
+ } else {
+ // Render the stream to screen.
+ mCpuConsumer = NULL;
+ mNativeWindow = surface;
+ }
+
+ mFrameListener = new FrameListener();
+ if (mCpuConsumer != 0) {
+ mCpuConsumer->setFrameAvailableListener(mFrameListener);
+ }
+ }
+
+ /**
+ * Finally create camera stream, and do the ASSERT check, since we
+ * can not do it in ctor.
+ */
+ void SetUp() {
+ ASSERT_EQ(OK,
+ mDevice->createStream(mNativeWindow,
+ mWidth, mHeight, mFormat, /*size (for jpegs)*/0,
+ &mStreamId));
+
+ ASSERT_NE(-1, mStreamId);
+ }
+
+ int GetStreamId() { return mStreamId; }
+ sp<CpuConsumer> GetConsumer() { return mCpuConsumer; }
+ sp<FrameListener> GetFrameListener() { return mFrameListener; }
+
+ protected:
+ ~CameraStream() {
+ if (mDevice.get()) {
+ mDevice->waitUntilDrained();
+ mDevice->deleteStream(mStreamId);
+ }
+ // Clear producer before consumer.
+ mNativeWindow.clear();
+ mCpuConsumer.clear();
+ }
+
+ private:
+ sp<FrameListener> mFrameListener;
+ sp<CpuConsumer> mCpuConsumer;
+ sp<ANativeWindow> mNativeWindow;
+ sp<CameraDeviceBase> mDevice;
+ int mStreamId;
+ int mWidth;
+ int mHeight;
+ int mFormat;
+ };
+
+ int64_t GetExposureValue(const CameraMetadata& metaData) {
+ camera_metadata_ro_entry_t entry =
+ metaData.find(ANDROID_SENSOR_EXPOSURE_TIME);
+ EXPECT_EQ(1u, entry.count);
+ if (entry.count == 1) {
+ return entry.data.i64[0];
+ }
+ return -1;
+ }
+
+ int32_t GetSensitivity(const CameraMetadata& metaData) {
+ camera_metadata_ro_entry_t entry =
+ metaData.find(ANDROID_SENSOR_SENSITIVITY);
+ EXPECT_EQ(1u, entry.count);
+ if (entry.count == 1) {
+ return entry.data.i32[0];
+ }
+ return -1;
+ }
+
+ int64_t GetFrameDuration(const CameraMetadata& metaData) {
+ camera_metadata_ro_entry_t entry =
+ metaData.find(ANDROID_SENSOR_FRAME_DURATION);
+ EXPECT_EQ(1u, entry.count);
+ if (entry.count == 1) {
+ return entry.data.i64[0];
+ }
+ return -1;
+ }
+
+ void CreateRequests(CameraMetadata& previewRequest,
+ CameraMetadata& meteringRequest,
+ CameraMetadata& captureRequest,
+ int previewStreamId,
+ int meteringStreamId,
+ int captureStreamId) {
+ int32_t requestId = 1;
+ Vector<uint8_t> previewStreamIds;
+ previewStreamIds.push(previewStreamId);
+ ASSERT_EQ(OK, mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+ &previewRequest));
+ ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+ previewStreamIds));
+ ASSERT_EQ(OK, previewRequest.update(ANDROID_REQUEST_ID,
+ &requestId, 1));
+
+ // Create metering request, manual settings
+ // Manual control: Disable 3A, noise reduction, edge sharping
+ uint8_t cmOff = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
+ uint8_t nrOff = static_cast<uint8_t>(ANDROID_NOISE_REDUCTION_MODE_OFF);
+ uint8_t sharpOff = static_cast<uint8_t>(ANDROID_EDGE_MODE_OFF);
+ Vector<uint8_t> meteringStreamIds;
+ meteringStreamIds.push(meteringStreamId);
+ ASSERT_EQ(OK, mDevice->createDefaultRequest(
+ CAMERA2_TEMPLATE_PREVIEW,
+ &meteringRequest));
+ ASSERT_EQ(OK, meteringRequest.update(
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ meteringStreamIds));
+ ASSERT_EQ(OK, meteringRequest.update(
+ ANDROID_REQUEST_ID,
+ &requestId, 1));
+ ASSERT_EQ(OK, meteringRequest.update(
+ ANDROID_CONTROL_MODE,
+ &cmOff, 1));
+ ASSERT_EQ(OK, meteringRequest.update(
+ ANDROID_NOISE_REDUCTION_MODE,
+ &nrOff, 1));
+ ASSERT_EQ(OK, meteringRequest.update(
+ ANDROID_EDGE_MODE,
+ &sharpOff, 1));
+
+ // Create capture request, manual settings
+ requestId++;
+ Vector<uint8_t> captureStreamIds;
+ captureStreamIds.push(captureStreamId);
+ ASSERT_EQ(OK, mDevice->createDefaultRequest(
+ CAMERA2_TEMPLATE_PREVIEW,
+ &captureRequest));
+ ASSERT_EQ(OK, captureRequest.update(
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ captureStreamIds));
+ ASSERT_EQ(OK, captureRequest.update(
+ ANDROID_REQUEST_ID,
+ &requestId, 1));
+ ASSERT_EQ(OK, captureRequest.update(
+ ANDROID_CONTROL_MODE,
+ &cmOff, 1));
+ ASSERT_EQ(OK, captureRequest.update(
+ ANDROID_NOISE_REDUCTION_MODE,
+ &nrOff, 1));
+ ASSERT_EQ(OK, captureRequest.update(
+ ANDROID_EDGE_MODE,
+ &sharpOff, 1));
+ }
+
+ sp<CameraStream> CreateStream(
+ int width,
+ int height,
+ const sp<CameraDeviceBase>& device,
+ CameraStreamParams param = DEFAULT_STREAM_PARAMETERS,
+ sp<ANativeWindow> surface = NULL,
+ bool useCpuConsumer = true) {
+ param.mFormat = MapAutoFormat(param.mFormat);
+ return new CameraStream(width, height, device,
+ param, surface, useCpuConsumer);
+ }
+
+ void CaptureBurst(CameraMetadata& request, size_t requestCount,
+ const Vector<int64_t>& exposures,
+ const Vector<int32_t>& sensitivities,
+ const sp<CameraStream>& stream,
+ int64_t minFrameDuration) {
+ ASSERT_EQ(OK, request.update(ANDROID_SENSOR_FRAME_DURATION,
+ &minFrameDuration, 1));
+ // Submit a series of requests with the specified exposure/gain values.
+ for (size_t i = 0; i < requestCount; i++) {
+ ASSERT_EQ(OK, request.update(ANDROID_SENSOR_EXPOSURE_TIME,
+ &exposures[i], 1));
+ ASSERT_EQ(OK, request.update(ANDROID_SENSOR_SENSITIVITY,
+ &sensitivities[i], 1));
+ ASSERT_EQ(OK, mDevice->capture(request));
+ ALOGV("Submitting capture %d with exposure %lld, sensitivity %d",
+ i, exposures[i], sensitivities[i]);
+ if (CAMERA_MULTI_STREAM_DEBUGGING) {
+ request.dump(STDOUT_FILENO);
+ }
+ }
+ // Get capture burst results.
+ Vector<nsecs_t> captureBurstTimes;
+ sp<CpuConsumer> consumer = stream->GetConsumer();
+ sp<FrameListener> listener = stream->GetFrameListener();
+
+ // Set wait limit based on expected frame duration.
+ int64_t waitLimit = CAMERA_FRAME_TIMEOUT;
+ for (size_t i = 0; i < requestCount; i++) {
+ ALOGV("Reading request result %d", i);
+
+ /**
+ * Raise the timeout to be at least twice as long as the exposure
+ * time. to avoid a false positive when the timeout is too short.
+ */
+ if ((exposures[i] * EXP_WAIT_MULTIPLIER) > waitLimit) {
+ waitLimit = exposures[i] * EXP_WAIT_MULTIPLIER;
+ }
+
+ ASSERT_EQ(OK, mDevice->waitForNextFrame(waitLimit));
+ CameraMetadata frameMetadata;
+ ASSERT_EQ(OK, mDevice->getNextFrame(&frameMetadata));
+ ALOGV("Got capture burst result for request %d", i);
+ // Validate capture result
+ if (CAMERA_MULTI_STREAM_DEBUGGING) {
+ frameMetadata.dump(STDOUT_FILENO);
+ }
+
+ // TODO: Need revisit it to figure out an accurate margin.
+ EXPECT_EQ(sensitivities[i], GetSensitivity(frameMetadata));
+ EXPECT_EQ(exposures[i], GetExposureValue(frameMetadata));
+
+ ASSERT_EQ(OK, listener->waitForFrame(waitLimit));
+ captureBurstTimes.push_back(systemTime());
+ CpuConsumer::LockedBuffer imgBuffer;
+ ASSERT_EQ(OK, consumer->lockNextBuffer(&imgBuffer));
+ ALOGV("Got capture buffer for request %d", i);
+
+ /**
+ * TODO: Validate capture buffer. Current brightness calculation
+ * is too slow, it also doesn't account for saturation effects,
+ * which is quite common since we are going over a significant
+ * range of EVs. we need figure out some reliable way to validate
+ * buffer data.
+ */
+
+ ASSERT_EQ(OK, consumer->unlockBuffer(imgBuffer));
+ if (i > 0) {
+ nsecs_t timeDelta =
+ captureBurstTimes[i] - captureBurstTimes[i-1];
+ EXPECT_GE(timeDelta, exposures[i]);
+ }
+ }
+ }
+
+ /**
+ * Intentionally shadow default CreateStream function from base class,
+ * because we don't want any test in this class to use the default
+ * stream creation function.
+ */
+ void CreateStream() {
+ }
+};
+
+/**
+ * This test adds multiple stream use case test, basically, test 3
+ * streams:
+ *
+ * 1. Preview stream, with large size that is no bigger than 1080p
+ * we render this stream to display and vary the exposure time for
+ * for certain amount of time for visualization purpose.
+ *
+ * 2. Metering stream, with small size that is no bigger than VGA size.
+ * a burst is issued for different exposure times and analog gains
+ * (or analog gain implemented sensitivities) then check if the capture
+ * result metadata matches the request.
+ *
+ * 3. Capture stream, this is basically similar as meterting stream, but
+ * has large size, which is the largest supported JPEG capture size.
+ *
+ * This multiple stream test is to test if HAL supports:
+ *
+ * 1. Multiple streams like above, HAL should support at least 3 streams
+ * concurrently: one preview stream, 2 other YUV stream.
+ *
+ * 2. Manual control(gain/exposure) of mutiple burst capture.
+ */
+TEST_F(CameraMultiStreamTest, MultiBurst) {
+
+ TEST_EXTENSION_FORKING_INIT;
+
+ camera_metadata_ro_entry availableProcessedSizes =
+ GetStaticEntry(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+ ASSERT_EQ(0u, availableProcessedSizes.count % 2);
+ ASSERT_GE(availableProcessedSizes.count, 2u);
+ camera_metadata_ro_entry availableProcessedMinFrameDurations =
+ GetStaticEntry(ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS);
+ EXPECT_EQ(availableProcessedSizes.count,
+ availableProcessedMinFrameDurations.count * 2);
+
+ camera_metadata_ro_entry availableJpegSizes =
+ GetStaticEntry(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+ ASSERT_EQ(0u, availableJpegSizes.count % 2);
+ ASSERT_GE(availableJpegSizes.count, 2u);
+
+ // Find the right sizes for preview, metering, and capture streams
+ // assumes at least 2 entries in availableProcessedSizes.
+ int64_t minFrameDuration = DEFAULT_FRAME_DURATION;
+ Size processedMinSize, processedMaxSize, jpegMaxSize;
+ const int32_t* data = availableProcessedSizes.data.i32;
+ size_t count = availableProcessedSizes.count;
+
+ int32_t minIdx, maxIdx;
+ GetMinSize(data, count, &processedMinSize, &minIdx);
+ GetMaxSize(data, count, &processedMaxSize, &maxIdx);
+ ALOGV("Found processed max size: %dx%d, min size = %dx%d",
+ processedMaxSize.width, processedMaxSize.height,
+ processedMinSize.width, processedMinSize.height);
+
+ if (availableProcessedSizes.count ==
+ availableProcessedMinFrameDurations.count * 2) {
+ minFrameDuration =
+ availableProcessedMinFrameDurations.data.i64[maxIdx / 2];
+ }
+
+ EXPECT_GT(minFrameDuration, 0);
+
+ if (minFrameDuration <= 0) {
+ minFrameDuration = DEFAULT_FRAME_DURATION;
+ }
+
+ ALOGV("targeted minimal frame duration is: %lldns", minFrameDuration);
+
+ data = &(availableJpegSizes.data.i32[0]);
+ count = availableJpegSizes.count;
+ GetMaxSize(data, count, &jpegMaxSize, &maxIdx);
+ ALOGV("Found Jpeg size max idx = %d", maxIdx);
+
+ // Max Jpeg size should be available in processed sizes. Use it for
+ // YUV capture anyway.
+ EXPECT_EQ(processedMaxSize.width, jpegMaxSize.width);
+ EXPECT_EQ(processedMaxSize.height, jpegMaxSize.height);
+
+ // Cap preview size.
+ Size previewLimit = { PREVIEW_WIDTH_CAP, PREVIEW_HEIGHT_CAP };
+ // FIXME: need make sure the previewLimit is supported by HAL.
+ Size previewSize = CapSize(previewLimit, processedMaxSize);
+ // Cap Metering size.
+ Size meteringLimit = { METERING_WIDTH_CAP, METERING_HEIGHT_CAP };
+ // Cap metering size to VGA (VGA is mandatory by CDD)
+ Size meteringSize = CapSize(meteringLimit, processedMinSize);
+ // Capture stream should be the max size of jpeg sizes.
+ ALOGV("preview size: %dx%d, metering size: %dx%d, capture size: %dx%d",
+ previewSize.width, previewSize.height,
+ meteringSize.width, meteringSize.height,
+ jpegMaxSize.width, jpegMaxSize.height);
+
+ // Create streams
+ // Preview stream: small resolution, render on the screen.
+ sp<CameraStream> previewStream;
+ {
+ sp<ANativeWindow> surface;
+ ASSERT_NO_FATAL_FAILURE(CreateOnScreenSurface(/*out*/surface));
+ previewStream = CreateStream(
+ previewSize.width,
+ previewSize.height,
+ mDevice,
+ DISPLAY_STREAM_PARAMETERS,
+ surface,
+ false);
+ ASSERT_NE((void*)NULL, previewStream.get());
+ ASSERT_NO_FATAL_FAILURE(previewStream->SetUp());
+ }
+ // Metering burst stream: small resolution yuv stream
+ sp<CameraStream> meteringStream =
+ CreateStream(
+ meteringSize.width,
+ meteringSize.height,
+ mDevice);
+ ASSERT_NE((void*)NULL, meteringStream.get());
+ ASSERT_NO_FATAL_FAILURE(meteringStream->SetUp());
+ // Capture burst stream: full resolution yuv stream
+ sp<CameraStream> captureStream =
+ CreateStream(
+ jpegMaxSize.width,
+ jpegMaxSize.height,
+ mDevice);
+ ASSERT_NE((void*)NULL, captureStream.get());
+ ASSERT_NO_FATAL_FAILURE(captureStream->SetUp());
+
+ // Create Preview request.
+ CameraMetadata previewRequest, meteringRequest, captureRequest;
+ ASSERT_NO_FATAL_FAILURE(CreateRequests(previewRequest, meteringRequest,
+ captureRequest, previewStream->GetStreamId(),
+ meteringStream->GetStreamId(), captureStream->GetStreamId()));
+
+ // Start preview
+ if (CAMERA_MULTI_STREAM_DEBUGGING) {
+ previewRequest.dump(STDOUT_FILENO);
+ }
+
+ // Generate exposure and sensitivity lists
+ camera_metadata_ro_entry exposureTimeRange =
+ GetStaticEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE);
+ ASSERT_EQ(exposureTimeRange.count, 2u);
+ int64_t minExp = exposureTimeRange.data.i64[0];
+ int64_t maxExp = exposureTimeRange.data.i64[1];
+ ASSERT_GT(maxExp, minExp);
+
+ camera_metadata_ro_entry sensivityRange =
+ GetStaticEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE);
+ ASSERT_EQ(2u, sensivityRange.count);
+ int32_t minSensitivity = sensivityRange.data.i32[0];
+ int32_t maxSensitivity = sensivityRange.data.i32[1];
+ camera_metadata_ro_entry maxAnalogSenEntry =
+ GetStaticEntry(ANDROID_SENSOR_MAX_ANALOG_SENSITIVITY);
+ EXPECT_EQ(1u, maxAnalogSenEntry.count);
+ int32_t maxAnalogSensitivity = maxAnalogSenEntry.data.i32[0];
+ EXPECT_LE(maxAnalogSensitivity, maxSensitivity);
+ // Only test the sensitivity implemented by analog gain.
+ if (maxAnalogSensitivity > maxSensitivity) {
+ // Fallback to maxSensitity
+ maxAnalogSensitivity = maxSensitivity;
+ }
+
+ // sensitivity list, only include the sensitivities that are implemented
+ // purely by analog gain if possible.
+ Vector<int32_t> sensitivities;
+ Vector<int64_t> exposures;
+ count = (maxAnalogSensitivity - minSensitivity + 99) / 100;
+ sensitivities.push_back(minSensitivity);
+ for (size_t i = 1; i < count; i++) {
+ sensitivities.push_back(minSensitivity + i * 100);
+ }
+ sensitivities.push_back(maxAnalogSensitivity);
+ ALOGV("Sensitivity Range: min=%d, max=%d", minSensitivity,
+ maxAnalogSensitivity);
+ int64_t exp = minExp;
+ while (exp < maxExp) {
+ exposures.push_back(exp);
+ exp *= 2;
+ }
+ // Sweep the exposure value for preview, just for visual inspection purpose.
+ uint8_t cmOff = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
+ for (size_t i = 0; i < exposures.size(); i++) {
+ ASSERT_EQ(OK, previewRequest.update(
+ ANDROID_CONTROL_MODE,
+ &cmOff, 1));
+ ASSERT_EQ(OK, previewRequest.update(
+ ANDROID_SENSOR_EXPOSURE_TIME,
+ &exposures[i], 1));
+ ALOGV("Submitting preview request %d with exposure %lld",
+ i, exposures[i]);
+
+ ASSERT_EQ(OK, mDevice->setStreamingRequest(previewRequest));
+
+ // Let preview run 200ms on screen for each exposure time.
+ usleep(PREVIEW_RENDERING_TIME_INTERVAL);
+ }
+
+ size_t requestCount = sensitivities.size();
+ if (requestCount > exposures.size()) {
+ requestCount = exposures.size();
+ }
+
+ /**
+ * Submit metering request, set default frame duration to minimal possible
+ * value, we want the capture to run as fast as possible. HAL should adjust
+ * the frame duration to minimal necessary value to support the requested
+ * exposure value if exposure is larger than frame duration.
+ */
+ CaptureBurst(meteringRequest, requestCount, exposures, sensitivities,
+ meteringStream, minFrameDuration);
+
+ /**
+ * Submit capture request, set default frame duration to minimal possible
+ * value, we want the capture to run as fast as possible. HAL should adjust
+ * the frame duration to minimal necessary value to support the requested
+ * exposure value if exposure is larger than frame duration.
+ */
+ CaptureBurst(captureRequest, requestCount, exposures, sensitivities,
+ captureStream, minFrameDuration);
+
+ ASSERT_EQ(OK, mDevice->clearStreamingRequest());
+}
+
+}
+}
+}
diff --git a/tests/camera2/CameraStreamFixture.h b/tests/camera2/CameraStreamFixture.h
index 6b31544..a1f3aae 100644
--- a/tests/camera2/CameraStreamFixture.h
+++ b/tests/camera2/CameraStreamFixture.h
@@ -93,7 +93,6 @@ private:
CameraModuleFixture::SetUp();
- CameraStreamParams p = mParam;
sp<CameraDeviceBase> device = mDevice;
/* use an arbitrary w,h */
diff --git a/tests/camera2/camera2.cpp b/tests/camera2/camera2.cpp
index 17e4792..600d440 100644
--- a/tests/camera2/camera2.cpp
+++ b/tests/camera2/camera2.cpp
@@ -201,7 +201,8 @@ class Camera2Test: public testing::Test {
if (mDevice != NULL) {
closeCameraDevice(&mDevice);
}
- mDevice = openCameraDevice(id);
+ mId = id;
+ mDevice = openCameraDevice(mId);
ASSERT_TRUE(NULL != mDevice) << "Failed to open camera device";
camera_info info;
@@ -334,6 +335,7 @@ class Camera2Test: public testing::Test {
TearDownModule();
}
+ int mId;
camera2_device *mDevice;
const camera_metadata_t *mStaticInfo;
diff --git a/tests/camera2/camera2_utils.cpp b/tests/camera2/camera2_utils.cpp
index 76a7233..3c0767a 100644
--- a/tests/camera2/camera2_utils.cpp
+++ b/tests/camera2/camera2_utils.cpp
@@ -210,7 +210,6 @@ int MetadataQueue::consumer_dequeue(const camera2_request_queue_src_ops_t *q,
int MetadataQueue::consumer_free(const camera2_request_queue_src_ops_t *q,
camera_metadata_t *old_buffer) {
- MetadataQueue *queue = getInstance(q);
free_camera_metadata(old_buffer);
return OK;
}