Merge "MediaCas: add CAS support to MPEG2TSExtractor and MediaCodec"
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index 2a7a67f..77ba716 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -315,6 +315,10 @@
WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
[&] (const WriteStatus& writeStatus) {
*written = writeStatus.reply.written;
+ // Diagnostics of the cause of b/35813113.
+ ALOGE_IF(*written > bytes,
+ "hal reports more bytes written than asked for: %lld > %lld",
+ (long long)*written, (long long)bytes);
});
}
@@ -328,8 +332,8 @@
if (data != nullptr) {
size_t availableToWrite = mDataMQ->availableToWrite();
if (dataSize > availableToWrite) {
- ALOGW("truncating write data from %d to %d due to insufficient data queue space",
- (int32_t)dataSize, (int32_t)availableToWrite);
+ ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
+ (long long)dataSize, (long long)availableToWrite);
dataSize = availableToWrite;
}
if (!mDataMQ->write(data, dataSize)) {
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 82a2627..0bf7854 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -277,19 +277,20 @@
}
void MtpDevice::print() {
- if (mDeviceInfo) {
- mDeviceInfo->print();
+ if (!mDeviceInfo)
+ return;
- if (mDeviceInfo->mDeviceProperties) {
- ALOGI("***** DEVICE PROPERTIES *****\n");
- int count = mDeviceInfo->mDeviceProperties->size();
- for (int i = 0; i < count; i++) {
- MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
- MtpProperty* property = getDevicePropDesc(propCode);
- if (property) {
- property->print();
- delete property;
- }
+ mDeviceInfo->print();
+
+ if (mDeviceInfo->mDeviceProperties) {
+ ALOGI("***** DEVICE PROPERTIES *****\n");
+ int count = mDeviceInfo->mDeviceProperties->size();
+ for (int i = 0; i < count; i++) {
+ MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
+ MtpProperty* property = getDevicePropDesc(propCode);
+ if (property) {
+ property->print();
+ delete property;
}
}
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index e710f0a..79e7ff0 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -507,6 +507,14 @@
return res;
if (!isStreamInfoValid) {
+ // Streaming sharing is only supported for IMPLEMENTATION_DEFINED
+ // formats.
+ if (isShared && streamInfo.format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ String8 msg = String8::format("Camera %s: Stream sharing is only supported for "
+ "IMPLEMENTATION_DEFINED format", mCameraIdStr.string());
+ ALOGW("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
isStreamInfoValid = true;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 068a2b3..f20556d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -3956,7 +3956,8 @@
}
}
- res = outputStream->getBuffer(&outputBuffers->editItemAt(i));
+ res = outputStream->getBuffer(&outputBuffers->editItemAt(i),
+ captureRequest->mOutputSurfaces[i]);
if (res != OK) {
// Can't get output buffer from gralloc queue - this could be due to
// abandoned queue or other consumer misbehavior, so not a fatal
@@ -3968,13 +3969,6 @@
}
halRequest->num_output_buffers++;
- res = outputStream->notifyRequestedSurfaces(halRequest->frame_number,
- captureRequest->mOutputSurfaces[i]);
- if (res != OK) {
- ALOGE("RequestThread: Cannot register output surfaces: %s (%d)",
- strerror(-res), res);
- return INVALID_OPERATION;
- }
}
totalNumBuffers += halRequest->num_output_buffers;
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 1a730d6..9c951b7 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -36,7 +36,8 @@
}
-status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *) {
+status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *,
+ const std::vector<size_t>&) {
ATRACE_CALL();
ALOGE("%s: Stream %d: Dummy stream cannot produce buffers!", __FUNCTION__, mId);
return INVALID_OPERATION;
@@ -83,14 +84,6 @@
return OK;
}
-status_t Camera3DummyStream::notifyRequestedSurfaces(uint32_t frame_number,
- const std::vector<size_t>& surface_ids) {
- (void) frame_number;
- (void) surface_ids;
- // Do nothing
- return OK;
-}
-
status_t Camera3DummyStream::configureQueueLocked() {
// Do nothing
return OK;
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index b6ec99c..35a6a18 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -56,9 +56,6 @@
virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
- virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
- const std::vector<size_t>& surface_ids);
-
/**
* Return if this output stream is for video encoding.
*/
@@ -102,7 +99,8 @@
/**
* Internal Camera3Stream interface
*/
- virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+ virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
+ const std::vector<size_t>& surface_ids = std::vector<size_t>());
virtual status_t returnBufferLocked(
const camera3_stream_buffer &buffer,
nsecs_t timestamp);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index f971116..51dc20a 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -148,73 +148,17 @@
disconnectLocked();
}
-status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) {
+status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer,
+ const std::vector<size_t>&) {
ATRACE_CALL();
- status_t res;
-
- if ((res = getBufferPreconditionCheckLocked()) != OK) {
- return res;
- }
ANativeWindowBuffer* anb;
int fenceFd = -1;
- bool gotBufferFromManager = false;
- if (mUseBufferManager) {
- sp<GraphicBuffer> gb;
- res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, &fenceFd);
- if (res == OK) {
- // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after a
- // successful return.
- anb = gb.get();
- res = mConsumer->attachBuffer(anb);
- if (res != OK) {
- ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- return res;
- }
- gotBufferFromManager = true;
- ALOGV("Stream %d: Attached new buffer", getId());
- } else if (res == ALREADY_EXISTS) {
- // Have sufficient free buffers already attached, can just
- // dequeue from buffer queue
- ALOGV("Stream %d: Reusing attached buffer", getId());
- gotBufferFromManager = false;
- } else if (res != OK) {
- ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- return res;
- }
- }
- if (!gotBufferFromManager) {
- /**
- * Release the lock briefly to avoid deadlock for below scenario:
- * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
- * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
- * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
- * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
- * StreamingProcessor lock.
- * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
- * and try to lock bufferQueue lock.
- * Then there is circular locking dependency.
- */
- sp<ANativeWindow> currentConsumer = mConsumer;
- mLock.unlock();
-
- res = currentConsumer->dequeueBuffer(currentConsumer.get(), &anb, &fenceFd);
- mLock.lock();
- if (res != OK) {
- ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
-
- // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
- // let prepareNextBuffer handle the error.)
- if (res == NO_INIT && mState == STATE_CONFIGURED) {
- mState = STATE_ABANDONED;
- }
-
- return res;
- }
+ status_t res;
+ res = getBufferLockedCommon(&anb, &fenceFd);
+ if (res != OK) {
+ return res;
}
/**
@@ -227,6 +171,11 @@
return OK;
}
+status_t Camera3OutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
+ ANativeWindowBuffer* buffer, int anwReleaseFence) {
+ return consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
+}
+
status_t Camera3OutputStream::returnBufferLocked(
const camera3_stream_buffer &buffer,
nsecs_t timestamp) {
@@ -269,6 +218,7 @@
sp<ANativeWindow> currentConsumer = mConsumer;
mLock.unlock();
+ ANativeWindowBuffer *anwBuffer = container_of(buffer.buffer, ANativeWindowBuffer, handle);
/**
* Return buffer back to ANativeWindow
*/
@@ -276,13 +226,14 @@
// Cancel buffer
ALOGW("A frame is dropped for stream %d", mId);
res = currentConsumer->cancelBuffer(currentConsumer.get(),
- container_of(buffer.buffer, ANativeWindowBuffer, handle),
+ anwBuffer,
anwReleaseFence);
if (res != OK) {
ALOGE("%s: Stream %d: Error cancelling buffer to native window:"
" %s (%d)", __FUNCTION__, mId, strerror(-res), res);
}
+ notifyBufferReleased(anwBuffer);
if (mUseBufferManager) {
// Return this buffer back to buffer manager.
mBufferReleasedListener->onBufferReleased();
@@ -308,9 +259,7 @@
return res;
}
- res = currentConsumer->queueBuffer(currentConsumer.get(),
- container_of(buffer.buffer, ANativeWindowBuffer, handle),
- anwReleaseFence);
+ res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence);
if (res != OK) {
ALOGE("%s: Stream %d: Error queueing buffer to native window: "
"%s (%d)", __FUNCTION__, mId, strerror(-res), res);
@@ -527,6 +476,76 @@
return OK;
}
+status_t Camera3OutputStream::getBufferLockedCommon(ANativeWindowBuffer** anb, int* fenceFd) {
+ ATRACE_CALL();
+ status_t res;
+
+ if ((res = getBufferPreconditionCheckLocked()) != OK) {
+ return res;
+ }
+
+ bool gotBufferFromManager = false;
+
+ if (mUseBufferManager) {
+ sp<GraphicBuffer> gb;
+ res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, fenceFd);
+ if (res == OK) {
+ // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after a
+ // successful return.
+ *anb = gb.get();
+ res = mConsumer->attachBuffer(*anb);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+ gotBufferFromManager = true;
+ ALOGV("Stream %d: Attached new buffer", getId());
+ } else if (res == ALREADY_EXISTS) {
+ // Have sufficient free buffers already attached, can just
+ // dequeue from buffer queue
+ ALOGV("Stream %d: Reusing attached buffer", getId());
+ gotBufferFromManager = false;
+ } else if (res != OK) {
+ ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+ }
+ if (!gotBufferFromManager) {
+ /**
+ * Release the lock briefly to avoid deadlock for below scenario:
+ * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
+ * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
+ * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
+ * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
+ * StreamingProcessor lock.
+ * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
+ * and try to lock bufferQueue lock.
+ * Then there is circular locking dependency.
+ */
+ sp<ANativeWindow> currentConsumer = mConsumer;
+ mLock.unlock();
+
+ res = currentConsumer->dequeueBuffer(currentConsumer.get(), anb, fenceFd);
+ mLock.lock();
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+
+ // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
+ // let prepareNextBuffer handle the error.)
+ if (res == NO_INIT && mState == STATE_CONFIGURED) {
+ mState = STATE_ABANDONED;
+ }
+
+ return res;
+ }
+ }
+
+ return res;
+}
+
status_t Camera3OutputStream::disconnectLocked() {
status_t res;
@@ -702,8 +721,7 @@
return OK;
}
-status_t Camera3OutputStream::notifyRequestedSurfaces(uint32_t /*frame_number*/,
- const std::vector<size_t>& /*surface_ids*/) {
+status_t Camera3OutputStream::notifyBufferReleased(ANativeWindowBuffer* /*anwBuffer*/) {
return OK;
}
@@ -717,6 +735,7 @@
}
status_t Camera3OutputStream::setConsumers(const std::vector<sp<Surface>>& consumers) {
+ Mutex::Autolock l(mLock);
if (consumers.size() != 1) {
ALOGE("%s: it's illegal to set %zu consumer surfaces!",
__FUNCTION__, consumers.size());
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 080c721..24e4e05 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -158,8 +158,11 @@
virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
- virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
- const std::vector<size_t>& surface_ids);
+ /**
+ * Notify that the buffer is being released to the buffer queue instead of
+ * being queued to the consumer.
+ */
+ virtual status_t notifyBufferReleased(ANativeWindowBuffer *anwBuffer);
/**
* Set the graphic buffer manager to get/return the stream buffers.
@@ -198,6 +201,9 @@
static const nsecs_t kDequeueBufferTimeout = 1000000000; // 1 sec
+ status_t getBufferLockedCommon(ANativeWindowBuffer** anb, int* fenceFd);
+
+
private:
int mTransform;
@@ -243,11 +249,16 @@
/**
* Internal Camera3Stream interface
*/
- virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+ virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
+ const std::vector<size_t>& surface_ids);
+
virtual status_t returnBufferLocked(
const camera3_stream_buffer &buffer,
nsecs_t timestamp);
+ virtual status_t queueBufferToConsumer(sp<ANativeWindow>& consumer,
+ ANativeWindowBuffer* buffer, int anwReleaseFence);
+
virtual status_t configureQueueLocked();
virtual status_t getEndpointUsage(uint32_t *usage) const;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 11868e7..8107dd0 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -59,20 +59,6 @@
*
*/
virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd) = 0;
-
- /**
- * Notify which surfaces are requested for a particular frame number.
- *
- * Mulitple surfaces could share the same output stream, but a request may
- * be only for a subset of surfaces. In this case, the
- * Camera3OutputStreamInterface object needs to manage the output surfaces on
- * a per request basis.
- *
- * If there is only one surface for this output stream, calling this
- * function is a no-op.
- */
- virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
- const std::vector<size_t>& surface_ids) = 0;
};
} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 0d6a96c..2ae5660 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -44,7 +44,7 @@
uint32_t usage;
getEndpointUsage(&usage);
- res = mStreamSplitter->connect(mSurfaces, usage, camera3_stream::max_buffers, mConsumer);
+ res = mStreamSplitter->connect(mSurfaces, usage, camera3_stream::max_buffers, &mConsumer);
if (res != OK) {
ALOGE("%s: Failed to connect to stream splitter: %s(%d)",
__FUNCTION__, strerror(-res), res);
@@ -54,13 +54,13 @@
return res;
}
-status_t Camera3SharedOutputStream::notifyRequestedSurfaces(uint32_t /*frame_number*/,
- const std::vector<size_t>& surface_ids) {
+status_t Camera3SharedOutputStream::notifyBufferReleased(ANativeWindowBuffer *anwBuffer) {
Mutex::Autolock l(mLock);
status_t res = OK;
+ const sp<GraphicBuffer> buffer(static_cast<GraphicBuffer*>(anwBuffer));
if (mStreamSplitter != nullptr) {
- res = mStreamSplitter->notifyRequestedSurfaces(surface_ids);
+ res = mStreamSplitter->notifyBufferReleased(buffer);
}
return res;
@@ -72,6 +72,7 @@
}
status_t Camera3SharedOutputStream::setConsumers(const std::vector<sp<Surface>>& surfaces) {
+ Mutex::Autolock l(mLock);
if (surfaces.size() == 0) {
ALOGE("%s: it's illegal to set zero consumer surfaces!", __FUNCTION__);
return INVALID_OPERATION;
@@ -88,7 +89,7 @@
// Only call addOutput if the splitter has been connected.
if (mStreamSplitter != nullptr) {
- ret = mStreamSplitter->addOutput(surface, camera3_stream::max_buffers);
+ ret = mStreamSplitter->addOutput(surface);
if (ret != OK) {
ALOGE("%s: addOutput failed with error code %d", __FUNCTION__, ret);
return ret;
@@ -99,6 +100,64 @@
return ret;
}
+status_t Camera3SharedOutputStream::getBufferLocked(camera3_stream_buffer *buffer,
+ const std::vector<size_t>& surface_ids) {
+ ANativeWindowBuffer* anb;
+ int fenceFd = -1;
+
+ status_t res;
+ res = getBufferLockedCommon(&anb, &fenceFd);
+ if (res != OK) {
+ return res;
+ }
+
+ // Attach the buffer to the splitter output queues. This could block if
+ // the output queue doesn't have any empty slot. So unlock during the course
+ // of attachBufferToOutputs.
+ sp<Camera3StreamSplitter> splitter = mStreamSplitter;
+ mLock.unlock();
+ res = splitter->attachBufferToOutputs(anb, surface_ids);
+ mLock.lock();
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Cannot attach stream splitter buffer to outputs: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
+ // let prepareNextBuffer handle the error.)
+ if (res == NO_INIT && mState == STATE_CONFIGURED) {
+ mState = STATE_ABANDONED;
+ }
+
+ return res;
+ }
+
+ /**
+ * FenceFD now owned by HAL except in case of error,
+ * in which case we reassign it to acquire_fence
+ */
+ handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
+ /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);
+
+ return OK;
+}
+
+status_t Camera3SharedOutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
+ ANativeWindowBuffer* buffer, int anwReleaseFence) {
+ status_t res = consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
+
+ // After queuing buffer to the internal consumer queue, check whether the buffer is
+ // successfully queued to the output queues.
+ if (res == OK) {
+ res = mStreamSplitter->getOnFrameAvailableResult();
+ if (res != OK) {
+ ALOGE("%s: getOnFrameAvailable returns %d", __FUNCTION__, res);
+ }
+ } else {
+ ALOGE("%s: queueBufer failed %d", __FUNCTION__, res);
+ }
+
+ return res;
+}
+
status_t Camera3SharedOutputStream::configureQueueLocked() {
status_t res;
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index cc96076..7be0940 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -40,8 +40,7 @@
virtual ~Camera3SharedOutputStream();
- virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
- const std::vector<size_t>& surface_ids);
+ virtual status_t notifyBufferReleased(ANativeWindowBuffer *buffer);
virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
@@ -62,6 +61,15 @@
*/
status_t connectStreamSplitterLocked();
+ /**
+ * Internal Camera3Stream interface
+ */
+ virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
+ const std::vector<size_t>& surface_ids);
+
+ virtual status_t queueBufferToConsumer(sp<ANativeWindow>& consumer,
+ ANativeWindowBuffer* buffer, int anwReleaseFence);
+
virtual status_t configureQueueLocked();
virtual status_t disconnectLocked();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index c3b7565..53a3168 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -443,7 +443,8 @@
return OK;
}
-status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) {
+status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer,
+ const std::vector<size_t>& surface_ids) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
status_t res = OK;
@@ -470,7 +471,7 @@
}
}
- res = getBufferLocked(buffer);
+ res = getBufferLocked(buffer, surface_ids);
if (res == OK) {
fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true);
if (buffer->buffer) {
@@ -745,7 +746,8 @@
return res;
}
-status_t Camera3Stream::getBufferLocked(camera3_stream_buffer *) {
+status_t Camera3Stream::getBufferLocked(camera3_stream_buffer *,
+ const std::vector<size_t>&) {
ALOGE("%s: This type of stream does not support output", __FUNCTION__);
return INVALID_OPERATION;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 471b393..56cb827 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -277,12 +277,18 @@
* Fill in the camera3_stream_buffer with the next valid buffer for this
* stream, to hand over to the HAL.
*
+ * Multiple surfaces could share the same HAL stream, but a request may
+ * be only for a subset of surfaces. In this case, the
+ * Camera3StreamInterface object needs the surface ID information to acquire
+ * buffers for those surfaces.
+ *
* This method may only be called once finishConfiguration has been called.
* For bidirectional streams, this method applies to the output-side
* buffers.
*
*/
- status_t getBuffer(camera3_stream_buffer *buffer);
+ status_t getBuffer(camera3_stream_buffer *buffer,
+ const std::vector<size_t>& surface_ids = std::vector<size_t>());
/**
* Return a buffer to the stream after use by the HAL.
@@ -412,7 +418,8 @@
// cast to camera3_stream*, implementations must increment the
// refcount of the stream manually in getBufferLocked, and decrement it in
// returnBufferLocked.
- virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+ virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
+ const std::vector<size_t>& surface_ids = std::vector<size_t>());
virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer,
nsecs_t timestamp);
virtual status_t getInputBufferLocked(camera3_stream_buffer *buffer);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index ceea08a..f7b092f 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -200,12 +200,19 @@
* Fill in the camera3_stream_buffer with the next valid buffer for this
* stream, to hand over to the HAL.
*
+ * Multiple surfaces could share the same HAL stream, but a request may
+ * be only for a subset of surfaces. In this case, the
+ * Camera3StreamInterface object needs the surface ID information to acquire
+ * buffers for those surfaces. For the case of single surface for a HAL
+ * stream, surface_ids parameter has no effect.
+ *
* This method may only be called once finishConfiguration has been called.
* For bidirectional streams, this method applies to the output-side
* buffers.
*
*/
- virtual status_t getBuffer(camera3_stream_buffer *buffer) = 0;
+ virtual status_t getBuffer(camera3_stream_buffer *buffer,
+ const std::vector<size_t>& surface_ids = std::vector<size_t>()) = 0;
/**
* Return a buffer to the stream after use by the HAL.
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index c9f43aa..deb6735 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -37,10 +37,10 @@
namespace android {
status_t Camera3StreamSplitter::connect(const std::vector<sp<Surface> >& surfaces,
- uint32_t consumerUsage, size_t hal_max_buffers,
- sp<Surface>& consumer) {
- if (consumer != nullptr) {
- ALOGE("%s: output Surface is not NULL", __FUNCTION__);
+ uint32_t consumerUsage, size_t halMaxBuffers, sp<Surface>* consumer) {
+ ATRACE_CALL();
+ if (consumer == nullptr) {
+ SP_LOGE("%s: consumer pointer is NULL", __FUNCTION__);
return BAD_VALUE;
}
@@ -48,129 +48,147 @@
status_t res = OK;
if (mOutputs.size() > 0 || mConsumer != nullptr) {
- ALOGE("%s: StreamSplitter already connected", __FUNCTION__);
+ SP_LOGE("%s: already connected", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ if (mBuffers.size() > 0) {
+ SP_LOGE("%s: still has %zu pending buffers", __FUNCTION__, mBuffers.size());
return BAD_VALUE;
}
+ mMaxHalBuffers = halMaxBuffers;
+ mConsumerName = getUniqueConsumerName();
// Add output surfaces. This has to be before creating internal buffer queue
// in order to get max consumer side buffers.
for (size_t i = 0; i < surfaces.size(); i++) {
if (surfaces[i] == nullptr) {
- ALOGE("%s: Fatal: surface is NULL", __FUNCTION__);
+ SP_LOGE("%s: Fatal: surface is NULL", __FUNCTION__);
return BAD_VALUE;
}
- res = addOutputLocked(surfaces[i], hal_max_buffers, OutputType::NonDeferred);
+ res = addOutputLocked(surfaces[i]);
if (res != OK) {
- ALOGE("%s: Failed to add output surface: %s(%d)",
+ SP_LOGE("%s: Failed to add output surface: %s(%d)",
__FUNCTION__, strerror(-res), res);
return res;
}
}
- // Create buffer queue for input
+ // Create BufferQueue for input
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ // Allocate 1 extra buffer to handle the case where all buffers are detached
+ // from input, and attached to the outputs. In this case, the input queue's
+ // dequeueBuffer can still allocate 1 extra buffer before being blocked by
+ // the output's attachBuffer().
mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage,
- mMaxConsumerBuffers);
+ mMaxConsumerBuffers+1);
if (mBufferItemConsumer == nullptr) {
return NO_MEMORY;
}
- mConsumer->setConsumerName(getUniqueConsumerName());
+ mConsumer->setConsumerName(mConsumerName);
- mSurface = new Surface(mProducer);
- if (mSurface == nullptr) {
+ *consumer = new Surface(mProducer);
+ if (*consumer == nullptr) {
return NO_MEMORY;
}
- consumer = mSurface;
res = mConsumer->consumerConnect(this, /* controlledByApp */ false);
+ SP_LOGV("%s: connected", __FUNCTION__);
return res;
}
+status_t Camera3StreamSplitter::getOnFrameAvailableResult() {
+ ATRACE_CALL();
+ return mOnFrameAvailableRes.load();
+}
+
void Camera3StreamSplitter::disconnect() {
+ ATRACE_CALL();
Mutex::Autolock lock(mMutex);
+ for (auto& notifier : mNotifiers) {
+ sp<IGraphicBufferProducer> producer = notifier.first;
+ sp<OutputListener> listener = notifier.second;
+ IInterface::asBinder(producer)->unlinkToDeath(listener);
+ }
+ mNotifiers.clear();
+
for (auto& output : mOutputs) {
output->disconnect(NATIVE_WINDOW_API_CAMERA);
}
mOutputs.clear();
+ mOutputSlots.clear();
- if (mConsumer != nullptr) {
- mConsumer->consumerDisconnect();
- mConsumer.clear();
- }
+ mConsumer->consumerDisconnect();
if (mBuffers.size() > 0) {
- ALOGI("%zu buffers still being tracked", mBuffers.size());
+ SP_LOGW("%zu buffers still being tracked", mBuffers.size());
+ mBuffers.clear();
}
+
+ mMaxHalBuffers = 0;
+ mMaxConsumerBuffers = 0;
+ SP_LOGV("%s: Disconnected", __FUNCTION__);
}
+
Camera3StreamSplitter::~Camera3StreamSplitter() {
disconnect();
}
-status_t Camera3StreamSplitter::addOutput(
- const sp<Surface>& outputQueue, size_t hal_max_buffers) {
+status_t Camera3StreamSplitter::addOutput(const sp<Surface>& outputQueue) {
+ ATRACE_CALL();
Mutex::Autolock lock(mMutex);
- return addOutputLocked(outputQueue, hal_max_buffers, OutputType::Deferred);
+ status_t res = addOutputLocked(outputQueue);
+
+ if (res != OK) {
+ SP_LOGE("%s: addOutputLocked failed %d", __FUNCTION__, res);
+ return res;
+ }
+
+ res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
+
+ return res;
}
-status_t Camera3StreamSplitter::addOutputLocked(
- const sp<Surface>& outputQueue, size_t hal_max_buffers,
- OutputType outputType) {
+status_t Camera3StreamSplitter::addOutputLocked(const sp<Surface>& outputQueue) {
+ ATRACE_CALL();
if (outputQueue == nullptr) {
- ALOGE("addOutput: outputQueue must not be NULL");
- return BAD_VALUE;
- }
- if (hal_max_buffers < 1) {
- ALOGE("%s: Camera HAL requested max_buffer count: %zu, requires at least 1",
- __FUNCTION__, hal_max_buffers);
+ SP_LOGE("addOutput: outputQueue must not be NULL");
return BAD_VALUE;
}
sp<IGraphicBufferProducer> gbp = outputQueue->getIGraphicBufferProducer();
// Connect to the buffer producer
- IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
sp<OutputListener> listener(new OutputListener(this, gbp));
IInterface::asBinder(gbp)->linkToDeath(listener);
- status_t status = gbp->connect(listener, NATIVE_WINDOW_API_CAMERA,
- /* producerControlledByApp */ true, &queueBufferOutput);
- if (status != NO_ERROR) {
- ALOGE("addOutput: failed to connect (%d)", status);
- return status;
+ status_t res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener);
+ if (res != NO_ERROR) {
+ SP_LOGE("addOutput: failed to connect (%d)", res);
+ return res;
}
// Query consumer side buffer count, and update overall buffer count
int maxConsumerBuffers = 0;
- status = static_cast<ANativeWindow*>(outputQueue.get())->query(
+ res = static_cast<ANativeWindow*>(outputQueue.get())->query(
outputQueue.get(),
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
- if (status != OK) {
- ALOGE("%s: Unable to query consumer undequeued buffer count"
+ if (res != OK) {
+ SP_LOGE("%s: Unable to query consumer undequeued buffer count"
" for surface", __FUNCTION__);
- return status;
+ return res;
}
- if (maxConsumerBuffers > mMaxConsumerBuffers) {
- if (outputType == OutputType::Deferred) {
- ALOGE("%s: Fatal: Deferred surface has higher consumer buffer count"
- " %d than what's already configured %d", __FUNCTION__,
- maxConsumerBuffers, mMaxConsumerBuffers);
- return BAD_VALUE;
- }
- mMaxConsumerBuffers = maxConsumerBuffers;
- }
-
- ALOGV("%s: Consumer wants %d buffers, HAL wants %zu", __FUNCTION__,
- maxConsumerBuffers, hal_max_buffers);
- size_t totalBufferCount = maxConsumerBuffers + hal_max_buffers;
- status = native_window_set_buffer_count(outputQueue.get(),
+ SP_LOGV("%s: Consumer wants %d buffers, Producer wants %zu", __FUNCTION__,
+ maxConsumerBuffers, mMaxHalBuffers);
+ size_t totalBufferCount = maxConsumerBuffers + mMaxHalBuffers;
+ res = native_window_set_buffer_count(outputQueue.get(),
totalBufferCount);
- if (status != OK) {
- ALOGE("%s: Unable to set buffer count for surface %p",
+ if (res != OK) {
+ SP_LOGE("%s: Unable to set buffer count for surface %p",
__FUNCTION__, outputQueue.get());
- return status;
+ return res;
}
// Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
@@ -183,157 +201,239 @@
outputQueue->setDequeueTimeout(kDequeueBufferTimeout);
}
- status = gbp->allowAllocation(false);
- if (status != OK) {
- ALOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
- return status;
+ res = gbp->allowAllocation(false);
+ if (res != OK) {
+ SP_LOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
+ return res;
}
// Add new entry into mOutputs
mOutputs.push_back(gbp);
+ mNotifiers[gbp] = listener;
+ mOutputSlots[gbp] = std::make_unique<OutputSlots>(totalBufferCount);
+
+ mMaxConsumerBuffers += maxConsumerBuffers;
return NO_ERROR;
}
+status_t Camera3StreamSplitter::outputBufferLocked(const sp<IGraphicBufferProducer>& output,
+ const BufferItem& bufferItem) {
+ ATRACE_CALL();
+ status_t res;
+ IGraphicBufferProducer::QueueBufferInput queueInput(
+ bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
+ bufferItem.mDataSpace, bufferItem.mCrop,
+ static_cast<int32_t>(bufferItem.mScalingMode),
+ bufferItem.mTransform, bufferItem.mFence);
+
+ IGraphicBufferProducer::QueueBufferOutput queueOutput;
+
+ uint64_t bufferId = bufferItem.mGraphicBuffer->getId();
+ const BufferTracker& tracker = *(mBuffers[bufferId]);
+ int slot = getSlotForOutputLocked(output, tracker.getBuffer());
+
+ // In case the output BufferQueue has its own lock, if we hold splitter lock while calling
+ // queueBuffer (which will try to acquire the output lock), the output could be holding its
+ // own lock calling releaseBuffer (which will try to acquire the splitter lock), running into
+ // circular lock situation.
+ mMutex.unlock();
+ res = output->queueBuffer(slot, queueInput, &queueOutput);
+ mMutex.lock();
+
+ SP_LOGV("%s: Queuing buffer to buffer queue %p slot %d returns %d",
+ __FUNCTION__, output.get(), slot, res);
+ if (res != OK) {
+ if (res != NO_INIT && res != DEAD_OBJECT) {
+ SP_LOGE("Queuing buffer to output failed (%d)", res);
+ }
+ // If we just discovered that this output has been abandoned, note
+ // that, increment the release count so that we still release this
+ // buffer eventually, and move on to the next output
+ onAbandonedLocked();
+ decrementBufRefCountLocked(bufferItem.mGraphicBuffer->getId(), output);
+ return res;
+ }
+
+ // If the queued buffer replaces a pending buffer in the async
+ // queue, no onBufferReleased is called by the buffer queue.
+ // Proactively trigger the callback to avoid buffer loss.
+ if (queueOutput.bufferReplaced) {
+ onBufferReleasedByOutputLocked(output);
+ }
+
+ return res;
+}
+
String8 Camera3StreamSplitter::getUniqueConsumerName() {
static volatile int32_t counter = 0;
return String8::format("Camera3StreamSplitter-%d", android_atomic_inc(&counter));
}
-status_t Camera3StreamSplitter::notifyRequestedSurfaces(
- const std::vector<size_t>& surfaces) {
+status_t Camera3StreamSplitter::notifyBufferReleased(const sp<GraphicBuffer>& buffer) {
ATRACE_CALL();
+ status_t res = OK;
+
Mutex::Autolock lock(mMutex);
- mRequestedSurfaces.push_back(surfaces);
- return OK;
-}
+ uint64_t bufferId = buffer->getId();
+ std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[bufferId]);
+ mBuffers.erase(bufferId);
-
-void Camera3StreamSplitter::onFrameAvailable(const BufferItem& /* item */) {
- ATRACE_CALL();
- Mutex::Autolock lock(mMutex);
-
- // The current policy is that if any one consumer is consuming buffers too
- // slowly, the splitter will stall the rest of the outputs by not acquiring
- // any more buffers from the input. This will cause back pressure on the
- // input queue, slowing down its producer.
-
- // If there are too many outstanding buffers, we block until a buffer is
- // released back to the input in onBufferReleased
- while (mOutstandingBuffers >= mMaxConsumerBuffers) {
- mReleaseCondition.wait(mMutex);
-
- // If the splitter is abandoned while we are waiting, the release
- // condition variable will be broadcast, and we should just return
- // without attempting to do anything more (since the input queue will
- // also be abandoned).
- if (mIsAbandoned) {
- return;
+ for (const auto surface : tracker_ptr->requestedSurfaces()) {
+ sp<IGraphicBufferProducer>& gbp = mOutputs[surface];
+ OutputSlots& outputSlots = *(mOutputSlots[gbp]);
+ int slot = getSlotForOutputLocked(gbp, buffer);
+ if (slot != BufferItem::INVALID_BUFFER_SLOT) {
+ gbp->detachBuffer(slot);
+ outputSlots[slot].clear();
}
}
- // If the splitter is abandoned without reaching mMaxConsumerBuffers, just
- // return without attempting to do anything more.
- if (mIsAbandoned) {
- return;
+
+ return res;
+}
+
+status_t Camera3StreamSplitter::attachBufferToOutputs(ANativeWindowBuffer* anb,
+ const std::vector<size_t>& surface_ids) {
+ ATRACE_CALL();
+ status_t res = OK;
+
+ Mutex::Autolock lock(mMutex);
+
+ sp<GraphicBuffer> gb(static_cast<GraphicBuffer*>(anb));
+ uint64_t bufferId = gb->getId();
+
+ // Initialize buffer tracker for this input buffer
+ auto tracker = std::make_unique<BufferTracker>(gb, surface_ids);
+
+ for (auto& surface_id : surface_ids) {
+ sp<IGraphicBufferProducer>& gbp = mOutputs[surface_id];
+ int slot = BufferItem::INVALID_BUFFER_SLOT;
+ //Temporarly Unlock the mutex when trying to attachBuffer to the output
+ //queue, because attachBuffer could block in case of a slow consumer. If
+ //we block while holding the lock, onFrameAvailable and onBufferReleased
+ //will block as well because they need to acquire the same lock.
+ mMutex.unlock();
+ res = gbp->attachBuffer(&slot, gb);
+ mMutex.lock();
+ if (res != OK) {
+ SP_LOGE("%s: Cannot acquireBuffer from GraphicBufferProducer %p: %s (%d)",
+ __FUNCTION__, gbp.get(), strerror(-res), res);
+ return res;
+ }
+ auto& outputSlots = *mOutputSlots[gbp];
+ if (outputSlots[slot] != nullptr) {
+ // If the buffer is attached to a slot which already contains a buffer,
+ // the previous buffer will be removed from the output queue. Decrement
+ // the reference count accordingly.
+ decrementBufRefCountLocked(outputSlots[slot]->getId(), gbp);
+ }
+ SP_LOGV("%s: Attached buffer %p to slot %d on output %p.",__FUNCTION__, gb.get(),
+ slot, gbp.get());
+ outputSlots[slot] = gb;
}
- ++mOutstandingBuffers;
+ mBuffers[bufferId] = std::move(tracker);
+
+ return res;
+}
+
+void Camera3StreamSplitter::onFrameAvailable(const BufferItem& /*item*/) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mMutex);
// Acquire and detach the buffer from the input
BufferItem bufferItem;
- status_t status = mConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "acquiring buffer from input failed (%d)", status);
+ status_t res = mConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
+ if (res != NO_ERROR) {
+ SP_LOGE("%s: Acquiring buffer from input failed (%d)", __FUNCTION__, res);
+ mOnFrameAvailableRes.store(res);
+ return;
+ }
+ if (mBuffers.find(bufferItem.mGraphicBuffer->getId()) == mBuffers.end()) {
+ SP_LOGE("%s: Acquired buffer doesn't exist in attached buffer map",
+ __FUNCTION__);
+ mOnFrameAvailableRes.store(INVALID_OPERATION);
+ return;
+ }
- ALOGV("acquired buffer %#" PRIx64 " from input",
- bufferItem.mGraphicBuffer->getId());
+ SP_LOGV("acquired buffer %" PRId64 " from input at slot %d",
+ bufferItem.mGraphicBuffer->getId(), bufferItem.mSlot);
- status = mConsumer->detachBuffer(bufferItem.mSlot);
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "detaching buffer from input failed (%d)", status);
-
- IGraphicBufferProducer::QueueBufferInput queueInput(
- bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
- bufferItem.mDataSpace, bufferItem.mCrop,
- static_cast<int32_t>(bufferItem.mScalingMode),
- bufferItem.mTransform, bufferItem.mFence);
+ res = mConsumer->detachBuffer(bufferItem.mSlot);
+ if (res != NO_ERROR) {
+ SP_LOGE("%s: detaching buffer from input failed (%d)", __FUNCTION__, res);
+ mOnFrameAvailableRes.store(res);
+ return;
+ }
// Attach and queue the buffer to each of the outputs
- std::vector<std::vector<size_t> >::iterator surfaces = mRequestedSurfaces.begin();
- if (surfaces != mRequestedSurfaces.end()) {
+ BufferTracker& tracker = *(mBuffers[bufferItem.mGraphicBuffer->getId()]);
- LOG_ALWAYS_FATAL_IF(surfaces->size() == 0,
- "requested surface ids shouldn't be empty");
+ SP_LOGV("%s: BufferTracker for buffer %" PRId64 ", number of requests %zu",
+ __FUNCTION__, bufferItem.mGraphicBuffer->getId(), tracker.requestedSurfaces().size());
+ for (const auto id : tracker.requestedSurfaces()) {
- // Initialize our reference count for this buffer
- mBuffers[bufferItem.mGraphicBuffer->getId()] =
- std::unique_ptr<BufferTracker>(
- new BufferTracker(bufferItem.mGraphicBuffer, surfaces->size()));
+ LOG_ALWAYS_FATAL_IF(id >= mOutputs.size(),
+ "requested surface id exceeding max registered ids");
- for (auto id : *surfaces) {
-
- LOG_ALWAYS_FATAL_IF(id >= mOutputs.size(),
- "requested surface id exceeding max registered ids");
-
- int slot = BufferItem::INVALID_BUFFER_SLOT;
- status = mOutputs[id]->attachBuffer(&slot, bufferItem.mGraphicBuffer);
- if (status == NO_INIT) {
- // If we just discovered that this output has been abandoned, note
- // that, decrement the reference count so that we still release this
- // buffer eventually, and move on to the next output
- onAbandonedLocked();
- mBuffers[bufferItem.mGraphicBuffer->getId()]->
- decrementReferenceCountLocked();
- continue;
- } else if (status == WOULD_BLOCK) {
- // If the output is async, attachBuffer may return WOULD_BLOCK
- // indicating number of dequeued buffers has reached limit. In
- // this case, simply decrement the reference count, and move on
- // to the next output.
- // TODO: Do we need to report BUFFER_ERROR for this result?
- mBuffers[bufferItem.mGraphicBuffer->getId()]->
- decrementReferenceCountLocked();
- continue;
- } else if (status == TIMED_OUT) {
- // If attachBuffer times out due to the value set by
- // setDequeueTimeout, simply decrement the reference count, and
- // move on to the next output.
- // TODO: Do we need to report BUFFER_ERROR for this result?
- mBuffers[bufferItem.mGraphicBuffer->getId()]->
- decrementReferenceCountLocked();
- continue;
- } else {
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "attaching buffer to output failed (%d)", status);
- }
-
- IGraphicBufferProducer::QueueBufferOutput queueOutput;
- status = mOutputs[id]->queueBuffer(slot, queueInput, &queueOutput);
- if (status == NO_INIT) {
- // If we just discovered that this output has been abandoned, note
- // that, increment the release count so that we still release this
- // buffer eventually, and move on to the next output
- onAbandonedLocked();
- mBuffers[bufferItem.mGraphicBuffer->getId()]->
- decrementReferenceCountLocked();
- continue;
- } else {
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "queueing buffer to output failed (%d)", status);
- }
-
- // If the queued buffer replaces a pending buffer in the async
- // queue, no onBufferReleased is called by the buffer queue.
- // Proactively trigger the callback to avoid buffer loss.
- if (queueOutput.bufferReplaced) {
- onBufferReleasedByOutputLocked(mOutputs[id]);
- }
-
- ALOGV("queued buffer %#" PRIx64 " to output %p",
- bufferItem.mGraphicBuffer->getId(), mOutputs[id].get());
+ res = outputBufferLocked(mOutputs[id], bufferItem);
+ if (res != OK) {
+ SP_LOGE("%s: outputBufferLocked failed %d", __FUNCTION__, res);
+ mOnFrameAvailableRes.store(res);
+ // If we fail to send buffer to certain output, keep sending to
+ // other outputs.
+ continue;
}
+ }
- mRequestedSurfaces.erase(surfaces);
+ mOnFrameAvailableRes.store(res);
+}
+
+void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id,
+ const sp<IGraphicBufferProducer>& from) {
+ ATRACE_CALL();
+ size_t referenceCount = mBuffers[id]->decrementReferenceCountLocked();
+
+ removeSlotForOutputLocked(from, mBuffers[id]->getBuffer());
+ if (referenceCount > 0) {
+ return;
+ }
+
+ // We no longer need to track the buffer now that it is being returned to the
+ // input. Note that this should happen before we unlock the mutex and call
+ // releaseBuffer, to avoid the case where the same bufferId is acquired in
+ // attachBufferToOutputs resulting in a new BufferTracker with same bufferId
+ // overwrites the current one.
+ std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[id]);
+ mBuffers.erase(id);
+
+ // Attach and release the buffer back to the input
+ int consumerSlot = BufferItem::INVALID_BUFFER_SLOT;
+ status_t res = mConsumer->attachBuffer(&consumerSlot, tracker_ptr->getBuffer());
+ if (res != NO_ERROR) {
+ SP_LOGE("%s: attaching buffer to input failed (%d)", __FUNCTION__, res);
+ return;
+ }
+
+ // Temporarily unlock mutex to avoid circular lock:
+ // 1. This function holds splitter lock, calls releaseBuffer which triggers
+ // onBufferReleased in Camera3OutputStream. onBufferReleased waits on the
+ // OutputStream lock
+ // 2. Camera3SharedOutputStream::getBufferLocked calls
+ // attachBufferToOutputs, which holds the stream lock, and waits for the
+ // splitter lock.
+ sp<IGraphicBufferConsumer> consumer(mConsumer);
+ mMutex.unlock();
+ if (consumer != nullptr) {
+ res = consumer->releaseBuffer(consumerSlot, /* frameNumber */ 0,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence());
+ } else {
+ SP_LOGE("%s: consumer has become null!", __FUNCTION__);
+ }
+ mMutex.lock();
+ // If the producer of this queue is disconnected, -22 error will occur
+ if (res != NO_ERROR) {
+ SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res);
}
}
@@ -347,73 +447,79 @@
void Camera3StreamSplitter::onBufferReleasedByOutputLocked(
const sp<IGraphicBufferProducer>& from) {
-
+ ATRACE_CALL();
sp<GraphicBuffer> buffer;
sp<Fence> fence;
- status_t status = from->detachNextBuffer(&buffer, &fence);
- if (status == NO_INIT) {
+ status_t res = from->detachNextBuffer(&buffer, &fence);
+ if (res == NO_INIT) {
// If we just discovered that this output has been abandoned, note that,
// but we can't do anything else, since buffer is invalid
onAbandonedLocked();
return;
+ } else if (res == NO_MEMORY) {
+ SP_LOGV("%s: No free buffers", __FUNCTION__);
+ return;
} else {
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "detaching buffer from output failed (%d)", status);
+ LOG_ALWAYS_FATAL_IF(res != NO_ERROR,
+ "detaching buffer from output failed (%d)", res);
}
- ALOGV("detached buffer %#" PRIx64 " from output %p",
- buffer->getId(), from.get());
-
BufferTracker& tracker = *(mBuffers[buffer->getId()]);
-
// Merge the release fence of the incoming buffer so that the fence we send
// back to the input includes all of the outputs' fences
- tracker.mergeFence(fence);
+ if (fence != nullptr && fence->isValid()) {
+ tracker.mergeFence(fence);
+ }
+ SP_LOGV("detached buffer %" PRId64 " %p from output %p",
+ buffer->getId(), buffer.get(), from.get());
// Check to see if this is the last outstanding reference to this buffer
- size_t referenceCount = tracker.decrementReferenceCountLocked();
- ALOGV("buffer %#" PRIx64 " reference count %zu", buffer->getId(),
- referenceCount);
- if (referenceCount > 0) {
- return;
- }
-
- // If we've been abandoned, we can't return the buffer to the input, so just
- // stop tracking it and move on
- if (mIsAbandoned) {
- mBuffers.erase(buffer->getId());
- return;
- }
-
- // Attach and release the buffer back to the input
- int consumerSlot = BufferItem::INVALID_BUFFER_SLOT;
- status = mConsumer->attachBuffer(&consumerSlot, tracker.getBuffer());
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "attaching buffer to input failed (%d)", status);
-
- status = mConsumer->releaseBuffer(consumerSlot, /* frameNumber */ 0,
- EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker.getMergedFence());
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "releasing buffer to input failed (%d)", status);
-
- ALOGV("released buffer %#" PRIx64 " to input", buffer->getId());
-
- // We no longer need to track the buffer once it has been returned to the
- // input
- mBuffers.erase(buffer->getId());
-
- // Notify any waiting onFrameAvailable calls
- --mOutstandingBuffers;
- mReleaseCondition.signal();
+ decrementBufRefCountLocked(buffer->getId(), from);
}
void Camera3StreamSplitter::onAbandonedLocked() {
- ALOGE("one of my outputs has abandoned me");
- if (!mIsAbandoned && mConsumer != nullptr) {
- mConsumer->consumerDisconnect();
+ // If this is called from binderDied callback, it means the app process
+ // holding the binder has died. CameraService will be notified of the binder
+ // death, and camera device will be closed, which in turn calls
+ // disconnect().
+ //
+ // If this is called from onBufferReleasedByOutput or onFrameAvailable, one
+ // consumer being abanoned shouldn't impact the other consumer. So we won't
+ // stop the buffer flow.
+ //
+ // In both cases, we don't need to do anything here.
+ SP_LOGV("One of my outputs has abandoned me");
+}
+
+int Camera3StreamSplitter::getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+ const sp<GraphicBuffer>& gb) {
+ auto& outputSlots = *mOutputSlots[gbp];
+
+ for (size_t i = 0; i < outputSlots.size(); i++) {
+ if (outputSlots[i] == gb) {
+ return (int)i;
+ }
}
- mIsAbandoned = true;
- mReleaseCondition.broadcast();
+
+ SP_LOGE("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
+ gbp.get());
+ return BufferItem::INVALID_BUFFER_SLOT;
+}
+
+status_t Camera3StreamSplitter::removeSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+ const sp<GraphicBuffer>& gb) {
+ auto& outputSlots = *mOutputSlots[gbp];
+
+ for (size_t i = 0; i < outputSlots.size(); i++) {
+ if (outputSlots[i] == gb) {
+ outputSlots[i].clear();
+ return NO_ERROR;
+ }
+ }
+
+ SP_LOGE("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
+ gbp.get());
+ return BAD_VALUE;
}
Camera3StreamSplitter::OutputListener::OutputListener(
@@ -422,6 +528,7 @@
: mSplitter(splitter), mOutput(output) {}
void Camera3StreamSplitter::OutputListener::onBufferReleased() {
+ ATRACE_CALL();
sp<Camera3StreamSplitter> splitter = mSplitter.promote();
sp<IGraphicBufferProducer> output = mOutput.promote();
if (splitter != nullptr && output != nullptr) {
@@ -438,9 +545,9 @@
}
Camera3StreamSplitter::BufferTracker::BufferTracker(
- const sp<GraphicBuffer>& buffer, size_t referenceCount)
- : mBuffer(buffer), mMergedFence(Fence::NO_FENCE),
- mReferenceCount(referenceCount) {}
+ const sp<GraphicBuffer>& buffer, const std::vector<size_t>& requestedSurfaces)
+ : mBuffer(buffer), mMergedFence(Fence::NO_FENCE), mRequestedSurfaces(requestedSurfaces),
+ mReferenceCount(requestedSurfaces.size()) {}
void Camera3StreamSplitter::BufferTracker::mergeFence(const sp<Fence>& with) {
mMergedFence = Fence::merge(String8("Camera3StreamSplitter"), mMergedFence, with);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 92371ff..cc623e0 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -26,6 +26,11 @@
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
+#define SP_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+#define SP_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+#define SP_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+#define SP_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+
namespace android {
class GraphicBuffer;
@@ -47,8 +52,8 @@
// Connect to the stream splitter by creating buffer queue and connecting it
// with output surfaces.
status_t connect(const std::vector<sp<Surface> >& surfaces,
- uint32_t consumerUsage, size_t hal_max_buffers,
- sp<Surface>& consumer);
+ uint32_t consumerUsage, size_t halMaxBuffers,
+ sp<Surface>* consumer);
// addOutput adds an output BufferQueue to the splitter. The splitter
// connects to outputQueue as a CPU producer, and any buffers queued
@@ -61,13 +66,22 @@
// outputQueue has not been added to the splitter. BAD_VALUE is returned if
// outputQueue is NULL. See IGraphicBufferProducer::connect for explanations
// of other error codes.
- status_t addOutput(const sp<Surface>& outputQueue, size_t hal_max_buffers);
+ status_t addOutput(const sp<Surface>& outputQueue);
- // Request surfaces for a particular frame number. The requested surfaces
- // are stored in a FIFO queue. And when the buffer becomes available from the
- // input queue, the registered surfaces are used to decide which output is
- // the buffer sent to.
- status_t notifyRequestedSurfaces(const std::vector<size_t>& surfaces);
+ // Notification that the graphic buffer has been released to the input
+ // BufferQueue. The buffer should be reused by the camera device instead of
+ // queuing to the outputs.
+ status_t notifyBufferReleased(const sp<GraphicBuffer>& buffer);
+
+ // Attach a buffer to the specified outputs. This call reserves a buffer
+ // slot in the output queue.
+ status_t attachBufferToOutputs(ANativeWindowBuffer* anb,
+ const std::vector<size_t>& surface_ids);
+
+ // Get return value of onFrameAvailable to work around problem that
+ // onFrameAvailable is void. This function should be called by the producer
+ // right after calling queueBuffer().
+ status_t getOnFrameAvailableResult();
// Disconnect the buffer queue from output surfaces.
void disconnect();
@@ -115,6 +129,10 @@
// acquire. This must be called with mMutex locked.
void onAbandonedLocked();
+ // Decrement the buffer's reference count. Once the reference count becomes
+ // 0, return the buffer back to the input BufferQueue.
+ void decrementBufRefCountLocked(uint64_t id, const sp<IGraphicBufferProducer>& from);
+
// This is a thin wrapper class that lets us determine which BufferQueue
// the IProducerListener::onBufferReleased callback is associated with. We
// create one of these per output BufferQueue, and then pass the producer
@@ -139,7 +157,8 @@
class BufferTracker {
public:
- BufferTracker(const sp<GraphicBuffer>& buffer, size_t referenceCount);
+ BufferTracker(const sp<GraphicBuffer>& buffer,
+ const std::vector<size_t>& requestedSurfaces);
~BufferTracker() = default;
const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
@@ -151,6 +170,8 @@
// Only called while mMutex is held
size_t decrementReferenceCountLocked();
+ const std::vector<size_t> requestedSurfaces() const { return mRequestedSurfaces; }
+
private:
// Disallow copying
@@ -159,39 +180,43 @@
sp<GraphicBuffer> mBuffer; // One instance that holds this native handle
sp<Fence> mMergedFence;
+
+ // Request surfaces for a particular buffer. And when the buffer becomes
+ // available from the input queue, the registered surfaces are used to decide
+ // which output is the buffer sent to.
+ std::vector<size_t> mRequestedSurfaces;
size_t mReferenceCount;
};
- // A deferred output is an output being added to the splitter after
- // connect() call, whereas a non deferred output is added within connect()
- // call.
- enum class OutputType { NonDeferred, Deferred };
-
// Must be accessed through RefBase
virtual ~Camera3StreamSplitter();
- status_t addOutputLocked(const sp<Surface>& outputQueue,
- size_t hal_max_buffers, OutputType outputType);
+ status_t addOutputLocked(const sp<Surface>& outputQueue);
+
+ // Send a buffer to particular output, and increment the reference count
+ // of the buffer. If this output is abandoned, the buffer's reference count
+ // won't be incremented.
+ status_t outputBufferLocked(const sp<IGraphicBufferProducer>& output,
+ const BufferItem& bufferItem);
// Get unique name for the buffer queue consumer
- static String8 getUniqueConsumerName();
+ String8 getUniqueConsumerName();
- // Max consumer side buffers for deferred surface. This will be used as a
- // lower bound for overall consumer side max buffers.
- static const int MAX_BUFFERS_DEFERRED_OUTPUT = 2;
- int mMaxConsumerBuffers = MAX_BUFFERS_DEFERRED_OUTPUT;
+ // Helper function to get the BufferQueue slot where a particular buffer is attached to.
+ int getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+ const sp<GraphicBuffer>& gb);
+ // Helper function to remove the buffer from the BufferQueue slot
+ status_t removeSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+ const sp<GraphicBuffer>& gb);
+
+
+ // Sum of max consumer buffers for all outputs
+ size_t mMaxConsumerBuffers = 0;
+ size_t mMaxHalBuffers = 0;
static const nsecs_t kDequeueBufferTimeout = s2ns(1); // 1 sec
- // mIsAbandoned is set to true when an output dies. Once the Camera3StreamSplitter
- // has been abandoned, it will continue to detach buffers from other
- // outputs, but it will disconnect from the input and not attempt to
- // communicate with it further.
- bool mIsAbandoned = false;
-
Mutex mMutex;
- Condition mReleaseCondition;
- int mOutstandingBuffers = 0;
sp<IGraphicBufferProducer> mProducer;
sp<IGraphicBufferConsumer> mConsumer;
@@ -199,14 +224,28 @@
sp<Surface> mSurface;
std::vector<sp<IGraphicBufferProducer> > mOutputs;
- // Tracking which outputs should the buffer be attached and queued
- // to for each input buffer.
- std::vector<std::vector<size_t> > mRequestedSurfaces;
-
// Map of GraphicBuffer IDs (GraphicBuffer::getId()) to buffer tracking
// objects (which are mostly for counting how many outputs have released the
// buffer, but also contain merged release fences).
std::unordered_map<uint64_t, std::unique_ptr<BufferTracker> > mBuffers;
+
+ struct GBPHash {
+ std::size_t operator()(const sp<IGraphicBufferProducer>& producer) const {
+ return std::hash<IGraphicBufferProducer *>{}(producer.get());
+ }
+ };
+
+ std::unordered_map<sp<IGraphicBufferProducer>, sp<OutputListener>,
+ GBPHash> mNotifiers;
+
+ typedef std::vector<sp<GraphicBuffer>> OutputSlots;
+ std::unordered_map<sp<IGraphicBufferProducer>, std::unique_ptr<OutputSlots>,
+ GBPHash> mOutputSlots;
+
+ // Latest onFrameAvailable return value
+ std::atomic<status_t> mOnFrameAvailableRes{0};
+
+ String8 mConsumerName;
};
} // namespace android