diff options
author | Igor Murashkin <iam@google.com> | 2013-05-13 14:53:44 -0700 |
---|---|---|
committer | Igor Murashkin <iam@google.com> | 2013-05-13 18:21:41 -0700 |
commit | 5282713a976184e41451315f1286d8075b257d58 (patch) | |
tree | d6d3484980644d1d66d00aba3f2113e3c70cddf6 /services/camera | |
parent | 8dbaa56a9de51d506977bda112f75b8af50920e9 (diff) | |
download | frameworks_av-5282713a976184e41451315f1286d8075b257d58.zip frameworks_av-5282713a976184e41451315f1286d8075b257d58.tar.gz frameworks_av-5282713a976184e41451315f1286d8075b257d58.tar.bz2 |
Camera: Pause preview when needing to delete jpeg/zsl streams
Bug: 8876221
Change-Id: Idf9490a48462fa44d49c4ebe99425c3149ae6378
Diffstat (limited to 'services/camera')
7 files changed, 126 insertions, 9 deletions
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index 48f3606..2e01dae 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -690,7 +690,7 @@ status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart) { outputStreams.push(getCallbackStreamId()); } if (params.zslMode && !params.recordingHint) { - res = mZslProcessor->updateStream(params); + res = updateProcessorStream(mZslProcessor, params); if (res != OK) { ALOGE("%s: Camera %d: Unable to update ZSL stream: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); @@ -718,7 +718,7 @@ status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart) { // assumption that the user will record video. To optimize recording // startup time, create the necessary output streams for recording and // video snapshot now if they don't already exist. - res = mJpegProcessor->updateStream(params); + res = updateProcessorStream(mJpegProcessor, params); if (res != OK) { ALOGE("%s: Camera %d: Can't pre-configure still image " "stream: %s (%d)", @@ -1125,7 +1125,7 @@ status_t Camera2Client::takePicture(int msgType) { ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId); - res = mJpegProcessor->updateStream(l.mParameters); + res = updateProcessorStream(mJpegProcessor, l.mParameters); if (res != OK) { ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); @@ -1605,5 +1605,47 @@ status_t Camera2Client::syncWithDevice() { return res; } +template <typename ProcessorT> +status_t Camera2Client::updateProcessorStream(sp<ProcessorT> processor, + camera2::Parameters params) { + status_t res; + + res = processor->updateStream(params); + + /** + * Can't update the stream if it's busy? + * + * Then we need to stop the device (by temporarily clearing the request + * queue) and then try again. Resume streaming once we're done. + */ + if (res == -EBUSY) { + res = mStreamingProcessor->togglePauseStream(/*pause*/true); + if (res != OK) { + ALOGE("%s: Camera %d: Can't pause streaming: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + } + + res = mDevice->waitUntilDrained(); + if (res != OK) { + ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + } + + res = processor->updateStream(params); + if (res != OK) { + ALOGE("%s: Camera %d: Failed to update processing stream " + " despite having halted streaming first: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + } + + res = mStreamingProcessor->togglePauseStream(/*pause*/false); + if (res != OK) { + ALOGE("%s: Camera %d: Can't unpause streaming: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + } + } + + return res; +} } // namespace android diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h index af72ab2..f42d022 100644 --- a/services/camera/libcameraservice/Camera2Client.h +++ b/services/camera/libcameraservice/Camera2Client.h @@ -159,6 +159,9 @@ private: // Used with stream IDs static const int NO_STREAM = -1; + template <typename ProcessorT> + status_t updateProcessorStream(sp<ProcessorT> processor, Parameters params); + sp<camera2::FrameProcessor> mFrameProcessor; /* Preview/Recording related members */ diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp index 5e5bfc2..6f4f4c8 100644 --- a/services/camera/libcameraservice/Camera3Device.cpp +++ b/services/camera/libcameraservice/Camera3Device.cpp @@ -680,8 +680,8 @@ status_t Camera3Device::deleteStream(int id) { // CameraDevice semantics require device to already be idle before // deleteStream is called, unlike for createStream. if (mStatus != STATUS_IDLE) { - CLOGE("Device not idle"); - return INVALID_OPERATION; + ALOGV("%s: Camera %d: Device not idle", __FUNCTION__, mId); + return -EBUSY; } sp<Camera3StreamInterface> deletedStream; diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.cpp b/services/camera/libcameraservice/camera2/JpegProcessor.cpp index 01d7f9c..f0a13ca 100644 --- a/services/camera/libcameraservice/camera2/JpegProcessor.cpp +++ b/services/camera/libcameraservice/camera2/JpegProcessor.cpp @@ -113,7 +113,11 @@ status_t JpegProcessor::updateStream(const Parameters ¶ms) { ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed", __FUNCTION__, mId, mCaptureStreamId); res = device->deleteStream(mCaptureStreamId); - if (res != OK) { + if (res == -EBUSY) { + ALOGV("%s: Camera %d: Device is busy, call updateStream again " + " after it becomes idle", __FUNCTION__, mId); + return res; + } else if (res != OK) { ALOGE("%s: Camera %d: Unable to delete old output stream " "for capture: %s (%d)", __FUNCTION__, mId, strerror(-res), res); diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp index c36cf87..ab83714 100644 --- a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp +++ b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp @@ -36,6 +36,7 @@ StreamingProcessor::StreamingProcessor(sp<Camera2Client> client): mDevice(client->getCameraDevice()), mId(client->getCameraId()), mActiveRequest(NONE), + mPaused(false), mPreviewRequestId(Camera2Client::kPreviewRequestIdStart), mPreviewStreamId(NO_STREAM), mRecordingRequestId(Camera2Client::kRecordingRequestIdStart), @@ -419,10 +420,59 @@ status_t StreamingProcessor::startStream(StreamType type, return res; } mActiveRequest = type; + mPaused = false; return OK; } +status_t StreamingProcessor::togglePauseStream(bool pause) { + ATRACE_CALL(); + status_t res; + + sp<CameraDeviceBase> device = mDevice.promote(); + if (device == 0) { + ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); + return INVALID_OPERATION; + } + + ALOGV("%s: Camera %d: toggling pause to %d", __FUNCTION__, mId, pause); + + Mutex::Autolock m(mMutex); + + if (mActiveRequest == NONE) { + ALOGE("%s: Camera %d: Can't toggle pause, streaming was not started", + __FUNCTION__, mId); + return INVALID_OPERATION; + } + + if (mPaused == pause) { + return OK; + } + + if (pause) { + res = device->clearStreamingRequest(); + if (res != OK) { + ALOGE("%s: Camera %d: Can't clear stream request: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + return res; + } + } else { + CameraMetadata &request = + (mActiveRequest == PREVIEW) ? mPreviewRequest + : mRecordingRequest; + res = device->setStreamingRequest(request); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to set preview request to resume: " + "%s (%d)", + __FUNCTION__, mId, strerror(-res), res); + return res; + } + } + + mPaused = pause; + return OK; +} + status_t StreamingProcessor::stopStream() { ATRACE_CALL(); status_t res; @@ -443,6 +493,7 @@ status_t StreamingProcessor::stopStream() { } mActiveRequest = NONE; + mPaused = false; return OK; } @@ -662,20 +713,29 @@ status_t StreamingProcessor::dump(int fd, const Vector<String16>& /*args*/) { result.append(" Preview request:\n"); write(fd, result.string(), result.size()); mPreviewRequest.dump(fd, 2, 6); + result.clear(); } else { result.append(" Preview request: undefined\n"); - write(fd, result.string(), result.size()); } if (mRecordingRequest.entryCount() != 0) { result = " Recording request:\n"; write(fd, result.string(), result.size()); mRecordingRequest.dump(fd, 2, 6); + result.clear(); } else { result = " Recording request: undefined\n"; - write(fd, result.string(), result.size()); } + const char* streamTypeString[] = { + "none", "preview", "record" + }; + result.append(String8::format(" Active request: %s (paused: %s)\n", + streamTypeString[mActiveRequest], + mPaused ? "yes" : "no")); + + write(fd, result.string(), result.size()); + return OK; } diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.h b/services/camera/libcameraservice/camera2/StreamingProcessor.h index 643114e..281b344 100644 --- a/services/camera/libcameraservice/camera2/StreamingProcessor.h +++ b/services/camera/libcameraservice/camera2/StreamingProcessor.h @@ -65,6 +65,9 @@ class StreamingProcessor: public BufferItemConsumer::FrameAvailableListener { status_t startStream(StreamType type, const Vector<uint8_t> &outputStreams); + // Toggle between paused and unpaused. Stream must be started first. + status_t togglePauseStream(bool pause); + status_t stopStream(); // Returns the request ID for the currently streaming request @@ -91,6 +94,7 @@ class StreamingProcessor: public BufferItemConsumer::FrameAvailableListener { int mId; StreamType mActiveRequest; + bool mPaused; // Preview-related members int32_t mPreviewRequestId; diff --git a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp index be1ffeb..defcafc 100644 --- a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp +++ b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp @@ -112,7 +112,11 @@ status_t ZslProcessor3::updateStream(const Parameters ¶ms) { "dimensions changed", __FUNCTION__, client->getCameraId(), mZslStreamId); res = device->deleteStream(mZslStreamId); - if (res != OK) { + if (res == -EBUSY) { + ALOGV("%s: Camera %d: Device is busy, call updateStream again " + " after it becomes idle", __FUNCTION__, mId); + return res; + } else if(res != OK) { ALOGE("%s: Camera %d: Unable to delete old output stream " "for ZSL: %s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res); |