Merge "stagefright: detect output format changes without event" into nyc-dev
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index ef0ccc2..3f4594d 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -552,19 +552,6 @@
mNewPosition = mPosition + mUpdatePeriod;
int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
- sp<AudioTrackThread> t = mAudioTrackThread;
- if (t != 0) {
- if (previousState == STATE_STOPPING) {
- mProxy->interrupt();
- } else {
- t->resume();
- }
- } else {
- mPreviousPriority = getpriority(PRIO_PROCESS, 0);
- get_sched_policy(0, &mPreviousSchedulingGroup);
- androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
- }
-
status_t status = NO_ERROR;
if (!(flags & CBLK_INVALID)) {
status = mAudioTrack->start();
@@ -576,7 +563,21 @@
status = restoreTrack_l("start");
}
- if (status != NO_ERROR) {
+ // resume or pause the callback thread as needed.
+ sp<AudioTrackThread> t = mAudioTrackThread;
+ if (status == NO_ERROR) {
+ if (t != 0) {
+ if (previousState == STATE_STOPPING) {
+ mProxy->interrupt();
+ } else {
+ t->resume();
+ }
+ } else {
+ mPreviousPriority = getpriority(PRIO_PROCESS, 0);
+ get_sched_policy(0, &mPreviousSchedulingGroup);
+ androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
+ }
+ } else {
ALOGE("start() status %d", status);
mState = previousState;
if (t != 0) {
diff --git a/services/audioflinger/AutoPark.h b/services/audioflinger/AutoPark.h
new file mode 100644
index 0000000..e539e47
--- /dev/null
+++ b/services/audioflinger/AutoPark.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace android {
+
+// T is FastMixer or FastCapture
+template<typename T> class AutoPark {
+public:
+
+ // Park the specific FastThread, which can be nullptr, in hot idle if not currently idling
+ AutoPark(const sp<T>& fastThread) : mFastThread(fastThread)
+ {
+ mPreviousCommand = FastThreadState::HOT_IDLE;
+ if (fastThread != nullptr) {
+ auto sq = mFastThread->sq();
+ FastThreadState *state = sq->begin();
+ if (!(state->mCommand & FastThreadState::IDLE)) {
+ mPreviousCommand = state->mCommand;
+ state->mCommand = FastThreadState::HOT_IDLE;
+ sq->end();
+ sq->push(sq->BLOCK_UNTIL_ACKED);
+ } else {
+ sq->end(false /*didModify*/);
+ }
+ }
+ }
+
+ // Remove the FastThread from hot idle if necessary
+ ~AutoPark()
+ {
+ if (!(mPreviousCommand & FastThreadState::IDLE)) {
+ ALOG_ASSERT(mFastThread != nullptr);
+ auto sq = mFastThread->sq();
+ FastThreadState *state = sq->begin();
+ ALOG_ASSERT(state->mCommand == FastThreadState::HOT_IDLE);
+ state->mCommand = mPreviousCommand;
+ sq->end();
+ sq->push(sq->BLOCK_UNTIL_PUSHED);
+ }
+ }
+
+private:
+ const sp<T> mFastThread;
+ // if !&IDLE, holds the FastThread state to restore after new parameters processed
+ FastThreadState::Command mPreviousCommand;
+}; // class AutoPark
+
+} // namespace
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 973c983..bc17339 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -71,6 +71,8 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
+#include "AutoPark.h"
+
// ----------------------------------------------------------------------------
// Note: the following macro is used for extremely verbose logging message. In
@@ -3283,31 +3285,9 @@
status_t AudioFlinger::MixerThread::createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle)
{
- // if !&IDLE, holds the FastMixer state to restore after new parameters processed
- FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE;
- if (mFastMixer != 0) {
- FastMixerStateQueue *sq = mFastMixer->sq();
- FastMixerState *state = sq->begin();
- if (!(state->mCommand & FastMixerState::IDLE)) {
- previousCommand = state->mCommand;
- state->mCommand = FastMixerState::HOT_IDLE;
- sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
- } else {
- sq->end(false /*didModify*/);
- }
- }
- status_t status = PlaybackThread::createAudioPatch_l(patch, handle);
+ AutoPark<FastMixer> park(mFastMixer);
- if (!(previousCommand & FastMixerState::IDLE)) {
- ALOG_ASSERT(mFastMixer != 0);
- FastMixerStateQueue *sq = mFastMixer->sq();
- FastMixerState *state = sq->begin();
- ALOG_ASSERT(state->mCommand == FastMixerState::HOT_IDLE);
- state->mCommand = previousCommand;
- sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
- }
+ status_t status = PlaybackThread::createAudioPatch_l(patch, handle);
return status;
}
@@ -3390,33 +3370,10 @@
status_t AudioFlinger::MixerThread::releaseAudioPatch_l(const audio_patch_handle_t handle)
{
- // if !&IDLE, holds the FastMixer state to restore after new parameters processed
- FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE;
- if (mFastMixer != 0) {
- FastMixerStateQueue *sq = mFastMixer->sq();
- FastMixerState *state = sq->begin();
- if (!(state->mCommand & FastMixerState::IDLE)) {
- previousCommand = state->mCommand;
- state->mCommand = FastMixerState::HOT_IDLE;
- sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
- } else {
- sq->end(false /*didModify*/);
- }
- }
+ AutoPark<FastMixer> park(mFastMixer);
status_t status = PlaybackThread::releaseAudioPatch_l(handle);
- if (!(previousCommand & FastMixerState::IDLE)) {
- ALOG_ASSERT(mFastMixer != 0);
- FastMixerStateQueue *sq = mFastMixer->sq();
- FastMixerState *state = sq->begin();
- ALOG_ASSERT(state->mCommand == FastMixerState::HOT_IDLE);
- state->mCommand = previousCommand;
- sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
- }
-
return status;
}
@@ -4464,20 +4421,7 @@
status = NO_ERROR;
- // if !&IDLE, holds the FastMixer state to restore after new parameters processed
- FastMixerState::Command previousCommand = FastMixerState::HOT_IDLE;
- if (mFastMixer != 0) {
- FastMixerStateQueue *sq = mFastMixer->sq();
- FastMixerState *state = sq->begin();
- if (!(state->mCommand & FastMixerState::IDLE)) {
- previousCommand = state->mCommand;
- state->mCommand = FastMixerState::HOT_IDLE;
- sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
- } else {
- sq->end(false /*didModify*/);
- }
- }
+ AutoPark<FastMixer> park(mFastMixer);
AudioParameter param = AudioParameter(keyValuePair);
int value;
@@ -4572,16 +4516,6 @@
}
}
- if (!(previousCommand & FastMixerState::IDLE)) {
- ALOG_ASSERT(mFastMixer != 0);
- FastMixerStateQueue *sq = mFastMixer->sq();
- FastMixerState *state = sq->begin();
- ALOG_ASSERT(state->mCommand == FastMixerState::HOT_IDLE);
- state->mCommand = previousCommand;
- sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
- }
-
return reconfig || a2dpDeviceChanged;
}
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 61e1442..e3d6906 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -41,6 +41,7 @@
mNewAEState(false),
mNewFrameReceived(false),
mNewCaptureReceived(false),
+ mNewCaptureErrorCnt(0),
mShutterNotified(false),
mHalNotifiedShutter(false),
mShutterCaptureId(-1),
@@ -131,7 +132,7 @@
}
void CaptureSequencer::onCaptureAvailable(nsecs_t timestamp,
- sp<MemoryBase> captureBuffer) {
+ sp<MemoryBase> captureBuffer, bool captureError) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
Mutex::Autolock l(mInputMutex);
@@ -139,6 +140,11 @@
mCaptureBuffer = captureBuffer;
if (!mNewCaptureReceived) {
mNewCaptureReceived = true;
+ if (captureError) {
+ mNewCaptureErrorCnt++;
+ } else {
+ mNewCaptureErrorCnt = 0;
+ }
mNewCaptureSignal.signal();
}
}
@@ -623,6 +629,17 @@
break;
}
}
+ if (mNewCaptureReceived) {
+ if (mNewCaptureErrorCnt > kMaxRetryCount) {
+ ALOGW("Exceeding multiple retry limit of %d due to buffer drop", kMaxRetryCount);
+ return DONE;
+ } else if (mNewCaptureErrorCnt > 0) {
+ ALOGW("Capture error happened, retry %d...", mNewCaptureErrorCnt);
+ mNewCaptureReceived = false;
+ return STANDARD_CAPTURE;
+ }
+ }
+
if (mTimeoutCount <= 0) {
ALOGW("Timed out waiting for capture to complete");
return DONE;
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index b05207e..a7c61d2 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -69,7 +69,7 @@
virtual void onResultAvailable(const CaptureResult &result);
// Notifications from the JPEG processor
- void onCaptureAvailable(nsecs_t timestamp, sp<MemoryBase> captureBuffer);
+ void onCaptureAvailable(nsecs_t timestamp, sp<MemoryBase> captureBuffer, bool captureError);
void dump(int fd, const Vector<String16>& args);
@@ -94,6 +94,7 @@
Condition mNewFrameSignal;
bool mNewCaptureReceived;
+ int32_t mNewCaptureErrorCnt;
nsecs_t mCaptureTimestamp;
sp<MemoryBase> mCaptureBuffer;
Condition mNewCaptureSignal;
@@ -110,6 +111,7 @@
static const int kMaxTimeoutsForPrecaptureStart = 10; // 1 sec
static const int kMaxTimeoutsForPrecaptureEnd = 20; // 2 sec
static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec
+ static const int kMaxRetryCount = 3; // 3 retries in case of buffer drop
wp<Camera2Client> mClient;
wp<ZslProcessor> mZslProcessor;
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index e97618c..ffe96fc 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -42,7 +42,8 @@
mDevice(client->getCameraDevice()),
mSequencer(sequencer),
mId(client->getCameraId()),
- mCaptureAvailable(false),
+ mCaptureDone(false),
+ mCaptureSuccess(false),
mCaptureStreamId(NO_STREAM) {
}
@@ -53,9 +54,26 @@
void JpegProcessor::onFrameAvailable(const BufferItem& /*item*/) {
Mutex::Autolock l(mInputMutex);
- if (!mCaptureAvailable) {
- mCaptureAvailable = true;
- mCaptureAvailableSignal.signal();
+ ALOGV("%s", __FUNCTION__);
+ if (!mCaptureDone) {
+ mCaptureDone = true;
+ mCaptureSuccess = true;
+ mCaptureDoneSignal.signal();
+ }
+}
+
+void JpegProcessor::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
+ // Intentionally left empty
+}
+
+void JpegProcessor::onBufferReleased(const BufferInfo& bufferInfo) {
+ Mutex::Autolock l(mInputMutex);
+ ALOGV("%s", __FUNCTION__);
+
+ if (bufferInfo.mError) {
+ mCaptureDone = true;
+ mCaptureSuccess = false;
+ mCaptureDoneSignal.signal();
}
}
@@ -154,6 +172,12 @@
return res;
}
+ res = device->addBufferListenerForStream(mCaptureStreamId, this);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't add buffer listeneri: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
}
return OK;
}
@@ -192,24 +216,26 @@
bool JpegProcessor::threadLoop() {
status_t res;
+ bool captureSuccess = false;
{
Mutex::Autolock l(mInputMutex);
- while (!mCaptureAvailable) {
- res = mCaptureAvailableSignal.waitRelative(mInputMutex,
+
+ while (!mCaptureDone) {
+ res = mCaptureDoneSignal.waitRelative(mInputMutex,
kWaitDuration);
if (res == TIMED_OUT) return true;
}
- mCaptureAvailable = false;
+
+ captureSuccess = mCaptureSuccess;
+ mCaptureDone = false;
}
- do {
- res = processNewCapture();
- } while (res == OK);
+ res = processNewCapture(captureSuccess);
return true;
}
-status_t JpegProcessor::processNewCapture() {
+status_t JpegProcessor::processNewCapture(bool captureSuccess) {
ATRACE_CALL();
status_t res;
sp<Camera2Heap> captureHeap;
@@ -217,7 +243,7 @@
CpuConsumer::LockedBuffer imgBuffer;
- {
+ if (captureSuccess) {
Mutex::Autolock l(mInputMutex);
if (mCaptureStreamId == NO_STREAM) {
ALOGW("%s: Camera %d: No stream is available", __FUNCTION__, mId);
@@ -269,7 +295,7 @@
sp<CaptureSequencer> sequencer = mSequencer.promote();
if (sequencer != 0) {
- sequencer->onCaptureAvailable(imgBuffer.timestamp, captureBuffer);
+ sequencer->onCaptureAvailable(imgBuffer.timestamp, captureBuffer, !captureSuccess);
}
return OK;
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.h b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
index ac6f5c7..7187ad9 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
@@ -41,7 +41,8 @@
* Still image capture output image processing
*/
class JpegProcessor:
- public Thread, public CpuConsumer::FrameAvailableListener {
+ public Thread, public CpuConsumer::FrameAvailableListener,
+ public camera3::Camera3StreamBufferListener {
public:
JpegProcessor(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
~JpegProcessor();
@@ -49,6 +50,10 @@
// CpuConsumer listener implementation
void onFrameAvailable(const BufferItem& item);
+ // Camera3StreamBufferListener implementation
+ void onBufferAcquired(const BufferInfo& bufferInfo) override;
+ void onBufferReleased(const BufferInfo& bufferInfo) override;
+
status_t updateStream(const Parameters ¶ms);
status_t deleteStream();
int getStreamId() const;
@@ -61,8 +66,9 @@
int mId;
mutable Mutex mInputMutex;
- bool mCaptureAvailable;
- Condition mCaptureAvailableSignal;
+ bool mCaptureDone;
+ bool mCaptureSuccess;
+ Condition mCaptureDoneSignal;
enum {
NO_STREAM = -1
@@ -75,7 +81,7 @@
virtual bool threadLoop();
- status_t processNewCapture();
+ status_t processNewCapture(bool captureSuccess);
size_t findJpegSize(uint8_t* jpegBuffer, size_t maxSize);
};
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index ccb3bc8..d570d4b 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -296,6 +296,12 @@
virtual status_t tearDown(int streamId) = 0;
/**
+ * Add buffer listener for a particular stream in the device.
+ */
+ virtual status_t addBufferListenerForStream(int streamId,
+ wp<camera3::Camera3StreamBufferListener> listener) = 0;
+
+ /**
* Prepare stream by preallocating up to maxCount buffers for it asynchronously.
* Calls notifyPrepared() once allocation is complete.
*/
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 331f10d..1caf157 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1652,6 +1652,26 @@
return stream->tearDown();
}
+status_t Camera3Device::addBufferListenerForStream(int streamId,
+ wp<Camera3StreamBufferListener> listener) {
+ ATRACE_CALL();
+ ALOGV("%s: Camera %d: Adding buffer listener for stream %d", __FUNCTION__, mId, streamId);
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ sp<Camera3StreamInterface> stream;
+ ssize_t outputStreamIdx = mOutputStreams.indexOfKey(streamId);
+ if (outputStreamIdx == NAME_NOT_FOUND) {
+ CLOGE("Stream %d does not exist", streamId);
+ return BAD_VALUE;
+ }
+
+ stream = mOutputStreams.editValueAt(outputStreamIdx);
+ stream->addBufferListener(listener);
+
+ return OK;
+}
+
uint32_t Camera3Device::getDeviceVersion() {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index ba092d0..96ca7b7 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -146,6 +146,9 @@
virtual status_t tearDown(int streamId);
+ virtual status_t addBufferListenerForStream(int streamId,
+ wp<camera3::Camera3StreamBufferListener> listener);
+
virtual status_t prepare(int maxCount, int streamId);
virtual uint32_t getDeviceVersion();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 50f7a91..a4714a7 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -560,7 +560,7 @@
}
void Camera3Stream::fireBufferListenersLocked(
- const camera3_stream_buffer& /*buffer*/, bool acquired, bool output) {
+ const camera3_stream_buffer& buffer, bool acquired, bool output) {
List<wp<Camera3StreamBufferListener> >::iterator it, end;
// TODO: finish implementing
@@ -568,6 +568,7 @@
Camera3StreamBufferListener::BufferInfo info =
Camera3StreamBufferListener::BufferInfo();
info.mOutput = output;
+ info.mError = (buffer.status == CAMERA3_BUFFER_STATUS_ERROR);
// TODO: rest of fields
for (it = mBufferListenerList.begin(), end = mBufferListenerList.end();
diff --git a/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
index 62ea6c0..2db333d 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
@@ -34,6 +34,7 @@
uint32_t mScalingMode;
int64_t mTimestamp;
uint64_t mFrameNumber;
+ bool mError;
};
// Buffer was acquired by the HAL