diff options
17 files changed, 386 insertions, 188 deletions
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index 34bae29..df25d7b 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -278,7 +278,7 @@ private: void deferMessage(const sp<AMessage> &msg); void processDeferredMessages(); - void sendFormatChange(); + void sendFormatChange(const sp<AMessage> &reply); void signalError( OMX_ERRORTYPE error = OMX_ErrorUndefined, diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 54f8d9e..85232e7 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -82,7 +82,7 @@ const effect_descriptor_t gBassBoostDescriptor = { {0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }}, {0x8631f300, 0x72e2, 0x11df, 0xb57e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid EFFECT_CONTROL_API_VERSION, - (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | EFFECT_FLAG_DEVICE_IND + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_VOLUME_CTRL), BASS_BOOST_CUP_LOAD_ARM9E, BUNDLE_MEM_USAGE, @@ -108,7 +108,7 @@ const effect_descriptor_t gEqualizerDescriptor = { {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type {0xce772f20, 0x847d, 0x11df, 0xbb17, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid Eq NXP EFFECT_CONTROL_API_VERSION, - (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST | EFFECT_FLAG_VOLUME_CTRL), + (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_VOLUME_CTRL), EQUALIZER_CUP_LOAD_ARM9E, BUNDLE_MEM_USAGE, "Equalizer", diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index 1e6cd94..f00f488 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -71,6 +71,12 @@ status_t Drm::initCheck() const { status_t Drm::setListener(const sp<IDrmClient>& listener) { Mutex::Autolock lock(mEventLock); + if (mListener != NULL){ + mListener->asBinder()->unlinkToDeath(this); + } + if (listener != NULL) { + listener->asBinder()->linkToDeath(this); + } mListener = listener; return NO_ERROR; } @@ -576,4 +582,12 @@ status_t Drm::verify(Vector<uint8_t> const &sessionId, return mPlugin->verify(sessionId, keyId, message, signature, match); } +void Drm::binderDied(const wp<IBinder> &the_late_who) +{ + delete mPlugin; + mPlugin = NULL; + closeFactory(); + mListener.clear(); +} + } // namespace android diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h index 3da8ad4..3f460f1 100644 --- a/media/libmediaplayerservice/Drm.h +++ b/media/libmediaplayerservice/Drm.h @@ -29,7 +29,9 @@ namespace android { struct DrmFactory; struct DrmPlugin; -struct Drm : public BnDrm, public DrmPluginListener { +struct Drm : public BnDrm, + public IBinder::DeathRecipient, + public DrmPluginListener { Drm(); virtual ~Drm(); @@ -115,6 +117,8 @@ struct Drm : public BnDrm, public DrmPluginListener { Vector<uint8_t> const *sessionId, Vector<uint8_t> const *data); + virtual void binderDied(const wp<IBinder> &the_late_who); + private: mutable Mutex mLock; diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 64e3885..cf41cf2 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2229,7 +2229,7 @@ void ACodec::processDeferredMessages() { } } -void ACodec::sendFormatChange() { +void ACodec::sendFormatChange(const sp<AMessage> &reply) { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatOutputFormatChanged); @@ -2294,14 +2294,12 @@ void ACodec::sendFormatChange() { rect.nTop + rect.nHeight - 1); if (mNativeWindow != NULL) { - android_native_rect_t crop; - crop.left = rect.nLeft; - crop.top = rect.nTop; - crop.right = rect.nLeft + rect.nWidth; - crop.bottom = rect.nTop + rect.nHeight; - - CHECK_EQ(0, native_window_set_crop( - mNativeWindow.get(), &crop)); + reply->setRect( + "crop", + rect.nLeft, + rect.nTop, + rect.nLeft + rect.nWidth, + rect.nTop + rect.nHeight); } } break; @@ -3057,8 +3055,11 @@ bool ACodec::BaseState::onOMXFillBufferDone( break; } + sp<AMessage> reply = + new AMessage(kWhatOutputBufferDrained, mCodec->id()); + if (!mCodec->mSentFormat) { - mCodec->sendFormatChange(); + mCodec->sendFormatChange(reply); } info->mData->setRange(rangeOffset, rangeLength); @@ -3081,9 +3082,6 @@ bool ACodec::BaseState::onOMXFillBufferDone( notify->setBuffer("buffer", info->mData); notify->setInt32("flags", flags); - sp<AMessage> reply = - new AMessage(kWhatOutputBufferDrained, mCodec->id()); - reply->setPointer("buffer-id", info->mBufferID); notify->setMessage("reply", reply); @@ -3127,6 +3125,13 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) { mCodec->findBufferByID(kPortIndexOutput, bufferID, &index); CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_DOWNSTREAM); + android_native_rect_t crop; + if (msg->findRect("crop", + &crop.left, &crop.top, &crop.right, &crop.bottom)) { + CHECK_EQ(0, native_window_set_crop( + mCodec->mNativeWindow.get(), &crop)); + } + int32_t render; if (mCodec->mNativeWindow != NULL && msg->findInt32("render", &render) && render != 0 diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index d66294c..942ea35 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -680,7 +680,7 @@ status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device) return mStatus; } status_t status = NO_ERROR; - if (device && (mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) { + if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) { status_t cmdStatus; uint32_t size = sizeof(status_t); uint32_t cmd = audio_is_output_devices(device) ? EFFECT_CMD_SET_DEVICE : diff --git a/services/audioflinger/ISchedulingPolicyService.cpp b/services/audioflinger/ISchedulingPolicyService.cpp index 0079968..f55bc02 100644 --- a/services/audioflinger/ISchedulingPolicyService.cpp +++ b/services/audioflinger/ISchedulingPolicyService.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "SchedulingPolicyService" +#define LOG_TAG "ISchedulingPolicyService" //#define LOG_NDEBUG 0 #include <binder/Parcel.h> @@ -45,9 +45,17 @@ public: data.writeInt32(tid); data.writeInt32(prio); uint32_t flags = asynchronous ? IBinder::FLAG_ONEWAY : 0; - remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, flags); - // fail on exception - if (reply.readExceptionCode() != 0) return -1; + status_t status = remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, flags); + if (status != NO_ERROR) { + return status; + } + if (asynchronous) { + return NO_ERROR; + } + // fail on exception: force binder reconnection + if (reply.readExceptionCode() != 0) { + return DEAD_OBJECT; + } return reply.readInt32(); } }; diff --git a/services/audioflinger/SchedulingPolicyService.cpp b/services/audioflinger/SchedulingPolicyService.cpp index 36e62e9..70a3f1a 100644 --- a/services/audioflinger/SchedulingPolicyService.cpp +++ b/services/audioflinger/SchedulingPolicyService.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#define LOG_TAG "SchedulingPolicyService" +//#define LOG_NDEBUG 0 + #include <binder/IServiceManager.h> #include <utils/Mutex.h> #include "ISchedulingPolicyService.h" @@ -28,25 +31,32 @@ static Mutex sMutex; int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous) { // FIXME merge duplicated code related to service lookup, caching, and error recovery - sp<ISchedulingPolicyService> sps; + int ret; for (;;) { sMutex.lock(); - sps = sSchedulingPolicyService; + sp<ISchedulingPolicyService> sps = sSchedulingPolicyService; sMutex.unlock(); - if (sps != 0) { - break; - } - sp<IBinder> binder = defaultServiceManager()->checkService(_scheduling_policy); - if (binder != 0) { + if (sps == 0) { + sp<IBinder> binder = defaultServiceManager()->checkService(_scheduling_policy); + if (binder == 0) { + sleep(1); + continue; + } sps = interface_cast<ISchedulingPolicyService>(binder); sMutex.lock(); sSchedulingPolicyService = sps; sMutex.unlock(); + } + ret = sps->requestPriority(pid, tid, prio, asynchronous); + if (ret != DEAD_OBJECT) { break; } - sleep(1); + ALOGW("SchedulingPolicyService died"); + sMutex.lock(); + sSchedulingPolicyService.clear(); + sMutex.unlock(); } - return sps->requestPriority(pid, tid, prio, asynchronous); + return ret; } } // namespace android diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 539bb4f..97f66f4 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -1330,13 +1330,11 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) track->mResetDone = false; track->mPresentationCompleteFrames = 0; mActiveTracks.add(track); - if (track->mainBuffer() != mMixBuffer) { - sp<EffectChain> chain = getEffectChain_l(track->sessionId()); - if (chain != 0) { - ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), - track->sessionId()); - chain->incActiveTrackCnt(); - } + sp<EffectChain> chain = getEffectChain_l(track->sessionId()); + if (chain != 0) { + ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), + track->sessionId()); + chain->incActiveTrackCnt(); } status = NO_ERROR; @@ -2992,9 +2990,11 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l() // forward device change to effects that have requested to be // aware of attached audio device. - mOutDevice = value; - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->setDevice_l(mOutDevice); + if (value != AUDIO_DEVICE_NONE) { + mOutDevice = value; + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->setDevice_l(mOutDevice); + } } } diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index dd50e3c..16688cf 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -102,6 +102,9 @@ status_t Camera2Client::initialize(camera_module_t *module) String8 threadName; mStreamingProcessor = new StreamingProcessor(this); + threadName = String8::format("C2-%d-StreamProc", + mCameraId); + mStreamingProcessor->run(threadName.string()); mFrameProcessor = new FrameProcessor(mDevice, this); threadName = String8::format("C2-%d-FrameProc", @@ -411,6 +414,7 @@ void Camera2Client::disconnect() { mCallbackProcessor->deleteStream(); mZslProcessor->deleteStream(); + mStreamingProcessor->requestExit(); mFrameProcessor->requestExit(); mCaptureSequencer->requestExit(); mJpegProcessor->requestExit(); @@ -419,6 +423,7 @@ void Camera2Client::disconnect() { ALOGV("Camera %d: Waiting for threads", mCameraId); + mStreamingProcessor->join(); mFrameProcessor->join(); mCaptureSequencer->join(); mJpegProcessor->join(); @@ -606,27 +611,35 @@ void Camera2Client::setPreviewCallbackFlag(int flag) { void Camera2Client::setPreviewCallbackFlagL(Parameters ¶ms, 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)); + } } } @@ -677,10 +690,46 @@ status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart) { return res; } + // We could wait to create the JPEG output stream until first actual use + // (first takePicture call). However, this would substantially increase the + // first capture latency on HAL3 devices, and potentially on some HAL2 + // devices. So create it unconditionally at preview start. As a drawback, + // this increases gralloc memory consumption for applications that don't + // ever take a picture. + // TODO: Find a better compromise, though this likely would involve HAL + // changes. + res = updateProcessorStream(mJpegProcessor, params); + if (res != OK) { + ALOGE("%s: Camera %d: Can't pre-configure still image " + "stream: %s (%d)", + __FUNCTION__, mCameraId, strerror(-res), res); + return res; + } + Vector<uint8_t> outputStreams; 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)", @@ -714,18 +763,6 @@ status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart) { res = mStreamingProcessor->startStream(StreamingProcessor::PREVIEW, outputStreams); } else { - // With recording hint set, we're going to be operating under the - // 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 = updateProcessorStream(mJpegProcessor, params); - if (res != OK) { - ALOGE("%s: Camera %d: Can't pre-configure still image " - "stream: %s (%d)", - __FUNCTION__, mCameraId, strerror(-res), res); - return res; - } - if (!restart) { res = mStreamingProcessor->updateRecordingRequest(params); if (res != OK) { @@ -889,6 +926,29 @@ status_t Camera2Client::startRecordingL(Parameters ¶ms, 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, @@ -900,17 +960,6 @@ status_t Camera2Client::startRecordingL(Parameters ¶ms, 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()); @@ -1007,8 +1056,12 @@ status_t Camera2Client::autoFocus() { * If the camera does not support auto-focus, it is a no-op and * onAutoFocus(boolean, Camera) callback will be called immediately * with a fake value of success set to true. + * + * Similarly, if focus mode is set to INFINITY, there's no reason to + * bother the HAL. */ - if (l.mParameters.focusMode == Parameters::FOCUS_MODE_FIXED) { + if (l.mParameters.focusMode == Parameters::FOCUS_MODE_FIXED || + l.mParameters.focusMode == Parameters::FOCUS_MODE_INFINITY) { notifyImmediately = true; notifySuccess = true; } @@ -1068,6 +1121,11 @@ status_t Camera2Client::cancelAutoFocus() { int triggerId; { SharedParameters::Lock l(mParameters); + // Canceling does nothing in FIXED or INFINITY modes + if (l.mParameters.focusMode == Parameters::FOCUS_MODE_FIXED || + l.mParameters.focusMode == Parameters::FOCUS_MODE_INFINITY) { + return OK; + } triggerId = ++l.mParameters.afTriggerCounter; // When using triggerAfWithAuto quirk, may need to reset focus mode to @@ -1633,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/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp index 0b5e9c4..cc7802b 100644 --- a/services/camera/libcameraservice/Camera3Device.cpp +++ b/services/camera/libcameraservice/Camera3Device.cpp @@ -170,6 +170,7 @@ status_t Camera3Device::initialize(camera_module_t *module) mHal3Device = device; mStatus = STATUS_IDLE; mNextStreamId = 0; + mNeedConfig = true; return OK; } @@ -180,24 +181,29 @@ status_t Camera3Device::disconnect() { ALOGV("%s: E", __FUNCTION__); - status_t res; - if (mStatus == STATUS_UNINITIALIZED) return OK; + status_t res = OK; + if (mStatus == STATUS_UNINITIALIZED) return res; if (mStatus == STATUS_ACTIVE || (mStatus == STATUS_ERROR && mRequestThread != NULL)) { res = mRequestThread->clearRepeatingRequests(); if (res != OK) { SET_ERR_L("Can't stop streaming"); - return res; - } - res = waitUntilDrainedLocked(); - if (res != OK) { - SET_ERR_L("Timeout waiting for HAL to drain"); - return res; + // Continue to close device even in case of error + } else { + res = waitUntilDrainedLocked(); + if (res != OK) { + SET_ERR_L("Timeout waiting for HAL to drain"); + // Continue to close device even in case of error + } } } assert(mStatus == STATUS_IDLE || mStatus == STATUS_ERROR); + if (mStatus == STATUS_ERROR) { + CLOGE("Shutting down in an error state"); + } + if (mRequestThread != NULL) { mRequestThread->requestExit(); } @@ -206,7 +212,12 @@ status_t Camera3Device::disconnect() { mInputStream.clear(); if (mRequestThread != NULL) { - mRequestThread->join(); + if (mStatus != STATUS_ERROR) { + // HAL may be in a bad state, so waiting for request thread + // (which may be stuck in the HAL processCaptureRequest call) + // could be dangerous. + mRequestThread->join(); + } mRequestThread.clear(); } @@ -218,7 +229,7 @@ status_t Camera3Device::disconnect() { mStatus = STATUS_UNINITIALIZED; ALOGV("%s: X", __FUNCTION__); - return OK; + return res; } status_t Camera3Device::dump(int fd, const Vector<String16> &args) { @@ -582,6 +593,7 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer, } *id = mNextStreamId++; + mNeedConfig = true; // Continue captures if active at start if (wasActive) { @@ -707,6 +719,7 @@ status_t Camera3Device::deleteStream(int id) { // fall through since we want to still list the stream as deleted. } mDeletedStreams.add(deletedStream); + mNeedConfig = true; return res; } @@ -1007,6 +1020,12 @@ status_t Camera3Device::configureStreamsLocked() { return INVALID_OPERATION; } + if (!mNeedConfig) { + ALOGV("%s: Skipping config, no stream changes", __FUNCTION__); + mStatus = STATUS_ACTIVE; + return OK; + } + // Start configuring the streams camera3_stream_configuration config; @@ -1091,6 +1110,7 @@ status_t Camera3Device::configureStreamsLocked() { // Finish configuring the streams lazily on first reference mStatus = STATUS_ACTIVE; + mNeedConfig = false; return OK; } @@ -1125,7 +1145,7 @@ void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) { ALOGE("Camera %d: %s", mId, errorCause.string()); // But only do error state transition steps for the first error - if (mStatus == STATUS_ERROR) return; + if (mStatus == STATUS_ERROR || mStatus == STATUS_UNINITIALIZED) return; mErrorCause = errorCause; diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h index 7a8c22a..faa42b9 100644 --- a/services/camera/libcameraservice/Camera3Device.h +++ b/services/camera/libcameraservice/Camera3Device.h @@ -149,6 +149,7 @@ class Camera3Device : StreamSet mOutputStreams; sp<camera3::Camera3Stream> mInputStream; int mNextStreamId; + bool mNeedConfig; // Need to hold on to stream references until configure completes. Vector<sp<camera3::Camera3StreamInterface> > mDeletedStreams; 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 { |