Merge "Camera2 Tests: Add multiple stream tests" into klp-dev
This commit is contained in:
commit
a7ff78d4ed
5 changed files with 655 additions and 3 deletions
|
@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \
|
|||
CameraStreamTests.cpp \
|
||||
CameraFrameTests.cpp \
|
||||
CameraBurstTests.cpp \
|
||||
CameraMultiStreamTests.cpp\
|
||||
ForkedTests.cpp \
|
||||
TestForkerEventListener.cpp \
|
||||
TestSettings.cpp \
|
||||
|
|
651
tests/camera2/CameraMultiStreamTests.cpp
Normal file
651
tests/camera2/CameraMultiStreamTests.cpp
Normal file
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -93,7 +93,6 @@ private:
|
|||
|
||||
CameraModuleFixture::SetUp();
|
||||
|
||||
CameraStreamParams p = mParam;
|
||||
sp<CameraDeviceBase> device = mDevice;
|
||||
|
||||
/* use an arbitrary w,h */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue