From 16a2ada049447c156648812b94d25be07869f284 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Wed, 27 Aug 2014 14:41:33 -0700 Subject: CameraService: Create a dummy stream when 0 streams are requested. A workaround for a camera device HAL v3.2 or older specification hole - it's not acceptable to configure_streams with 0 output streams. However, we allow for this at the public API level, to allow an application to release all output streams. So in this case, create a dummy stream that doesn't actually do anything as a placeholder. Bug: 17220694 Change-Id: Ib25242ffc2c9f2b2f619fd5fe6d652266579da85 --- services/camera/libcameraservice/Android.mk | 1 + .../libcameraservice/device3/Camera3Device.cpp | 76 ++++++++++++++++- .../libcameraservice/device3/Camera3Device.h | 15 ++++ .../device3/Camera3DummyStream.cpp | 97 +++++++++++++++++++++ .../libcameraservice/device3/Camera3DummyStream.h | 98 ++++++++++++++++++++++ 5 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 services/camera/libcameraservice/device3/Camera3DummyStream.cpp create mode 100644 services/camera/libcameraservice/device3/Camera3DummyStream.h (limited to 'services') diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index 2f485b9..9d6ab23 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -47,6 +47,7 @@ LOCAL_SRC_FILES:= \ device3/Camera3InputStream.cpp \ device3/Camera3OutputStream.cpp \ device3/Camera3ZslStream.cpp \ + device3/Camera3DummyStream.cpp \ device3/StatusTracker.cpp \ gui/RingBufferConsumer.cpp \ utils/CameraTraces.cpp \ diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 9b51b99..6f78db5 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -48,6 +48,7 @@ #include "device3/Camera3OutputStream.h" #include "device3/Camera3InputStream.h" #include "device3/Camera3ZslStream.h" +#include "device3/Camera3DummyStream.h" #include "CameraService.h" using namespace android::camera3; @@ -181,6 +182,7 @@ status_t Camera3Device::initialize(camera_module_t *module) mHal3Device = device; mStatus = STATUS_UNCONFIGURED; mNextStreamId = 0; + mDummyStreamId = NO_STREAM; mNeedConfig = true; mPauseStateNotify = false; @@ -1418,6 +1420,15 @@ status_t Camera3Device::configureStreamsLocked() { return OK; } + // Workaround for device HALv3.2 or older spec bug - zero streams requires + // adding a dummy stream instead. + // TODO: Bug: 17321404 for fixing the HAL spec and removing this workaround. + if (mOutputStreams.size() == 0) { + addDummyStreamLocked(); + } else { + tryRemoveDummyStreamLocked(); + } + // Start configuring the streams ALOGV("%s: Camera %d: Starting stream configuration", __FUNCTION__, mId); @@ -1540,7 +1551,7 @@ status_t Camera3Device::configureStreamsLocked() { mNeedConfig = false; - if (config.num_streams > 0) { + if (mDummyStreamId == NO_STREAM) { mStatus = STATUS_CONFIGURED; } else { mStatus = STATUS_UNCONFIGURED; @@ -1554,6 +1565,69 @@ status_t Camera3Device::configureStreamsLocked() { return OK; } +status_t Camera3Device::addDummyStreamLocked() { + ATRACE_CALL(); + status_t res; + + if (mDummyStreamId != NO_STREAM) { + // Should never be adding a second dummy stream when one is already + // active + SET_ERR_L("%s: Camera %d: A dummy stream already exists!", + __FUNCTION__, mId); + return INVALID_OPERATION; + } + + ALOGV("%s: Camera %d: Adding a dummy stream", __FUNCTION__, mId); + + sp dummyStream = + new Camera3DummyStream(mNextStreamId); + + res = mOutputStreams.add(mNextStreamId, dummyStream); + if (res < 0) { + SET_ERR_L("Can't add dummy stream to set: %s (%d)", strerror(-res), res); + return res; + } + + mDummyStreamId = mNextStreamId; + mNextStreamId++; + + return OK; +} + +status_t Camera3Device::tryRemoveDummyStreamLocked() { + ATRACE_CALL(); + status_t res; + + if (mDummyStreamId == NO_STREAM) return OK; + if (mOutputStreams.size() == 1) return OK; + + ALOGV("%s: Camera %d: Removing the dummy stream", __FUNCTION__, mId); + + // Ok, have a dummy stream and there's at least one other output stream, + // so remove the dummy + + sp deletedStream; + ssize_t outputStreamIdx = mOutputStreams.indexOfKey(mDummyStreamId); + if (outputStreamIdx == NAME_NOT_FOUND) { + SET_ERR_L("Dummy stream %d does not appear to exist", mDummyStreamId); + return INVALID_OPERATION; + } + + deletedStream = mOutputStreams.editValueAt(outputStreamIdx); + mOutputStreams.removeItemsAt(outputStreamIdx); + + // Free up the stream endpoint so that it can be used by some other stream + res = deletedStream->disconnect(); + if (res != OK) { + SET_ERR_L("Can't disconnect deleted dummy stream %d", mDummyStreamId); + // fall through since we want to still list the stream as deleted. + } + mDeletedStreams.add(deletedStream); + mDummyStreamId = NO_STREAM; + + return res; +} + void Camera3Device::setErrorState(const char *fmt, ...) { Mutex::Autolock l(mLock); va_list args; diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index e3c98ef..b99ed7e 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -151,6 +151,8 @@ class Camera3Device : struct RequestTrigger; // minimal jpeg buffer size: 256KB + blob header static const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(camera3_jpeg_blob); + // Constant to use for stream ID when one doesn't exist + static const int NO_STREAM = -1; // A lock to enforce serialization on the input/configure side // of the public interface. @@ -196,6 +198,8 @@ class Camera3Device : int mNextStreamId; bool mNeedConfig; + int mDummyStreamId; + // Whether to send state updates upstream // Pause when doing transparent reconfiguration bool mPauseStateNotify; @@ -291,6 +295,17 @@ class Camera3Device : status_t configureStreamsLocked(); /** + * Add a dummy stream to the current stream set as a workaround for + * not allowing 0 streams in the camera HAL spec. + */ + status_t addDummyStreamLocked(); + + /** + * Remove a dummy stream if the current config includes real streams. + */ + status_t tryRemoveDummyStreamLocked(); + + /** * Set device into an error state due to some fatal failure, and set an * error message to indicate why. Only the first call's message will be * used. The message is also sent to the log. diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp new file mode 100644 index 0000000..6656b09 --- /dev/null +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2014 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 "Camera3-DummyStream" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include +#include +#include "Camera3DummyStream.h" + +namespace android { + +namespace camera3 { + +Camera3DummyStream::Camera3DummyStream(int id) : + Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, DUMMY_WIDTH, DUMMY_HEIGHT, + /*maxSize*/0, DUMMY_FORMAT) { + +} + +Camera3DummyStream::~Camera3DummyStream() { + +} + +status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *buffer) { + ATRACE_CALL(); + ALOGE("%s: Stream %d: Dummy stream cannot produce buffers!", mId); + return INVALID_OPERATION; +} + +status_t Camera3DummyStream::returnBufferLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp) { + ATRACE_CALL(); + ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", mId); + return INVALID_OPERATION; +} + +status_t Camera3DummyStream::returnBufferCheckedLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output, + /*out*/ + sp *releaseFenceOut) { + ATRACE_CALL(); + ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", mId); + return INVALID_OPERATION; +} + +void Camera3DummyStream::dump(int fd, const Vector &args) const { + (void) args; + String8 lines; + lines.appendFormat(" Stream[%d]: Dummy\n", mId); + write(fd, lines.string(), lines.size()); + + Camera3IOStreamBase::dump(fd, args); +} + +status_t Camera3DummyStream::setTransform(int transform) { + ATRACE_CALL(); + // Do nothing + return OK; +} + +status_t Camera3DummyStream::configureQueueLocked() { + // Do nothing + return OK; +} + +status_t Camera3DummyStream::disconnectLocked() { + mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG + : STATE_CONSTRUCTED; + return OK; +} + +status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) { + *usage = DUMMY_USAGE; + return OK; +} + +}; // namespace camera3 + +}; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h new file mode 100644 index 0000000..3e42623 --- /dev/null +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2014 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. + */ + +#ifndef ANDROID_SERVERS_CAMERA3_DUMMY_STREAM_H +#define ANDROID_SERVERS_CAMERA3_DUMMY_STREAM_H + +#include +#include + +#include "Camera3Stream.h" +#include "Camera3IOStreamBase.h" +#include "Camera3OutputStreamInterface.h" + +namespace android { +namespace camera3 { + +/** + * A dummy output stream class, to be used as a placeholder when no valid + * streams are configured by the client. + * This is necessary because camera HAL v3.2 or older disallow configuring + * 0 output streams, while the public camera2 API allows for it. + */ +class Camera3DummyStream : + public Camera3IOStreamBase, + public Camera3OutputStreamInterface { + + public: + /** + * Set up a dummy stream; doesn't actually connect to anything, and uses + * a default dummy format and size. + */ + Camera3DummyStream(int id); + + virtual ~Camera3DummyStream(); + + /** + * Camera3Stream interface + */ + + virtual void dump(int fd, const Vector &args) const; + + status_t setTransform(int transform); + + protected: + + /** + * Note that we release the lock briefly in this function + */ + virtual status_t returnBufferCheckedLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output, + /*out*/ + sp *releaseFenceOut); + + virtual status_t disconnectLocked(); + + private: + + // Default dummy parameters; 320x240 is a required size for all devices, + // otherwise act like a SurfaceView would. + static const int DUMMY_WIDTH = 320; + static const int DUMMY_HEIGHT = 240; + static const int DUMMY_FORMAT = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + static const uint32_t DUMMY_USAGE = GRALLOC_USAGE_HW_COMPOSER; + + /** + * Internal Camera3Stream interface + */ + virtual status_t getBufferLocked(camera3_stream_buffer *buffer); + virtual status_t returnBufferLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp); + + virtual status_t configureQueueLocked(); + + virtual status_t getEndpointUsage(uint32_t *usage); + +}; // class Camera3DummyStream + +} // namespace camera3 + +} // namespace android + +#endif -- cgit v1.1