Loading services/camera/libcameraservice/Camera2Client.cpp +280 −17 Original line number Diff line number Diff line Loading @@ -52,8 +52,10 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService, Client(cameraService, cameraClient, cameraId, cameraFacing, clientPid), mState(NOT_INITIALIZED), mPreviewStreamId(NO_PREVIEW_STREAM), mPreviewRequest(NULL) mPreviewStreamId(NO_STREAM), mPreviewRequest(NULL), mCaptureStreamId(NO_STREAM), mCaptureRequest(NULL) { ATRACE_CALL(); Loading Loading @@ -280,9 +282,16 @@ void Camera2Client::disconnect() { stopPreviewLocked(); if (mPreviewStreamId != NO_PREVIEW_STREAM) { mDevice->waitUntilDrained(); if (mPreviewStreamId != NO_STREAM) { mDevice->deleteStream(mPreviewStreamId); mPreviewStreamId = NO_PREVIEW_STREAM; mPreviewStreamId = NO_STREAM; } if (mCaptureStreamId != NO_STREAM) { mDevice->deleteStream(mCaptureStreamId); mCaptureStreamId = NO_STREAM; } CameraService::Client::disconnect(); Loading Loading @@ -323,7 +332,7 @@ status_t Camera2Client::setPreviewDisplay( window = surface; } return setPreviewWindow(binder,window); return setPreviewWindowLocked(binder,window); } status_t Camera2Client::setPreviewTexture( Loading @@ -339,10 +348,10 @@ status_t Camera2Client::setPreviewTexture( binder = surfaceTexture->asBinder(); window = new SurfaceTextureClient(surfaceTexture); } return setPreviewWindow(binder, window); return setPreviewWindowLocked(binder, window); } status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder, status_t Camera2Client::setPreviewWindowLocked(const sp<IBinder>& binder, const sp<ANativeWindow>& window) { ATRACE_CALL(); status_t res; Loading @@ -351,7 +360,9 @@ status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder, return NO_ERROR; } if (mPreviewStreamId != NO_PREVIEW_STREAM) { // TODO: Should wait until HAL has no remaining requests if (mPreviewStreamId != NO_STREAM) { res = mDevice->deleteStream(mPreviewStreamId); if (res != OK) { return res; Loading @@ -359,7 +370,7 @@ status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder, } res = mDevice->createStream(window, mParameters.previewWidth, mParameters.previewHeight, CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mPreviewStreamId); if (res != OK) { return res; Loading @@ -368,7 +379,7 @@ status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder, mPreviewSurface = binder; if (mState == WAITING_FOR_PREVIEW_WINDOW) { return startPreview(); return startPreviewLocked(); } return OK; Loading @@ -382,11 +393,15 @@ void Camera2Client::setPreviewCallbackFlag(int flag) { status_t Camera2Client::startPreview() { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); return startPreviewLocked(); } status_t Camera2Client::startPreviewLocked() { ATRACE_CALL(); status_t res; if (mState == PREVIEW) return INVALID_OPERATION; if (mState >= PREVIEW) return INVALID_OPERATION; if (mPreviewStreamId == NO_PREVIEW_STREAM) { if (mPreviewStreamId == NO_STREAM) { mState = WAITING_FOR_PREVIEW_WINDOW; return OK; } Loading Loading @@ -438,10 +453,28 @@ void Camera2Client::stopPreview() { void Camera2Client::stopPreviewLocked() { ATRACE_CALL(); if (mState != PREVIEW) return; switch (mState) { case NOT_INITIALIZED: ALOGE("%s: Camera %d: Call before initialized", __FUNCTION__, mCameraId); break; case STOPPED: break; case STILL_CAPTURE: ALOGE("%s: Camera %d: Cannot stop preview during still capture.", __FUNCTION__, mCameraId); break; case RECORD: // TODO: Handle record stop here case PREVIEW: mDevice->setStreamingRequest(NULL); case WAITING_FOR_PREVIEW_WINDOW: mState = STOPPED; break; default: ALOGE("%s: Camera %d: Unknown state %d", __FUNCTION__, mCameraId, mState); } } bool Camera2Client::previewEnabled() { Loading Loading @@ -493,7 +526,95 @@ status_t Camera2Client::cancelAutoFocus() { status_t Camera2Client::takePicture(int msgType) { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); return BAD_VALUE; status_t res; switch (mState) { case NOT_INITIALIZED: case STOPPED: case WAITING_FOR_PREVIEW_WINDOW: ALOGE("%s: Camera %d: Cannot take picture without preview enabled", __FUNCTION__, mCameraId); return INVALID_OPERATION; case PREVIEW: case RECORD: // Good to go for takePicture break; case STILL_CAPTURE: case VIDEO_SNAPSHOT: ALOGE("%s: Camera %d: Already taking a picture", __FUNCTION__, mCameraId); return INVALID_OPERATION; } Mutex::Autolock pl(mParamsLock); res = updateCaptureStream(); if (mCaptureRequest == NULL) { updateCaptureRequest(); } // TODO: For video snapshot, need 3 streams here camera_metadata_entry_t outputStreams; uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId }; res = find_camera_metadata_entry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreams); if (res == NAME_NOT_FOUND) { res = add_camera_metadata_entry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS, streamIds, 2); } else if (res == OK) { res = update_camera_metadata_entry(mCaptureRequest, outputStreams.index, streamIds, 2, NULL); } if (res != OK) { ALOGE("%s: Camera %d: Unable to set up still image capture request: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } camera_metadata_t *captureCopy = clone_camera_metadata(mCaptureRequest); if (captureCopy == NULL) { ALOGE("%s: Camera %d: Unable to copy capture request for HAL device", __FUNCTION__, mCameraId); return NO_MEMORY; } if (mState == PREVIEW) { res = mDevice->setStreamingRequest(NULL); if (res != OK) { ALOGE("%s: Camera %d: Unable to stop preview for still capture: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } } res = mDevice->capture(captureCopy); if (res != OK) { ALOGE("%s: Camera %d: Unable to submit still image capture request: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } switch (mState) { case PREVIEW: mState = STILL_CAPTURE; break; case RECORD: mState = VIDEO_SNAPSHOT; break; default: ALOGE("%s: Camera %d: Unknown state for still capture!", __FUNCTION__, mCameraId); return INVALID_OPERATION; } return OK; } status_t Camera2Client::setParameters(const String8& params) { Loading Loading @@ -991,6 +1112,7 @@ status_t Camera2Client::setParameters(const String8& params) { mParameters.videoStabilization = videoStabilization; updatePreviewRequest(); updateCaptureRequest(); return OK; } Loading @@ -1013,6 +1135,65 @@ status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) { /** Device-related methods */ void Camera2Client::onCaptureAvailable() { ATRACE_CALL(); status_t res; sp<ICameraClient> currentClient; CpuConsumer::LockedBuffer imgBuffer; { Mutex::Autolock icl(mICameraLock); // TODO: Signal errors here upstream if (mState != STILL_CAPTURE && mState != VIDEO_SNAPSHOT) { ALOGE("%s: Camera %d: Still image produced unexpectedly!", __FUNCTION__, mCameraId); return; } res = mCaptureConsumer->lockNextBuffer(&imgBuffer); if (res != OK) { ALOGE("%s: Camera %d: Error receiving still image buffer: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return; } if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) { ALOGE("%s: Camera %d: Unexpected format for still image: " "%x, expected %x", __FUNCTION__, mCameraId, imgBuffer.format, HAL_PIXEL_FORMAT_BLOB); mCaptureConsumer->unlockBuffer(imgBuffer); return; } // TODO: Optimize this to avoid memcopy void* captureMemory = mCaptureHeap->getBase(); size_t size = mCaptureHeap->getSize(); memcpy(captureMemory, imgBuffer.data, size); mCaptureConsumer->unlockBuffer(imgBuffer); currentClient = mCameraClient; switch (mState) { case STILL_CAPTURE: mState = STOPPED; break; case VIDEO_SNAPSHOT: mState = RECORD; break; default: ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__, mCameraId, mState); break; } } // Call outside mICameraLock to allow re-entrancy from notification if (currentClient != 0) { currentClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mCaptureMemory, NULL); } } camera_metadata_entry_t Camera2Client::staticInfo(uint32_t tag, size_t minCount, size_t maxCount) { status_t res; Loading Loading @@ -1752,6 +1933,88 @@ status_t Camera2Client::updatePreviewRequest() { return OK; } status_t Camera2Client::updateCaptureStream() { status_t res; // Find out buffer size for JPEG camera_metadata_entry_t maxJpegSize = staticInfo(ANDROID_JPEG_MAX_SIZE); if (maxJpegSize.count == 0) { ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!", __FUNCTION__, mCameraId); return INVALID_OPERATION; } if (mCaptureConsumer == 0) { // Create CPU buffer queue endpoint mCaptureConsumer = new CpuConsumer(1); mCaptureConsumer->setFrameAvailableListener(new CaptureWaiter(this)); mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer")); mCaptureWindow = new SurfaceTextureClient( mCaptureConsumer->getProducerInterface()); // Create memory for API consumption mCaptureHeap = new MemoryHeapBase(maxJpegSize.data.i32[0], 0, "Camera2Client::CaptureHeap"); if (mCaptureHeap->getSize() == 0) { ALOGE("%s: Camera %d: Unable to allocate memory for capture", __FUNCTION__, mCameraId); return NO_MEMORY; } mCaptureMemory = new MemoryBase(mCaptureHeap, 0, maxJpegSize.data.i32[0]); } if (mCaptureStreamId == NO_STREAM) { // Create stream for HAL production res = mDevice->createStream(mCaptureWindow, mParameters.pictureWidth, mParameters.pictureHeight, HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0], &mCaptureStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for capture: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } } else { // Check if stream parameters have to change uint32_t currentWidth, currentHeight; res = mDevice->getStreamInfo(mCaptureStreamId, ¤tWidth, ¤tHeight, 0); if (res != OK) { ALOGE("%s: Camera %d: Error querying capture output stream info: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } if (currentWidth != (uint32_t)mParameters.pictureWidth || currentHeight != (uint32_t)mParameters.pictureHeight) { res = mDevice->deleteStream(mCaptureStreamId); if (res != OK) { ALOGE("%s: Camera %d: Unable to delete old output stream " "for capture: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } mCaptureStreamId = NO_STREAM; return updateCaptureStream(); } } return OK; } status_t Camera2Client::updateCaptureRequest() { ATRACE_CALL(); status_t res; if (mCaptureRequest == NULL) { res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_STILL_CAPTURE, &mCaptureRequest); if (res != OK) { ALOGE("%s: Camera %d: Unable to create default still image request:" " %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } } // TODO: Adjust for params changes return OK; } int Camera2Client::formatStringToEnum(const char *format) { return !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ? Loading services/camera/libcameraservice/Camera2Client.h +36 −5 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ #include "Camera2Device.h" #include "CameraService.h" #include "camera/CameraParameters.h" #include <binder/MemoryBase.h> #include <binder/MemoryHeapBase.h> #include <gui/CpuConsumer.h> namespace android { Loading Loading @@ -73,7 +76,8 @@ private: WAITING_FOR_PREVIEW_WINDOW, PREVIEW, RECORD, STILL_CAPTURE STILL_CAPTURE, VIDEO_SNAPSHOT } mState; /** ICamera interface-related private members */ Loading @@ -82,11 +86,15 @@ private: // Ensures serialization between incoming ICamera calls mutable Mutex mICameraLock; status_t setPreviewWindow(const sp<IBinder>& binder, // The following must be called with mICamaeraLock already locked status_t setPreviewWindowLocked(const sp<IBinder>& binder, const sp<ANativeWindow>& window); void stopPreviewLocked(); status_t startPreviewLocked(); // Mutex that must be locked before accessing mParams, mParamsFlattened // Mutex that must be locked before accessing mParameters, mParamsFlattened mutable Mutex mParamsLock; String8 mParamsFlattened; // Current camera state; this is the contents of the CameraParameters object Loading Loading @@ -164,16 +172,34 @@ private: /** Camera device-related private members */ // Simple listener that forwards frame available notifications from // a CPU consumer to the capture notification class CaptureWaiter: public CpuConsumer::FrameAvailableListener { public: CaptureWaiter(Camera2Client *parent) : mParent(parent) {} void onFrameAvailable() { mParent->onCaptureAvailable(); } private: Camera2Client *mParent; }; void onCaptureAvailable(); // Number of zoom steps to simulate static const unsigned int NUM_ZOOM_STEPS = 10; // Used with mPreviewStreamId static const int NO_PREVIEW_STREAM = -1; // Used with mPreviewStreamId, mCaptureStreamId static const int NO_STREAM = -1; sp<IBinder> mPreviewSurface; int mPreviewStreamId; camera_metadata_t *mPreviewRequest; int mCaptureStreamId; sp<CpuConsumer> mCaptureConsumer; sp<ANativeWindow> mCaptureWindow; sp<CaptureWaiter> mCaptureWaiter; camera_metadata_t *mCaptureRequest; sp<MemoryHeapBase> mCaptureHeap; sp<MemoryBase> mCaptureMemory; sp<Camera2Device> mDevice; Loading @@ -194,6 +220,11 @@ private: // Update preview request based on mParams status_t updatePreviewRequest(); // Update capture request based on mParams status_t updateCaptureRequest(); // Update capture stream based on mParams status_t updateCaptureStream(); // Convert camera1 preview format string to camera2 enum static int formatStringToEnum(const char *format); static const char *formatEnumToString(int format); Loading services/camera/libcameraservice/Camera2Device.cpp +81 −18 Original line number Diff line number Diff line Loading @@ -111,8 +111,15 @@ camera_metadata_t *Camera2Device::info() { return mDeviceInfo; } status_t Camera2Device::setStreamingRequest(camera_metadata_t* request) { status_t Camera2Device::capture(camera_metadata_t* request) { ALOGV("%s: E", __FUNCTION__); mRequestQueue.enqueue(request); return OK; } status_t Camera2Device::setStreamingRequest(camera_metadata_t* request) { ALOGV("%s: E", __FUNCTION__); mRequestQueue.setStreamSlot(request); Loading @@ -120,13 +127,13 @@ status_t Camera2Device::setStreamingRequest(camera_metadata_t* request) } status_t Camera2Device::createStream(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format, int *id) { uint32_t width, uint32_t height, int format, size_t size, int *id) { status_t res; ALOGV("%s: E", __FUNCTION__); sp<StreamAdapter> stream = new StreamAdapter(mDevice); res = stream->connectToDevice(consumer, width, height, format); res = stream->connectToDevice(consumer, width, height, format, size); if (res != OK) { ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):" "%s (%d)", Loading @@ -140,6 +147,31 @@ status_t Camera2Device::createStream(sp<ANativeWindow> consumer, return OK; } status_t Camera2Device::getStreamInfo(int id, uint32_t *width, uint32_t *height, uint32_t *format) { ALOGV("%s: E", __FUNCTION__); bool found = false; StreamList::iterator streamI; for (streamI = mStreams.begin(); streamI != mStreams.end(); streamI++) { if ((*streamI)->getId() == id) { found = true; break; } } if (!found) { ALOGE("%s: Camera %d: Stream %d does not exist", __FUNCTION__, mId, id); return BAD_VALUE; } if (width) *width = (*streamI)->getWidth(); if (height) *height = (*streamI)->getHeight(); if (format) *format = (*streamI)->getFormat(); return OK; } status_t Camera2Device::deleteStream(int id) { ALOGV("%s: E", __FUNCTION__); Loading @@ -163,7 +195,29 @@ status_t Camera2Device::deleteStream(int id) { status_t Camera2Device::createDefaultRequest(int templateId, camera_metadata_t **request) { ALOGV("%s: E", __FUNCTION__); return mDevice->ops->construct_default_request(mDevice, templateId, request); return mDevice->ops->construct_default_request( mDevice, templateId, request); } status_t Camera2Device::waitUntilDrained() { static const uint32_t kSleepTime = 50000; // 50 ms static const uint32_t kMaxSleepTime = 10000000; // 10 s if (mRequestQueue.getBufferCount() == CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION; // TODO: Set up notifications from HAL, instead of sleeping here uint32_t totalTime = 0; while (mDevice->ops->get_in_progress_count(mDevice) > 0) { usleep(kSleepTime); totalTime += kSleepTime; if (totalTime > kMaxSleepTime) { ALOGE("%s: Waited %d us, requests still in flight", __FUNCTION__, totalTime); return TIMED_OUT; } } return OK; } /** Loading Loading @@ -463,8 +517,9 @@ Camera2Device::StreamAdapter::~StreamAdapter() { disconnect(); } status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format) { status_t Camera2Device::StreamAdapter::connectToDevice( sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format, size_t size) { status_t res; if (mState != DISCONNECTED) return INVALID_OPERATION; Loading @@ -476,6 +531,7 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume mConsumerInterface = consumer; mWidth = width; mHeight = height; mSize = (format == HAL_PIXEL_FORMAT_BLOB) ? size : 0; mFormatRequested = format; // Allocate device-side stream interface Loading Loading @@ -534,6 +590,16 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume return res; } if (mFormat == HAL_PIXEL_FORMAT_BLOB) { res = native_window_set_buffers_geometry(mConsumerInterface.get(), mSize, 1, mFormat); if (res != OK) { ALOGE("%s: Unable to configure compressed stream buffer geometry" " %d x %d, size %d for stream %d", __FUNCTION__, mWidth, mHeight, mSize, mId); return res; } } else { res = native_window_set_buffers_geometry(mConsumerInterface.get(), mWidth, mHeight, mFormat); if (res != OK) { Loading @@ -542,6 +608,7 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume __FUNCTION__, mWidth, mHeight, mFormat, mId); return res; } } int maxConsumerBuffers; res = mConsumerInterface->query(mConsumerInterface.get(), Loading Loading @@ -641,10 +708,6 @@ status_t Camera2Device::StreamAdapter::disconnect() { return OK; } int Camera2Device::StreamAdapter::getId() { return mId; } const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() { return static_cast<camera2_stream_ops *>(this); } Loading services/camera/libcameraservice/Camera2Device.h +61 −5 Original line number Diff line number Diff line Loading @@ -37,17 +37,58 @@ class Camera2Device : public virtual RefBase { camera_metadata_t* info(); /** * Submit request for capture. The Camera2Device takes ownership of the * passed-in buffer. */ status_t capture(camera_metadata_t *request); /** * Submit request for streaming. The Camera2Device makes a copy of the * passed-in buffer and the caller retains ownership. */ status_t setStreamingRequest(camera_metadata_t *request); /** * Create an output stream of the requested size and format. * * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects * an appropriate format; it can be queried with getStreamInfo. * * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be * equal to the size in bytes of the buffers to allocate for the stream. For * other formats, the size parameter is ignored. */ status_t createStream(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format, uint32_t width, uint32_t height, int format, size_t size, int *id); /** * Get information about a given stream. */ status_t getStreamInfo(int id, uint32_t *width, uint32_t *height, uint32_t *format); /** * Delete stream. Must not be called if there are requests in flight which * reference that stream. */ status_t deleteStream(int id); /** * Create a metadata buffer with fields that the HAL device believes are * best for the given use case */ status_t createDefaultRequest(int templateId, camera_metadata_t **request); /** * Wait until all requests have been processed. Returns INVALID_OPERATION if * the streaming slot is not empty, or TIMED_OUT if the requests haven't * finished processing in 10 seconds. */ status_t waitUntilDrained(); private: const int mId; Loading Loading @@ -150,13 +191,27 @@ class Camera2Device : public virtual RefBase { ~StreamAdapter(); /** * Create a HAL device stream of the requested size and format. * * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device * selects an appropriate format; it can be queried with getFormat. * * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must * be equal to the size in bytes of the buffers to allocate for the * stream. For other formats, the size parameter is ignored. */ status_t connectToDevice(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format); uint32_t width, uint32_t height, int format, size_t size); status_t disconnect(); // Get stream ID. Only valid after a successful connectToDevice call. int getId(); // Get stream parameters. // Only valid after a successful connectToDevice call. int getId() const { return mId; } uint32_t getWidth() const { return mWidth; } uint32_t getHeight() const { return mHeight; } uint32_t getFormat() const { return mFormat; } private: enum { Loading @@ -174,6 +229,7 @@ class Camera2Device : public virtual RefBase { uint32_t mWidth; uint32_t mHeight; uint32_t mFormat; size_t mSize; uint32_t mUsage; uint32_t mMaxProducerBuffers; uint32_t mMaxConsumerBuffers; Loading Loading
services/camera/libcameraservice/Camera2Client.cpp +280 −17 Original line number Diff line number Diff line Loading @@ -52,8 +52,10 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService, Client(cameraService, cameraClient, cameraId, cameraFacing, clientPid), mState(NOT_INITIALIZED), mPreviewStreamId(NO_PREVIEW_STREAM), mPreviewRequest(NULL) mPreviewStreamId(NO_STREAM), mPreviewRequest(NULL), mCaptureStreamId(NO_STREAM), mCaptureRequest(NULL) { ATRACE_CALL(); Loading Loading @@ -280,9 +282,16 @@ void Camera2Client::disconnect() { stopPreviewLocked(); if (mPreviewStreamId != NO_PREVIEW_STREAM) { mDevice->waitUntilDrained(); if (mPreviewStreamId != NO_STREAM) { mDevice->deleteStream(mPreviewStreamId); mPreviewStreamId = NO_PREVIEW_STREAM; mPreviewStreamId = NO_STREAM; } if (mCaptureStreamId != NO_STREAM) { mDevice->deleteStream(mCaptureStreamId); mCaptureStreamId = NO_STREAM; } CameraService::Client::disconnect(); Loading Loading @@ -323,7 +332,7 @@ status_t Camera2Client::setPreviewDisplay( window = surface; } return setPreviewWindow(binder,window); return setPreviewWindowLocked(binder,window); } status_t Camera2Client::setPreviewTexture( Loading @@ -339,10 +348,10 @@ status_t Camera2Client::setPreviewTexture( binder = surfaceTexture->asBinder(); window = new SurfaceTextureClient(surfaceTexture); } return setPreviewWindow(binder, window); return setPreviewWindowLocked(binder, window); } status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder, status_t Camera2Client::setPreviewWindowLocked(const sp<IBinder>& binder, const sp<ANativeWindow>& window) { ATRACE_CALL(); status_t res; Loading @@ -351,7 +360,9 @@ status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder, return NO_ERROR; } if (mPreviewStreamId != NO_PREVIEW_STREAM) { // TODO: Should wait until HAL has no remaining requests if (mPreviewStreamId != NO_STREAM) { res = mDevice->deleteStream(mPreviewStreamId); if (res != OK) { return res; Loading @@ -359,7 +370,7 @@ status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder, } res = mDevice->createStream(window, mParameters.previewWidth, mParameters.previewHeight, CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mPreviewStreamId); if (res != OK) { return res; Loading @@ -368,7 +379,7 @@ status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder, mPreviewSurface = binder; if (mState == WAITING_FOR_PREVIEW_WINDOW) { return startPreview(); return startPreviewLocked(); } return OK; Loading @@ -382,11 +393,15 @@ void Camera2Client::setPreviewCallbackFlag(int flag) { status_t Camera2Client::startPreview() { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); return startPreviewLocked(); } status_t Camera2Client::startPreviewLocked() { ATRACE_CALL(); status_t res; if (mState == PREVIEW) return INVALID_OPERATION; if (mState >= PREVIEW) return INVALID_OPERATION; if (mPreviewStreamId == NO_PREVIEW_STREAM) { if (mPreviewStreamId == NO_STREAM) { mState = WAITING_FOR_PREVIEW_WINDOW; return OK; } Loading Loading @@ -438,10 +453,28 @@ void Camera2Client::stopPreview() { void Camera2Client::stopPreviewLocked() { ATRACE_CALL(); if (mState != PREVIEW) return; switch (mState) { case NOT_INITIALIZED: ALOGE("%s: Camera %d: Call before initialized", __FUNCTION__, mCameraId); break; case STOPPED: break; case STILL_CAPTURE: ALOGE("%s: Camera %d: Cannot stop preview during still capture.", __FUNCTION__, mCameraId); break; case RECORD: // TODO: Handle record stop here case PREVIEW: mDevice->setStreamingRequest(NULL); case WAITING_FOR_PREVIEW_WINDOW: mState = STOPPED; break; default: ALOGE("%s: Camera %d: Unknown state %d", __FUNCTION__, mCameraId, mState); } } bool Camera2Client::previewEnabled() { Loading Loading @@ -493,7 +526,95 @@ status_t Camera2Client::cancelAutoFocus() { status_t Camera2Client::takePicture(int msgType) { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); return BAD_VALUE; status_t res; switch (mState) { case NOT_INITIALIZED: case STOPPED: case WAITING_FOR_PREVIEW_WINDOW: ALOGE("%s: Camera %d: Cannot take picture without preview enabled", __FUNCTION__, mCameraId); return INVALID_OPERATION; case PREVIEW: case RECORD: // Good to go for takePicture break; case STILL_CAPTURE: case VIDEO_SNAPSHOT: ALOGE("%s: Camera %d: Already taking a picture", __FUNCTION__, mCameraId); return INVALID_OPERATION; } Mutex::Autolock pl(mParamsLock); res = updateCaptureStream(); if (mCaptureRequest == NULL) { updateCaptureRequest(); } // TODO: For video snapshot, need 3 streams here camera_metadata_entry_t outputStreams; uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId }; res = find_camera_metadata_entry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreams); if (res == NAME_NOT_FOUND) { res = add_camera_metadata_entry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS, streamIds, 2); } else if (res == OK) { res = update_camera_metadata_entry(mCaptureRequest, outputStreams.index, streamIds, 2, NULL); } if (res != OK) { ALOGE("%s: Camera %d: Unable to set up still image capture request: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } camera_metadata_t *captureCopy = clone_camera_metadata(mCaptureRequest); if (captureCopy == NULL) { ALOGE("%s: Camera %d: Unable to copy capture request for HAL device", __FUNCTION__, mCameraId); return NO_MEMORY; } if (mState == PREVIEW) { res = mDevice->setStreamingRequest(NULL); if (res != OK) { ALOGE("%s: Camera %d: Unable to stop preview for still capture: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } } res = mDevice->capture(captureCopy); if (res != OK) { ALOGE("%s: Camera %d: Unable to submit still image capture request: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } switch (mState) { case PREVIEW: mState = STILL_CAPTURE; break; case RECORD: mState = VIDEO_SNAPSHOT; break; default: ALOGE("%s: Camera %d: Unknown state for still capture!", __FUNCTION__, mCameraId); return INVALID_OPERATION; } return OK; } status_t Camera2Client::setParameters(const String8& params) { Loading Loading @@ -991,6 +1112,7 @@ status_t Camera2Client::setParameters(const String8& params) { mParameters.videoStabilization = videoStabilization; updatePreviewRequest(); updateCaptureRequest(); return OK; } Loading @@ -1013,6 +1135,65 @@ status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) { /** Device-related methods */ void Camera2Client::onCaptureAvailable() { ATRACE_CALL(); status_t res; sp<ICameraClient> currentClient; CpuConsumer::LockedBuffer imgBuffer; { Mutex::Autolock icl(mICameraLock); // TODO: Signal errors here upstream if (mState != STILL_CAPTURE && mState != VIDEO_SNAPSHOT) { ALOGE("%s: Camera %d: Still image produced unexpectedly!", __FUNCTION__, mCameraId); return; } res = mCaptureConsumer->lockNextBuffer(&imgBuffer); if (res != OK) { ALOGE("%s: Camera %d: Error receiving still image buffer: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return; } if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) { ALOGE("%s: Camera %d: Unexpected format for still image: " "%x, expected %x", __FUNCTION__, mCameraId, imgBuffer.format, HAL_PIXEL_FORMAT_BLOB); mCaptureConsumer->unlockBuffer(imgBuffer); return; } // TODO: Optimize this to avoid memcopy void* captureMemory = mCaptureHeap->getBase(); size_t size = mCaptureHeap->getSize(); memcpy(captureMemory, imgBuffer.data, size); mCaptureConsumer->unlockBuffer(imgBuffer); currentClient = mCameraClient; switch (mState) { case STILL_CAPTURE: mState = STOPPED; break; case VIDEO_SNAPSHOT: mState = RECORD; break; default: ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__, mCameraId, mState); break; } } // Call outside mICameraLock to allow re-entrancy from notification if (currentClient != 0) { currentClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mCaptureMemory, NULL); } } camera_metadata_entry_t Camera2Client::staticInfo(uint32_t tag, size_t minCount, size_t maxCount) { status_t res; Loading Loading @@ -1752,6 +1933,88 @@ status_t Camera2Client::updatePreviewRequest() { return OK; } status_t Camera2Client::updateCaptureStream() { status_t res; // Find out buffer size for JPEG camera_metadata_entry_t maxJpegSize = staticInfo(ANDROID_JPEG_MAX_SIZE); if (maxJpegSize.count == 0) { ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!", __FUNCTION__, mCameraId); return INVALID_OPERATION; } if (mCaptureConsumer == 0) { // Create CPU buffer queue endpoint mCaptureConsumer = new CpuConsumer(1); mCaptureConsumer->setFrameAvailableListener(new CaptureWaiter(this)); mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer")); mCaptureWindow = new SurfaceTextureClient( mCaptureConsumer->getProducerInterface()); // Create memory for API consumption mCaptureHeap = new MemoryHeapBase(maxJpegSize.data.i32[0], 0, "Camera2Client::CaptureHeap"); if (mCaptureHeap->getSize() == 0) { ALOGE("%s: Camera %d: Unable to allocate memory for capture", __FUNCTION__, mCameraId); return NO_MEMORY; } mCaptureMemory = new MemoryBase(mCaptureHeap, 0, maxJpegSize.data.i32[0]); } if (mCaptureStreamId == NO_STREAM) { // Create stream for HAL production res = mDevice->createStream(mCaptureWindow, mParameters.pictureWidth, mParameters.pictureHeight, HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0], &mCaptureStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for capture: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } } else { // Check if stream parameters have to change uint32_t currentWidth, currentHeight; res = mDevice->getStreamInfo(mCaptureStreamId, ¤tWidth, ¤tHeight, 0); if (res != OK) { ALOGE("%s: Camera %d: Error querying capture output stream info: " "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } if (currentWidth != (uint32_t)mParameters.pictureWidth || currentHeight != (uint32_t)mParameters.pictureHeight) { res = mDevice->deleteStream(mCaptureStreamId); if (res != OK) { ALOGE("%s: Camera %d: Unable to delete old output stream " "for capture: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } mCaptureStreamId = NO_STREAM; return updateCaptureStream(); } } return OK; } status_t Camera2Client::updateCaptureRequest() { ATRACE_CALL(); status_t res; if (mCaptureRequest == NULL) { res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_STILL_CAPTURE, &mCaptureRequest); if (res != OK) { ALOGE("%s: Camera %d: Unable to create default still image request:" " %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); return res; } } // TODO: Adjust for params changes return OK; } int Camera2Client::formatStringToEnum(const char *format) { return !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ? Loading
services/camera/libcameraservice/Camera2Client.h +36 −5 Original line number Diff line number Diff line Loading @@ -20,6 +20,9 @@ #include "Camera2Device.h" #include "CameraService.h" #include "camera/CameraParameters.h" #include <binder/MemoryBase.h> #include <binder/MemoryHeapBase.h> #include <gui/CpuConsumer.h> namespace android { Loading Loading @@ -73,7 +76,8 @@ private: WAITING_FOR_PREVIEW_WINDOW, PREVIEW, RECORD, STILL_CAPTURE STILL_CAPTURE, VIDEO_SNAPSHOT } mState; /** ICamera interface-related private members */ Loading @@ -82,11 +86,15 @@ private: // Ensures serialization between incoming ICamera calls mutable Mutex mICameraLock; status_t setPreviewWindow(const sp<IBinder>& binder, // The following must be called with mICamaeraLock already locked status_t setPreviewWindowLocked(const sp<IBinder>& binder, const sp<ANativeWindow>& window); void stopPreviewLocked(); status_t startPreviewLocked(); // Mutex that must be locked before accessing mParams, mParamsFlattened // Mutex that must be locked before accessing mParameters, mParamsFlattened mutable Mutex mParamsLock; String8 mParamsFlattened; // Current camera state; this is the contents of the CameraParameters object Loading Loading @@ -164,16 +172,34 @@ private: /** Camera device-related private members */ // Simple listener that forwards frame available notifications from // a CPU consumer to the capture notification class CaptureWaiter: public CpuConsumer::FrameAvailableListener { public: CaptureWaiter(Camera2Client *parent) : mParent(parent) {} void onFrameAvailable() { mParent->onCaptureAvailable(); } private: Camera2Client *mParent; }; void onCaptureAvailable(); // Number of zoom steps to simulate static const unsigned int NUM_ZOOM_STEPS = 10; // Used with mPreviewStreamId static const int NO_PREVIEW_STREAM = -1; // Used with mPreviewStreamId, mCaptureStreamId static const int NO_STREAM = -1; sp<IBinder> mPreviewSurface; int mPreviewStreamId; camera_metadata_t *mPreviewRequest; int mCaptureStreamId; sp<CpuConsumer> mCaptureConsumer; sp<ANativeWindow> mCaptureWindow; sp<CaptureWaiter> mCaptureWaiter; camera_metadata_t *mCaptureRequest; sp<MemoryHeapBase> mCaptureHeap; sp<MemoryBase> mCaptureMemory; sp<Camera2Device> mDevice; Loading @@ -194,6 +220,11 @@ private: // Update preview request based on mParams status_t updatePreviewRequest(); // Update capture request based on mParams status_t updateCaptureRequest(); // Update capture stream based on mParams status_t updateCaptureStream(); // Convert camera1 preview format string to camera2 enum static int formatStringToEnum(const char *format); static const char *formatEnumToString(int format); Loading
services/camera/libcameraservice/Camera2Device.cpp +81 −18 Original line number Diff line number Diff line Loading @@ -111,8 +111,15 @@ camera_metadata_t *Camera2Device::info() { return mDeviceInfo; } status_t Camera2Device::setStreamingRequest(camera_metadata_t* request) { status_t Camera2Device::capture(camera_metadata_t* request) { ALOGV("%s: E", __FUNCTION__); mRequestQueue.enqueue(request); return OK; } status_t Camera2Device::setStreamingRequest(camera_metadata_t* request) { ALOGV("%s: E", __FUNCTION__); mRequestQueue.setStreamSlot(request); Loading @@ -120,13 +127,13 @@ status_t Camera2Device::setStreamingRequest(camera_metadata_t* request) } status_t Camera2Device::createStream(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format, int *id) { uint32_t width, uint32_t height, int format, size_t size, int *id) { status_t res; ALOGV("%s: E", __FUNCTION__); sp<StreamAdapter> stream = new StreamAdapter(mDevice); res = stream->connectToDevice(consumer, width, height, format); res = stream->connectToDevice(consumer, width, height, format, size); if (res != OK) { ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):" "%s (%d)", Loading @@ -140,6 +147,31 @@ status_t Camera2Device::createStream(sp<ANativeWindow> consumer, return OK; } status_t Camera2Device::getStreamInfo(int id, uint32_t *width, uint32_t *height, uint32_t *format) { ALOGV("%s: E", __FUNCTION__); bool found = false; StreamList::iterator streamI; for (streamI = mStreams.begin(); streamI != mStreams.end(); streamI++) { if ((*streamI)->getId() == id) { found = true; break; } } if (!found) { ALOGE("%s: Camera %d: Stream %d does not exist", __FUNCTION__, mId, id); return BAD_VALUE; } if (width) *width = (*streamI)->getWidth(); if (height) *height = (*streamI)->getHeight(); if (format) *format = (*streamI)->getFormat(); return OK; } status_t Camera2Device::deleteStream(int id) { ALOGV("%s: E", __FUNCTION__); Loading @@ -163,7 +195,29 @@ status_t Camera2Device::deleteStream(int id) { status_t Camera2Device::createDefaultRequest(int templateId, camera_metadata_t **request) { ALOGV("%s: E", __FUNCTION__); return mDevice->ops->construct_default_request(mDevice, templateId, request); return mDevice->ops->construct_default_request( mDevice, templateId, request); } status_t Camera2Device::waitUntilDrained() { static const uint32_t kSleepTime = 50000; // 50 ms static const uint32_t kMaxSleepTime = 10000000; // 10 s if (mRequestQueue.getBufferCount() == CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION; // TODO: Set up notifications from HAL, instead of sleeping here uint32_t totalTime = 0; while (mDevice->ops->get_in_progress_count(mDevice) > 0) { usleep(kSleepTime); totalTime += kSleepTime; if (totalTime > kMaxSleepTime) { ALOGE("%s: Waited %d us, requests still in flight", __FUNCTION__, totalTime); return TIMED_OUT; } } return OK; } /** Loading Loading @@ -463,8 +517,9 @@ Camera2Device::StreamAdapter::~StreamAdapter() { disconnect(); } status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format) { status_t Camera2Device::StreamAdapter::connectToDevice( sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format, size_t size) { status_t res; if (mState != DISCONNECTED) return INVALID_OPERATION; Loading @@ -476,6 +531,7 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume mConsumerInterface = consumer; mWidth = width; mHeight = height; mSize = (format == HAL_PIXEL_FORMAT_BLOB) ? size : 0; mFormatRequested = format; // Allocate device-side stream interface Loading Loading @@ -534,6 +590,16 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume return res; } if (mFormat == HAL_PIXEL_FORMAT_BLOB) { res = native_window_set_buffers_geometry(mConsumerInterface.get(), mSize, 1, mFormat); if (res != OK) { ALOGE("%s: Unable to configure compressed stream buffer geometry" " %d x %d, size %d for stream %d", __FUNCTION__, mWidth, mHeight, mSize, mId); return res; } } else { res = native_window_set_buffers_geometry(mConsumerInterface.get(), mWidth, mHeight, mFormat); if (res != OK) { Loading @@ -542,6 +608,7 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume __FUNCTION__, mWidth, mHeight, mFormat, mId); return res; } } int maxConsumerBuffers; res = mConsumerInterface->query(mConsumerInterface.get(), Loading Loading @@ -641,10 +708,6 @@ status_t Camera2Device::StreamAdapter::disconnect() { return OK; } int Camera2Device::StreamAdapter::getId() { return mId; } const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() { return static_cast<camera2_stream_ops *>(this); } Loading
services/camera/libcameraservice/Camera2Device.h +61 −5 Original line number Diff line number Diff line Loading @@ -37,17 +37,58 @@ class Camera2Device : public virtual RefBase { camera_metadata_t* info(); /** * Submit request for capture. The Camera2Device takes ownership of the * passed-in buffer. */ status_t capture(camera_metadata_t *request); /** * Submit request for streaming. The Camera2Device makes a copy of the * passed-in buffer and the caller retains ownership. */ status_t setStreamingRequest(camera_metadata_t *request); /** * Create an output stream of the requested size and format. * * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects * an appropriate format; it can be queried with getStreamInfo. * * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be * equal to the size in bytes of the buffers to allocate for the stream. For * other formats, the size parameter is ignored. */ status_t createStream(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format, uint32_t width, uint32_t height, int format, size_t size, int *id); /** * Get information about a given stream. */ status_t getStreamInfo(int id, uint32_t *width, uint32_t *height, uint32_t *format); /** * Delete stream. Must not be called if there are requests in flight which * reference that stream. */ status_t deleteStream(int id); /** * Create a metadata buffer with fields that the HAL device believes are * best for the given use case */ status_t createDefaultRequest(int templateId, camera_metadata_t **request); /** * Wait until all requests have been processed. Returns INVALID_OPERATION if * the streaming slot is not empty, or TIMED_OUT if the requests haven't * finished processing in 10 seconds. */ status_t waitUntilDrained(); private: const int mId; Loading Loading @@ -150,13 +191,27 @@ class Camera2Device : public virtual RefBase { ~StreamAdapter(); /** * Create a HAL device stream of the requested size and format. * * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device * selects an appropriate format; it can be queried with getFormat. * * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must * be equal to the size in bytes of the buffers to allocate for the * stream. For other formats, the size parameter is ignored. */ status_t connectToDevice(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format); uint32_t width, uint32_t height, int format, size_t size); status_t disconnect(); // Get stream ID. Only valid after a successful connectToDevice call. int getId(); // Get stream parameters. // Only valid after a successful connectToDevice call. int getId() const { return mId; } uint32_t getWidth() const { return mWidth; } uint32_t getHeight() const { return mHeight; } uint32_t getFormat() const { return mFormat; } private: enum { Loading @@ -174,6 +229,7 @@ class Camera2Device : public virtual RefBase { uint32_t mWidth; uint32_t mHeight; uint32_t mFormat; size_t mSize; uint32_t mUsage; uint32_t mMaxProducerBuffers; uint32_t mMaxConsumerBuffers; Loading