Camera3: add deferred surface support
Initial native implementation and aidl changes for surfaceless support.
Bug: 28323863
Change-Id: Id6634c3ef2ecc84422a88f63de0a19a0cb496e96
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index dbec34e..a7fe5e7 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -338,13 +338,15 @@
status_t err = mDevice->configureStreams(isConstrainedHighSpeed);
if (err == BAD_VALUE) {
- res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
- "Camera %d: Unsupported set of inputs/outputs provided",
+ String8 msg = String8::format("Camera %d: Unsupported set of inputs/outputs provided",
mCameraId);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ res = STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
} else if (err != OK) {
- res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
- "Camera %d: Error configuring streams: %s (%d)",
+ String8 msg = String8::format("Camera %d: Error configuring streams: %s (%d)",
mCameraId, strerror(-err), err);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
return res;
@@ -365,6 +367,7 @@
bool isInput = false;
ssize_t index = NAME_NOT_FOUND;
+ ssize_t dIndex = NAME_NOT_FOUND;
if (mInputStream.configured && mInputStream.id == streamId) {
isInput = true;
@@ -378,10 +381,19 @@
}
if (index == NAME_NOT_FOUND) {
- String8 msg = String8::format("Camera %d: Invalid stream ID (%d) specified, no such "
- "stream created yet", mCameraId, streamId);
- ALOGW("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ // See if this stream is one of the deferred streams.
+ for (size_t i = 0; i < mDeferredStreams.size(); ++i) {
+ if (streamId == mDeferredStreams[i]) {
+ dIndex = i;
+ break;
+ }
+ }
+ if (dIndex == NAME_NOT_FOUND) {
+ String8 msg = String8::format("Camera %d: Invalid stream ID (%d) specified, no such"
+ " stream created yet", mCameraId, streamId);
+ ALOGW("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
}
}
@@ -396,8 +408,10 @@
} else {
if (isInput) {
mInputStream.configured = false;
- } else {
+ } else if (index != NAME_NOT_FOUND) {
mStreamMap.removeItemsAt(index);
+ } else {
+ mDeferredStreams.removeItemsAt(dIndex);
}
}
@@ -416,14 +430,30 @@
Mutex::Autolock icl(mBinderSerializationLock);
sp<IGraphicBufferProducer> bufferProducer = outputConfiguration.getGraphicBufferProducer();
- if (bufferProducer == NULL) {
- ALOGE("%s: bufferProducer must not be null", __FUNCTION__);
+ bool deferredConsumer = bufferProducer == NULL;
+ int surfaceType = outputConfiguration.getSurfaceType();
+ bool validSurfaceType = ((surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) ||
+ (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE));
+ if (deferredConsumer && !validSurfaceType) {
+ ALOGE("%s: Target surface is invalid: bufferProducer = %p, surfaceType = %d.",
+ __FUNCTION__, bufferProducer.get(), surfaceType);
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
}
+
if (!mDevice.get()) {
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
+ int width, height, format;
+ int32_t consumerUsage;
+ android_dataspace dataSpace;
+ status_t err;
+
+ // Create stream for deferred surface case.
+ if (deferredConsumer) {
+ return createDeferredSurfaceStreamLocked(outputConfiguration, newStreamId);
+ }
+
// Don't create multiple streams for the same target surface
{
ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
@@ -435,13 +465,10 @@
}
}
- status_t err;
-
// HACK b/10949105
// Query consumer usage bits to set async operation mode for
// GLConsumer using controlledByApp parameter.
bool useAsync = false;
- int32_t consumerUsage;
if ((err = bufferProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
&consumerUsage)) != OK) {
String8 msg = String8::format("Camera %d: Failed to query Surface consumer usage: %s (%d)",
@@ -450,8 +477,8 @@
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
- ALOGW("%s: Camera %d: Forcing asynchronous mode for stream",
- __FUNCTION__, mCameraId);
+ ALOGW("%s: Camera %d with consumer usage flag: 0x%x: Forcing asynchronous mode for stream",
+ __FUNCTION__, mCameraId, consumerUsage);
useAsync = true;
}
@@ -467,9 +494,6 @@
sp<Surface> surface = new Surface(bufferProducer, useAsync);
ANativeWindow *anw = surface.get();
- int width, height, format;
- android_dataspace dataSpace;
-
if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) {
String8 msg = String8::format("Camera %d: Failed to query Surface width: %s (%d)",
mCameraId, strerror(-err), err);
@@ -526,29 +550,12 @@
} else {
mStreamMap.add(binder, streamId);
- ALOGV("%s: Camera %d: Successfully created a new stream ID %d",
- __FUNCTION__, mCameraId, streamId);
+ ALOGV("%s: Camera %d: Successfully created a new stream ID %d for output surface"
+ " (%d x %d) with format 0x%x.",
+ __FUNCTION__, mCameraId, streamId, width, height, format);
- /**
- * Set the stream transform flags to automatically
- * rotate the camera stream for preview use cases.
- */
- int32_t transform = 0;
- err = getRotationTransformLocked(&transform);
-
- if (err != OK) {
- // Error logged by getRotationTransformLocked.
- return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
- "Unable to calculate rotation transform for new stream");
- }
-
- err = mDevice->setStreamTransform(streamId, transform);
- if (err != OK) {
- String8 msg = String8::format("Failed to set stream transform (stream id %d)",
- streamId);
- ALOGE("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
- }
+ // Set transform flags to ensure preview to be rotated correctly.
+ res = setStreamTransformLocked(streamId);
*newStreamId = streamId;
}
@@ -556,6 +563,84 @@
return res;
}
+binder::Status CameraDeviceClient::createDeferredSurfaceStreamLocked(
+ const hardware::camera2::params::OutputConfiguration &outputConfiguration,
+ /*out*/
+ int* newStreamId) {
+ int width, height, format, surfaceType;
+ int32_t consumerUsage;
+ android_dataspace dataSpace;
+ status_t err;
+ binder::Status res;
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ // Infer the surface info for deferred surface stream creation.
+ width = outputConfiguration.getWidth();
+ height = outputConfiguration.getHeight();
+ surfaceType = outputConfiguration.getSurfaceType();
+ format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
+ // Hardcode consumer usage flags: SurfaceView--0x900, SurfaceTexture--0x100.
+ consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE;
+ if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
+ consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
+ }
+ int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
+ err = mDevice->createStream(/*surface*/nullptr, width, height, format, dataSpace,
+ static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
+ &streamId, outputConfiguration.getSurfaceSetID(), consumerUsage);
+
+ if (err != OK) {
+ res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+ "Camera %d: Error creating output stream (%d x %d, fmt %x, dataSpace %x): %s (%d)",
+ mCameraId, width, height, format, dataSpace, strerror(-err), err);
+ } else {
+ // Can not add streamId to mStreamMap here, as the surface is deferred. Add it to
+ // a separate list to track. Once the deferred surface is set, this id will be
+ // relocated to mStreamMap.
+ mDeferredStreams.push_back(streamId);
+
+ ALOGV("%s: Camera %d: Successfully created a new stream ID %d for a deferred surface"
+ " (%d x %d) stream with format 0x%x.",
+ __FUNCTION__, mCameraId, streamId, width, height, format);
+
+ // Set transform flags to ensure preview to be rotated correctly.
+ res = setStreamTransformLocked(streamId);
+
+ *newStreamId = streamId;
+ }
+ return res;
+}
+
+binder::Status CameraDeviceClient::setStreamTransformLocked(int streamId) {
+ int32_t transform = 0;
+ status_t err;
+ binder::Status res;
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ err = getRotationTransformLocked(&transform);
+ if (err != OK) {
+ // Error logged by getRotationTransformLocked.
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+ "Unable to calculate rotation transform for new stream");
+ }
+
+ err = mDevice->setStreamTransform(streamId, transform);
+ if (err != OK) {
+ String8 msg = String8::format("Failed to set stream transform (stream id %d)",
+ streamId);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+ }
+
+ return res;
+}
binder::Status CameraDeviceClient::createInputStream(
int width, int height, int format,
@@ -934,6 +1019,76 @@
return res;
}
+binder::Status CameraDeviceClient::setDeferredConfiguration(int32_t streamId,
+ const hardware::camera2::params::OutputConfiguration &outputConfiguration) {
+ ATRACE_CALL();
+
+ binder::Status res;
+ if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ sp<IGraphicBufferProducer> bufferProducer = outputConfiguration.getGraphicBufferProducer();
+
+ // Client code should guarantee that the surface is from SurfaceView or SurfaceTexture.
+ if (bufferProducer == NULL) {
+ ALOGE("%s: bufferProducer must not be null", __FUNCTION__);
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
+ }
+ // Check if this stram id is one of the deferred streams
+ ssize_t index = NAME_NOT_FOUND;
+ for (size_t i = 0; i < mDeferredStreams.size(); i++) {
+ if (streamId == mDeferredStreams[i]) {
+ index = i;
+ break;
+ }
+ }
+ if (index == NAME_NOT_FOUND) {
+ String8 msg = String8::format("Camera %d: deferred surface is set to a unknown stream"
+ "(ID %d)", mCameraId, streamId);
+ ALOGW("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ // Don't create multiple streams for the same target surface
+ {
+ ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
+ if (index != NAME_NOT_FOUND) {
+ String8 msg = String8::format("Camera %d: Surface already has a stream created "
+ " for it (ID %zd)", mCameraId, index);
+ ALOGW("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.string());
+ }
+ }
+
+ status_t err;
+
+ // Always set to async, as we know the deferred surface is for preview streaming.
+ sp<Surface> consumerSurface = new Surface(bufferProducer, /*useAsync*/true);
+
+ // Finish the deferred stream configuration with the surface.
+ err = mDevice->setConsumerSurface(streamId, consumerSurface);
+ if (err == OK) {
+ sp<IBinder> binder = IInterface::asBinder(bufferProducer);
+ mStreamMap.add(binder, streamId);
+ mDeferredStreams.removeItemsAt(index);
+ } else if (err == NO_INIT) {
+ res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Camera %d: Deferred surface is invalid: %s (%d)",
+ mCameraId, strerror(-err), err);
+ } else {
+ res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+ "Camera %d: Error setting output stream deferred surface: %s (%d)",
+ mCameraId, strerror(-err), err);
+ }
+
+ return res;
+}
+
status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
return BasicClient::dump(fd, args);
}
@@ -959,6 +1114,11 @@
for (size_t i = 0; i < mStreamMap.size(); i++) {
result.appendFormat(" Stream %d\n", mStreamMap.valueAt(i));
}
+ } else if (!mDeferredStreams.isEmpty()) {
+ result.append(" Current deferred surface output stream IDs:\n");
+ for (auto& streamId : mDeferredStreams) {
+ result.appendFormat(" Stream %d\n", streamId);
+ }
} else {
result.append(" No output streams configured.\n");
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index d792b7d..dde23fb 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -131,6 +131,10 @@
// Prepare stream by preallocating up to maxCount of its buffers
virtual binder::Status prepare2(int32_t maxCount, int32_t streamId);
+ // Set the deferred surface for a stream.
+ virtual binder::Status setDeferredConfiguration(int32_t streamId,
+ const hardware::camera2::params::OutputConfiguration &outputConfiguration);
+
/**
* Interface used by CameraService
*/
@@ -188,6 +192,15 @@
// Find the square of the euclidean distance between two points
static int64_t euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
+ // Create an output stream with surface deferred for future.
+ binder::Status createDeferredSurfaceStreamLocked(
+ const hardware::camera2::params::OutputConfiguration &outputConfiguration,
+ int* newStreamId = NULL);
+
+ // Set the stream transform flags to automatically rotate the camera stream for preview use
+ // cases.
+ binder::Status setStreamTransformLocked(int streamId);
+
// Find the closest dimensions for a given format in available stream configurations with
// a width <= ROUNDING_WIDTH_CAP
static const int32_t ROUNDING_WIDTH_CAP = 1920;
@@ -213,6 +226,10 @@
int32_t mRequestIdCounter;
+ // The list of output streams whose surfaces are deferred. We have to track them separately
+ // as there are no surfaces available and can not be put into mStreamMap. Once the deferred
+ // Surface is configured, the stream id will be moved to mStreamMap.
+ Vector<int32_t> mDeferredStreams;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 35ec531..8707f2a 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -110,7 +110,8 @@
virtual status_t createStream(sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
- int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID) = 0;
+ int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
+ uint32_t consumerUsage = 0) = 0;
/**
* Create an input stream of width, height, and format.
@@ -312,6 +313,12 @@
* Get the HAL device version.
*/
virtual uint32_t getDeviceVersion() = 0;
+
+ /**
+ * Set the deferred consumer surface and finish the rest of the stream configuration.
+ */
+ virtual status_t setConsumerSurface(int streamId, sp<Surface> consumer) = 0;
+
};
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index c0de95a..e545fb5 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -997,12 +997,13 @@
status_t Camera3Device::createStream(sp<Surface> consumer,
uint32_t width, uint32_t height, int format, android_dataspace dataSpace,
- camera3_stream_rotation_t rotation, int *id, int streamSetId) {
+ camera3_stream_rotation_t rotation, int *id, int streamSetId, uint32_t consumerUsage) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
- ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d",
- mId, mNextStreamId, width, height, format, dataSpace, rotation);
+ ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
+ " consumer usage 0x%x", mId, mNextStreamId, width, height, format, dataSpace, rotation,
+ consumerUsage);
status_t res;
bool wasActive = false;
@@ -1039,6 +1040,19 @@
if (mDeviceVersion <= CAMERA_DEVICE_API_VERSION_3_2) {
streamSetId = CAMERA3_STREAM_SET_ID_INVALID;
}
+
+ // HAL3.1 doesn't support deferred consumer stream creation as it requires buffer registration
+ // which requires a consumer surface to be available.
+ if (consumer == nullptr && mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGE("HAL3.1 doesn't support deferred consumer stream creation");
+ return BAD_VALUE;
+ }
+
+ if (consumer == nullptr && format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ ALOGE("Deferred consumer stream creation only support IMPLEMENTATION_DEFINED format");
+ return BAD_VALUE;
+ }
+
// Use legacy dataspace values for older HALs
if (mDeviceVersion <= CAMERA_DEVICE_API_VERSION_3_3) {
dataSpace = mapToLegacyDataspace(dataSpace);
@@ -1070,6 +1084,10 @@
newStream = new Camera3OutputStream(mNextStreamId, consumer,
width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
mTimestampOffset, streamSetId);
+ } else if (consumer == nullptr) {
+ newStream = new Camera3OutputStream(mNextStreamId,
+ width, height, format, consumerUsage, dataSpace, rotation,
+ mTimestampOffset, streamSetId);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumer,
width, height, format, dataSpace, rotation,
@@ -1729,6 +1747,44 @@
}
}
+status_t Camera3Device::setConsumerSurface(int streamId, sp<Surface> consumer) {
+ ATRACE_CALL();
+ ALOGV("%s: Camera %d: set consumer surface for stream %d", __FUNCTION__, mId, streamId);
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ if (consumer == nullptr) {
+ CLOGE("Null consumer is passed!");
+ return BAD_VALUE;
+ }
+
+ ssize_t idx = mOutputStreams.indexOfKey(streamId);
+ if (idx == NAME_NOT_FOUND) {
+ CLOGE("Stream %d is unknown", streamId);
+ return idx;
+ }
+ sp<Camera3OutputStreamInterface> stream = mOutputStreams[idx];
+ status_t res = stream->setConsumer(consumer);
+ if (res != OK) {
+ CLOGE("Stream %d set consumer failed (error %d %s) ", streamId, res, strerror(-res));
+ return res;
+ }
+
+ if (!stream->isConfiguring()) {
+ CLOGE("Stream %d was already fully configured.", streamId);
+ return INVALID_OPERATION;
+ }
+
+ res = stream->finishConfiguration(mHal3Device);
+ if (res != OK) {
+ SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
+ stream->getId(), strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
/**
* Camera3Device private methods
*/
@@ -1788,6 +1844,13 @@
sp<Camera3OutputStreamInterface> stream =
mOutputStreams.editValueAt(idx);
+ // It is illegal to include a deferred consumer output stream into a request
+ if (stream->isConsumerConfigurationDeferred()) {
+ CLOGE("Stream %d hasn't finished configuration yet due to deferred consumer",
+ stream->getId());
+ return NULL;
+ }
+
// Lazy completion of stream configuration (allocation/registration)
// on first use
if (stream->isConfiguring()) {
@@ -1952,7 +2015,7 @@
for (size_t i = 0; i < mOutputStreams.size(); i++) {
sp<Camera3OutputStreamInterface> outputStream =
mOutputStreams.editValueAt(i);
- if (outputStream->isConfiguring()) {
+ if (outputStream->isConfiguring() && !outputStream->isConsumerConfigurationDeferred()) {
res = outputStream->finishConfiguration(mHal3Device);
if (res != OK) {
SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 0366ef6..679a156 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -95,11 +95,14 @@
// Actual stream creation/deletion is delayed until first request is submitted
// If adding streams while actively capturing, will pause device before adding
- // stream, reconfiguring device, and unpausing.
+ // stream, reconfiguring device, and unpausing. If the client create a stream
+ // with nullptr consumer surface, the client must then call setConsumer()
+ // and finish the stream configuration before starting output streaming.
virtual status_t createStream(sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
- int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID);
+ int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
+ uint32_t consumerUsage = 0);
virtual status_t createInputStream(
uint32_t width, uint32_t height, int format,
int *id);
@@ -160,6 +163,12 @@
// Methods called by subclasses
void notifyStatus(bool idle); // updates from StatusTracker
+ /**
+ * Set the deferred consumer surface to the output stream and finish the deferred
+ * consumer configuration.
+ */
+ virtual status_t setConsumerSurface(int streamId, sp<Surface> consumer);
+
private:
static const size_t kDumpLockAttempts = 10;
static const size_t kDumpSleepDuration = 100000; // 0.10 sec
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 5bf76bd..c74038b 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -96,6 +96,15 @@
return false;
}
+bool Camera3DummyStream::isConsumerConfigurationDeferred() const {
+ return false;
+}
+
+status_t Camera3DummyStream::setConsumer(sp<Surface> consumer) {
+ ALOGE("%s: Stream %d: Dummy stream doesn't support set consumer surface %p!",
+ __FUNCTION__, mId, consumer.get());
+ return INVALID_OPERATION;
+}
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 97c0c96..6c8859c 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -59,6 +59,16 @@
*/
bool isVideoStream() const;
+ /**
+ * Return if the consumer configuration of this stream is deferred.
+ */
+ virtual bool isConsumerConfigurationDeferred() const;
+
+ /**
+ * Set the consumer surface to the output stream.
+ */
+ virtual status_t setConsumer(sp<Surface> consumer);
+
protected:
/**
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index d2b98e6..dcadf36 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -42,7 +42,8 @@
mTransform(0),
mTraceFirstBuffer(true),
mUseBufferManager(false),
- mTimestampOffset(timestampOffset) {
+ mTimestampOffset(timestampOffset),
+ mConsumerUsage(0) {
if (mConsumer == NULL) {
ALOGE("%s: Consumer is NULL!", __FUNCTION__);
@@ -66,7 +67,8 @@
mTraceFirstBuffer(true),
mUseMonoTimestamp(false),
mUseBufferManager(false),
- mTimestampOffset(timestampOffset) {
+ mTimestampOffset(timestampOffset),
+ mConsumerUsage(0) {
if (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
@@ -84,6 +86,39 @@
}
}
+Camera3OutputStream::Camera3OutputStream(int id,
+ uint32_t width, uint32_t height, int format,
+ uint32_t consumerUsage, android_dataspace dataSpace,
+ camera3_stream_rotation_t rotation, nsecs_t timestampOffset, int setId) :
+ Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height,
+ /*maxSize*/0, format, dataSpace, rotation, setId),
+ mConsumer(nullptr),
+ mTransform(0),
+ mTraceFirstBuffer(true),
+ mUseBufferManager(false),
+ mTimestampOffset(timestampOffset),
+ mConsumerUsage(consumerUsage) {
+ // Deferred consumer only support preview surface format now.
+ if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ ALOGE("%s: Deferred consumer only supports IMPLEMENTATION_DEFINED format now!",
+ __FUNCTION__);
+ mState = STATE_ERROR;
+ }
+
+ // Sanity check for the consumer usage flag.
+ if ((consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) == 0 &&
+ (consumerUsage & GraphicBuffer::USAGE_HW_COMPOSER) == 0) {
+ ALOGE("%s: Deferred consumer usage flag is illegal (0x%x)!", __FUNCTION__, consumerUsage);
+ mState = STATE_ERROR;
+ }
+
+ mConsumerName = String8("Deferred");
+ if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
+ mBufferReleasedListener = new BufferReleasedListener(this);
+ }
+
+}
+
Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
uint32_t width, uint32_t height,
int format,
@@ -96,7 +131,8 @@
mTransform(0),
mTraceFirstBuffer(true),
mUseMonoTimestamp(false),
- mUseBufferManager(false) {
+ mUseBufferManager(false),
+ mConsumerUsage(0) {
if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
mBufferReleasedListener = new BufferReleasedListener(this);
@@ -459,11 +495,16 @@
return res;
}
+ // Stream configuration was not finished (can only be in STATE_IN_CONFIG or STATE_CONSTRUCTED
+ // state), don't need change the stream state, return OK.
+ if (mConsumer == nullptr) {
+ return OK;
+ }
+
ALOGV("%s: disconnecting stream %d from native window", __FUNCTION__, getId());
res = native_window_api_disconnect(mConsumer.get(),
NATIVE_WINDOW_API_CAMERA);
-
/**
* This is not an error. if client calling process dies, the window will
* also die and all calls to it will return DEAD_OBJECT, thus it's already
@@ -505,6 +546,12 @@
status_t res;
int32_t u = 0;
+ if (mConsumer == nullptr) {
+ // mConsumerUsage was sanitized before the Camera3OutputStream was constructed.
+ *usage = mConsumerUsage;
+ return OK;
+ }
+
res = static_cast<ANativeWindow*>(mConsumer.get())->query(mConsumer.get(),
NATIVE_WINDOW_CONSUMER_USAGE_BITS, &u);
@@ -540,7 +587,7 @@
status_t Camera3OutputStream::setBufferManager(sp<Camera3BufferManager> bufferManager) {
Mutex::Autolock l(mLock);
if (mState != STATE_CONSTRUCTED) {
- ALOGE("%s: this method can only be called when stream in in CONSTRUCTED state.",
+ ALOGE("%s: this method can only be called when stream in CONSTRUCTED state.",
__FUNCTION__);
return INVALID_OPERATION;
}
@@ -591,6 +638,26 @@
}
}
+bool Camera3OutputStream::isConsumerConfigurationDeferred() const {
+ Mutex::Autolock l(mLock);
+ return mConsumer == nullptr;
+}
+
+status_t Camera3OutputStream::setConsumer(sp<Surface> consumer) {
+ if (consumer == nullptr) {
+ ALOGE("%s: it's illegal to set a null consumer surface!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (mConsumer != nullptr) {
+ ALOGE("%s: consumer surface was already set!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ mConsumer = consumer;
+ return OK;
+}
+
bool Camera3OutputStream::isConsumedByHWComposer() const {
uint32_t usage = 0;
status_t res = getEndpointUsage(&usage);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index a883448..2feca27 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -94,6 +94,16 @@
android_dataspace dataSpace, camera3_stream_rotation_t rotation,
nsecs_t timestampOffset, int setId = CAMERA3_STREAM_SET_ID_INVALID);
+ /**
+ * Set up a stream with deferred consumer for formats that have 2 dimensions, such as
+ * RAW and YUV. The consumer must be set before using this stream for output. A valid
+ * stream set id needs to be set to support buffer sharing between multiple streams.
+ */
+ Camera3OutputStream(int id, uint32_t width, uint32_t height, int format,
+ uint32_t consumerUsage, android_dataspace dataSpace,
+ camera3_stream_rotation_t rotation, nsecs_t timestampOffset,
+ int setId = CAMERA3_STREAM_SET_ID_INVALID);
+
virtual ~Camera3OutputStream();
/**
@@ -117,6 +127,16 @@
*/
bool isConsumedByHWComposer() const;
+ /**
+ * Return if the consumer configuration of this stream is deferred.
+ */
+ virtual bool isConsumerConfigurationDeferred() const;
+
+ /**
+ * Set the consumer surface to the output stream.
+ */
+ virtual status_t setConsumer(sp<Surface> consumer);
+
class BufferReleasedListener : public BnProducerListener {
public:
BufferReleasedListener(wp<Camera3OutputStream> parent) : mParent(parent) {}
@@ -157,6 +177,7 @@
virtual status_t disconnectLocked();
sp<Surface> mConsumer;
+
private:
int mTransform;
@@ -193,6 +214,12 @@
nsecs_t mTimestampOffset;
/**
+ * Consumer end point usage flag set by the constructor for the deferred
+ * consumer case.
+ */
+ uint32_t mConsumerUsage;
+
+ /**
* Internal Camera3Stream interface
*/
virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index df89b34..7c09c40 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -39,6 +39,16 @@
* Return if this output stream is for video encoding.
*/
virtual bool isVideoStream() const = 0;
+
+ /**
+ * Return if the consumer configuration of this stream is deferred.
+ */
+ virtual bool isConsumerConfigurationDeferred() const = 0;
+
+ /**
+ * Set the consumer surface to the output stream.
+ */
+ virtual status_t setConsumer(sp<Surface> consumer) = 0;
};
} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 96d62d4..3ffd9d1 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -55,7 +55,7 @@
mMaxSize(maxSize),
mState(STATE_CONSTRUCTED),
mStatusId(StatusTracker::NO_STATUS_ID),
- mStreamUnpreparable(false),
+ mStreamUnpreparable(true),
mOldUsage(0),
mOldMaxBuffers(0),
mPrepared(false),
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 0755700..1ff215d 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -175,7 +175,8 @@
* OK on a successful configuration
* NO_INIT in case of a serious error from the HAL device
* NO_MEMORY in case of an error registering buffers
- * INVALID_OPERATION in case connecting to the consumer failed
+ * INVALID_OPERATION in case connecting to the consumer failed or consumer
+ * doesn't exist yet.
*/
status_t finishConfiguration(camera3_device *hal3Device);