Configure streams.
Set up the camera HAL according to the request streams.
Upgrades this flow from the 3.0 to 3.4 version, where
streams are not registered with buffers, and have a few
additional fields.
BUG: http://b/29921457, http://b/29221641
Change-Id: I36f67da374e6919caad6f202f31b72b0de2bb3bf
diff --git a/modules/camera/3_4/Camera.cpp b/modules/camera/3_4/Camera.cpp
index bbcdf7e..d1d1a9e 100644
--- a/modules/camera/3_4/Camera.cpp
+++ b/modules/camera/3_4/Camera.cpp
@@ -152,6 +152,7 @@
{
camera3_stream_t *astream;
Stream **newStreams = NULL;
+ int res = 0;
ALOGV("%s:%d: stream_config=%p", __func__, mId, stream_config);
ATRACE_CALL();
@@ -193,13 +194,19 @@
}
// Verify the set of streams in aggregate
- if (!isValidStreamSet(newStreams, stream_config->num_streams)) {
+ 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)
- setupStreams(newStreams, stream_config->num_streams);
+ // Set up all streams (calculate usage/max_buffers for each,
+ // do any device-specific initialization)
+ res = setupStreams(newStreams, stream_config->num_streams);
+ if (res) {
+ ALOGE("%s:%d: Failed to setup stream set", __func__, mId);
+ goto err_out;
+ }
// Destroy all old streams and replace stream array with new one
destroyStreams(mStreams, mNumStreams);
@@ -213,7 +220,11 @@
err_out:
// Clean up temporary streams, preserve existing mStreams/mNumStreams
destroyStreams(newStreams, stream_config->num_streams);
- return -EINVAL;
+ // Set error if it wasn't specified.
+ if (!res) {
+ res = -EINVAL;
+ }
+ return res;
}
void Camera::destroyStreams(Stream **streams, int count)
@@ -241,7 +252,7 @@
return priv;
}
-bool Camera::isValidStreamSet(Stream **streams, int count)
+bool Camera::isValidStreamSet(Stream **streams, int count, uint32_t mode)
{
int inputs = 0;
int outputs = 0;
@@ -272,50 +283,37 @@
ALOGE("%s:%d: Stream config must have <= 1 input", __func__, mId);
return false;
}
- // TODO: check for correct number of Bayer/YUV/JPEG/Encoder streams
- return true;
+
+ // check for correct number of Bayer/YUV/JPEG/Encoder streams
+ return isSupportedStreamSet(streams, count, mode);
}
-void Camera::setupStreams(Stream **streams, int count)
+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 HAL may not return an error from this point.
- *
- * In this demo HAL, we just set all streams to be the same dummy values;
- * real implementations will want to avoid USAGE_SW_{READ|WRITE}_OFTEN.
+ * 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 |
- GRALLOC_USAGE_HW_CAMERA_WRITE;
+ usage |= GRALLOC_USAGE_HW_CAMERA_WRITE;
if (streams[i]->isInputType())
- usage |= GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_HW_CAMERA_READ;
-
+ usage |= GRALLOC_USAGE_HW_CAMERA_READ;
streams[i]->setUsage(usage);
- streams[i]->setMaxBuffers(1);
- }
-}
-int Camera::registerStreamBuffers(const camera3_stream_buffer_set_t *buf_set)
-{
- ALOGV("%s:%d: buffer_set=%p", __func__, mId, buf_set);
- if (buf_set == NULL) {
- ALOGE("%s:%d: NULL buffer set", __func__, mId);
- return -EINVAL;
+ uint32_t max_buffers;
+ int res = setupStream(streams[i], &max_buffers);
+ if (res) {
+ return res;
+ }
+ streams[i]->setMaxBuffers(max_buffers);
}
- if (buf_set->stream == NULL) {
- ALOGE("%s:%d: NULL stream handle", __func__, mId);
- return -EINVAL;
- }
- Stream *stream = reinterpret_cast<Stream*>(buf_set->stream->priv);
- return stream->registerBuffers(buf_set);
+ return 0;
}
bool Camera::isValidTemplateType(int type)
@@ -562,13 +560,6 @@
return camdev_to_camera(dev)->configureStreams(stream_list);
}
-// TODO(b/29221641): remove
-static int register_stream_buffers(const camera3_device_t *dev,
- const camera3_stream_buffer_set_t *buffer_set)
-{
- return camdev_to_camera(dev)->registerStreamBuffers(buffer_set);
-}
-
static const camera_metadata_t *construct_default_request_settings(
const camera3_device_t *dev, int type)
{
@@ -588,6 +579,7 @@
static int flush(const camera3_device_t*)
{
+ // TODO(b/29937783)
ALOGE("%s: unimplemented.", __func__);
return -1;
}
@@ -601,7 +593,7 @@
.construct_default_request_settings
= default_camera_hal::construct_default_request_settings,
.process_capture_request = default_camera_hal::process_capture_request,
- .get_metadata_vendor_tag_ops = NULL,
+ .get_metadata_vendor_tag_ops = nullptr,
.dump = default_camera_hal::dump,
.flush = default_camera_hal::flush,
.reserved = {0},
diff --git a/modules/camera/3_4/Camera.h b/modules/camera/3_4/Camera.h
index a61cee2..c596350 100644
--- a/modules/camera/3_4/Camera.h
+++ b/modules/camera/3_4/Camera.h
@@ -47,7 +47,6 @@
// Camera v3 Device Operations (see <hardware/camera3.h>)
int initialize(const camera3_callback_ops_t *callback_ops);
int configureStreams(camera3_stream_configuration_t *stream_list);
- int registerStreamBuffers(const camera3_stream_buffer_set_t *buf_set);
const camera_metadata_t *constructDefaultRequestSettings(int type);
int processCaptureRequest(camera3_capture_request_t *request);
void dump(int fd);
@@ -63,6 +62,12 @@
// Initialize device info: facing, orientation, 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
virtual bool isValidCaptureSettings(const camera_metadata_t *) = 0;
// Separate initialization method for individual devices when opened
@@ -80,9 +85,9 @@
// 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);
+ bool isValidStreamSet(Stream **array, int count, uint32_t mode);
// Calculate usage and max_bufs of each stream
- void setupStreams(Stream **array, int count);
+ int setupStreams(Stream **array, int count);
// Copy new settings for re-use and clean up old settings.
void setSettings(const camera_metadata_t *new_settings);
// Verify settings are valid for reprocessing an input buffer
diff --git a/modules/camera/3_4/Stream.cpp b/modules/camera/3_4/Stream.cpp
index fdd08d6..0d021ef 100644
--- a/modules/camera/3_4/Stream.cpp
+++ b/modules/camera/3_4/Stream.cpp
@@ -42,17 +42,14 @@
mHeight(s->height),
mFormat(s->format),
mUsage(0),
- mMaxBuffers(0),
- mRegistered(false),
- mBuffers(0),
- mNumBuffers(0)
+ mRotation(s->rotation),
+ mDataSpace(s->data_space),
+ mMaxBuffers(0)
{
}
Stream::~Stream()
{
- android::Mutex::Autolock al(mLock);
- unregisterBuffers_L();
}
void Stream::setUsage(uint32_t usage)
@@ -61,7 +58,6 @@
if (usage != mUsage) {
mUsage = usage;
mStream->usage = usage;
- unregisterBuffers_L();
}
}
@@ -71,22 +67,25 @@
if (max_buffers != mMaxBuffers) {
mMaxBuffers = max_buffers;
mStream->max_buffers = max_buffers;
- unregisterBuffers_L();
}
}
-int Stream::getType()
+void Stream::setDataSpace(android_dataspace_t data_space)
{
- return mType;
+ android::Mutex::Autolock al(mLock);
+ if (data_space != mDataSpace) {
+ mDataSpace = data_space;
+ mStream->data_space = data_space;
+ }
}
-bool Stream::isInputType()
+bool Stream::isInputType() const
{
return mType == CAMERA3_STREAM_INPUT ||
mType == CAMERA3_STREAM_BIDIRECTIONAL;
}
-bool Stream::isOutputType()
+bool Stream::isOutputType() const
{
return mType == CAMERA3_STREAM_OUTPUT ||
mType == CAMERA3_STREAM_BIDIRECTIONAL;
@@ -145,11 +144,6 @@
return "Invalid stream format!";
}
-bool Stream::isRegistered()
-{
- return mRegistered;
-}
-
bool Stream::isValidReuseStream(int id, camera3_stream_t *s)
{
if (id != mId) {
@@ -187,40 +181,6 @@
return true;
}
-int Stream::registerBuffers(const camera3_stream_buffer_set_t *buf_set)
-{
- ATRACE_CALL();
- android::Mutex::Autolock al(mLock);
-
- if (buf_set->stream != mStream) {
- ALOGE("%s:%d: Buffer set for invalid stream. Got %p expect %p",
- __func__, mId, buf_set->stream, mStream);
- return -EINVAL;
- }
-
- mNumBuffers = buf_set->num_buffers;
- mBuffers = new buffer_handle_t*[mNumBuffers];
-
- for (unsigned int i = 0; i < mNumBuffers; i++) {
- ALOGV("%s:%d: Registering buffer %p", __func__, mId,
- buf_set->buffers[i]);
- mBuffers[i] = buf_set->buffers[i];
- // TODO: register buffers with hw, handle error cases
- }
- mRegistered = true;
-
- return 0;
-}
-
-// This must only be called with mLock held
-void Stream::unregisterBuffers_L()
-{
- mRegistered = false;
- mNumBuffers = 0;
- delete [] mBuffers;
- // TODO: unregister buffers from hw
-}
-
void Stream::dump(int fd)
{
android::Mutex::Autolock al(mLock);
@@ -231,13 +191,9 @@
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);
- dprintf(fd, "Buffers Registered: %s\n", mRegistered ? "true" : "false");
- dprintf(fd, "Number of Buffers: %" PRIu32 "\n", mNumBuffers);
- for (uint32_t i = 0; i < mNumBuffers; i++) {
- dprintf(fd, "Buffer %" PRIu32 "/%" PRIu32 ": %p\n", i, mNumBuffers,
- mBuffers[i]);
- }
}
} // namespace default_camera_hal
diff --git a/modules/camera/3_4/Stream.h b/modules/camera/3_4/Stream.h
index 2187f2b..1531b12 100644
--- a/modules/camera/3_4/Stream.h
+++ b/modules/camera/3_4/Stream.h
@@ -34,16 +34,18 @@
// validate that astream's parameters match this stream's parameters
bool isValidReuseStream(int id, camera3_stream_t *s);
- // Register buffers with hardware
- int registerBuffers(const camera3_stream_buffer_set_t *buf_set);
-
void setUsage(uint32_t usage);
void setMaxBuffers(uint32_t max_buffers);
+ void setDataSpace(android_dataspace_t data_space);
- int getType();
- bool isInputType();
- bool isOutputType();
- bool isRegistered();
+ 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);
@@ -52,8 +54,6 @@
bool mReuse;
private:
- // Clean up buffer state. must be called with mLock held.
- void unregisterBuffers_L();
// The camera device id this stream belongs to
const int mId;
@@ -69,14 +69,12 @@
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;
- // Buffers have been registered for this stream and are ready
- bool mRegistered;
- // Array of handles to buffers currently in use by the stream
- buffer_handle_t **mBuffers;
- // Number of buffers in mBuffers
- unsigned int mNumBuffers;
// Lock protecting the Stream object for modifications
android::Mutex mLock;
};
diff --git a/modules/camera/3_4/V4L2Camera.cpp b/modules/camera/3_4/V4L2Camera.cpp
index b3ae4fc..289a2cf 100644
--- a/modules/camera/3_4/V4L2Camera.cpp
+++ b/modules/camera/3_4/V4L2Camera.cpp
@@ -49,6 +49,10 @@
V4L2Camera::V4L2Camera(int id, std::string path)
: default_camera_hal::Camera(id),
mDevicePath(std::move(path)),
+ mOutStreamFormat(0),
+ mOutStreamWidth(0),
+ mOutStreamHeight(0),
+ mOutStreamMaxBuffers(0),
mTemplatesInitialized(false),
mCharacteristicsInitialized(false) {
HAL_LOG_ENTER();
@@ -58,6 +62,16 @@
HAL_LOG_ENTER();
}
+// Helper function. Should be used instead of ioctl throughout this class.
+template<typename T>
+int V4L2Camera::ioctlLocked(int request, T data) {
+ android::Mutex::Autolock al(mDeviceLock);
+ if (mDeviceFd.get() < 0) {
+ return -ENODEV;
+ }
+ return TEMP_FAILURE_RETRY(ioctl(mDeviceFd.get(), request, data));
+}
+
int V4L2Camera::connect() {
HAL_LOG_ENTER();
@@ -381,17 +395,19 @@
/* android.request. */
- // Resources may be an issue, so just using minimum allowable
- // for LIMITED devices.
int32_t max_num_output_streams[] = {
- /*Raw*/0, /*YUV*/2, /*JPEG*/1};
+ mMaxRawOutputStreams, mMaxYuvOutputStreams, mMaxJpegOutputStreams};
res = info.update(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
max_num_output_streams, ARRAY_SIZE(max_num_output_streams));
if (res != android::OK) {
return res;
}
- // Reprocessing not supported, so no maxNumInputStreams.
+ res = info.update(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
+ &mMaxInputStreams, 1);
+ if (res != android::OK) {
+ return res;
+ }
// No way to know for V4L2, so fake with max allowable latency.
// Doesn't mean much without per-frame controls.
@@ -1170,6 +1186,180 @@
return 0;
}
+bool V4L2Camera::isSupportedStreamSet(default_camera_hal::Stream** streams,
+ int count, uint32_t mode) {
+ 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_yuv = 0;
+ int32_t num_jpeg = 0;
+ for (int i = 0; i < count; ++i) {
+ default_camera_hal::Stream* stream = streams[i];
+
+ if (stream->isInputType()) {
+ ++num_input;
+ }
+
+ if (stream->isOutputType()) {
+ switch (halToV4L2PixelFormat(stream->getFormat())) {
+ case V4L2_PIX_FMT_YUV420:
+ ++num_yuv;
+ break;
+ case V4L2_PIX_FMT_JPEG:
+ ++num_jpeg;
+ break;
+ default:
+ // Note: no supported raw formats at this time.
+ HAL_LOGE("Unsupported format for stream %d: %d", i, stream->getFormat());
+ return false;
+ }
+ }
+ }
+
+ if (num_input > mMaxInputStreams || num_raw > mMaxRawOutputStreams ||
+ num_yuv > mMaxYuvOutputStreams || num_jpeg > mMaxJpegOutputStreams) {
+ HAL_LOGE("Invalid stream configuration: %d input, %d RAW, %d YUV, %d JPEG "
+ "(max supported: %d input, %d RAW, %d YUV, %d JPEG)",
+ mMaxInputStreams, mMaxRawOutputStreams, mMaxYuvOutputStreams,
+ mMaxJpegOutputStreams, num_input, num_raw, num_yuv, num_jpeg);
+ 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());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int V4L2Camera::setupStream(default_camera_hal::Stream* stream,
+ uint32_t* max_buffers) {
+ 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);
+
+ int ret = setFormat(stream);
+ if (ret) {
+ return ret;
+ }
+
+ // Only do buffer setup if we don't know our maxBuffers.
+ if (mOutStreamMaxBuffers < 1) {
+ ret = setupBuffers();
+ if (ret) {
+ return ret;
+ }
+ }
+
+ // Sanity check.
+ if (mOutStreamMaxBuffers < 1) {
+ HAL_LOGE("HAL failed to determine max number of buffers.");
+ return -ENODEV;
+ }
+ *max_buffers = mOutStreamMaxBuffers;
+
+ return 0;
+}
+
+int V4L2Camera::setFormat(const default_camera_hal::Stream* stream) {
+ HAL_LOG_ENTER();
+
+ // Should be checked earlier; sanity check.
+ if (stream->isInputType()) {
+ HAL_LOGE("Input streams not supported.");
+ return -EINVAL;
+ }
+
+ v4l2_format format;
+ memset(&format, 0, sizeof(format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ format.fmt.pix.width = stream->getWidth();
+ format.fmt.pix.height = stream->getHeight();
+ format.fmt.pix.pixelformat = halToV4L2PixelFormat(stream->getFormat());
+ // Check to make sure we're not already in the correct format.
+ if (mOutStreamFormat == format.fmt.pix.pixelformat &&
+ mOutStreamWidth == format.fmt.pix.width &&
+ mOutStreamHeight == format.fmt.pix.height) {
+ return 0;
+ }
+ // Not in the correct format, set our format.
+ int ret = ioctlLocked(VIDIOC_S_FMT, &format);
+ if (ret < 0) {
+ HAL_LOGE("S_FMT failed: %s", strerror(errno));
+ return -ENODEV;
+ }
+ // Check that the driver actually set to the requested values.
+ if (format.fmt.pix.pixelformat != halToV4L2PixelFormat(stream->getFormat()) ||
+ format.fmt.pix.width != stream->getWidth() ||
+ format.fmt.pix.height != stream->getHeight()) {
+ HAL_LOGE("Device doesn't support desired stream configuration.");
+ return -EINVAL;
+ }
+ // Since our format changed, our maxBuffers may be incorrect.
+ mOutStreamMaxBuffers = 0;
+
+ return 0;
+}
+
+int V4L2Camera::setupBuffers() {
+ HAL_LOG_ENTER();
+
+ // "Request" a buffer (since we're using a userspace buffer, this just
+ // tells V4L2 to switch into userspace buffer mode).
+ v4l2_requestbuffers req_buffers;
+ memset(&req_buffers, 0, sizeof(req_buffers));
+ req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req_buffers.memory = V4L2_MEMORY_USERPTR;
+ req_buffers.count = 1;
+ if (ioctlLocked(VIDIOC_REQBUFS, &req_buffers) < 0) {
+ HAL_LOGE("REQBUFS failed: %s", strerror(errno));
+ return -ENODEV;
+ }
+
+ // V4L2 will set req_buffers.count to a number of buffers it can handle.
+ mOutStreamMaxBuffers = req_buffers.count;
+ return 0;
+}
+
bool V4L2Camera::isValidCaptureSettings(const camera_metadata_t* settings) {
HAL_LOG_ENTER();
@@ -1227,6 +1417,14 @@
// TODO(b/29394024): query V4L2_CID_FOCUS_ABSOLUTE for focus range.
mFocusDistance = 0; // Fixed focus.
+ // TODO(b/29939583): V4L2 can only support 1 stream at a time.
+ // For now, just reporting minimum allowable for LIMITED devices.
+ mMaxRawOutputStreams = 0;
+ mMaxYuvOutputStreams = 2;
+ mMaxJpegOutputStreams = 1;
+ // Reprocessing not supported.
+ mMaxInputStreams = 0;
+
/* Features with (potentially) multiple options. */
// TODO(b/29394024): query V4L2_CID_EXPOSURE_AUTO for ae modes.
@@ -1272,23 +1470,15 @@
// Need to support YUV_420_888 and JPEG.
// TODO(b/29394024): query VIDIOC_ENUM_FMT.
std::vector<uint32_t> formats = {{V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420}};
- int32_t hal_format;
// We want to find the smallest maximum frame duration amongst formats.
mMaxFrameDuration = std::numeric_limits<int64_t>::max();
int64_t min_yuv_frame_duration = std::numeric_limits<int64_t>::max();
for (auto format : formats) {
- // Translate V4L2 format to HAL format.
- switch (format) {
- case V4L2_PIX_FMT_JPEG:
- hal_format = HAL_PIXEL_FORMAT_BLOB;
- break;
- case V4L2_PIX_FMT_YUV420:
- hal_format = HAL_PIXEL_FORMAT_YCbCr_420_888;
- default:
- // Unrecognized/unused format. Skip it.
- continue;
+ int32_t hal_format = V4L2ToHalPixelFormat(format);
+ if (hal_format < 0) {
+ // Unrecognized/unused format. Skip it.
+ continue;
}
-
// TODO(b/29394024): query VIDIOC_ENUM_FRAMESIZES.
// For now, just 640x480.
ArrayVector<int32_t, 2> frame_sizes;
@@ -1354,4 +1544,39 @@
return 0;
}
+int V4L2Camera::V4L2ToHalPixelFormat(uint32_t v4l2_format) {
+ // Translate V4L2 format to HAL format.
+ int hal_format = -1;
+ switch (v4l2_format) {
+ case V4L2_PIX_FMT_JPEG:
+ hal_format = HAL_PIXEL_FORMAT_BLOB;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ hal_format = HAL_PIXEL_FORMAT_YCbCr_420_888;
+ break;
+ default:
+ // Unrecognized format.
+ break;
+ }
+ return hal_format;
+}
+
+uint32_t V4L2Camera::halToV4L2PixelFormat(int hal_format) {
+ // Translate HAL format to V4L2 format.
+ uint32_t v4l2_format = 0;
+ switch (hal_format) {
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: // fall-through.
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ v4l2_format = V4L2_PIX_FMT_YUV420;
+ break;
+ case HAL_PIXEL_FORMAT_BLOB:
+ v4l2_format = V4L2_PIX_FMT_JPEG;
+ break;
+ default:
+ // Unrecognized format.
+ break;
+ }
+ return v4l2_format;
+}
+
} // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/V4L2Camera.h b/modules/camera/3_4/V4L2Camera.h
index 7aece03..e57c5b8 100644
--- a/modules/camera/3_4/V4L2Camera.h
+++ b/modules/camera/3_4/V4L2Camera.h
@@ -53,13 +53,39 @@
void initDeviceInfo(camera_info_t* info) override;
// Initialize whole device (templates/etc) 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 settings are valid for a capture with this device.
bool isValidCaptureSettings(const camera_metadata_t* settings) override;
+ // Helper functions for V4L2 functionality.
+ int setFormat(const default_camera_hal::Stream* stream);
+ int setupBuffers();
+
+ // HAL <-> V4L2 conversions.
+ uint32_t halToV4L2PixelFormat(int hal_format); // 0 for unrecognized.
+ int V4L2ToHalPixelFormat(uint32_t v4l2_format); // -1 for unrecognized.
+
// The camera device path. For example, /dev/video0.
const std::string mDevicePath;
// The opened device fd.
ScopedFd mDeviceFd;
+ // Lock protecting use of the device.
+ android::Mutex mDeviceLock;
+ // Wrapper around ioctl.
+ template<typename T>
+ int ioctlLocked(int request, T data);
+
+ // Current output stream settings.
+ uint32_t mOutStreamFormat;
+ uint32_t mOutStreamWidth;
+ uint32_t mOutStreamHeight;
+ uint32_t mOutStreamMaxBuffers;
bool mTemplatesInitialized;
int initTemplates();
@@ -81,6 +107,11 @@
uint8_t mAwbLockAvailable;
uint8_t mFlashAvailable;
float mFocusDistance;
+ int32_t mMaxRawOutputStreams;
+ int32_t mMaxYuvOutputStreams;
+ int32_t mMaxJpegOutputStreams;
+ int32_t mMaxInputStreams;
+ std::vector<int32_t> mSupportedFormats;
// Variable characteristics available options.
std::vector<uint8_t> mAeModes;
std::vector<uint8_t> mAeAntibandingModes;