Correctly process streams
The reference implementation stream validation/setting
was all out of whack, particularly the handling of "reuse"
streams. This CL does away with that, and plugs in the
static_properties/request_tracker validation/tracking of
configured streams.
Implementation specific features, such as gralloc flags,
are moved down into the V4L2Camera class out of the Camera class.
BUG: https://b/33057320, https://b/31044638
TEST: unit tests pass, some previously failing CTS tests are passing
(and no regressions), simple test camera preview app runs.
Change-Id: Ie8568239a1348dac45bf829ef928e500e01fdcda
diff --git a/modules/camera/3_4/Android.mk b/modules/camera/3_4/Android.mk
index 8e3c85a..592aa2f 100644
--- a/modules/camera/3_4/Android.mk
+++ b/modules/camera/3_4/Android.mk
@@ -46,7 +46,6 @@
metadata/metadata_reader.cpp \
request_tracker.cpp \
static_properties.cpp \
- stream.cpp \
stream_format.cpp \
v4l2_camera.cpp \
v4l2_camera_hal.cpp \
diff --git a/modules/camera/3_4/camera.cpp b/modules/camera/3_4/camera.cpp
index 5a89e3e..30035bd 100644
--- a/modules/camera/3_4/camera.cpp
+++ b/modules/camera/3_4/camera.cpp
@@ -27,7 +27,6 @@
#include <utils/Mutex.h>
#include "metadata/metadata_common.h"
-#include "stream.h"
//#define LOG_NDEBUG 0
#define LOG_TAG "Camera"
@@ -57,8 +56,6 @@
mSettingsSet(false),
mBusy(false),
mCallbackOps(NULL),
- mStreams(NULL),
- mNumStreams(0),
mInFlightTracker(new RequestTracker)
{
memset(&mTemplates, 0, sizeof(mTemplates));
@@ -175,176 +172,86 @@
int Camera::configureStreams(camera3_stream_configuration_t *stream_config)
{
- camera3_stream_t *astream;
- Stream **newStreams = NULL;
- int res = 0;
-
- // Must provide new settings after configureStreams.
- mSettingsSet = false;
+ android::Mutex::Autolock al(mDeviceLock);
ALOGV("%s:%d: stream_config=%p", __func__, mId, stream_config);
ATRACE_CALL();
- android::Mutex::Autolock al(mDeviceLock);
- if (stream_config == NULL) {
- ALOGE("%s:%d: NULL stream configuration array", __func__, mId);
- return -EINVAL;
- }
- if (stream_config->num_streams == 0) {
- ALOGE("%s:%d: Empty stream configuration array", __func__, mId);
+ // Check that there are no in-flight requests.
+ if (!mInFlightTracker->Empty()) {
+ ALOGE("%s:%d: Can't configure streams while frames are in flight.",
+ __func__, mId);
return -EINVAL;
}
- // Create new stream array
- newStreams = new Stream*[stream_config->num_streams];
- ALOGV("%s:%d: Number of Streams: %d", __func__, mId,
- stream_config->num_streams);
-
- // Mark all current streams unused for now
- for (int i = 0; i < mNumStreams; i++)
- mStreams[i]->mReuse = false;
- // Fill new stream array with reused streams and new streams
- for (unsigned int i = 0; i < stream_config->num_streams; i++) {
- astream = stream_config->streams[i];
- if (astream->max_buffers > 0) {
- ALOGV("%s:%d: Reusing stream %d", __func__, mId, i);
- newStreams[i] = reuseStream(astream);
- } else {
- ALOGV("%s:%d: Creating new stream %d", __func__, mId, i);
- newStreams[i] = new Stream(mId, astream);
- }
-
- if (newStreams[i] == NULL) {
- ALOGE("%s:%d: Error processing stream %d", __func__, mId, i);
- goto err_out;
- }
- astream->priv = newStreams[i];
- }
-
- // Verify the set of streams in aggregate
- if (!isValidStreamSet(newStreams, stream_config->num_streams,
- stream_config->operation_mode)) {
- ALOGE("%s:%d: Invalid stream set", __func__, mId);
- goto err_out;
- }
-
- // Set up all streams (calculate usage/max_buffers for each,
- // do any device-specific initialization)
- res = setupStreams(newStreams, stream_config->num_streams);
+ // Verify the set of streams in aggregate, and perform configuration if valid.
+ int res = validateStreamConfiguration(stream_config);
if (res) {
- ALOGE("%s:%d: Failed to setup stream set", __func__, mId);
- goto err_out;
+ ALOGE("%s:%d: Failed to validate stream set", __func__, mId);
+ } else {
+ // Set up all streams. Since they've been validated,
+ // this should only result in fatal (-ENODEV) errors.
+ // This occurs after validation to ensure that if there
+ // is a non-fatal error, the stream configuration doesn't change states.
+ res = setupStreams(stream_config);
+ if (res) {
+ ALOGE("%s:%d: Failed to setup stream set", __func__, mId);
+ }
}
- // Destroy all old streams and replace stream array with new one
- destroyStreams(mStreams, mNumStreams);
- mStreams = newStreams;
- mNumStreams = stream_config->num_streams;
-
- // Update the request tracker.
- mInFlightTracker->SetStreamConfiguration(*stream_config);
-
- return 0;
-
-err_out:
- // Clean up temporary streams, preserve existing mStreams/mNumStreams
- destroyStreams(newStreams, stream_config->num_streams);
- // Set error if it wasn't specified.
+ // Set trackers based on result.
if (!res) {
- res = -EINVAL;
+ // Success, set up the in-flight trackers for the new streams.
+ mInFlightTracker->SetStreamConfiguration(*stream_config);
+ // Must provide new settings for the new configuration.
+ mSettingsSet = false;
} else if (res != -EINVAL) {
- // Fatal error, clear stream configuration.
+ // Fatal error, the old configuration is invalid.
mInFlightTracker->ClearStreamConfiguration();
}
+ // On a non-fatal error the old configuration, if any, remains valid.
return res;
}
-void Camera::destroyStreams(Stream **streams, int count)
+int Camera::validateStreamConfiguration(
+ const camera3_stream_configuration_t* stream_config)
{
- if (streams == NULL)
- return;
- for (int i = 0; i < count; i++) {
- // Only destroy streams that weren't reused
- if (streams[i] != NULL && !streams[i]->mReuse)
- delete streams[i];
- }
- delete [] streams;
-}
-
-Stream *Camera::reuseStream(camera3_stream_t *astream)
-{
- Stream *priv = reinterpret_cast<Stream*>(astream->priv);
- // Verify the re-used stream's parameters match
- if (!priv->isValidReuseStream(mId, astream)) {
- ALOGE("%s:%d: Mismatched parameter in reused stream", __func__, mId);
- return NULL;
- }
- // Mark stream to be reused
- priv->mReuse = true;
- return priv;
-}
-
-bool Camera::isValidStreamSet(Stream **streams, int count, uint32_t mode)
-{
- int inputs = 0;
- int outputs = 0;
-
- if (streams == NULL) {
+ // Check that the configuration is well-formed.
+ if (stream_config == nullptr) {
+ ALOGE("%s:%d: NULL stream configuration array", __func__, mId);
+ return -EINVAL;
+ } else if (stream_config->num_streams == 0) {
+ ALOGE("%s:%d: Empty stream configuration array", __func__, mId);
+ return -EINVAL;
+ } else if (stream_config->streams == nullptr) {
ALOGE("%s:%d: NULL stream configuration streams", __func__, mId);
- return false;
- }
- if (count == 0) {
- ALOGE("%s:%d: Zero count stream configuration streams", __func__, mId);
- return false;
- }
- // Validate there is at most one input stream and at least one output stream
- for (int i = 0; i < count; i++) {
- // A stream may be both input and output (bidirectional)
- if (streams[i]->isInputType())
- inputs++;
- if (streams[i]->isOutputType())
- outputs++;
- }
- ALOGV("%s:%d: Configuring %d output streams and %d input streams",
- __func__, mId, outputs, inputs);
- if (outputs < 1) {
- ALOGE("%s:%d: Stream config must have >= 1 output", __func__, mId);
- return false;
- }
- if (inputs > 1) {
- ALOGE("%s:%d: Stream config must have <= 1 input", __func__, mId);
- return false;
+ return -EINVAL;
}
- // check for correct number of Bayer/YUV/JPEG/Encoder streams
- return isSupportedStreamSet(streams, count, mode);
-}
-
-int Camera::setupStreams(Stream **streams, int count)
-{
- /*
- * This is where the HAL has to decide internally how to handle all of the
- * streams, and then produce usage and max_buffer values for each stream.
- * Note, the stream array has been checked before this point for ALL invalid
- * conditions, so it must find a successful configuration for this stream
- * array. The only errors should be from individual streams requesting
- * unsupported features (such as data_space or rotation).
- */
- for (int i = 0; i < count; i++) {
- uint32_t usage = 0;
- if (streams[i]->isOutputType())
- usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
- if (streams[i]->isInputType())
- usage |= GRALLOC_USAGE_SW_READ_OFTEN;
- streams[i]->setUsage(usage);
-
- uint32_t max_buffers;
- int res = setupStream(streams[i], &max_buffers);
+ // Check that the configuration is supported.
+ // Make sure static info has been initialized before trying to use it.
+ if (!mStaticInfo) {
+ int res = loadStaticInfo();
if (res) {
- return res;
+ return res;
}
- streams[i]->setMaxBuffers(max_buffers);
}
+ if (!mStaticInfo->StreamConfigurationSupported(stream_config)) {
+ ALOGE("%s:%d: Stream configuration does not match static "
+ "metadata restrictions.", __func__, mId);
+ return -EINVAL;
+ }
+
+ // Dataspace support is poorly documented - unclear if the expectation
+ // is that a device supports ALL dataspaces that could match a given
+ // format. For now, defer to child class implementation.
+ // Rotation support isn't described by metadata, so must defer to device.
+ if (!validateDataspacesAndRotations(stream_config)) {
+ ALOGE("%s:%d: Device can not handle configuration "
+ "dataspaces or rotations.", __func__, mId);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -409,6 +316,12 @@
ALOGV("%s:%d: frame: %d", __func__, mId, request->frame_number);
+ if (!mInFlightTracker->CanAddRequest(*request)) {
+ // Streams are full or frame number is not unique.
+ ALOGE("%s:%d: Can not add request.", __func__, mId);
+ return -EINVAL;
+ }
+
// Null/Empty indicates use last settings
if (request->settings.isEmpty() && !mSettingsSet) {
ALOGE("%s:%d: NULL settings without previous set Frame:%d",
@@ -423,14 +336,10 @@
ALOGV("%s:%d: Capturing new frame.", __func__, mId);
}
- if (!isValidRequest(*request)) {
- ALOGE("%s:%d: Invalid request.", __func__, mId);
+ if (!isValidRequestSettings(request->settings)) {
+ ALOGE("%s:%d: Invalid request settings.", __func__, mId);
return -EINVAL;
}
- // Valid settings have been provided (mSettingsSet is a misnomer;
- // all that matters is that a previous request with valid settings
- // has been passed to the device, not that they've been set).
- mSettingsSet = true;
// Pre-process output buffers.
if (request->output_buffers.size() <= 0) {
@@ -451,6 +360,11 @@
return -ENODEV;
}
+ // Valid settings have been provided (mSettingsSet is a misnomer;
+ // all that matters is that a previous request with valid settings
+ // has been passed to the device, not that they've been set).
+ mSettingsSet = true;
+
// Send the request off to the device for completion.
enqueueRequest(request);
@@ -603,12 +517,6 @@
dprintf(fd, "Camera ID: %d (Busy: %d)\n", mId, mBusy);
// TODO: dump all settings
-
- dprintf(fd, "Number of streams: %d\n", mNumStreams);
- for (int i = 0; i < mNumStreams; i++) {
- dprintf(fd, "Stream %d/%d:\n", i, mNumStreams);
- mStreams[i]->dump(fd);
- }
}
const char* Camera::templateToString(int type)
diff --git a/modules/camera/3_4/camera.h b/modules/camera/3_4/camera.h
index 2685fd1..687c733 100644
--- a/modules/camera/3_4/camera.h
+++ b/modules/camera/3_4/camera.h
@@ -28,7 +28,6 @@
#include "metadata/metadata.h"
#include "request_tracker.h"
#include "static_properties.h"
-#include "stream.h"
namespace default_camera_hal {
// Camera represents a physical camera on a device.
@@ -70,16 +69,17 @@
// Initialize device info: resource cost and conflicting devices
// (/conflicting devices length)
virtual void initDeviceInfo(struct camera_info *info) = 0;
- // Verify stream configuration is device-compatible
- virtual bool isSupportedStreamSet(Stream** streams, int count,
- uint32_t mode) = 0;
- // Set up the device for a stream, and get the maximum number of
- // buffers that stream can handle (max_buffers is an output parameter)
- virtual int setupStream(Stream* stream, uint32_t* max_buffers) = 0;
- // Verify settings are valid for a capture or reprocessing
- virtual bool isValidRequest(const CaptureRequest& request) = 0;
// Separate initialization method for individual devices when opened
virtual int initDevice() = 0;
+ // Verify stream configuration dataspaces and rotation values
+ virtual bool validateDataspacesAndRotations(
+ const camera3_stream_configuration_t* stream_config) = 0;
+ // Set up the streams, including seting usage & max_buffers
+ virtual int setupStreams(
+ camera3_stream_configuration_t* stream_config) = 0;
+ // Verify settings are valid for a capture or reprocessing
+ virtual bool isValidRequestSettings(
+ const android::CameraMetadata& settings) = 0;
// Enqueue a request to receive data from the camera
virtual int enqueueRequest(
std::shared_ptr<CaptureRequest> request) = 0;
@@ -100,14 +100,9 @@
camera3_device_t mDevice;
// Get static info from the device and store it in mStaticInfo.
int loadStaticInfo();
- // Reuse a stream already created by this device
- Stream *reuseStream(camera3_stream_t *astream);
- // Destroy all streams in a stream array, and the array itself
- void destroyStreams(Stream **array, int count);
- // Verify a set of streams is valid in aggregate
- bool isValidStreamSet(Stream **array, int count, uint32_t mode);
- // Calculate usage and max_bufs of each stream
- int setupStreams(Stream **array, int count);
+ // Confirm that a stream configuration is valid.
+ int validateStreamConfiguration(
+ const camera3_stream_configuration_t* stream_config);
// Verify settings are valid for reprocessing an input buffer
bool isValidReprocessSettings(const camera_metadata_t *settings);
// Pre-process an output buffer
@@ -140,10 +135,6 @@
// be accessed without the camera device open
android::Mutex mStaticInfoLock;
android::Mutex mFlushLock;
- // Array of handles to streams currently in use by the device
- Stream **mStreams;
- // Number of streams in mStreams
- int mNumStreams;
// Standard camera settings templates
std::unique_ptr<const android::CameraMetadata> mTemplates[CAMERA3_TEMPLATE_COUNT];
// Track in flight requests.
diff --git a/modules/camera/3_4/static_properties.cpp b/modules/camera/3_4/static_properties.cpp
index b075e6e..5be9dcd 100644
--- a/modules/camera/3_4/static_properties.cpp
+++ b/modules/camera/3_4/static_properties.cpp
@@ -294,8 +294,8 @@
bool StaticProperties::InputStreamsSupported(
const camera3_stream_configuration_t* stream_config) {
// Find the input stream(s).
- size_t num_input_streams;
- int input_format;
+ size_t num_input_streams = 0;
+ int input_format = -1;
for (size_t i = 0; i < stream_config->num_streams; ++i) {
const camera3_stream_t* stream = stream_config->streams[i];
if (IsInputType(stream->stream_type)) {
diff --git a/modules/camera/3_4/stream.cpp b/modules/camera/3_4/stream.cpp
deleted file mode 100644
index 97d8634..0000000
--- a/modules/camera/3_4/stream.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Modified from hardware/libhardware/modules/camera/Stream.cpp
-
-#include <stdio.h>
-#include <hardware/camera3.h>
-#include <hardware/gralloc.h>
-#include <system/graphics.h>
-#include <utils/Mutex.h>
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Stream"
-#include <cutils/log.h>
-
-#define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL)
-#include <utils/Trace.h>
-
-#include "stream.h"
-
-namespace default_camera_hal {
-
-Stream::Stream(int id, camera3_stream_t *s)
- : mReuse(false),
- mId(id),
- mStream(s),
- mType(s->stream_type),
- mWidth(s->width),
- mHeight(s->height),
- mFormat(s->format),
- mUsage(0),
- mRotation(s->rotation),
- mDataSpace(s->data_space),
- mMaxBuffers(0)
-{
-}
-
-Stream::~Stream()
-{
-}
-
-void Stream::setUsage(uint32_t usage)
-{
- android::Mutex::Autolock al(mLock);
- if (usage != mUsage) {
- mUsage = usage;
- mStream->usage = usage;
- }
-}
-
-void Stream::setMaxBuffers(uint32_t max_buffers)
-{
- android::Mutex::Autolock al(mLock);
- if (max_buffers != mMaxBuffers) {
- mMaxBuffers = max_buffers;
- mStream->max_buffers = max_buffers;
- }
-}
-
-void Stream::setDataSpace(android_dataspace_t data_space)
-{
- android::Mutex::Autolock al(mLock);
- if (data_space != mDataSpace) {
- mDataSpace = data_space;
- mStream->data_space = data_space;
- }
-}
-
-bool Stream::isInputType() const
-{
- return mType == CAMERA3_STREAM_INPUT ||
- mType == CAMERA3_STREAM_BIDIRECTIONAL;
-}
-
-bool Stream::isOutputType() const
-{
- return mType == CAMERA3_STREAM_OUTPUT ||
- mType == CAMERA3_STREAM_BIDIRECTIONAL;
-}
-
-const char* Stream::typeToString(int type)
-{
- switch (type) {
- case CAMERA3_STREAM_INPUT:
- return "CAMERA3_STREAM_INPUT";
- case CAMERA3_STREAM_OUTPUT:
- return "CAMERA3_STREAM_OUTPUT";
- case CAMERA3_STREAM_BIDIRECTIONAL:
- return "CAMERA3_STREAM_BIDIRECTIONAL";
- }
- return "Invalid stream type!";
-}
-
-const char* Stream::formatToString(int format)
-{
- // See <system/graphics.h> for full list
- switch (format) {
- case HAL_PIXEL_FORMAT_BGRA_8888:
- return "BGRA 8888";
- case HAL_PIXEL_FORMAT_RGBA_8888:
- return "RGBA 8888";
- case HAL_PIXEL_FORMAT_RGBX_8888:
- return "RGBX 8888";
- case HAL_PIXEL_FORMAT_RGB_888:
- return "RGB 888";
- case HAL_PIXEL_FORMAT_RGB_565:
- return "RGB 565";
- case HAL_PIXEL_FORMAT_Y8:
- return "Y8";
- case HAL_PIXEL_FORMAT_Y16:
- return "Y16";
- case HAL_PIXEL_FORMAT_YV12:
- return "YV12";
- case HAL_PIXEL_FORMAT_YCbCr_422_SP:
- return "NV16";
- case HAL_PIXEL_FORMAT_YCrCb_420_SP:
- return "NV21";
- case HAL_PIXEL_FORMAT_YCbCr_422_I:
- return "YUY2";
- case HAL_PIXEL_FORMAT_RAW10:
- return "RAW10";
- case HAL_PIXEL_FORMAT_RAW16:
- return "RAW16";
- case HAL_PIXEL_FORMAT_BLOB:
- return "BLOB";
- case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
- return "IMPLEMENTATION DEFINED";
- case HAL_PIXEL_FORMAT_YCbCr_420_888:
- return "FLEXIBLE YCbCr 420 888";
- }
- return "Invalid stream format!";
-}
-
-bool Stream::isValidReuseStream(int id, camera3_stream_t *s)
-{
- if (id != mId) {
- ALOGE("%s:%d: Invalid camera id for reuse. Got %d expect %d",
- __func__, mId, id, mId);
- return false;
- }
- if (s != mStream) {
- ALOGE("%s:%d: Invalid stream handle for reuse. Got %p expect %p",
- __func__, mId, s, mStream);
- return false;
- }
- if (s->stream_type != mType) {
- ALOGE("%s:%d: Mismatched type in reused stream. Got %s(%d) "
- "expect %s(%d)", __func__, mId, typeToString(s->stream_type),
- s->stream_type, typeToString(mType), mType);
- return false;
- }
- if (s->format != mFormat) {
- ALOGE("%s:%d: Mismatched format in reused stream. Got %s(%d) "
- "expect %s(%d)", __func__, mId, formatToString(s->format),
- s->format, formatToString(mFormat), mFormat);
- return false;
- }
- if (s->width != mWidth) {
- ALOGE("%s:%d: Mismatched width in reused stream. Got %d expect %d",
- __func__, mId, s->width, mWidth);
- return false;
- }
- if (s->height != mHeight) {
- ALOGE("%s:%d: Mismatched height in reused stream. Got %d expect %d",
- __func__, mId, s->height, mHeight);
- return false;
- }
- return true;
-}
-
-void Stream::dump(int fd)
-{
- android::Mutex::Autolock al(mLock);
-
- dprintf(fd, "Stream ID: %d (%p)\n", mId, mStream);
- dprintf(fd, "Stream Type: %s (%d)\n", typeToString(mType), mType);
- dprintf(fd, "Width: %" PRIu32 " Height: %" PRIu32 "\n", mWidth, mHeight);
- dprintf(fd, "Stream Format: %s (%d)", formatToString(mFormat), mFormat);
- // ToDo: prettyprint usage mask flags
- dprintf(fd, "Gralloc Usage Mask: %#" PRIx32 "\n", mUsage);
- dprintf(fd, "Stream Rotation: %d\n", mRotation);
- dprintf(fd, "Stream Dataspace: 0x%x\n", mDataSpace);
- dprintf(fd, "Max Buffer Count: %" PRIu32 "\n", mMaxBuffers);
-}
-
-} // namespace default_camera_hal
diff --git a/modules/camera/3_4/stream.h b/modules/camera/3_4/stream.h
deleted file mode 100644
index 781f946..0000000
--- a/modules/camera/3_4/stream.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-// Modified from hardware/libhardware/modules/camera/Stream.h
-
-#ifndef DEFAULT_CAMERA_HAL_STREAM_H_
-#define DEFAULT_CAMERA_HAL_STREAM_H_
-
-#include <hardware/camera3.h>
-#include <hardware/gralloc.h>
-#include <system/graphics.h>
-#include <utils/Mutex.h>
-
-namespace default_camera_hal {
-// Stream represents a single input or output stream for a camera device.
-class Stream {
- public:
- Stream(int id, camera3_stream_t *s);
- ~Stream();
-
- // validate that astream's parameters match this stream's parameters
- bool isValidReuseStream(int id, camera3_stream_t *s);
-
- void setUsage(uint32_t usage);
- void setMaxBuffers(uint32_t max_buffers);
- void setDataSpace(android_dataspace_t data_space);
-
- inline int getFormat() const { return mFormat; };
- inline int getType() const { return mType; };
- inline uint32_t getWidth() const { return mWidth; };
- inline uint32_t getHeight() const { return mHeight; };
- inline int getRotation() const { return mRotation; };
-
- bool isInputType() const;
- bool isOutputType() const;
- const char* typeToString(int type);
- const char* formatToString(int format);
- void dump(int fd);
-
- // This stream is being reused. Used in stream configuration passes
- bool mReuse;
-
- private:
-
- // The camera device id this stream belongs to
- const int mId;
- // Handle to framework's stream, used as a cookie for buffers
- camera3_stream_t *mStream;
- // Stream type: CAMERA3_STREAM_* (see <hardware/camera3.h>)
- const int mType;
- // Width in pixels of the buffers in this stream
- const uint32_t mWidth;
- // Height in pixels of the buffers in this stream
- const uint32_t mHeight;
- // Gralloc format: HAL_PIXEL_FORMAT_* (see <system/graphics.h>)
- const int mFormat;
- // Gralloc usage mask : GRALLOC_USAGE_* (see <hardware/gralloc.h>)
- uint32_t mUsage;
- // Output rotation this stream should undergo
- const int mRotation;
- // Color space of image data.
- android_dataspace_t mDataSpace;
- // Max simultaneous in-flight buffers for this stream
- uint32_t mMaxBuffers;
- // Lock protecting the Stream object for modifications
- android::Mutex mLock;
-};
-} // namespace default_camera_hal
-
-#endif // DEFAULT_CAMERA_HAL_STREAM_H_
diff --git a/modules/camera/3_4/stream_format.cpp b/modules/camera/3_4/stream_format.cpp
index 2abfdb0..c85c26b 100644
--- a/modules/camera/3_4/stream_format.cpp
+++ b/modules/camera/3_4/stream_format.cpp
@@ -18,18 +18,18 @@
#include <linux/videodev2.h>
+#include <system/graphics.h>
+
#include "common.h"
-#include "stream.h"
namespace v4l2_camera_hal {
-StreamFormat::StreamFormat(const default_camera_hal::Stream& stream)
+StreamFormat::StreamFormat(int format, uint32_t width, uint32_t height)
// TODO(b/30000211): multiplanar support.
: type_(V4L2_BUF_TYPE_VIDEO_CAPTURE),
- v4l2_pixel_format_(
- StreamFormat::HalToV4L2PixelFormat(stream.getFormat())),
- width_(stream.getWidth()),
- height_(stream.getHeight()),
+ v4l2_pixel_format_(StreamFormat::HalToV4L2PixelFormat(format)),
+ width_(width),
+ height_(height),
bytes_per_line_(0),
min_buffer_size_(0) {}
diff --git a/modules/camera/3_4/stream_format.h b/modules/camera/3_4/stream_format.h
index 9358d3d..66c5965 100644
--- a/modules/camera/3_4/stream_format.h
+++ b/modules/camera/3_4/stream_format.h
@@ -17,10 +17,11 @@
#ifndef V4L2_CAMERA_HAL_STREAM_FORMAT_H_
#define V4L2_CAMERA_HAL_STREAM_FORMAT_H_
+#include <string.h>
+
#include <linux/videodev2.h>
#include "common.h"
-#include "stream.h"
namespace v4l2_camera_hal {
@@ -33,7 +34,7 @@
class StreamFormat {
public:
- StreamFormat(const default_camera_hal::Stream& stream);
+ StreamFormat(int format, uint32_t width, uint32_t height);
StreamFormat(const v4l2_format& format);
virtual ~StreamFormat() = default;
// Only uint32_t members, use default generated copy and assign.
diff --git a/modules/camera/3_4/v4l2_camera.cpp b/modules/camera/3_4/v4l2_camera.cpp
index 3383645..3e5b859 100644
--- a/modules/camera/3_4/v4l2_camera.cpp
+++ b/modules/camera/3_4/v4l2_camera.cpp
@@ -325,117 +325,25 @@
return true;
}
-bool V4L2Camera::isSupportedStreamSet(default_camera_hal::Stream** streams,
- int count,
- uint32_t mode) {
+bool V4L2Camera::validateDataspacesAndRotations(
+ const camera3_stream_configuration_t* stream_config) {
HAL_LOG_ENTER();
- if (mode != CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE) {
- HAL_LOGE("Unsupported stream configuration mode: %d", mode);
- return false;
- }
-
- // This should be checked by the caller, but put here as a sanity check.
- if (count < 1) {
- HAL_LOGE("Must request at least 1 stream");
- return false;
- }
-
- // Count the number of streams of each type.
- int32_t num_input = 0;
- int32_t num_raw = 0;
- int32_t num_stalling = 0;
- int32_t num_non_stalling = 0;
- for (int i = 0; i < count; ++i) {
- default_camera_hal::Stream* stream = streams[i];
-
- if (stream->isInputType()) {
- ++num_input;
- }
-
- if (stream->isOutputType()) {
- StreamFormat format(*stream);
- switch (format.Category()) {
- case kFormatCategoryRaw:
- ++num_raw;
- case kFormatCategoryStalling:
- ++num_stalling;
- break;
- case kFormatCategoryNonStalling:
- ++num_non_stalling;
- break;
- case kFormatCategoryUnknown: // Fall through.
- default:
- HAL_LOGE(
- "Unsupported format for stream %d: %d", i, stream->getFormat());
- return false;
- }
- }
- }
-
- if (num_input > max_input_streams_ || num_raw > max_output_streams_[0] ||
- num_non_stalling > max_output_streams_[1] ||
- num_stalling > max_output_streams_[2]) {
- HAL_LOGE(
- "Invalid stream configuration: %d input, %d RAW, %d non-stalling, "
- "%d stalling (max supported: %d input, %d RAW, %d non-stalling, "
- "%d stalling)",
- max_input_streams_,
- max_output_streams_[0],
- max_output_streams_[1],
- max_output_streams_[2],
- num_input,
- num_raw,
- num_non_stalling,
- num_stalling);
- return false;
- }
-
- // TODO(b/29939583): The above logic should be all that's necessary,
- // but V4L2 doesn't actually support more than 1 stream at a time. So for now,
- // if not all streams are the same format and size, error. Note that this
- // means the HAL is not spec-compliant; the requested streams are technically
- // valid and it is not technically allowed to error once it has reached this
- // point.
- int format = streams[0]->getFormat();
- uint32_t width = streams[0]->getWidth();
- uint32_t height = streams[0]->getHeight();
- for (int i = 1; i < count; ++i) {
- const default_camera_hal::Stream* stream = streams[i];
- if (stream->getFormat() != format || stream->getWidth() != width ||
- stream->getHeight() != height) {
- HAL_LOGE(
- "V4L2 only supports 1 stream configuration at a time "
- "(stream 0 is format %d, width %u, height %u, "
- "stream %d is format %d, width %u, height %u).",
- format,
- width,
- height,
- i,
- stream->getFormat(),
- stream->getWidth(),
- stream->getHeight());
+ for (uint32_t i = 0; i < stream_config->num_streams; ++i) {
+ if (stream_config->streams[i]->rotation != CAMERA3_STREAM_ROTATION_0) {
+ HAL_LOGV("Rotation %d for stream %d not supported",
+ stream_config->streams[i]->rotation,
+ i);
return false;
}
+ // Accept all dataspaces, as it will just be overwritten below anyways.
}
-
return true;
}
-int V4L2Camera::setupStream(default_camera_hal::Stream* stream,
- uint32_t* max_buffers) {
+int V4L2Camera::setupStreams(camera3_stream_configuration_t* stream_config) {
HAL_LOG_ENTER();
- if (stream->getRotation() != CAMERA3_STREAM_ROTATION_0) {
- HAL_LOGE("Rotation %d not supported", stream->getRotation());
- return -EINVAL;
- }
-
- // Doesn't matter what was requested, we always use dataspace V0_JFIF.
- // Note: according to camera3.h, this isn't allowed, but etalvala@google.com
- // claims it's underdocumented; the implementation lets the HAL overwrite it.
- stream->setDataSpace(HAL_DATASPACE_V0_JFIF);
-
std::lock_guard<std::mutex> guard(in_flight_lock_);
// The framework should be enforcing this, but doesn't hurt to be safe.
if (!in_flight_.empty()) {
@@ -443,44 +351,100 @@
return -EINVAL;
}
+ // stream_config should have been validated; assume at least 1 stream.
+ camera3_stream_t* stream = stream_config->streams[0];
+ int format = stream->format;
+ uint32_t width = stream->width;
+ uint32_t height = stream->height;
+
+ if (stream_config->num_streams > 1) {
+ // TODO(b/29939583): V4L2 doesn't actually support more than 1
+ // stream at a time. If not all streams are the same format
+ // and size, error. Note that this means the HAL is not spec-compliant.
+ // Technically, this error should be thrown during validation, but
+ // since it isn't a spec-valid error validation isn't set up to check it.
+ for (uint32_t i = 1; i < stream_config->num_streams; ++i) {
+ stream = stream_config->streams[i];
+ if (stream->format != format || stream->width != width ||
+ stream->height != height) {
+ HAL_LOGE(
+ "V4L2 only supports 1 stream configuration at a time "
+ "(stream 0 is format %d, width %u, height %u, "
+ "stream %d is format %d, width %u, height %u).",
+ format,
+ width,
+ height,
+ i,
+ stream->format,
+ stream->width,
+ stream->height);
+ return -EINVAL;
+ }
+ }
+ }
+
// Ensure the stream is off.
int res = device_->StreamOff();
if (res) {
- HAL_LOGE("Device failed to turn off stream for reconfiguration.");
+ HAL_LOGE("Device failed to turn off stream for reconfiguration: %d.", res);
return -ENODEV;
}
- res = device_->SetFormat(*stream, max_buffers);
+ StreamFormat stream_format(format, width, height);
+ uint32_t max_buffers = 0;
+ res = device_->SetFormat(stream_format, &max_buffers);
if (res) {
- HAL_LOGE("Failed to set device to correct format for stream.");
- return res;
+ HAL_LOGE("Failed to set device to correct format for stream: %d.", res);
+ return -ENODEV;
}
// Sanity check.
- if (*max_buffers < 1) {
+ if (max_buffers < 1) {
HAL_LOGE("Setting format resulted in an invalid maximum of %u buffers.",
- *max_buffers);
+ max_buffers);
return -ENODEV;
}
+ // Set all the streams dataspaces, usages, and max buffers.
+ for (uint32_t i = 0; i < stream_config->num_streams; ++i) {
+ stream = stream_config->streams[i];
+
+ // Max buffers as reported by the device.
+ stream->max_buffers = max_buffers;
+
+ // Usage: currently using sw graphics.
+ switch (stream->stream_type) {
+ case CAMERA3_STREAM_INPUT:
+ stream->usage = GRALLOC_USAGE_SW_READ_OFTEN;
+ break;
+ case CAMERA3_STREAM_OUTPUT:
+ stream->usage = GRALLOC_USAGE_SW_WRITE_OFTEN;
+ break;
+ case CAMERA3_STREAM_BIDIRECTIONAL:
+ stream->usage =
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+ break;
+ default:
+ // nothing to do.
+ break;
+ }
+
+ // Doesn't matter what was requested, we always use dataspace V0_JFIF.
+ // Note: according to camera3.h, this isn't allowed, but the camera
+ // framework team claims it's underdocumented; the implementation lets the
+ // HAL overwrite it. If this is changed, change the validation above.
+ stream->data_space = HAL_DATASPACE_V0_JFIF;
+ }
+
return 0;
}
-bool V4L2Camera::isValidRequest(
- const default_camera_hal::CaptureRequest& request) {
- HAL_LOG_ENTER();
-
- if (request.input_buffer != nullptr) {
- HAL_LOGE("Input buffer reprocessing not implemented.");
- return false;
- } else if (request.output_buffers.size() > 1) {
- HAL_LOGE("Only 1 output buffer allowed per request.");
- return false;
- } else if (!metadata_->IsValidRequest(request.settings)) {
+bool V4L2Camera::isValidRequestSettings(
+ const android::CameraMetadata& settings) {
+ if (!metadata_->IsValidRequest(settings)) {
HAL_LOGE("Invalid request settings.");
return false;
}
-
return true;
}
diff --git a/modules/camera/3_4/v4l2_camera.h b/modules/camera/3_4/v4l2_camera.h
index 3dae649..1db8d40 100644
--- a/modules/camera/3_4/v4l2_camera.h
+++ b/modules/camera/3_4/v4l2_camera.h
@@ -67,17 +67,13 @@
void initDeviceInfo(camera_info_t* info) override;
// Extra initialization of device when opened.
int initDevice() override;
- // Verify stream configuration is device-compatible.
- bool isSupportedStreamSet(default_camera_hal::Stream** streams,
- int count,
- uint32_t mode) override;
- // Set up the device for a stream, and get the maximum number of
- // buffers that stream can handle (max_buffers is an output parameter).
- int setupStream(default_camera_hal::Stream* stream,
- uint32_t* max_buffers) override;
+ // Verify stream configuration dataspaces and rotation values
+ bool validateDataspacesAndRotations(
+ const camera3_stream_configuration_t* stream_config) override;
+ // Set up the streams, including seting usage & max_buffers
+ int setupStreams(camera3_stream_configuration_t* stream_config) override;
// Verify settings are valid for a capture or reprocessing.
- bool isValidRequest(
- const default_camera_hal::CaptureRequest& request) override;
+ bool isValidRequestSettings(const android::CameraMetadata& settings) override;
// Enqueue a request to receive data from the camera.
int enqueueRequest(
std::shared_ptr<default_camera_hal::CaptureRequest> request) override;
diff --git a/modules/camera/3_4/v4l2_wrapper.cpp b/modules/camera/3_4/v4l2_wrapper.cpp
index fd4f169..b24535c 100644
--- a/modules/camera/3_4/v4l2_wrapper.cpp
+++ b/modules/camera/3_4/v4l2_wrapper.cpp
@@ -31,7 +31,6 @@
#include <nativehelper/ScopedFd.h>
#include "common.h"
-#include "stream.h"
#include "stream_format.h"
#include "v4l2_gralloc.h"
@@ -440,17 +439,10 @@
return 0;
}
-int V4L2Wrapper::SetFormat(const default_camera_hal::Stream& stream,
+int V4L2Wrapper::SetFormat(const StreamFormat& desired_format,
uint32_t* result_max_buffers) {
HAL_LOG_ENTER();
- // Should be checked earlier; sanity check.
- if (stream.isInputType()) {
- HAL_LOGE("Input streams not supported.");
- return -EINVAL;
- }
-
- StreamFormat desired_format(stream);
if (format_ && desired_format == *format_) {
HAL_LOGV("Already in correct format, skipping format setting.");
*result_max_buffers = buffers_.size();
diff --git a/modules/camera/3_4/v4l2_wrapper.h b/modules/camera/3_4/v4l2_wrapper.h
index 8c10d4b..eb41239 100644
--- a/modules/camera/3_4/v4l2_wrapper.h
+++ b/modules/camera/3_4/v4l2_wrapper.h
@@ -27,7 +27,6 @@
#include <nativehelper/ScopedFd.h>
#include "common.h"
-#include "stream.h"
#include "stream_format.h"
#include "v4l2_gralloc.h"
@@ -75,7 +74,7 @@
uint32_t v4l2_format,
const std::array<int32_t, 2>& size,
std::array<int64_t, 2>* duration_range);
- virtual int SetFormat(const default_camera_hal::Stream& stream,
+ virtual int SetFormat(const StreamFormat& desired_format,
uint32_t* result_max_buffers);
// Manage buffers.
virtual int EnqueueBuffer(const camera3_stream_buffer_t* camera_buffer,
diff --git a/modules/camera/3_4/v4l2_wrapper_mock.h b/modules/camera/3_4/v4l2_wrapper_mock.h
index 5f8fc4a..d423cc5 100644
--- a/modules/camera/3_4/v4l2_wrapper_mock.h
+++ b/modules/camera/3_4/v4l2_wrapper_mock.h
@@ -42,8 +42,10 @@
int(uint32_t,
const std::array<int32_t, 2>&,
std::array<int64_t, 2>*));
- MOCK_METHOD2(SetFormat,
- int(const default_camera_hal::Stream& stream,
+ MOCK_METHOD4(SetFormat,
+ int(int format,
+ uint32_t width,
+ uint32_t height,
uint32_t* result_max_buffers));
MOCK_METHOD2(EnqueueBuffer,
int(const camera3_stream_buffer_t* camera_buffer,