diff options
Diffstat (limited to 'services/camera/libcameraservice/camera2')
5 files changed, 174 insertions, 98 deletions
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp index 5fa84e0..522f49a 100644 --- a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp +++ b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp @@ -74,8 +74,10 @@ status_t CallbackProcessor::updateStream(const Parameters ¶ms) { } if (mCallbackConsumer == 0) { - // Create CPU buffer queue endpoint - mCallbackConsumer = new CpuConsumer(kCallbackHeapCount); + // Create CPU buffer queue endpoint. Make it async to avoid disconnect + // deadlocks. + mCallbackConsumer = new CpuConsumer(kCallbackHeapCount, + /*synchronized*/ false); mCallbackConsumer->setFrameAvailableListener(this); mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer")); mCallbackWindow = new Surface( @@ -133,7 +135,7 @@ status_t CallbackProcessor::updateStream(const Parameters ¶ms) { status_t CallbackProcessor::deleteStream() { ATRACE_CALL(); sp<CameraDeviceBase> device; - + status_t res; { Mutex::Autolock l(mInputMutex); @@ -146,7 +148,19 @@ status_t CallbackProcessor::deleteStream() { return INVALID_OPERATION; } } - device->deleteStream(mCallbackStreamId); + res = device->waitUntilDrained(); + if (res != OK) { + ALOGE("%s: Error waiting for HAL to drain: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } + + res = device->deleteStream(mCallbackStreamId); + if (res != OK) { + ALOGE("%s: Unable to delete callback stream: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } { Mutex::Autolock l(mInputMutex); @@ -214,25 +228,33 @@ status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) { status_t res; sp<Camera2Heap> callbackHeap; - size_t heapIdx; - - CpuConsumer::LockedBuffer imgBuffer; - ALOGV("%s: Getting buffer", __FUNCTION__); - res = mCallbackConsumer->lockNextBuffer(&imgBuffer); - if (res != OK) { - if (res != BAD_VALUE) { - ALOGE("%s: Camera %d: Error receiving next callback buffer: " - "%s (%d)", __FUNCTION__, mId, strerror(-res), res); - } - return res; - } - ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__, - mId); - bool useFlexibleYuv = false; int32_t previewFormat = 0; + size_t heapIdx; + { + /* acquire SharedParameters before mMutex so we don't dead lock + with Camera2Client code calling into StreamingProcessor */ SharedParameters::Lock l(client->getParameters()); + Mutex::Autolock m(mInputMutex); + CpuConsumer::LockedBuffer imgBuffer; + if (mCallbackStreamId == NO_STREAM) { + ALOGV("%s: Camera %d:No stream is available" + , __FUNCTION__, mId); + return INVALID_OPERATION; + } + + ALOGV("%s: Getting buffer", __FUNCTION__); + res = mCallbackConsumer->lockNextBuffer(&imgBuffer); + if (res != OK) { + if (res != BAD_VALUE) { + ALOGE("%s: Camera %d: Error receiving next callback buffer: " + "%s (%d)", __FUNCTION__, mId, strerror(-res), res); + } + return res; + } + ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__, + mId); if ( l.mParameters.state != Parameters::PREVIEW && l.mParameters.state != Parameters::RECORD @@ -279,86 +301,89 @@ status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) { ALOGV("%s: clearing oneshot", __FUNCTION__); l.mParameters.previewCallbackOneShot = false; } - } - uint32_t destYStride = 0; - uint32_t destCStride = 0; - if (useFlexibleYuv) { - if (previewFormat == HAL_PIXEL_FORMAT_YV12) { - // Strides must align to 16 for YV12 - destYStride = ALIGN(imgBuffer.width, 16); - destCStride = ALIGN(destYStride / 2, 16); + uint32_t destYStride = 0; + uint32_t destCStride = 0; + if (useFlexibleYuv) { + if (previewFormat == HAL_PIXEL_FORMAT_YV12) { + // Strides must align to 16 for YV12 + destYStride = ALIGN(imgBuffer.width, 16); + destCStride = ALIGN(destYStride / 2, 16); + } else { + // No padding for NV21 + ALOG_ASSERT(previewFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP, + "Unexpected preview format 0x%x", previewFormat); + destYStride = imgBuffer.width; + destCStride = destYStride / 2; + } } else { - // No padding for NV21 - ALOG_ASSERT(previewFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP, - "Unexpected preview format 0x%x", previewFormat); - destYStride = imgBuffer.width; - destCStride = destYStride / 2; + destYStride = imgBuffer.stride; + // don't care about cStride } - } else { - destYStride = imgBuffer.stride; - // don't care about cStride - } - size_t bufferSize = Camera2Client::calculateBufferSize( - imgBuffer.width, imgBuffer.height, - previewFormat, destYStride); - size_t currentBufferSize = (mCallbackHeap == 0) ? - 0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount); - if (bufferSize != currentBufferSize) { - mCallbackHeap.clear(); - mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount, - "Camera2Client::CallbackHeap"); - if (mCallbackHeap->mHeap->getSize() == 0) { - ALOGE("%s: Camera %d: Unable to allocate memory for callbacks", + size_t bufferSize = Camera2Client::calculateBufferSize( + imgBuffer.width, imgBuffer.height, + previewFormat, destYStride); + size_t currentBufferSize = (mCallbackHeap == 0) ? + 0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount); + if (bufferSize != currentBufferSize) { + mCallbackHeap.clear(); + mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount, + "Camera2Client::CallbackHeap"); + if (mCallbackHeap->mHeap->getSize() == 0) { + ALOGE("%s: Camera %d: Unable to allocate memory for callbacks", + __FUNCTION__, mId); + mCallbackConsumer->unlockBuffer(imgBuffer); + return INVALID_OPERATION; + } + + mCallbackHeapHead = 0; + mCallbackHeapFree = kCallbackHeapCount; + } + + if (mCallbackHeapFree == 0) { + ALOGE("%s: Camera %d: No free callback buffers, dropping frame", __FUNCTION__, mId); mCallbackConsumer->unlockBuffer(imgBuffer); - return INVALID_OPERATION; + return OK; } - mCallbackHeapHead = 0; - mCallbackHeapFree = kCallbackHeapCount; - } + heapIdx = mCallbackHeapHead; - if (mCallbackHeapFree == 0) { - ALOGE("%s: Camera %d: No free callback buffers, dropping frame", - __FUNCTION__, mId); - mCallbackConsumer->unlockBuffer(imgBuffer); - return OK; - } + mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount; + mCallbackHeapFree--; - heapIdx = mCallbackHeapHead; + // TODO: Get rid of this copy by passing the gralloc queue all the way + // to app - mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount; - mCallbackHeapFree--; + ssize_t offset; + size_t size; + sp<IMemoryHeap> heap = + mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset, + &size); + uint8_t *data = (uint8_t*)heap->getBase() + offset; - // TODO: Get rid of this copy by passing the gralloc queue all the way - // to app + if (!useFlexibleYuv) { + // Can just memcpy when HAL format matches API format + memcpy(data, imgBuffer.data, bufferSize); + } else { + res = convertFromFlexibleYuv(previewFormat, data, imgBuffer, + destYStride, destCStride); + if (res != OK) { + ALOGE("%s: Camera %d: Can't convert between 0x%x and 0x%x formats!", + __FUNCTION__, mId, imgBuffer.format, previewFormat); + mCallbackConsumer->unlockBuffer(imgBuffer); + return BAD_VALUE; + } + } - ssize_t offset; - size_t size; - sp<IMemoryHeap> heap = - mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset, - &size); - uint8_t *data = (uint8_t*)heap->getBase() + offset; + ALOGV("%s: Freeing buffer", __FUNCTION__); + mCallbackConsumer->unlockBuffer(imgBuffer); - if (!useFlexibleYuv) { - // Can just memcpy when HAL format matches API format - memcpy(data, imgBuffer.data, bufferSize); - } else { - res = convertFromFlexibleYuv(previewFormat, data, imgBuffer, - destYStride, destCStride); - if (res != OK) { - ALOGE("%s: Camera %d: Can't convert between 0x%x and 0x%x formats!", - __FUNCTION__, mId, imgBuffer.format, previewFormat); - mCallbackConsumer->unlockBuffer(imgBuffer); - return BAD_VALUE; - } + // mCallbackHeap may get freed up once input mutex is released + callbackHeap = mCallbackHeap; } - ALOGV("%s: Freeing buffer", __FUNCTION__); - mCallbackConsumer->unlockBuffer(imgBuffer); - // Call outside parameter lock to allow re-entrancy from notification { Camera2Client::SharedCameraCallbacks::Lock @@ -367,7 +392,7 @@ status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) { ALOGV("%s: Camera %d: Invoking client data callback", __FUNCTION__, mId); l.mRemoteCallback->dataCallback(CAMERA_MSG_PREVIEW_FRAME, - mCallbackHeap->mBuffers[heapIdx], NULL); + callbackHeap->mBuffers[heapIdx], NULL); } } diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp index 266e516..e5a011c 100644 --- a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp +++ b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp @@ -253,6 +253,12 @@ CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp<Camera2Client> &c res = INVALID_OPERATION; break; case Parameters::STILL_CAPTURE: + res = client->getCameraDevice()->waitUntilDrained(); + if (res != OK) { + ALOGE("%s: Camera %d: Can't idle after still capture: " + "%s (%d)", __FUNCTION__, client->getCameraId(), + strerror(-res), res); + } l.mParameters.state = Parameters::STOPPED; break; case Parameters::VIDEO_SNAPSHOT: diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp index f4a9217..fed05a6 100644 --- a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp +++ b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp @@ -41,6 +41,7 @@ StreamingProcessor::StreamingProcessor(sp<Camera2Client> client): mPreviewStreamId(NO_STREAM), mRecordingRequestId(Camera2Client::kRecordingRequestIdStart), mRecordingStreamId(NO_STREAM), + mRecordingFrameAvailable(false), mRecordingHeapCount(kDefaultRecordingHeapCount) { } @@ -536,6 +537,36 @@ status_t StreamingProcessor::incrementStreamingIds() { void StreamingProcessor::onFrameAvailable() { ATRACE_CALL(); + Mutex::Autolock l(mMutex); + if (!mRecordingFrameAvailable) { + mRecordingFrameAvailable = true; + mRecordingFrameAvailableSignal.signal(); + } + +} + +bool StreamingProcessor::threadLoop() { + status_t res; + + { + Mutex::Autolock l(mMutex); + while (!mRecordingFrameAvailable) { + res = mRecordingFrameAvailableSignal.waitRelative( + mMutex, kWaitDuration); + if (res == TIMED_OUT) return true; + } + mRecordingFrameAvailable = false; + } + + do { + res = processRecordingFrame(); + } while (res == OK); + + return true; +} + +status_t StreamingProcessor::processRecordingFrame() { + ATRACE_CALL(); status_t res; sp<Camera2Heap> recordingHeap; size_t heapIdx = 0; @@ -547,12 +578,14 @@ void StreamingProcessor::onFrameAvailable() { BufferItemConsumer::BufferItem imgBuffer; res = mRecordingConsumer->acquireBuffer(&imgBuffer); if (res != OK) { - ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)", - __FUNCTION__, mId, strerror(-res), res); - return; + if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) { + ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + } + return res; } mRecordingConsumer->releaseBuffer(imgBuffer); - return; + return OK; } { @@ -563,23 +596,24 @@ void StreamingProcessor::onFrameAvailable() { BufferItemConsumer::BufferItem imgBuffer; res = mRecordingConsumer->acquireBuffer(&imgBuffer); if (res != OK) { - ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)", - __FUNCTION__, mId, strerror(-res), res); - return; + if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) { + ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + } + return res; } timestamp = imgBuffer.mTimestamp; mRecordingFrameCount++; ALOGV("OnRecordingFrame: Frame %d", mRecordingFrameCount); - // TODO: Signal errors here upstream if (l.mParameters.state != Parameters::RECORD && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) { ALOGV("%s: Camera %d: Discarding recording image buffers " "received after recording done", __FUNCTION__, mId); mRecordingConsumer->releaseBuffer(imgBuffer); - return; + return INVALID_OPERATION; } if (mRecordingHeap == 0) { @@ -594,7 +628,7 @@ void StreamingProcessor::onFrameAvailable() { ALOGE("%s: Camera %d: Unable to allocate memory for recording", __FUNCTION__, mId); mRecordingConsumer->releaseBuffer(imgBuffer); - return; + return NO_MEMORY; } for (size_t i = 0; i < mRecordingBuffers.size(); i++) { if (mRecordingBuffers[i].mBuf != @@ -615,7 +649,7 @@ void StreamingProcessor::onFrameAvailable() { ALOGE("%s: Camera %d: No free recording buffers, dropping frame", __FUNCTION__, mId); mRecordingConsumer->releaseBuffer(imgBuffer); - return; + return NO_MEMORY; } heapIdx = mRecordingHeapHead; @@ -649,6 +683,7 @@ void StreamingProcessor::onFrameAvailable() { CAMERA_MSG_VIDEO_FRAME, recordingHeap->mBuffers[heapIdx]); } + return OK; } void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) { diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.h b/services/camera/libcameraservice/camera2/StreamingProcessor.h index 281b344..9f71fa0 100644 --- a/services/camera/libcameraservice/camera2/StreamingProcessor.h +++ b/services/camera/libcameraservice/camera2/StreamingProcessor.h @@ -37,7 +37,8 @@ class Camera2Heap; /** * Management and processing for preview and recording streams */ -class StreamingProcessor: public BufferItemConsumer::FrameAvailableListener { +class StreamingProcessor: + public Thread, public BufferItemConsumer::FrameAvailableListener { public: StreamingProcessor(sp<Camera2Client> client); ~StreamingProcessor(); @@ -103,6 +104,8 @@ class StreamingProcessor: public BufferItemConsumer::FrameAvailableListener { sp<ANativeWindow> mPreviewWindow; // Recording-related members + static const nsecs_t kWaitDuration = 50000000; // 50 ms + int32_t mRecordingRequestId; int mRecordingStreamId; int mRecordingFrameCount; @@ -111,11 +114,17 @@ class StreamingProcessor: public BufferItemConsumer::FrameAvailableListener { CameraMetadata mRecordingRequest; sp<camera2::Camera2Heap> mRecordingHeap; + bool mRecordingFrameAvailable; + Condition mRecordingFrameAvailableSignal; + static const size_t kDefaultRecordingHeapCount = 8; size_t mRecordingHeapCount; Vector<BufferItemConsumer::BufferItem> mRecordingBuffers; size_t mRecordingHeapHead, mRecordingHeapFree; + virtual bool threadLoop(); + + status_t processRecordingFrame(); }; diff --git a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp index 2e06691..40c77df 100644 --- a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp +++ b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp @@ -329,8 +329,9 @@ void ZslProcessor3::dump(int fd, const Vector<String16>& /*args*/) const { } bool ZslProcessor3::threadLoop() { - // TODO: remove dependency on thread - return true; + // TODO: remove dependency on thread. For now, shut thread down right + // away. + return false; } void ZslProcessor3::dumpZslQueue(int fd) const { |