summaryrefslogtreecommitdiffstats
path: root/services/camera/libcameraservice/camera2
diff options
context:
space:
mode:
Diffstat (limited to 'services/camera/libcameraservice/camera2')
-rw-r--r--services/camera/libcameraservice/camera2/CallbackProcessor.cpp193
-rw-r--r--services/camera/libcameraservice/camera2/CaptureSequencer.cpp6
-rw-r--r--services/camera/libcameraservice/camera2/StreamingProcessor.cpp57
-rw-r--r--services/camera/libcameraservice/camera2/StreamingProcessor.h11
-rw-r--r--services/camera/libcameraservice/camera2/ZslProcessor3.cpp5
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 &params) {
}
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 &params) {
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 {