summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2013-06-26 18:23:23 -0700
committerEino-Ville Talvala <etalvala@google.com>2013-06-27 15:00:26 -0700
commita691ff3c03e38e148bbefed35ebb15e552a12613 (patch)
treee40a419e636ccc48551c5810887e872b5ac9ee44 /services
parent209bbbcf4190231f9dede758cbe77d109919f9f1 (diff)
downloadframeworks_av-a691ff3c03e38e148bbefed35ebb15e552a12613.zip
frameworks_av-a691ff3c03e38e148bbefed35ebb15e552a12613.tar.gz
frameworks_av-a691ff3c03e38e148bbefed35ebb15e552a12613.tar.bz2
Camera2/3: Don't allow recording and callbacks to coexist.
- Tear down conflicting streams when necessary. - Shut down callbacks if recording starts - Do not allow callbacks to start if recording is active Per the current camera API, recording and preview callbacks cannot be active simultaneously. However, the framework did not explicitly disallow this, and in fact left the streams configured once they were created, even if switching between the two operational modes. In addition, no guards existed for trying to enable both recording and callbacks at the same time. Bug: 9423825 Change-Id: I7d6e6114c2e14fcfb5299b4c72ad557895cbf4b8
Diffstat (limited to 'services')
-rw-r--r--services/camera/libcameraservice/Camera2Client.cpp92
-rw-r--r--services/camera/libcameraservice/camera2/CallbackProcessor.cpp22
2 files changed, 85 insertions, 29 deletions
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index a1971e3..16688cf 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -611,27 +611,35 @@ void Camera2Client::setPreviewCallbackFlag(int flag) {
void Camera2Client::setPreviewCallbackFlagL(Parameters &params, int flag) {
status_t res = OK;
+
+ switch(params.state) {
+ case Parameters::STOPPED:
+ case Parameters::WAITING_FOR_PREVIEW_WINDOW:
+ case Parameters::PREVIEW:
+ // OK
+ break;
+ default:
+ if (flag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
+ ALOGE("%s: Camera %d: Can't use preview callbacks "
+ "in state %d", __FUNCTION__, mCameraId, params.state);
+ return;
+ }
+ }
+
if (flag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
ALOGV("%s: setting oneshot", __FUNCTION__);
params.previewCallbackOneShot = true;
}
if (params.previewCallbackFlags != (uint32_t)flag) {
params.previewCallbackFlags = flag;
- switch(params.state) {
- case Parameters::PREVIEW:
+
+ if (params.state == Parameters::PREVIEW) {
res = startPreviewL(params, true);
- break;
- case Parameters::RECORD:
- case Parameters::VIDEO_SNAPSHOT:
- res = startRecordingL(params, true);
- break;
- default:
- break;
- }
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to refresh request in state %s",
- __FUNCTION__, mCameraId,
- Parameters::getStateName(params.state));
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to refresh request in state %s",
+ __FUNCTION__, mCameraId,
+ Parameters::getStateName(params.state));
+ }
}
}
@@ -702,6 +710,26 @@ status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
bool callbacksEnabled = params.previewCallbackFlags &
CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
if (callbacksEnabled) {
+ // Can't have recording stream hanging around when enabling callbacks,
+ // since it exceeds the max stream count on some devices.
+ if (mStreamingProcessor->getRecordingStreamId() != NO_STREAM) {
+ ALOGV("%s: Camera %d: Clearing out recording stream before "
+ "creating callback stream", __FUNCTION__, mCameraId);
+ res = mStreamingProcessor->stopStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't stop streaming to delete "
+ "recording stream", __FUNCTION__, mCameraId);
+ return res;
+ }
+ res = mStreamingProcessor->deleteRecordingStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete recording stream before "
+ "enabling callbacks: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ }
+
res = mCallbackProcessor->updateStream(params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)",
@@ -898,6 +926,29 @@ status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
}
}
+ // Not all devices can support a preview callback stream and a recording
+ // stream at the same time, so assume none of them can.
+ if (mCallbackProcessor->getStreamId() != NO_STREAM) {
+ ALOGV("%s: Camera %d: Clearing out callback stream before "
+ "creating recording stream", __FUNCTION__, mCameraId);
+ res = mStreamingProcessor->stopStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't stop streaming to delete callback stream",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+ res = mCallbackProcessor->deleteStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete callback stream before "
+ "record: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ }
+ // Disable callbacks if they're enabled; can't record and use callbacks,
+ // and we can't fail record start without stagefright asserting.
+ params.previewCallbackFlags = 0;
+
res = updateProcessorStream<
StreamingProcessor,
&StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
@@ -909,17 +960,6 @@ status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
}
Vector<uint8_t> outputStreams;
- bool callbacksEnabled = params.previewCallbackFlags &
- CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
- if (callbacksEnabled) {
- res = mCallbackProcessor->updateStream(params);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
- }
- outputStreams.push(getCallbackStreamId());
- }
outputStreams.push(getPreviewStreamId());
outputStreams.push(getRecordingStreamId());
@@ -1651,6 +1691,8 @@ status_t Camera2Client::updateProcessorStream(sp<ProcessorT> processor,
* queue) and then try again. Resume streaming once we're done.
*/
if (res == -EBUSY) {
+ ALOGV("%s: Camera %d: Pausing to update stream", __FUNCTION__,
+ mCameraId);
res = mStreamingProcessor->togglePauseStream(/*pause*/true);
if (res != OK) {
ALOGE("%s: Camera %d: Can't pause streaming: %s (%d)",
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
index 98673ff..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);