Loading services/camera/libcameraservice/Android.mk +4 −0 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,10 @@ LOCAL_SRC_FILES:= \ camera2/JpegCompressor.cpp \ camera2/JpegCompressor.cpp \ camera2/CaptureSequencer.cpp \ camera2/CaptureSequencer.cpp \ camera2/ProFrameProcessor.cpp \ camera2/ProFrameProcessor.cpp \ camera3/Camera3Stream.cpp \ camera3/Camera3InputStream.cpp \ camera3/Camera3OutputStream.cpp \ camera3/Camera3ZslStream.cpp LOCAL_SHARED_LIBRARIES:= \ LOCAL_SHARED_LIBRARIES:= \ libui \ libui \ Loading services/camera/libcameraservice/camera3/Camera3InputStream.cpp 0 → 100644 +77 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Camera3-InputStream" #define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 #include <utils/Log.h> #include <utils/Trace.h> #include "Camera3InputStream.h" namespace android { namespace camera3 { Camera3InputStream::Camera3InputStream(int id, uint32_t width, uint32_t height, int format) : Camera3Stream(id, CAMERA3_STREAM_INPUT, width, height, 0, format) { } status_t Camera3InputStream::getBufferLocked(camera3_stream_buffer *buffer) { (void) buffer; ALOGE("%s: Not implemented", __FUNCTION__); return INVALID_OPERATION; } status_t Camera3InputStream::returnBufferLocked( const camera3_stream_buffer &buffer, nsecs_t timestamp) { (void) timestamp; (void) buffer; ALOGE("%s: Not implemented", __FUNCTION__); return INVALID_OPERATION; } bool Camera3InputStream::hasOutstandingBuffersLocked() const { ALOGE("%s: Not implemented", __FUNCTION__); return false; } status_t Camera3InputStream::waitUntilIdle(nsecs_t timeout) { (void) timeout; ALOGE("%s: Not implemented", __FUNCTION__); return INVALID_OPERATION; } status_t Camera3InputStream::disconnectLocked() { ALOGE("%s: Not implemented", __FUNCTION__); return INVALID_OPERATION; } sp<IGraphicBufferProducer> Camera3InputStream::getProducerInterface() const { return mConsumer->getProducerInterface(); } void Camera3InputStream::dump(int fd, const Vector<String16> &args) const { (void) fd; (void) args; ALOGE("%s: Not implemented", __FUNCTION__); } }; // namespace camera3 }; // namespace android services/camera/libcameraservice/camera3/Camera3InputStream.h 0 → 100644 +70 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SERVERS_CAMERA3_INPUT_STREAM_H #define ANDROID_SERVERS_CAMERA3_INPUT_STREAM_H #include <utils/RefBase.h> #include <gui/Surface.h> #include <gui/BufferItemConsumer.h> #include "Camera3Stream.h" namespace android { namespace camera3 { /** * A class for managing a single stream of input data to the camera device. */ class Camera3InputStream : public Camera3Stream { public: /** * Set up a stream for formats that have fixed size, such as RAW and YUV. */ Camera3InputStream(int id, uint32_t width, uint32_t height, int format); virtual status_t waitUntilIdle(nsecs_t timeout); virtual void dump(int fd, const Vector<String16> &args) const; /** * Get the producer interface for this stream, to hand off to a producer. * The producer must be connected to the provided interface before * finishConfigure is called on this stream. */ sp<IGraphicBufferProducer> getProducerInterface() const; private: sp<BufferItemConsumer> mConsumer; /** * Camera3Stream interface */ virtual status_t getBufferLocked(camera3_stream_buffer *buffer); virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer, nsecs_t timestamp); virtual bool hasOutstandingBuffersLocked() const; virtual status_t disconnectLocked(); }; // class Camera3InputStream }; // namespace camera3 }; // namespace android #endif services/camera/libcameraservice/camera3/Camera3OutputStream.cpp 0 → 100644 +437 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Camera3-OutputStream" #define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 // This is needed for stdint.h to define INT64_MAX in C++ #define __STDC_LIMIT_MACROS #include <utils/Log.h> #include <utils/Trace.h> #include "Camera3OutputStream.h" #ifndef container_of #define container_of(ptr, type, member) \ (type *)((char*)(ptr) - offsetof(type, member)) #endif namespace android { namespace camera3 { Camera3OutputStream::Camera3OutputStream(int id, sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format) : Camera3Stream(id, CAMERA3_STREAM_OUTPUT, width, height, 0, format), mConsumer(consumer), mTransform(0), mTotalBufferCount(0), mDequeuedBufferCount(0), mFrameCount(0), mLastTimestamp(0) { mCombinedFence = new Fence(); if (mConsumer == NULL) { ALOGE("%s: Consumer is NULL!", __FUNCTION__); mState = STATE_ERROR; } } Camera3OutputStream::Camera3OutputStream(int id, sp<ANativeWindow> consumer, uint32_t width, uint32_t height, size_t maxSize, int format) : Camera3Stream(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize, format), mConsumer(consumer) { if (format != HAL_PIXEL_FORMAT_BLOB) { ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__, format); mState = STATE_ERROR; } if (mConsumer == NULL) { ALOGE("%s: Consumer is NULL!", __FUNCTION__); mState = STATE_ERROR; } } Camera3OutputStream::~Camera3OutputStream() { disconnectLocked(); } status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) { ATRACE_CALL(); status_t res; // Allow dequeue during IN_[RE]CONFIG for registration if (mState != STATE_CONFIGURED && mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) { ALOGE("%s: Stream %d: Can't get buffers in unconfigured state %d", __FUNCTION__, mId, mState); return INVALID_OPERATION; } // Only limit dequeue amount when fully configured if (mState == STATE_CONFIGURED && mDequeuedBufferCount == camera3_stream::max_buffers) { ALOGE("%s: Stream %d: Already dequeued maximum number of simultaneous" " buffers (%d)", __FUNCTION__, mId, camera3_stream::max_buffers); return INVALID_OPERATION; } ANativeWindowBuffer* anb; int fenceFd; res = mConsumer->dequeueBuffer(mConsumer.get(), &anb, &fenceFd); if (res != OK) { ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } // Handing out a raw pointer to this object. Increment internal refcount. incStrong(this); buffer->stream = this; buffer->buffer = &(anb->handle); buffer->acquire_fence = fenceFd; buffer->release_fence = -1; buffer->status = CAMERA3_BUFFER_STATUS_OK; mDequeuedBufferCount++; return OK; } status_t Camera3OutputStream::returnBufferLocked( const camera3_stream_buffer &buffer, nsecs_t timestamp) { ATRACE_CALL(); status_t res; // returnBuffer may be called from a raw pointer, not a sp<>, and we'll be // decrementing the internal refcount next. In case this is the last ref, we // might get destructed on the decStrong(), so keep an sp around until the // end of the call - otherwise have to sprinkle the decStrong on all exit // points. sp<Camera3OutputStream> keepAlive(this); decStrong(this); // Allow buffers to be returned in the error state, to allow for disconnect // and in the in-config states for registration if (mState == STATE_CONSTRUCTED) { ALOGE("%s: Stream %d: Can't return buffers in unconfigured state %d", __FUNCTION__, mId, mState); return INVALID_OPERATION; } if (mDequeuedBufferCount == 0) { ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__, mId); return INVALID_OPERATION; } if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) { res = mConsumer->cancelBuffer(mConsumer.get(), container_of(buffer.buffer, ANativeWindowBuffer, handle), buffer.release_fence); if (res != OK) { ALOGE("%s: Stream %d: Error cancelling buffer to native window:" " %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } } else { res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp); if (res != OK) { ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } sp<Fence> releaseFence = new Fence(buffer.release_fence); int anwReleaseFence = releaseFence->dup(); res = mConsumer->queueBuffer(mConsumer.get(), container_of(buffer.buffer, ANativeWindowBuffer, handle), anwReleaseFence); if (res != OK) { ALOGE("%s: Stream %d: Error queueing buffer to native window: %s (%d)", __FUNCTION__, mId, strerror(-res), res); close(anwReleaseFence); return res; } mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); } mDequeuedBufferCount--; mBufferReturnedSignal.signal(); mLastTimestamp = timestamp; return OK; } bool Camera3OutputStream::hasOutstandingBuffersLocked() const { nsecs_t signalTime = mCombinedFence->getSignalTime(); ALOGV("%s: Stream %d: Has %d outstanding buffers," " buffer signal time is %lld", __FUNCTION__, mId, mDequeuedBufferCount, signalTime); if (mDequeuedBufferCount > 0 || signalTime == INT64_MAX) { return true; } return false; } status_t Camera3OutputStream::waitUntilIdle(nsecs_t timeout) { status_t res; { Mutex::Autolock l(mLock); while (mDequeuedBufferCount > 0) { if (timeout != TIMEOUT_NEVER) { nsecs_t startTime = systemTime(); res = mBufferReturnedSignal.waitRelative(mLock, timeout); if (res == TIMED_OUT) { return res; } else if (res != OK) { ALOGE("%s: Error waiting for outstanding buffers: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } nsecs_t deltaTime = systemTime() - startTime; if (timeout <= deltaTime) { timeout = 0; } else { timeout -= deltaTime; } } else { res = mBufferReturnedSignal.wait(mLock); if (res != OK) { ALOGE("%s: Error waiting for outstanding buffers: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } } } } // No lock unsigned int timeoutMs; if (timeout == TIMEOUT_NEVER) { timeoutMs = Fence::TIMEOUT_NEVER; } else if (timeout == 0) { timeoutMs = 0; } else { // Round up to wait at least 1 ms timeoutMs = (timeout + 999999) / 1000000; } return mCombinedFence->wait(timeoutMs); } void Camera3OutputStream::dump(int fd, const Vector<String16> &args) const { (void) args; String8 lines; lines.appendFormat(" Stream[%d]: Output\n", mId); lines.appendFormat(" State: %d\n", mState); lines.appendFormat(" Dims: %d x %d, format 0x%x\n", camera3_stream::width, camera3_stream::height, camera3_stream::format); lines.appendFormat(" Max size: %d\n", mMaxSize); lines.appendFormat(" Usage: %d, max HAL buffers: %d\n", camera3_stream::usage, camera3_stream::max_buffers); lines.appendFormat(" Frames produced: %d, last timestamp: %lld ns\n", mFrameCount, mLastTimestamp); lines.appendFormat(" Total buffers: %d, currently dequeued: %d\n", mTotalBufferCount, mDequeuedBufferCount); write(fd, lines.string(), lines.size()); } status_t Camera3OutputStream::setTransform(int transform) { ATRACE_CALL(); Mutex::Autolock l(mLock); return setTransformLocked(transform); } status_t Camera3OutputStream::setTransformLocked(int transform) { status_t res = OK; if (mState == STATE_ERROR) { ALOGE("%s: Stream in error state", __FUNCTION__); return INVALID_OPERATION; } mTransform = transform; if (mState == STATE_CONFIGURED) { res = native_window_set_buffers_transform(mConsumer.get(), transform); if (res != OK) { ALOGE("%s: Unable to configure stream transform to %x: %s (%d)", __FUNCTION__, transform, strerror(-res), res); } } return res; } status_t Camera3OutputStream::configureQueueLocked() { status_t res; switch (mState) { case STATE_IN_RECONFIG: res = disconnect(); if (res != OK) { return res; } break; case STATE_IN_CONFIG: // OK break; default: ALOGE("%s: Bad state: %d", __FUNCTION__, mState); return INVALID_OPERATION; } // Configure consumer-side ANativeWindow interface res = native_window_api_connect(mConsumer.get(), NATIVE_WINDOW_API_CAMERA); if (res != OK) { ALOGE("%s: Unable to connect to native window for stream %d", __FUNCTION__, mId); return res; } res = native_window_set_usage(mConsumer.get(), camera3_stream::usage); if (res != OK) { ALOGE("%s: Unable to configure usage %08x for stream %d", __FUNCTION__, camera3_stream::usage, mId); return res; } res = native_window_set_scaling_mode(mConsumer.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); if (res != OK) { ALOGE("%s: Unable to configure stream scaling: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } res = setTransformLocked(0); if (res != OK) { return res; } if (mMaxSize == 0) { // For buffers of known size res = native_window_set_buffers_geometry(mConsumer.get(), camera3_stream::width, camera3_stream::height, camera3_stream::format); } else { // For buffers with bounded size res = native_window_set_buffers_geometry(mConsumer.get(), mMaxSize, 1, camera3_stream::format); } if (res != OK) { ALOGE("%s: Unable to configure stream buffer geometry" " %d x %d, format %x for stream %d", __FUNCTION__, camera3_stream::width, camera3_stream::height, camera3_stream::format, mId); return res; } int maxConsumerBuffers; res = mConsumer->query(mConsumer.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers); if (res != OK) { ALOGE("%s: Unable to query consumer undequeued" " buffer count for stream %d", __FUNCTION__, mId); return res; } ALOGV("%s: Consumer wants %d buffers", __FUNCTION__, maxConsumerBuffers); mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers; mDequeuedBufferCount = 0; mFrameCount = 0; mLastTimestamp = 0; res = native_window_set_buffer_count(mConsumer.get(), mTotalBufferCount); if (res != OK) { ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mId); return res; } res = native_window_set_buffers_transform(mConsumer.get(), mTransform); if (res != OK) { ALOGE("%s: Unable to configure stream transform to %x: %s (%d)", __FUNCTION__, mTransform, strerror(-res), res); } return OK; } size_t Camera3OutputStream::getBufferCountLocked() { return mTotalBufferCount; } status_t Camera3OutputStream::disconnectLocked() { status_t res; switch (mState) { case STATE_IN_RECONFIG: case STATE_CONFIGURED: // OK break; default: // No connection, nothing to do return OK; } if (mDequeuedBufferCount > 0) { ALOGE("%s: Can't disconnect with %d buffers still dequeued!", __FUNCTION__, mDequeuedBufferCount); return INVALID_OPERATION; } 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 * "disconnected" */ if (res == DEAD_OBJECT) { ALOGW("%s: While disconnecting stream %d from native window, the" " native window died from under us", __FUNCTION__, mId); } else if (res != OK) { ALOGE("%s: Unable to disconnect stream %d from native window (error %d %s)", __FUNCTION__, mId, res, strerror(-res)); mState = STATE_ERROR; return res; } mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG : STATE_CONSTRUCTED; return OK; } }; // namespace camera3 }; // namespace android services/camera/libcameraservice/camera3/Camera3OutputStream.h 0 → 100644 +95 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H #define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H #include <utils/RefBase.h> #include <gui/Surface.h> #include "Camera3Stream.h" namespace android { namespace camera3 { /** * A class for managing a single stream of output data from the camera device. */ class Camera3OutputStream : public Camera3Stream { public: /** * Set up a stream for formats that have 2 dimensions, such as RAW and YUV. */ Camera3OutputStream(int id, sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format); /** * Set up a stream for formats that have a variable buffer size for the same * dimensions, such as compressed JPEG. */ Camera3OutputStream(int id, sp<ANativeWindow> consumer, uint32_t width, uint32_t height, size_t maxSize, int format); virtual ~Camera3OutputStream(); /** * Camera3Stream interface */ virtual status_t waitUntilIdle(nsecs_t timeout); virtual void dump(int fd, const Vector<String16> &args) const; /** * Set the transform on the output stream; one of the * HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants. */ status_t setTransform(int transform); private: sp<ANativeWindow> mConsumer; int mTransform; size_t mTotalBufferCount; size_t mDequeuedBufferCount; Condition mBufferReturnedSignal; uint32_t mFrameCount; nsecs_t mLastTimestamp; // The merged release fence for all returned buffers sp<Fence> mCombinedFence; status_t setTransformLocked(int transform); /** * Internal Camera3Stream interface */ virtual status_t getBufferLocked(camera3_stream_buffer *buffer); virtual status_t returnBufferLocked( const camera3_stream_buffer &buffer, nsecs_t timestamp); virtual bool hasOutstandingBuffersLocked() const; virtual status_t configureQueueLocked(); virtual size_t getBufferCountLocked(); virtual status_t disconnectLocked(); }; // class Camera3OutputStream } // namespace camera3 } // namespace android #endif Loading
services/camera/libcameraservice/Android.mk +4 −0 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,10 @@ LOCAL_SRC_FILES:= \ camera2/JpegCompressor.cpp \ camera2/JpegCompressor.cpp \ camera2/CaptureSequencer.cpp \ camera2/CaptureSequencer.cpp \ camera2/ProFrameProcessor.cpp \ camera2/ProFrameProcessor.cpp \ camera3/Camera3Stream.cpp \ camera3/Camera3InputStream.cpp \ camera3/Camera3OutputStream.cpp \ camera3/Camera3ZslStream.cpp LOCAL_SHARED_LIBRARIES:= \ LOCAL_SHARED_LIBRARIES:= \ libui \ libui \ Loading
services/camera/libcameraservice/camera3/Camera3InputStream.cpp 0 → 100644 +77 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Camera3-InputStream" #define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 #include <utils/Log.h> #include <utils/Trace.h> #include "Camera3InputStream.h" namespace android { namespace camera3 { Camera3InputStream::Camera3InputStream(int id, uint32_t width, uint32_t height, int format) : Camera3Stream(id, CAMERA3_STREAM_INPUT, width, height, 0, format) { } status_t Camera3InputStream::getBufferLocked(camera3_stream_buffer *buffer) { (void) buffer; ALOGE("%s: Not implemented", __FUNCTION__); return INVALID_OPERATION; } status_t Camera3InputStream::returnBufferLocked( const camera3_stream_buffer &buffer, nsecs_t timestamp) { (void) timestamp; (void) buffer; ALOGE("%s: Not implemented", __FUNCTION__); return INVALID_OPERATION; } bool Camera3InputStream::hasOutstandingBuffersLocked() const { ALOGE("%s: Not implemented", __FUNCTION__); return false; } status_t Camera3InputStream::waitUntilIdle(nsecs_t timeout) { (void) timeout; ALOGE("%s: Not implemented", __FUNCTION__); return INVALID_OPERATION; } status_t Camera3InputStream::disconnectLocked() { ALOGE("%s: Not implemented", __FUNCTION__); return INVALID_OPERATION; } sp<IGraphicBufferProducer> Camera3InputStream::getProducerInterface() const { return mConsumer->getProducerInterface(); } void Camera3InputStream::dump(int fd, const Vector<String16> &args) const { (void) fd; (void) args; ALOGE("%s: Not implemented", __FUNCTION__); } }; // namespace camera3 }; // namespace android
services/camera/libcameraservice/camera3/Camera3InputStream.h 0 → 100644 +70 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SERVERS_CAMERA3_INPUT_STREAM_H #define ANDROID_SERVERS_CAMERA3_INPUT_STREAM_H #include <utils/RefBase.h> #include <gui/Surface.h> #include <gui/BufferItemConsumer.h> #include "Camera3Stream.h" namespace android { namespace camera3 { /** * A class for managing a single stream of input data to the camera device. */ class Camera3InputStream : public Camera3Stream { public: /** * Set up a stream for formats that have fixed size, such as RAW and YUV. */ Camera3InputStream(int id, uint32_t width, uint32_t height, int format); virtual status_t waitUntilIdle(nsecs_t timeout); virtual void dump(int fd, const Vector<String16> &args) const; /** * Get the producer interface for this stream, to hand off to a producer. * The producer must be connected to the provided interface before * finishConfigure is called on this stream. */ sp<IGraphicBufferProducer> getProducerInterface() const; private: sp<BufferItemConsumer> mConsumer; /** * Camera3Stream interface */ virtual status_t getBufferLocked(camera3_stream_buffer *buffer); virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer, nsecs_t timestamp); virtual bool hasOutstandingBuffersLocked() const; virtual status_t disconnectLocked(); }; // class Camera3InputStream }; // namespace camera3 }; // namespace android #endif
services/camera/libcameraservice/camera3/Camera3OutputStream.cpp 0 → 100644 +437 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Camera3-OutputStream" #define ATRACE_TAG ATRACE_TAG_CAMERA //#define LOG_NDEBUG 0 // This is needed for stdint.h to define INT64_MAX in C++ #define __STDC_LIMIT_MACROS #include <utils/Log.h> #include <utils/Trace.h> #include "Camera3OutputStream.h" #ifndef container_of #define container_of(ptr, type, member) \ (type *)((char*)(ptr) - offsetof(type, member)) #endif namespace android { namespace camera3 { Camera3OutputStream::Camera3OutputStream(int id, sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format) : Camera3Stream(id, CAMERA3_STREAM_OUTPUT, width, height, 0, format), mConsumer(consumer), mTransform(0), mTotalBufferCount(0), mDequeuedBufferCount(0), mFrameCount(0), mLastTimestamp(0) { mCombinedFence = new Fence(); if (mConsumer == NULL) { ALOGE("%s: Consumer is NULL!", __FUNCTION__); mState = STATE_ERROR; } } Camera3OutputStream::Camera3OutputStream(int id, sp<ANativeWindow> consumer, uint32_t width, uint32_t height, size_t maxSize, int format) : Camera3Stream(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize, format), mConsumer(consumer) { if (format != HAL_PIXEL_FORMAT_BLOB) { ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__, format); mState = STATE_ERROR; } if (mConsumer == NULL) { ALOGE("%s: Consumer is NULL!", __FUNCTION__); mState = STATE_ERROR; } } Camera3OutputStream::~Camera3OutputStream() { disconnectLocked(); } status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) { ATRACE_CALL(); status_t res; // Allow dequeue during IN_[RE]CONFIG for registration if (mState != STATE_CONFIGURED && mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) { ALOGE("%s: Stream %d: Can't get buffers in unconfigured state %d", __FUNCTION__, mId, mState); return INVALID_OPERATION; } // Only limit dequeue amount when fully configured if (mState == STATE_CONFIGURED && mDequeuedBufferCount == camera3_stream::max_buffers) { ALOGE("%s: Stream %d: Already dequeued maximum number of simultaneous" " buffers (%d)", __FUNCTION__, mId, camera3_stream::max_buffers); return INVALID_OPERATION; } ANativeWindowBuffer* anb; int fenceFd; res = mConsumer->dequeueBuffer(mConsumer.get(), &anb, &fenceFd); if (res != OK) { ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } // Handing out a raw pointer to this object. Increment internal refcount. incStrong(this); buffer->stream = this; buffer->buffer = &(anb->handle); buffer->acquire_fence = fenceFd; buffer->release_fence = -1; buffer->status = CAMERA3_BUFFER_STATUS_OK; mDequeuedBufferCount++; return OK; } status_t Camera3OutputStream::returnBufferLocked( const camera3_stream_buffer &buffer, nsecs_t timestamp) { ATRACE_CALL(); status_t res; // returnBuffer may be called from a raw pointer, not a sp<>, and we'll be // decrementing the internal refcount next. In case this is the last ref, we // might get destructed on the decStrong(), so keep an sp around until the // end of the call - otherwise have to sprinkle the decStrong on all exit // points. sp<Camera3OutputStream> keepAlive(this); decStrong(this); // Allow buffers to be returned in the error state, to allow for disconnect // and in the in-config states for registration if (mState == STATE_CONSTRUCTED) { ALOGE("%s: Stream %d: Can't return buffers in unconfigured state %d", __FUNCTION__, mId, mState); return INVALID_OPERATION; } if (mDequeuedBufferCount == 0) { ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__, mId); return INVALID_OPERATION; } if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) { res = mConsumer->cancelBuffer(mConsumer.get(), container_of(buffer.buffer, ANativeWindowBuffer, handle), buffer.release_fence); if (res != OK) { ALOGE("%s: Stream %d: Error cancelling buffer to native window:" " %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } } else { res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp); if (res != OK) { ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)", __FUNCTION__, mId, strerror(-res), res); return res; } sp<Fence> releaseFence = new Fence(buffer.release_fence); int anwReleaseFence = releaseFence->dup(); res = mConsumer->queueBuffer(mConsumer.get(), container_of(buffer.buffer, ANativeWindowBuffer, handle), anwReleaseFence); if (res != OK) { ALOGE("%s: Stream %d: Error queueing buffer to native window: %s (%d)", __FUNCTION__, mId, strerror(-res), res); close(anwReleaseFence); return res; } mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); } mDequeuedBufferCount--; mBufferReturnedSignal.signal(); mLastTimestamp = timestamp; return OK; } bool Camera3OutputStream::hasOutstandingBuffersLocked() const { nsecs_t signalTime = mCombinedFence->getSignalTime(); ALOGV("%s: Stream %d: Has %d outstanding buffers," " buffer signal time is %lld", __FUNCTION__, mId, mDequeuedBufferCount, signalTime); if (mDequeuedBufferCount > 0 || signalTime == INT64_MAX) { return true; } return false; } status_t Camera3OutputStream::waitUntilIdle(nsecs_t timeout) { status_t res; { Mutex::Autolock l(mLock); while (mDequeuedBufferCount > 0) { if (timeout != TIMEOUT_NEVER) { nsecs_t startTime = systemTime(); res = mBufferReturnedSignal.waitRelative(mLock, timeout); if (res == TIMED_OUT) { return res; } else if (res != OK) { ALOGE("%s: Error waiting for outstanding buffers: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } nsecs_t deltaTime = systemTime() - startTime; if (timeout <= deltaTime) { timeout = 0; } else { timeout -= deltaTime; } } else { res = mBufferReturnedSignal.wait(mLock); if (res != OK) { ALOGE("%s: Error waiting for outstanding buffers: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } } } } // No lock unsigned int timeoutMs; if (timeout == TIMEOUT_NEVER) { timeoutMs = Fence::TIMEOUT_NEVER; } else if (timeout == 0) { timeoutMs = 0; } else { // Round up to wait at least 1 ms timeoutMs = (timeout + 999999) / 1000000; } return mCombinedFence->wait(timeoutMs); } void Camera3OutputStream::dump(int fd, const Vector<String16> &args) const { (void) args; String8 lines; lines.appendFormat(" Stream[%d]: Output\n", mId); lines.appendFormat(" State: %d\n", mState); lines.appendFormat(" Dims: %d x %d, format 0x%x\n", camera3_stream::width, camera3_stream::height, camera3_stream::format); lines.appendFormat(" Max size: %d\n", mMaxSize); lines.appendFormat(" Usage: %d, max HAL buffers: %d\n", camera3_stream::usage, camera3_stream::max_buffers); lines.appendFormat(" Frames produced: %d, last timestamp: %lld ns\n", mFrameCount, mLastTimestamp); lines.appendFormat(" Total buffers: %d, currently dequeued: %d\n", mTotalBufferCount, mDequeuedBufferCount); write(fd, lines.string(), lines.size()); } status_t Camera3OutputStream::setTransform(int transform) { ATRACE_CALL(); Mutex::Autolock l(mLock); return setTransformLocked(transform); } status_t Camera3OutputStream::setTransformLocked(int transform) { status_t res = OK; if (mState == STATE_ERROR) { ALOGE("%s: Stream in error state", __FUNCTION__); return INVALID_OPERATION; } mTransform = transform; if (mState == STATE_CONFIGURED) { res = native_window_set_buffers_transform(mConsumer.get(), transform); if (res != OK) { ALOGE("%s: Unable to configure stream transform to %x: %s (%d)", __FUNCTION__, transform, strerror(-res), res); } } return res; } status_t Camera3OutputStream::configureQueueLocked() { status_t res; switch (mState) { case STATE_IN_RECONFIG: res = disconnect(); if (res != OK) { return res; } break; case STATE_IN_CONFIG: // OK break; default: ALOGE("%s: Bad state: %d", __FUNCTION__, mState); return INVALID_OPERATION; } // Configure consumer-side ANativeWindow interface res = native_window_api_connect(mConsumer.get(), NATIVE_WINDOW_API_CAMERA); if (res != OK) { ALOGE("%s: Unable to connect to native window for stream %d", __FUNCTION__, mId); return res; } res = native_window_set_usage(mConsumer.get(), camera3_stream::usage); if (res != OK) { ALOGE("%s: Unable to configure usage %08x for stream %d", __FUNCTION__, camera3_stream::usage, mId); return res; } res = native_window_set_scaling_mode(mConsumer.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); if (res != OK) { ALOGE("%s: Unable to configure stream scaling: %s (%d)", __FUNCTION__, strerror(-res), res); return res; } res = setTransformLocked(0); if (res != OK) { return res; } if (mMaxSize == 0) { // For buffers of known size res = native_window_set_buffers_geometry(mConsumer.get(), camera3_stream::width, camera3_stream::height, camera3_stream::format); } else { // For buffers with bounded size res = native_window_set_buffers_geometry(mConsumer.get(), mMaxSize, 1, camera3_stream::format); } if (res != OK) { ALOGE("%s: Unable to configure stream buffer geometry" " %d x %d, format %x for stream %d", __FUNCTION__, camera3_stream::width, camera3_stream::height, camera3_stream::format, mId); return res; } int maxConsumerBuffers; res = mConsumer->query(mConsumer.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers); if (res != OK) { ALOGE("%s: Unable to query consumer undequeued" " buffer count for stream %d", __FUNCTION__, mId); return res; } ALOGV("%s: Consumer wants %d buffers", __FUNCTION__, maxConsumerBuffers); mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers; mDequeuedBufferCount = 0; mFrameCount = 0; mLastTimestamp = 0; res = native_window_set_buffer_count(mConsumer.get(), mTotalBufferCount); if (res != OK) { ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mId); return res; } res = native_window_set_buffers_transform(mConsumer.get(), mTransform); if (res != OK) { ALOGE("%s: Unable to configure stream transform to %x: %s (%d)", __FUNCTION__, mTransform, strerror(-res), res); } return OK; } size_t Camera3OutputStream::getBufferCountLocked() { return mTotalBufferCount; } status_t Camera3OutputStream::disconnectLocked() { status_t res; switch (mState) { case STATE_IN_RECONFIG: case STATE_CONFIGURED: // OK break; default: // No connection, nothing to do return OK; } if (mDequeuedBufferCount > 0) { ALOGE("%s: Can't disconnect with %d buffers still dequeued!", __FUNCTION__, mDequeuedBufferCount); return INVALID_OPERATION; } 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 * "disconnected" */ if (res == DEAD_OBJECT) { ALOGW("%s: While disconnecting stream %d from native window, the" " native window died from under us", __FUNCTION__, mId); } else if (res != OK) { ALOGE("%s: Unable to disconnect stream %d from native window (error %d %s)", __FUNCTION__, mId, res, strerror(-res)); mState = STATE_ERROR; return res; } mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG : STATE_CONSTRUCTED; return OK; } }; // namespace camera3 }; // namespace android
services/camera/libcameraservice/camera3/Camera3OutputStream.h 0 → 100644 +95 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H #define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H #include <utils/RefBase.h> #include <gui/Surface.h> #include "Camera3Stream.h" namespace android { namespace camera3 { /** * A class for managing a single stream of output data from the camera device. */ class Camera3OutputStream : public Camera3Stream { public: /** * Set up a stream for formats that have 2 dimensions, such as RAW and YUV. */ Camera3OutputStream(int id, sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format); /** * Set up a stream for formats that have a variable buffer size for the same * dimensions, such as compressed JPEG. */ Camera3OutputStream(int id, sp<ANativeWindow> consumer, uint32_t width, uint32_t height, size_t maxSize, int format); virtual ~Camera3OutputStream(); /** * Camera3Stream interface */ virtual status_t waitUntilIdle(nsecs_t timeout); virtual void dump(int fd, const Vector<String16> &args) const; /** * Set the transform on the output stream; one of the * HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants. */ status_t setTransform(int transform); private: sp<ANativeWindow> mConsumer; int mTransform; size_t mTotalBufferCount; size_t mDequeuedBufferCount; Condition mBufferReturnedSignal; uint32_t mFrameCount; nsecs_t mLastTimestamp; // The merged release fence for all returned buffers sp<Fence> mCombinedFence; status_t setTransformLocked(int transform); /** * Internal Camera3Stream interface */ virtual status_t getBufferLocked(camera3_stream_buffer *buffer); virtual status_t returnBufferLocked( const camera3_stream_buffer &buffer, nsecs_t timestamp); virtual bool hasOutstandingBuffersLocked() const; virtual status_t configureQueueLocked(); virtual size_t getBufferCountLocked(); virtual status_t disconnectLocked(); }; // class Camera3OutputStream } // namespace camera3 } // namespace android #endif