From 9cca4c6d976d2d4127286e9eaa54d1b99880c25c Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 15 Jun 2012 15:41:44 -0700 Subject: Camera2: Add recording support - Support startRecording/stopRecording - Support lock/unlock/connect - Some rearrangement of class definitions for clarity/consistency Bug: 6243944 Change-Id: I00c600a798572d2f69bb3f2bab3d79e4bd9a91e5 --- services/camera/libcameraservice/Camera2Client.cpp | 404 +++++++++++++++++++-- services/camera/libcameraservice/Camera2Client.h | 114 ++++-- services/camera/libcameraservice/Camera2Device.cpp | 30 +- services/camera/libcameraservice/Camera2Device.h | 4 +- 4 files changed, 487 insertions(+), 65 deletions(-) diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index c90f81a..8d4add4 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -55,7 +55,9 @@ Camera2Client::Camera2Client(const sp& cameraService, mPreviewStreamId(NO_STREAM), mPreviewRequest(NULL), mCaptureStreamId(NO_STREAM), - mCaptureRequest(NULL) + mCaptureRequest(NULL), + mRecordingStreamId(NO_STREAM), + mRecordingRequest(NULL) { ATRACE_CALL(); @@ -341,23 +343,59 @@ void Camera2Client::disconnect() { status_t Camera2Client::connect(const sp& client) { ATRACE_CALL(); + Mutex::Autolock icl(mICameraLock); - return BAD_VALUE; + if (mClientPid != 0 && getCallingPid() != mClientPid) { + ALOGE("%s: Camera %d: Connection attempt from pid %d; " + "current locked to pid %d", __FUNCTION__, + mCameraId, getCallingPid(), mClientPid); + return BAD_VALUE; + } + + mClientPid = getCallingPid(); + mCameraClient = client; + + return OK; } status_t Camera2Client::lock() { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); + ALOGV("%s: Camera %d: Lock call from pid %d; current client pid %d", + __FUNCTION__, mCameraId, getCallingPid(), mClientPid); - return BAD_VALUE; + if (mClientPid == 0) { + mClientPid = getCallingPid(); + return OK; + } + + if (mClientPid != getCallingPid()) { + ALOGE("%s: Camera %d: Lock call from pid %d; currently locked to pid %d", + __FUNCTION__, mCameraId, getCallingPid(), mClientPid); + return EBUSY; + } + + return OK; } status_t Camera2Client::unlock() { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); + ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d", + __FUNCTION__, mCameraId, getCallingPid(), mClientPid); - return BAD_VALUE; + // TODO: Check for uninterruptable conditions + + if (mClientPid == getCallingPid()) { + mClientPid = 0; + mCameraClient.clear(); + return OK; + } + + ALOGE("%s: Camera %d: Unlock call from pid %d; currently locked to pid %d", + __FUNCTION__, mCameraId, getCallingPid(), mClientPid); + return EBUSY; } status_t Camera2Client::setPreviewDisplay( @@ -365,8 +403,6 @@ status_t Camera2Client::setPreviewDisplay( ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); - if (mState >= PREVIEW) return INVALID_OPERATION; - sp binder; sp window; if (surface != 0) { @@ -382,8 +418,6 @@ status_t Camera2Client::setPreviewTexture( ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); - if (mState >= PREVIEW) return INVALID_OPERATION; - sp binder; sp window; if (surfaceTexture != 0) { @@ -402,6 +436,27 @@ status_t Camera2Client::setPreviewWindowLocked(const sp& binder, return NO_ERROR; } + switch (mState) { + case NOT_INITIALIZED: + case RECORD: + case STILL_CAPTURE: + case VIDEO_SNAPSHOT: + ALOGE("%s: Camera %d: Cannot set preview display while in state %s", + __FUNCTION__, mCameraId, getStateName(mState)); + return INVALID_OPERATION; + case STOPPED: + case WAITING_FOR_PREVIEW_WINDOW: + // OK + break; + case PREVIEW: + // Already running preview - need to stop and create a new stream + // TODO: Optimize this so that we don't wait for old stream to drain + // before spinning up new stream + mDevice->setStreamingRequest(NULL); + mState = WAITING_FOR_PREVIEW_WINDOW; + break; + } + if (mPreviewStreamId != NO_STREAM) { res = mDevice->waitUntilDrained(); if (res != OK) { @@ -454,6 +509,8 @@ status_t Camera2Client::startPreviewLocked() { } mState = STOPPED; + Mutex::Autolock pl(mParamsLock); + res = updatePreviewStream(); if (res != OK) { ALOGE("%s: Camera %d: Unable to update preview stream: %s (%d)", @@ -544,23 +601,125 @@ status_t Camera2Client::storeMetaDataInBuffers(bool enabled) { status_t Camera2Client::startRecording() { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); - return BAD_VALUE; + status_t res; + switch (mState) { + case STOPPED: + res = startPreviewLocked(); + if (res != OK) return res; + break; + case PREVIEW: + // Ready to go + break; + case RECORD: + case VIDEO_SNAPSHOT: + // OK to call this when recording is already on + return OK; + break; + default: + ALOGE("%s: Camera %d: Can't start recording in state %s", + __FUNCTION__, mCameraId, getStateName(mState)); + return INVALID_OPERATION; + }; + + Mutex::Autolock pl(mParamsLock); + + res = updateRecordingStream(); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + + if (mRecordingRequest == NULL) { + res = updateRecordingRequest(); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to create recording request: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + } + + uint8_t outputStreams[2] = { mPreviewStreamId, mRecordingStreamId }; + res = updateEntry(mRecordingRequest, + ANDROID_REQUEST_OUTPUT_STREAMS, + outputStreams, 2); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to set up recording request: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + res = sort_camera_metadata(mRecordingRequest); + if (res != OK) { + ALOGE("%s: Camera %d: Error sorting recording request: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + + res = mDevice->setStreamingRequest(mRecordingRequest); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to set recording request to start " + "recording: %s (%d)", __FUNCTION__, mCameraId, + strerror(-res), res); + return res; + } + mState = RECORD; + + return OK; } void Camera2Client::stopRecording() { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); + status_t res; + switch (mState) { + case RECORD: + // OK to stop + break; + case STOPPED: + case PREVIEW: + case STILL_CAPTURE: + case VIDEO_SNAPSHOT: + default: + ALOGE("%s: Camera %d: Can't stop recording in state %s", + __FUNCTION__, mCameraId, getStateName(mState)); + return; + }; + + // Back to preview. Since record can only be reached through preview, + // all preview stream setup should be up to date. + res = mDevice->setStreamingRequest(mPreviewRequest); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to switch back to preview request: " + "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); + return; + } + + // TODO: Should recording heap be freed? Can't do it yet since requests + // could still be in flight. + + mState = PREVIEW; } bool Camera2Client::recordingEnabled() { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); - return BAD_VALUE; + return (mState == RECORD || mState == VIDEO_SNAPSHOT); } void Camera2Client::releaseRecordingFrame(const sp& mem) { ATRACE_CALL(); Mutex::Autolock icl(mICameraLock); + // Make sure this is for the current heap + ssize_t offset; + size_t size; + sp heap = mem->getMemory(&offset, &size); + if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) { + ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release " + "(got %x, expected %x)", __FUNCTION__, mCameraId, + heap->getHeapID(), mRecordingHeap->mHeap->getHeapID()); + return; + } + mRecordingHeapFree++; } status_t Camera2Client::autoFocus() { @@ -616,11 +775,18 @@ status_t Camera2Client::takePicture(int msgType) { } } - // TODO: For video snapshot, will need 3 streams here camera_metadata_entry_t outputStreams; - uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId }; - res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS, - &streamIds, 2); + if (mState == PREVIEW) { + uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId }; + res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS, + &streamIds, 2); + } else if (mState == RECORD) { + uint8_t streamIds[3] = { mPreviewStreamId, mRecordingStreamId, + mCaptureStreamId }; + res = updateEntry(mCaptureRequest, ANDROID_REQUEST_OUTPUT_STREAMS, + &streamIds, 3); + } + if (res != OK) { ALOGE("%s: Camera %d: Unable to set up still image capture request: " "%s (%d)", @@ -650,7 +816,7 @@ status_t Camera2Client::takePicture(int msgType) { return res; } } - + // TODO: Capture should be atomic with setStreamingRequest here res = mDevice->capture(captureCopy); if (res != OK) { ALOGE("%s: Camera %d: Unable to submit still image capture request: " @@ -699,7 +865,10 @@ status_t Camera2Client::setParameters(const String8& params) { previewHeight != mParameters.previewHeight) { if (mState >= PREVIEW) { ALOGE("%s: Preview size cannot be updated when preview " - "is active!", __FUNCTION__); + "is active! (Currently %d x %d, requested %d x %d", + __FUNCTION__, + mParameters.previewWidth, mParameters.previewHeight, + previewWidth, previewHeight); return BAD_VALUE; } camera_metadata_entry_t availablePreviewSizes = @@ -1127,6 +1296,7 @@ status_t Camera2Client::setParameters(const String8& params) { } /** Update internal parameters */ + mParameters.previewWidth = previewWidth; mParameters.previewHeight = previewHeight; mParameters.previewFpsRange[0] = previewFpsRange[0]; @@ -1183,6 +1353,13 @@ status_t Camera2Client::setParameters(const String8& params) { return res; } + res = updateRecordingRequest(); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + if (mState == PREVIEW) { res = mDevice->setStreamingRequest(mPreviewRequest); if (res != OK) { @@ -1190,8 +1367,17 @@ status_t Camera2Client::setParameters(const String8& params) { __FUNCTION__, mCameraId, strerror(-res), res); return res; } + } else if (mState == RECORD || mState == VIDEO_SNAPSHOT) { + res = mDevice->setStreamingRequest(mRecordingRequest); + if (res != OK) { + ALOGE("%s: Camera %d: Error streaming new record request: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } } + mParamsFlattened = params; + return OK; } @@ -1240,6 +1426,8 @@ void Camera2Client::onCaptureAvailable() { ATRACE_CALL(); status_t res; sp currentClient; + ALOGV("%s: Camera %d: Still capture available", __FUNCTION__, mCameraId); + CpuConsumer::LockedBuffer imgBuffer; { Mutex::Autolock icl(mICameraLock); @@ -1268,8 +1456,8 @@ void Camera2Client::onCaptureAvailable() { } // TODO: Optimize this to avoid memcopy - void* captureMemory = mCaptureHeap->getBase(); - size_t size = mCaptureHeap->getSize(); + void* captureMemory = mCaptureHeap->mHeap->getBase(); + size_t size = mCaptureHeap->mHeap->getSize(); memcpy(captureMemory, imgBuffer.data, size); mCaptureConsumer->unlockBuffer(imgBuffer); @@ -1291,7 +1479,100 @@ void Camera2Client::onCaptureAvailable() { // Call outside mICameraLock to allow re-entrancy from notification if (currentClient != 0) { currentClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, - mCaptureMemory, NULL); + mCaptureHeap->mBuffers[0], NULL); + } +} + +void Camera2Client::onRecordingFrameAvailable() { + ATRACE_CALL(); + status_t res; + sp currentClient; + size_t heapIdx = 0; + nsecs_t timestamp; + { + Mutex::Autolock icl(mICameraLock); + // TODO: Signal errors here upstream + if (mState != RECORD && mState != VIDEO_SNAPSHOT) { + ALOGE("%s: Camera %d: Recording image buffer produced unexpectedly!", + __FUNCTION__, mCameraId); + return; + } + + CpuConsumer::LockedBuffer imgBuffer; + res = mRecordingConsumer->lockNextBuffer(&imgBuffer); + if (res != OK) { + ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return; + } + + if (imgBuffer.format != (int)kRecordingFormat) { + ALOGE("%s: Camera %d: Unexpected recording format: %x", + __FUNCTION__, mCameraId, imgBuffer.format); + mRecordingConsumer->unlockBuffer(imgBuffer); + return; + } + size_t bufferSize = imgBuffer.width * imgBuffer.height * 3 / 2; + + if (mRecordingHeap == 0 || + bufferSize > + mRecordingHeap->mHeap->getSize() / kRecordingHeapCount) { + ALOGV("%s: Camera %d: Creating recording heap with %d buffers of " + "size %d bytes", __FUNCTION__, mCameraId, + kRecordingHeapCount, bufferSize); + if (mRecordingHeap != 0) { + ALOGV("%s: Camera %d: Previous heap has size %d " + "(new will be %d) bytes", __FUNCTION__, mCameraId, + mRecordingHeap->mHeap->getSize(), + bufferSize * kRecordingHeapCount); + } + // Need to allocate memory for heap + mRecordingHeap.clear(); + + mRecordingHeap = new Camera2Heap(bufferSize, kRecordingHeapCount, + "Camera2Client::RecordingHeap"); + if (mRecordingHeap->mHeap->getSize() == 0) { + ALOGE("%s: Camera %d: Unable to allocate memory for recording", + __FUNCTION__, mCameraId); + mRecordingConsumer->unlockBuffer(imgBuffer); + return; + } + mRecordingHeapHead = 0; + mRecordingHeapFree = kRecordingHeapCount; + } + + // TODO: Optimize this to avoid memcopy + if ( mRecordingHeapFree == 0) { + ALOGE("%s: Camera %d: No free recording buffers, dropping frame", + __FUNCTION__, mCameraId); + mRecordingConsumer->unlockBuffer(imgBuffer); + return; + } + heapIdx = mRecordingHeapHead; + timestamp = imgBuffer.timestamp; + mRecordingHeapHead = (mRecordingHeapHead + 1) % kRecordingHeapCount; + mRecordingHeapFree--; + + ALOGV("%s: Camera %d: Timestamp %lld", + __FUNCTION__, mCameraId, timestamp); + + ssize_t offset; + size_t size; + sp heap = + mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset, + &size); + + memcpy((uint8_t*)heap->getBase() + offset, imgBuffer.data, size); + + mRecordingConsumer->unlockBuffer(imgBuffer); + + currentClient = mCameraClient; + } + // Call outside mICameraLock to allow re-entrancy from notification + if (currentClient != 0) { + currentClient->dataCallbackTimestamp(timestamp, + CAMERA_MSG_VIDEO_FRAME, + mRecordingHeap->mBuffers[heapIdx]); } } @@ -1999,7 +2280,7 @@ status_t Camera2Client::buildDefaultParameters() { 0); params.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, - formatEnumToString(HAL_PIXEL_FORMAT_YCrCb_420_SP)); + formatEnumToString(kRecordingFormat)); params.set(CameraParameters::KEY_RECORDING_HINT, CameraParameters::FALSE); @@ -2126,15 +2407,13 @@ status_t Camera2Client::updateCaptureStream() { mCaptureWindow = new SurfaceTextureClient( mCaptureConsumer->getProducerInterface()); // Create memory for API consumption - mCaptureHeap = new MemoryHeapBase(maxJpegSize.data.i32[0], 0, - "Camera2Client::CaptureHeap"); - if (mCaptureHeap->getSize() == 0) { + mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1, + "Camera2Client::CaptureHeap"); + if (mCaptureHeap->mHeap->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) { @@ -2243,6 +2522,81 @@ status_t Camera2Client::updateCaptureRequest() { return OK; } +status_t Camera2Client::updateRecordingRequest() { + ATRACE_CALL(); + status_t res; + if (mRecordingRequest == NULL) { + res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_VIDEO_RECORD, + &mRecordingRequest); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to create default recording request:" + " %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + } + + res = updateRequestCommon(mRecordingRequest); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to update common entries of recording " + "request: %s (%d)", __FUNCTION__, mCameraId, + strerror(-res), res); + return res; + } + + return OK; +} + +status_t Camera2Client::updateRecordingStream() { + status_t res; + + if (mRecordingConsumer == 0) { + // Create CPU buffer queue endpoint + mRecordingConsumer = new CpuConsumer(1); + mRecordingConsumer->setFrameAvailableListener(new RecordingWaiter(this)); + mRecordingConsumer->setName(String8("Camera2Client::RecordingConsumer")); + mRecordingWindow = new SurfaceTextureClient( + mRecordingConsumer->getProducerInterface()); + // Allocate memory later, since we don't know buffer size until receipt + } + + if (mRecordingStreamId != NO_STREAM) { + // Check if stream parameters have to change + uint32_t currentWidth, currentHeight; + res = mDevice->getStreamInfo(mRecordingStreamId, + ¤tWidth, ¤tHeight, 0); + if (res != OK) { + ALOGE("%s: Camera %d: Error querying recording output stream info: " + "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + if (currentWidth != (uint32_t)mParameters.videoWidth || + currentHeight != (uint32_t)mParameters.videoHeight) { + // TODO: Should wait to be sure previous recording has finished + res = mDevice->deleteStream(mRecordingStreamId); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to delete old output stream " + "for recording: %s (%d)", __FUNCTION__, mCameraId, + strerror(-res), res); + return res; + } + mRecordingStreamId = NO_STREAM; + } + } + + if (mRecordingStreamId == NO_STREAM) { + res = mDevice->createStream(mRecordingWindow, + mParameters.videoWidth, mParameters.videoHeight, + kRecordingFormat, 0, &mRecordingStreamId); + if (res != OK) { + ALOGE("%s: Camera %d: Can't create output stream for recording: " + "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + } + + return OK; +} + status_t Camera2Client::updateRequestCommon(camera_metadata_t *request) { ATRACE_CALL(); status_t res; diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h index 2dc02bc..8d410f1 100644 --- a/services/camera/libcameraservice/Camera2Client.h +++ b/services/camera/libcameraservice/Camera2Client.h @@ -174,39 +174,109 @@ 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(); + class Camera2Heap; // Number of zoom steps to simulate static const unsigned int NUM_ZOOM_STEPS = 10; - // Used with mPreviewStreamId, mCaptureStreamId + // Used with stream IDs static const int NO_STREAM = -1; - sp mPreviewSurface; - sp mPreviewWindow; + /* Preview related members */ int mPreviewStreamId; camera_metadata_t *mPreviewRequest; + sp mPreviewSurface; + sp mPreviewWindow; + // Update preview request based on mParameters + status_t updatePreviewRequest(); + // Update preview stream based on mParameters + status_t updatePreviewStream(); + + /* Still image capture related members */ int mCaptureStreamId; sp mCaptureConsumer; sp mCaptureWindow; + // 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; + }; sp mCaptureWaiter; camera_metadata_t *mCaptureRequest; - sp mCaptureHeap; - sp mCaptureMemory; + sp mCaptureHeap; + // Handle captured image buffers + void onCaptureAvailable(); + // Update capture request based on mParameters + status_t updateCaptureRequest(); + // Update capture stream based on mParameters + status_t updateCaptureStream(); + + /* Recording related members */ + + int mRecordingStreamId; + sp mRecordingConsumer; + sp mRecordingWindow; + // Simple listener that forwards frame available notifications from + // a CPU consumer to the recording notification + class RecordingWaiter: public CpuConsumer::FrameAvailableListener { + public: + RecordingWaiter(Camera2Client *parent) : mParent(parent) {} + void onFrameAvailable() { mParent->onRecordingFrameAvailable(); } + private: + Camera2Client *mParent; + }; + sp mRecordingWaiter; + camera_metadata_t *mRecordingRequest; + sp mRecordingHeap; + + // TODO: This needs to be queried from somewhere, or the BufferQueue needs + // to be passed all the way to stagefright + static const size_t kRecordingHeapCount = 4; + static const uint32_t kRecordingFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; + size_t mRecordingHeapHead, mRecordingHeapFree; + // Handle new recording image buffers + void onRecordingFrameAvailable(); + // Update recording request based on mParameters + status_t updateRecordingRequest(); + // Update recording stream based on mParameters + status_t updateRecordingStream(); + + /** Camera2Device instance wrapping HAL2 entry */ sp mDevice; + /** Utility members */ + + // Utility class for managing a set of IMemory blocks + class Camera2Heap : public RefBase { + public: + Camera2Heap(size_t buf_size, uint_t num_buffers = 1, + const char *name = NULL) : + mBufSize(buf_size), + mNumBufs(num_buffers) { + mHeap = new MemoryHeapBase(buf_size * num_buffers, 0, name); + mBuffers = new sp[mNumBufs]; + for (uint_t i = 0; i < mNumBufs; i++) + mBuffers[i] = new MemoryBase(mHeap, + i * mBufSize, + mBufSize); + } + + virtual ~Camera2Heap() + { + delete [] mBuffers; + } + + size_t mBufSize; + uint_t mNumBufs; + sp mHeap; + sp *mBuffers; + }; // Get values for static camera info entry. min/maxCount are used for error // checking the number of values in the entry. 0 for max/minCount means to @@ -215,22 +285,10 @@ private: camera_metadata_entry_t staticInfo(uint32_t tag, size_t minCount=0, size_t maxCount=0); - /** Utility methods */ - // Convert static camera info from a camera2 device to the // old API parameter map. status_t buildDefaultParameters(); - // Update preview request based on mParameters - status_t updatePreviewRequest(); - // Update preview stream based on mParameters - status_t updatePreviewStream(); - - // Update capture request based on mParameters - status_t updateCaptureRequest(); - // Update capture stream based on mParameters - status_t updateCaptureStream(); - // Update parameters all requests use, based on mParameters status_t updateRequestCommon(camera_metadata_t *request); diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp index 8d07eee..54dde80 100644 --- a/services/camera/libcameraservice/Camera2Device.cpp +++ b/services/camera/libcameraservice/Camera2Device.cpp @@ -239,9 +239,9 @@ status_t Camera2Device::deleteStream(int id) { for (StreamList::iterator streamI = mStreams.begin(); streamI != mStreams.end(); streamI++) { if ((*streamI)->getId() == id) { - status_t res = (*streamI)->disconnect(); + status_t res = (*streamI)->release(); if (res != OK) { - ALOGE("%s: Unable to disconnect stream %d from HAL device: " + ALOGE("%s: Unable to release stream %d from HAL device: " "%s (%d)", __FUNCTION__, id, strerror(-res), res); return res; } @@ -615,7 +615,7 @@ int Camera2Device::MetadataQueue::producer_enqueue( #endif Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d): - mState(DISCONNECTED), + mState(RELEASED), mDevice(d), mId(-1), mWidth(0), mHeight(0), mFormat(0), mSize(0), mUsage(0), @@ -633,7 +633,9 @@ Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d): } Camera2Device::StreamAdapter::~StreamAdapter() { - disconnect(); + if (mState != RELEASED) { + release(); + } } status_t Camera2Device::StreamAdapter::connectToDevice( @@ -641,12 +643,15 @@ status_t Camera2Device::StreamAdapter::connectToDevice( uint32_t width, uint32_t height, int format, size_t size) { status_t res; - if (mState != DISCONNECTED) return INVALID_OPERATION; + if (mState != RELEASED) return INVALID_OPERATION; if (consumer == NULL) { ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__); return BAD_VALUE; } + ALOGV("%s: New stream parameters %d x %d, format 0x%x, size %d", + __FUNCTION__, width, height, format, size); + mConsumerInterface = consumer; mWidth = width; mHeight = height; @@ -668,6 +673,10 @@ status_t Camera2Device::StreamAdapter::connectToDevice( return res; } + ALOGV("%s: Allocated stream id %d, actual format 0x%x, " + "usage 0x%x, producer wants %d buffers", __FUNCTION__, + id, formatActual, usage, maxBuffers); + mId = id; mFormat = formatActual; mUsage = usage; @@ -737,8 +746,8 @@ status_t Camera2Device::StreamAdapter::connectToDevice( } mMaxConsumerBuffers = maxConsumerBuffers; - ALOGV("%s: Producer wants %d buffers, consumer wants %d", __FUNCTION__, - mMaxProducerBuffers, mMaxConsumerBuffers); + ALOGV("%s: Consumer wants %d buffers", __FUNCTION__, + mMaxConsumerBuffers); mTotalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers; mActiveBuffers = 0; @@ -761,7 +770,7 @@ status_t Camera2Device::StreamAdapter::connectToDevice( res = native_window_dequeue_buffer_and_wait(mConsumerInterface.get(), &anwBuffers[bufferIdx]); if (res != OK) { - ALOGE("%s: Unable to dequeue buffer %d for initial registration for" + ALOGE("%s: Unable to dequeue buffer %d for initial registration for " "stream %d", __FUNCTION__, bufferIdx, mId); goto cleanUpBuffers; } @@ -795,8 +804,9 @@ cleanUpBuffers: return res; } -status_t Camera2Device::StreamAdapter::disconnect() { +status_t Camera2Device::StreamAdapter::release() { status_t res; + ALOGV("%s: Releasing stream %d", __FUNCTION__, mId); if (mState >= ALLOCATED) { res = mDevice->ops->release_stream(mDevice, mId); if (res != OK) { @@ -815,7 +825,7 @@ status_t Camera2Device::StreamAdapter::disconnect() { } } mId = -1; - mState = DISCONNECTED; + mState = RELEASED; return OK; } diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h index 1116be0..4ac63df 100644 --- a/services/camera/libcameraservice/Camera2Device.h +++ b/services/camera/libcameraservice/Camera2Device.h @@ -219,7 +219,7 @@ class Camera2Device : public virtual RefBase { status_t connectToDevice(sp consumer, uint32_t width, uint32_t height, int format, size_t size); - status_t disconnect(); + status_t release(); status_t setTransform(int transform); @@ -236,7 +236,7 @@ class Camera2Device : public virtual RefBase { private: enum { ERROR = -1, - DISCONNECTED = 0, + RELEASED = 0, ALLOCATED, CONNECTED, ACTIVE -- cgit v1.1