Merge "audio_mutex: Add mutex priority inheritance flag" into main
diff --git a/media/codec2/hal/client/GraphicBufferAllocator.cpp b/media/codec2/hal/client/GraphicBufferAllocator.cpp
index bbef1b5..7045537 100644
--- a/media/codec2/hal/client/GraphicBufferAllocator.cpp
+++ b/media/codec2/hal/client/GraphicBufferAllocator.cpp
@@ -62,14 +62,12 @@
return ::ndk::ScopedAStatus::ok();
}
-::ndk::ScopedAStatus GraphicBufferAllocator::getWaitableFds(
- IGraphicBufferAllocator::WaitableFds* _aidl_return) {
- int allocFd;
- int statusFd;
- c2_status_t ret = mGraphicsTracker->getWaitableFds(&allocFd, &statusFd);
+::ndk::ScopedAStatus GraphicBufferAllocator::getWaitableFd(
+ ::ndk::ScopedFileDescriptor* _aidl_return) {
+ int pipeFd;
+ c2_status_t ret = mGraphicsTracker->getWaitableFd(&pipeFd);
if (ret == C2_OK) {
- _aidl_return->allocEvent.set(allocFd);
- _aidl_return->statusEvent.set(statusFd);
+ _aidl_return->set(pipeFd);
return ::ndk::ScopedAStatus::ok();
}
return ::ndk::ScopedAStatus::fromServiceSpecificError(ret);
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index 5a2cb86..2424f7b 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <sys/eventfd.h>
+#include <fcntl.h>
+#include <unistd.h>
#include <media/stagefright/foundation/ADebug.h>
#include <private/android/AHardwareBufferHelpers.h>
@@ -25,6 +26,9 @@
namespace {
+static constexpr int kMaxDequeueMin = 1;
+static constexpr int kMaxDequeueMax = ::android::BufferQueueDefs::NUM_BUFFER_SLOTS - 2;
+
c2_status_t retrieveAHardwareBufferId(const C2ConstGraphicBlock &blk, uint64_t *bid) {
// TODO
(void)blk;
@@ -139,21 +143,26 @@
mDequeueable{maxDequeueCount},
mTotalDequeued{0}, mTotalCancelled{0}, mTotalDropped{0}, mTotalReleased{0},
mInConfig{false}, mStopped{false} {
- if (maxDequeueCount <= 0) {
- mMaxDequeue = kDefaultMaxDequeue;
- mMaxDequeueRequested = kDefaultMaxDequeue;
- mMaxDequeueCommitted = kDefaultMaxDequeue;
- mDequeueable = kDefaultMaxDequeue;
+ if (maxDequeueCount < kMaxDequeueMin) {
+ mMaxDequeue = kMaxDequeueMin;
+ mMaxDequeueRequested = kMaxDequeueMin;
+ mMaxDequeueCommitted = kMaxDequeueMin;
+ mDequeueable = kMaxDequeueMin;
+ } else if(maxDequeueCount > kMaxDequeueMax) {
+ mMaxDequeue = kMaxDequeueMax;
+ mMaxDequeueRequested = kMaxDequeueMax;
+ mMaxDequeueCommitted = kMaxDequeueMax;
+ mDequeueable = kMaxDequeueMax;
}
- int allocEventFd = ::eventfd(mDequeueable, EFD_CLOEXEC | EFD_NONBLOCK | EFD_SEMAPHORE);
- int statusEventFd = ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+ int pipefd[2] = { -1, -1};
+ int ret = ::pipe2(pipefd, O_CLOEXEC | O_NONBLOCK);
- mAllocEventFd.reset(allocEventFd);
- mStopEventFd.reset(statusEventFd);
+ mReadPipeFd.reset(pipefd[0]);
+ mWritePipeFd.reset(pipefd[1]);
mEventQueueThread = std::thread([this](){processEvent();});
- CHECK(allocEventFd >= 0 && statusEventFd >= 0);
+ CHECK(ret >= 0);
CHECK(mEventQueueThread.joinable());
}
@@ -161,7 +170,6 @@
stop();
if (mEventQueueThread.joinable()) {
std::unique_lock<std::mutex> l(mEventLock);
- mStopEventThread = true;
l.unlock();
mEventCv.notify_one();
mEventQueueThread.join();
@@ -231,6 +239,11 @@
c2_status_t GraphicsTracker::configureMaxDequeueCount(int maxDequeueCount) {
std::shared_ptr<BufferCache> cache;
+ if (maxDequeueCount < kMaxDequeueMin || maxDequeueCount > kMaxDequeueMax) {
+ ALOGE("max dequeue count %d is not valid", maxDequeueCount);
+ return C2_BAD_VALUE;
+ }
+
// max dequeue count which can be committed to IGBP.
// (Sometimes maxDequeueCount cannot be committed if the number of
// dequeued buffer count is bigger.)
@@ -347,89 +360,76 @@
void GraphicsTracker::stop() {
bool expected = false;
+ std::unique_lock<std::mutex> l(mEventLock);
bool updated = mStopped.compare_exchange_strong(expected, true);
if (updated) {
- uint64_t val = 1ULL;
- int ret = ::write(mStopEventFd.get(), &val, 8);
- if (ret < 0) {
- // EINTR maybe
- std::unique_lock<std::mutex> l(mEventLock);
- mStopRequest = true;
- l.unlock();
- mEventCv.notify_one();
- ALOGW("stop() status update pending");
- }
+ int writeFd = mWritePipeFd.release();
+ ::close(writeFd);
}
}
void GraphicsTracker::writeIncDequeueable(int inc) {
- uint64_t val = inc;
- int ret = ::write(mAllocEventFd.get(), &val, 8);
- if (ret < 0) {
- // EINTR due to signal handling maybe, this should be rare
+ CHECK(inc > 0 && inc < kMaxDequeueMax);
+ thread_local char buf[kMaxDequeueMax];
+ int diff = 0;
+ {
std::unique_lock<std::mutex> l(mEventLock);
- mIncDequeueable += inc;
- l.unlock();
- mEventCv.notify_one();
- ALOGW("updating dequeueable to eventfd pending");
+ if (mStopped) {
+ return;
+ }
+ CHECK(mWritePipeFd.get() >= 0);
+ int ret = ::write(mWritePipeFd.get(), buf, inc);
+ if (ret == inc) {
+ return;
+ }
+ diff = ret < 0 ? inc : inc - ret;
+
+ // Partial write or EINTR. This will not happen in a real scenario.
+ mIncDequeueable += diff;
+ if (mIncDequeueable > 0) {
+ l.unlock();
+ mEventCv.notify_one();
+ ALOGW("updating dequeueable to pipefd pending");
+ }
}
}
void GraphicsTracker::processEvent() {
- // This is for write() failure of eventfds.
- // write() failure other than EINTR should not happen.
- int64_t acc = 0;
- bool stopRequest = false;
- bool stopCommitted = false;
-
+ // This is for partial/failed writes to the writing end.
+ // This may not happen in the real scenario.
+ thread_local char buf[kMaxDequeueMax];
while (true) {
- {
- std::unique_lock<std::mutex> l(mEventLock);
- acc += mIncDequeueable;
- mIncDequeueable = 0;
- stopRequest |= mStopRequest;
- mStopRequest = false;
- if (acc == 0 && stopRequest == stopCommitted) {
- if (mStopEventThread) {
- break;
+ std::unique_lock<std::mutex> l(mEventLock);
+ if (mStopped) {
+ break;
+ }
+ if (mIncDequeueable > 0) {
+ int inc = mIncDequeueable > kMaxDequeueMax ? kMaxDequeueMax : mIncDequeueable;
+ int ret = ::write(mWritePipeFd.get(), buf, inc);
+ int written = ret <= 0 ? 0 : ret;
+ mIncDequeueable -= written;
+ if (mIncDequeueable > 0) {
+ l.unlock();
+ if (ret < 0) {
+ ALOGE("write to writing end failed %d", errno);
+ } else {
+ ALOGW("partial write %d(%d)", inc, written);
}
- mEventCv.wait(l);
continue;
}
}
-
- if (acc > 0) {
- int ret = ::write(mAllocEventFd.get(), &acc, 8);
- if (ret > 0) {
- acc = 0;
- }
- }
- if (stopRequest && !stopCommitted) {
- uint64_t val = 1ULL;
- int ret = ::write(mStopEventFd.get(), &val, 8);
- if (ret > 0) {
- stopCommitted = true;
- }
- }
- if (mStopEventThread) {
- break;
- }
+ mEventCv.wait(l);
}
}
-c2_status_t GraphicsTracker::getWaitableFds(int *allocFd, int *statusFd) {
- *allocFd = ::dup(mAllocEventFd.get());
- *statusFd = ::dup(mStopEventFd.get());
-
- if (*allocFd < 0 || *statusFd < 0) {
- if (*allocFd >= 0) {
- ::close(*allocFd);
- *allocFd = -1;
+c2_status_t GraphicsTracker::getWaitableFd(int *pipeFd) {
+ *pipeFd = ::dup(mReadPipeFd.get());
+ if (*pipeFd < 0) {
+ if (mReadPipeFd.get() < 0) {
+ return C2_BAD_STATE;
}
- if (*statusFd >= 0) {
- ::close(*statusFd);
- *statusFd = -1;
- }
+ // dup error
+ ALOGE("dup() for the reading end failed %d", errno);
return C2_NO_MEMORY;
}
return C2_OK;
@@ -438,8 +438,8 @@
c2_status_t GraphicsTracker::requestAllocate(std::shared_ptr<BufferCache> *cache) {
std::lock_guard<std::mutex> l(mLock);
if (mDequeueable > 0) {
- uint64_t val;
- int ret = ::read(mAllocEventFd.get(), &val, 8);
+ char buf[1];
+ int ret = ::read(mReadPipeFd.get(), buf, 1);
if (ret < 0) {
if (errno == EINTR) {
// Do we really need to care for cancel due to signal handling?
@@ -452,6 +452,10 @@
}
CHECK(errno != 0);
}
+ if (ret == 0) {
+ // writing end is closed
+ return C2_BAD_STATE;
+ }
mDequeueable--;
*cache = mBufferCache;
return C2_OK;
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
index f9c8aca..902c53f 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
@@ -38,8 +38,8 @@
::ndk::ScopedAStatus deallocate(int64_t in_id, bool* _aidl_return) override;
- ::ndk::ScopedAStatus getWaitableFds(
- IGraphicBufferAllocator::WaitableFds* _aidl_return) override;
+ ::ndk::ScopedAStatus getWaitableFd(
+ ::ndk::ScopedFileDescriptor* _aidl_return) override;
/**
* Configuring Surface/BufferQueue for the interface.
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
index 681b7e8..1fd9049 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
@@ -142,15 +142,15 @@
void onReleased(uint32_t generation);
/**
- * Get waitable fds for events.(allocate is ready, end of life cycle)
+ * Get waitable fd for events.(allocate is ready, end of life cycle)
*
- * @param[out] allocFd eventFd which signals being ready to allocate
- * @param[out] statusFd eventFd which signals end of life cycle.
- * When signaled no more allocate is possible.
+ * @param[out] pipeFd a file descriptor created from pipe2()
+ * in order for notifying being ready to allocate
+ *
* @return C2_OK
* C2_NO_MEMORY Max # of fd reached.(not really a memory issue)
*/
- c2_status_t getWaitableFds(int *allocFd, int *statusFd);
+ c2_status_t getWaitableFd(int *pipeFd);
/**
* Ends to use the class. after the call, allocate will fail.
@@ -158,8 +158,6 @@
void stop();
private:
- static constexpr int kDefaultMaxDequeue = 2;
-
struct BufferCache;
struct BufferItem {
@@ -246,21 +244,30 @@
std::mutex mLock; // locks for data synchronization
std::mutex mConfigLock; // locks for configuration change.
+ // NOTE: pipe2() creates two file descriptors for allocatable events
+ // and irrecoverable error events notification.
+ //
+ // A byte will be written to the writing end whenever a buffer is ready to
+ // dequeue/allocate. A byte will be read from the reading end whenever
+ // an allocate/dequeue event happens.
+ //
+ // The writing end will be closed when the end-of-lifecycle event was met.
+ //
+ // The reading end will be shared to the remote processes. Remote processes
+ // use ::poll() to check whether a buffer is ready to allocate/ready.
+ // Also ::poll() will let remote processes know the end-of-lifecycle event
+ // by returning POLLHUP event from the reading end.
+ ::android::base::unique_fd mReadPipeFd; // The reading end file descriptor
+ ::android::base::unique_fd mWritePipeFd; // The writing end file descriptor
+
std::atomic<bool> mStopped;
-
- ::android::base::unique_fd mAllocEventFd; // eventfd in semaphore mode which
- // mirrors mDqueueable.
- ::android::base::unique_fd mStopEventFd; // eventfd which indicates the life
- // cycle of the class being stopped.
-
std::thread mEventQueueThread; // Thread to handle interrupted
- // writes to eventfd{s}.
+ // writes to the writing end.
std::mutex mEventLock;
std::condition_variable mEventCv;
bool mStopEventThread;
int mIncDequeueable; // pending # of write to increase dequeueable eventfd
- bool mStopRequest; // pending write to statusfd
private:
explicit GraphicsTracker(int maxDequeueCount);
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 1ffa78f..9064eb9 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -327,6 +327,450 @@
return C2_OK;
}
+static c2_status_t PopulatePlaneLayout(
+ buffer_handle_t buffer,
+ const Rect &rect,
+ uint32_t format,
+ uint64_t grallocUsage,
+ uint32_t stride,
+ C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+ // 'NATIVE' on Android means LITTLE_ENDIAN
+ constexpr C2PlaneInfo::endianness_t kEndianness = C2PlaneInfo::NATIVE;
+
+ // Try to resolve IMPLEMENTATION_DEFINED format to accurate format if
+ // possible.
+ uint32_t fourCc;
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
+ !GraphicBufferMapper::get().getPixelFormatFourCC(buffer, &fourCc)) {
+ switch (fourCc) {
+ case DRM_FORMAT_XBGR8888:
+ format = static_cast<uint32_t>(PixelFormat4::RGBX_8888);
+ break;
+ case DRM_FORMAT_ABGR8888:
+ format = static_cast<uint32_t>(PixelFormat4::RGBA_8888);
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (format) {
+ case static_cast<uint32_t>(PixelFormat4::RGBA_1010102): {
+ // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
+ // Surface. In all other cases it is RGBA. We don't know which case it is here, so
+ // default to YUV for now.
+ void *pointer = nullptr;
+ // TODO: fence
+ status_t err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(RGBA_1010102)");
+ return C2_CORRUPTED;
+ }
+ // treat as 32-bit values
+ addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
+ addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer;
+ addr[C2PlanarLayout::PLANE_V] = (uint8_t *)pointer;
+ addr[C2PlanarLayout::PLANE_A] = (uint8_t *)pointer;
+ layout->type = C2PlanarLayout::TYPE_YUVA;
+ layout->numPlanes = 4;
+ layout->rootPlanes = 1;
+ layout->planes[C2PlanarLayout::PLANE_Y] = {
+ C2PlaneInfo::CHANNEL_Y, // channel
+ 4, // colInc
+ static_cast<int32_t>(4 * stride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 32, // allocatedDepth
+ 10, // bitDepth
+ 10, // rightShift
+ C2PlaneInfo::LITTLE_END, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_U] = {
+ C2PlaneInfo::CHANNEL_CB, // channel
+ 4, // colInc
+ static_cast<int32_t>(4 * stride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 32, // allocatedDepth
+ 10, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::LITTLE_END, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_V] = {
+ C2PlaneInfo::CHANNEL_CR, // channel
+ 4, // colInc
+ static_cast<int32_t>(4 * stride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 32, // allocatedDepth
+ 10, // bitDepth
+ 20, // rightShift
+ C2PlaneInfo::LITTLE_END, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_A] = {
+ C2PlaneInfo::CHANNEL_A, // channel
+ 4, // colInc
+ static_cast<int32_t>(4 * stride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 32, // allocatedDepth
+ 2, // bitDepth
+ 30, // rightShift
+ C2PlaneInfo::LITTLE_END, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ break;
+ }
+
+ case static_cast<uint32_t>(PixelFormat4::RGBA_8888):
+ // TODO: alpha channel
+ // fall-through
+ case static_cast<uint32_t>(PixelFormat4::RGBX_8888): {
+ void *pointer = nullptr;
+ // TODO: fence
+ status_t err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t*>(buffer), grallocUsage, rect, &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(RGBA_8888)");
+ return C2_CORRUPTED;
+ }
+ addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer;
+ addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1;
+ addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
+ layout->type = C2PlanarLayout::TYPE_RGB;
+ layout->numPlanes = 3;
+ layout->rootPlanes = 1;
+ layout->planes[C2PlanarLayout::PLANE_R] = {
+ C2PlaneInfo::CHANNEL_R, // channel
+ 4, // colInc
+ static_cast<int32_t>(4 * stride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_R, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_G] = {
+ C2PlaneInfo::CHANNEL_G, // channel
+ 4, // colInc
+ static_cast<int32_t>(4 * stride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_R, // rootIx
+ 1, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_B] = {
+ C2PlaneInfo::CHANNEL_B, // channel
+ 4, // colInc
+ static_cast<int32_t>(4 * stride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_R, // rootIx
+ 2, // offset
+ };
+ break;
+ }
+
+ case static_cast<uint32_t>(PixelFormat4::BLOB): {
+ void *pointer = nullptr;
+ // TODO: fence
+ status_t err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t*>(buffer), grallocUsage, rect, &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(BLOB)");
+ return C2_CORRUPTED;
+ }
+ *addr = (uint8_t *)pointer;
+ break;
+ }
+
+ case static_cast<uint32_t>(PixelFormat4::YCBCR_422_SP):
+ // fall-through
+ case static_cast<uint32_t>(PixelFormat4::YCRCB_420_SP):
+ // fall-through
+ case static_cast<uint32_t>(PixelFormat4::YCBCR_422_I):
+ // fall-through
+ case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
+ // fall-through
+ case static_cast<uint32_t>(PixelFormat4::YV12): {
+ android_ycbcr ycbcrLayout;
+
+ status_t err = GraphicBufferMapper::get().lockYCbCr(
+ const_cast<native_handle_t*>(buffer), grallocUsage, rect, &ycbcrLayout);
+ if (err) {
+ ALOGE("failed transaction: lockYCbCr (err=%d)", err);
+ return C2_CORRUPTED;
+ }
+ if (!ycbcrLayout.y || !ycbcrLayout.cb || !ycbcrLayout.cr
+ || ycbcrLayout.ystride == 0
+ || ycbcrLayout.cstride == 0
+ || ycbcrLayout.chroma_step == 0) {
+ ALOGE("invalid layout: lockYCbCr (y=%s cb=%s cr=%s "
+ "ystride=%zu cstride=%zu chroma_step=%zu)",
+ ycbcrLayout.y ? "(non-null)" : "(null)",
+ ycbcrLayout.cb ? "(non-null)" : "(null)",
+ ycbcrLayout.cr ? "(non-null)" : "(null)",
+ ycbcrLayout.ystride, ycbcrLayout.cstride, ycbcrLayout.chroma_step);
+ return C2_CORRUPTED;
+ }
+
+ addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
+ addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
+ addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
+ layout->type = C2PlanarLayout::TYPE_YUV;
+ layout->numPlanes = 3;
+ layout->rootPlanes = 3;
+ layout->planes[C2PlanarLayout::PLANE_Y] = {
+ C2PlaneInfo::CHANNEL_Y, // channel
+ 1, // colInc
+ (int32_t)ycbcrLayout.ystride, // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_U] = {
+ C2PlaneInfo::CHANNEL_CB, // channel
+ (int32_t)ycbcrLayout.chroma_step, // colInc
+ (int32_t)ycbcrLayout.cstride, // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_U, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_V] = {
+ C2PlaneInfo::CHANNEL_CR, // channel
+ (int32_t)ycbcrLayout.chroma_step, // colInc
+ (int32_t)ycbcrLayout.cstride, // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_V, // rootIx
+ 0, // offset
+ };
+ break;
+ }
+
+ case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): {
+ // In Android T, P010 is relaxed to allow arbitrary stride for the Y and UV planes,
+ // try locking with the gralloc4 mapper first.
+ c2_status_t status = Gralloc4Mapper_lock(
+ const_cast<native_handle_t*>(buffer), grallocUsage, rect, layout, addr);
+ if (status == C2_OK) {
+ break;
+ }
+
+ void *pointer = nullptr;
+ status_t err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(YCBCR_P010)");
+ return C2_CORRUPTED;
+ }
+ addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
+ addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer + stride * 2 * rect.height();
+ addr[C2PlanarLayout::PLANE_V] = addr[C2PlanarLayout::PLANE_U] + 2;
+ layout->type = C2PlanarLayout::TYPE_YUV;
+ layout->numPlanes = 3;
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_Y] = {
+ C2PlaneInfo::CHANNEL_Y, // channel
+ 2, // colInc
+ static_cast<int32_t>(2 * stride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 16, // allocatedDepth
+ 10, // bitDepth
+ 6, // rightShift
+ kEndianness, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_U] = {
+ C2PlaneInfo::CHANNEL_CB, // channel
+ 4, // colInc
+ static_cast<int32_t>(2 * stride), // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 16, // allocatedDepth
+ 10, // bitDepth
+ 6, // rightShift
+ kEndianness, // endianness
+ C2PlanarLayout::PLANE_U, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_V] = {
+ C2PlaneInfo::CHANNEL_CR, // channel
+ 4, // colInc
+ static_cast<int32_t>(2 * stride), // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 16, // allocatedDepth
+ 10, // bitDepth
+ 6, // rightShift
+ kEndianness, // endianness
+ C2PlanarLayout::PLANE_U, // rootIx
+ 2, // offset
+ };
+ break;
+ }
+
+ default: {
+ // We don't know what it is, let's try to lock it with gralloc4
+ android_ycbcr ycbcrLayout;
+ if (isAtLeastT()) {
+ c2_status_t status = Gralloc4Mapper_lock(
+ const_cast<native_handle_t*>(buffer), grallocUsage, rect, layout, addr);
+ if (status == C2_OK) {
+ break;
+ }
+ }
+
+ // fallback to lockYCbCr
+ status_t err = GraphicBufferMapper::get().lockYCbCr(
+ const_cast<native_handle_t*>(buffer), grallocUsage, rect, &ycbcrLayout);
+ if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr
+ && ycbcrLayout.ystride > 0
+ && ycbcrLayout.cstride > 0
+ && ycbcrLayout.chroma_step > 0) {
+ addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
+ addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
+ addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
+ layout->type = C2PlanarLayout::TYPE_YUV;
+ layout->numPlanes = 3;
+ layout->rootPlanes = 3;
+ layout->planes[C2PlanarLayout::PLANE_Y] = {
+ C2PlaneInfo::CHANNEL_Y, // channel
+ 1, // colInc
+ (int32_t)ycbcrLayout.ystride, // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_Y, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_U] = {
+ C2PlaneInfo::CHANNEL_CB, // channel
+ (int32_t)ycbcrLayout.chroma_step, // colInc
+ (int32_t)ycbcrLayout.cstride, // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_U, // rootIx
+ 0, // offset
+ };
+ layout->planes[C2PlanarLayout::PLANE_V] = {
+ C2PlaneInfo::CHANNEL_CR, // channel
+ (int32_t)ycbcrLayout.chroma_step, // colInc
+ (int32_t)ycbcrLayout.cstride, // rowInc
+ 2, // mColSampling
+ 2, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ C2PlanarLayout::PLANE_V, // rootIx
+ 0, // offset
+ };
+ break;
+ }
+
+ // We really don't know what this is; lock the buffer and pass it through ---
+ // the client may know how to interpret it.
+
+ // unlock previous allocation if it was successful
+ if (err == OK) {
+ err = GraphicBufferMapper::get().unlock(buffer);
+ if (err) {
+ ALOGE("failed transaction: unlock");
+ return C2_CORRUPTED;
+ }
+ }
+
+ void *pointer = nullptr;
+ err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t *>(buffer), grallocUsage, rect, &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(??? %x)", format);
+ return C2_CORRUPTED;
+ }
+ addr[0] = (uint8_t *)pointer;
+ layout->type = C2PlanarLayout::TYPE_UNKNOWN;
+ layout->numPlanes = 1;
+ layout->rootPlanes = 1;
+ layout->planes[0] = {
+ // TODO: CHANNEL_UNKNOWN?
+ C2PlaneInfo::channel_t(0xFF), // channel
+ 1, // colInc
+ int32_t(stride), // rowInc
+ 1, // mColSampling
+ 1, // mRowSampling
+ 8, // allocatedDepth
+ 8, // bitDepth
+ 0, // rightShift
+ C2PlaneInfo::NATIVE, // endianness
+ 0, // rootIx
+ 0, // offset
+ };
+ break;
+ }
+ }
+ return C2_OK;
+}
+
+static void HandleInterleavedPlanes(
+ C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+ if (layout->type == C2PlanarLayout::TYPE_YUV && layout->rootPlanes == 3) {
+ intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
+ intptr_t uvColInc = layout->planes[C2PlanarLayout::PLANE_U].colInc;
+ if (uvOffset > 0 && uvOffset < uvColInc) {
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
+ layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
+ } else if (uvOffset < 0 && uvOffset > -uvColInc) {
+ layout->rootPlanes = 2;
+ layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
+ layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
+ }
+ }
+}
+
} // unnamed namespace
@@ -488,440 +932,14 @@
mStride, generation, igbp_id, igbp_slot);
}
- // 'NATIVE' on Android means LITTLE_ENDIAN
- constexpr C2PlaneInfo::endianness_t kEndianness = C2PlaneInfo::NATIVE;
-
- // Try to resolve IMPLEMENTATION_DEFINED format to accurate format if
- // possible.
- uint32_t format = mFormat;
- uint32_t fourCc;
- if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
- !GraphicBufferMapper::get().getPixelFormatFourCC(mBuffer, &fourCc)) {
- switch (fourCc) {
- case DRM_FORMAT_XBGR8888:
- format = static_cast<uint32_t>(PixelFormat4::RGBX_8888);
- break;
- case DRM_FORMAT_ABGR8888:
- format = static_cast<uint32_t>(PixelFormat4::RGBA_8888);
- break;
- default:
- break;
- }
- }
-
- switch (format) {
- case static_cast<uint32_t>(PixelFormat4::RGBA_1010102): {
- // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
- // Surface. In all other cases it is RGBA. We don't know which case it is here, so
- // default to YUV for now.
- void *pointer = nullptr;
- // TODO: fence
- status_t err = GraphicBufferMapper::get().lock(
- const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
- if (err) {
- ALOGE("failed transaction: lock(RGBA_1010102)");
- return C2_CORRUPTED;
- }
- // treat as 32-bit values
- addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
- addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer;
- addr[C2PlanarLayout::PLANE_V] = (uint8_t *)pointer;
- addr[C2PlanarLayout::PLANE_A] = (uint8_t *)pointer;
- layout->type = C2PlanarLayout::TYPE_YUVA;
- layout->numPlanes = 4;
- layout->rootPlanes = 1;
- layout->planes[C2PlanarLayout::PLANE_Y] = {
- C2PlaneInfo::CHANNEL_Y, // channel
- 4, // colInc
- static_cast<int32_t>(4 * mStride), // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 32, // allocatedDepth
- 10, // bitDepth
- 10, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
- C2PlanarLayout::PLANE_Y, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_U] = {
- C2PlaneInfo::CHANNEL_CB, // channel
- 4, // colInc
- static_cast<int32_t>(4 * mStride), // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 32, // allocatedDepth
- 10, // bitDepth
- 0, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
- C2PlanarLayout::PLANE_Y, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_V] = {
- C2PlaneInfo::CHANNEL_CR, // channel
- 4, // colInc
- static_cast<int32_t>(4 * mStride), // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 32, // allocatedDepth
- 10, // bitDepth
- 20, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
- C2PlanarLayout::PLANE_Y, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_A] = {
- C2PlaneInfo::CHANNEL_A, // channel
- 4, // colInc
- static_cast<int32_t>(4 * mStride), // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 32, // allocatedDepth
- 2, // bitDepth
- 30, // rightShift
- C2PlaneInfo::LITTLE_END, // endianness
- C2PlanarLayout::PLANE_Y, // rootIx
- 0, // offset
- };
- break;
- }
-
- case static_cast<uint32_t>(PixelFormat4::RGBA_8888):
- // TODO: alpha channel
- // fall-through
- case static_cast<uint32_t>(PixelFormat4::RGBX_8888): {
- void *pointer = nullptr;
- // TODO: fence
- status_t err = GraphicBufferMapper::get().lock(
- const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &pointer);
- if (err) {
- ALOGE("failed transaction: lock(RGBA_8888)");
- return C2_CORRUPTED;
- }
- addr[C2PlanarLayout::PLANE_R] = (uint8_t *)pointer;
- addr[C2PlanarLayout::PLANE_G] = (uint8_t *)pointer + 1;
- addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
- layout->type = C2PlanarLayout::TYPE_RGB;
- layout->numPlanes = 3;
- layout->rootPlanes = 1;
- layout->planes[C2PlanarLayout::PLANE_R] = {
- C2PlaneInfo::CHANNEL_R, // channel
- 4, // colInc
- static_cast<int32_t>(4 * mStride), // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_R, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_G] = {
- C2PlaneInfo::CHANNEL_G, // channel
- 4, // colInc
- static_cast<int32_t>(4 * mStride), // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_R, // rootIx
- 1, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_B] = {
- C2PlaneInfo::CHANNEL_B, // channel
- 4, // colInc
- static_cast<int32_t>(4 * mStride), // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_R, // rootIx
- 2, // offset
- };
- break;
- }
-
- case static_cast<uint32_t>(PixelFormat4::BLOB): {
- void *pointer = nullptr;
- // TODO: fence
- status_t err = GraphicBufferMapper::get().lock(
- const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &pointer);
- if (err) {
- ALOGE("failed transaction: lock(BLOB)");
- return C2_CORRUPTED;
- }
- *addr = (uint8_t *)pointer;
- break;
- }
-
- case static_cast<uint32_t>(PixelFormat4::YCBCR_422_SP):
- // fall-through
- case static_cast<uint32_t>(PixelFormat4::YCRCB_420_SP):
- // fall-through
- case static_cast<uint32_t>(PixelFormat4::YCBCR_422_I):
- // fall-through
- case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
- // fall-through
- case static_cast<uint32_t>(PixelFormat4::YV12): {
- android_ycbcr ycbcrLayout;
-
- status_t err = GraphicBufferMapper::get().lockYCbCr(
- const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
- if (err) {
- ALOGE("failed transaction: lockYCbCr (err=%d)", err);
- return C2_CORRUPTED;
- }
- if (!ycbcrLayout.y || !ycbcrLayout.cb || !ycbcrLayout.cr
- || ycbcrLayout.ystride == 0
- || ycbcrLayout.cstride == 0
- || ycbcrLayout.chroma_step == 0) {
- ALOGE("invalid layout: lockYCbCr (y=%s cb=%s cr=%s "
- "ystride=%zu cstride=%zu chroma_step=%zu)",
- ycbcrLayout.y ? "(non-null)" : "(null)",
- ycbcrLayout.cb ? "(non-null)" : "(null)",
- ycbcrLayout.cr ? "(non-null)" : "(null)",
- ycbcrLayout.ystride, ycbcrLayout.cstride, ycbcrLayout.chroma_step);
- return C2_CORRUPTED;
- }
-
- addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
- addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
- addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
- layout->type = C2PlanarLayout::TYPE_YUV;
- layout->numPlanes = 3;
- layout->rootPlanes = 3;
- layout->planes[C2PlanarLayout::PLANE_Y] = {
- C2PlaneInfo::CHANNEL_Y, // channel
- 1, // colInc
- (int32_t)ycbcrLayout.ystride, // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_Y, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_U] = {
- C2PlaneInfo::CHANNEL_CB, // channel
- (int32_t)ycbcrLayout.chroma_step, // colInc
- (int32_t)ycbcrLayout.cstride, // rowInc
- 2, // mColSampling
- 2, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_U, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_V] = {
- C2PlaneInfo::CHANNEL_CR, // channel
- (int32_t)ycbcrLayout.chroma_step, // colInc
- (int32_t)ycbcrLayout.cstride, // rowInc
- 2, // mColSampling
- 2, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_V, // rootIx
- 0, // offset
- };
- break;
- }
-
- case static_cast<uint32_t>(PixelFormat4::YCBCR_P010): {
- // In Android T, P010 is relaxed to allow arbitrary stride for the Y and UV planes,
- // try locking with the gralloc4 mapper first.
- c2_status_t status = Gralloc4Mapper_lock(
- const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
- if (status == C2_OK) {
- break;
- }
-
- void *pointer = nullptr;
- status_t err = GraphicBufferMapper::get().lock(
- const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
- if (err) {
- ALOGE("failed transaction: lock(YCBCR_P010)");
- return C2_CORRUPTED;
- }
- addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)pointer;
- addr[C2PlanarLayout::PLANE_U] = (uint8_t *)pointer + mStride * 2 * rect.height();
- addr[C2PlanarLayout::PLANE_V] = addr[C2PlanarLayout::PLANE_U] + 2;
- layout->type = C2PlanarLayout::TYPE_YUV;
- layout->numPlanes = 3;
- layout->rootPlanes = 2;
- layout->planes[C2PlanarLayout::PLANE_Y] = {
- C2PlaneInfo::CHANNEL_Y, // channel
- 2, // colInc
- static_cast<int32_t>(2 * mStride), // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 16, // allocatedDepth
- 10, // bitDepth
- 6, // rightShift
- kEndianness, // endianness
- C2PlanarLayout::PLANE_Y, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_U] = {
- C2PlaneInfo::CHANNEL_CB, // channel
- 4, // colInc
- static_cast<int32_t>(2 * mStride), // rowInc
- 2, // mColSampling
- 2, // mRowSampling
- 16, // allocatedDepth
- 10, // bitDepth
- 6, // rightShift
- kEndianness, // endianness
- C2PlanarLayout::PLANE_U, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_V] = {
- C2PlaneInfo::CHANNEL_CR, // channel
- 4, // colInc
- static_cast<int32_t>(2 * mStride), // rowInc
- 2, // mColSampling
- 2, // mRowSampling
- 16, // allocatedDepth
- 10, // bitDepth
- 6, // rightShift
- kEndianness, // endianness
- C2PlanarLayout::PLANE_U, // rootIx
- 2, // offset
- };
- break;
- }
-
- default: {
- // We don't know what it is, let's try to lock it with gralloc4
- android_ycbcr ycbcrLayout;
- if (isAtLeastT()) {
- c2_status_t status = Gralloc4Mapper_lock(
- const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, layout, addr);
- if (status == C2_OK) {
- break;
- }
- }
-
- // fallback to lockYCbCr
- status_t err = GraphicBufferMapper::get().lockYCbCr(
- const_cast<native_handle_t*>(mBuffer), grallocUsage, rect, &ycbcrLayout);
- if (err == OK && ycbcrLayout.y && ycbcrLayout.cb && ycbcrLayout.cr
- && ycbcrLayout.ystride > 0
- && ycbcrLayout.cstride > 0
- && ycbcrLayout.chroma_step > 0) {
- addr[C2PlanarLayout::PLANE_Y] = (uint8_t *)ycbcrLayout.y;
- addr[C2PlanarLayout::PLANE_U] = (uint8_t *)ycbcrLayout.cb;
- addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
- layout->type = C2PlanarLayout::TYPE_YUV;
- layout->numPlanes = 3;
- layout->rootPlanes = 3;
- layout->planes[C2PlanarLayout::PLANE_Y] = {
- C2PlaneInfo::CHANNEL_Y, // channel
- 1, // colInc
- (int32_t)ycbcrLayout.ystride, // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_Y, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_U] = {
- C2PlaneInfo::CHANNEL_CB, // channel
- (int32_t)ycbcrLayout.chroma_step, // colInc
- (int32_t)ycbcrLayout.cstride, // rowInc
- 2, // mColSampling
- 2, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_U, // rootIx
- 0, // offset
- };
- layout->planes[C2PlanarLayout::PLANE_V] = {
- C2PlaneInfo::CHANNEL_CR, // channel
- (int32_t)ycbcrLayout.chroma_step, // colInc
- (int32_t)ycbcrLayout.cstride, // rowInc
- 2, // mColSampling
- 2, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- C2PlanarLayout::PLANE_V, // rootIx
- 0, // offset
- };
- break;
- }
-
- // We really don't know what this is; lock the buffer and pass it through ---
- // the client may know how to interpret it.
-
- // unlock previous allocation if it was successful
- if (err == OK) {
- err = GraphicBufferMapper::get().unlock(mBuffer);
- if (err) {
- ALOGE("failed transaction: unlock");
- return C2_CORRUPTED;
- }
- }
-
- void *pointer = nullptr;
- err = GraphicBufferMapper::get().lock(
- const_cast<native_handle_t *>(mBuffer), grallocUsage, rect, &pointer);
- if (err) {
- ALOGE("failed transaction: lock(??? %x)", mFormat);
- return C2_CORRUPTED;
- }
- addr[0] = (uint8_t *)pointer;
- layout->type = C2PlanarLayout::TYPE_UNKNOWN;
- layout->numPlanes = 1;
- layout->rootPlanes = 1;
- layout->planes[0] = {
- // TODO: CHANNEL_UNKNOWN?
- C2PlaneInfo::channel_t(0xFF), // channel
- 1, // colInc
- int32_t(mStride), // rowInc
- 1, // mColSampling
- 1, // mRowSampling
- 8, // allocatedDepth
- 8, // bitDepth
- 0, // rightShift
- C2PlaneInfo::NATIVE, // endianness
- 0, // rootIx
- 0, // offset
- };
- break;
- }
+ c2_status_t ret = PopulatePlaneLayout(
+ mBuffer, rect, mFormat, grallocUsage, mStride, layout, addr);
+ if (ret != C2_OK) {
+ return ret;
}
mLocked = true;
- // handle interleaved formats
- if (layout->type == C2PlanarLayout::TYPE_YUV && layout->rootPlanes == 3) {
- intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
- intptr_t uvColInc = layout->planes[C2PlanarLayout::PLANE_U].colInc;
- if (uvOffset > 0 && uvOffset < uvColInc) {
- layout->rootPlanes = 2;
- layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
- layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
- } else if (uvOffset < 0 && uvOffset > -uvColInc) {
- layout->rootPlanes = 2;
- layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
- layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
- }
- }
+ HandleInterleavedPlanes(layout, addr);
ALOGV("C2AllocationGralloc::map: layout: type=%d numPlanes=%d rootPlanes=%d",
layout->type, layout->numPlanes, layout->rootPlanes);
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
index 0344fd3..b91ac6d 100644
--- a/media/codec2/vndk/C2Fence.cpp
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -16,6 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2FenceFactory"
+#include <poll.h>
+
+#include <android-base/unique_fd.h>
#include <cutils/native_handle.h>
#include <utils/Log.h>
#include <ui/Fence.h>
@@ -32,6 +35,7 @@
NULL_FENCE,
SURFACE_FENCE,
SYNC_FENCE,
+ PIPE_FENCE,
};
virtual c2_status_t wait(c2_nsecs_t timeoutNs) = 0;
@@ -353,6 +357,154 @@
return C2Fence(p);
}
+/**
+ * Fence implementation for notifying # of events available based on
+ * file descriptors created by pipe()/pipe2(). The writing end of the
+ * file descriptors is used to create the implementation.
+ * The implementation supports all C2Fence interface.
+ */
+class _C2FenceFactory::PipeFenceImpl: public C2Fence::Impl {
+private:
+ bool waitEvent(c2_nsecs_t timeoutNs, bool *hangUp, bool *event) const {
+ if (!mValid) {
+ *hangUp = true;
+ return true;
+ }
+
+ struct pollfd pfd;
+ pfd.fd = mPipeFd.get();
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ struct timespec ts;
+ if (timeoutNs >= 0) {
+ ts.tv_sec = int(timeoutNs / 1000000000);
+ ts.tv_nsec = timeoutNs;
+ } else {
+ ALOGD("polling for indefinite duration requested, but changed to wait for %d sec",
+ kPipeFenceWaitLimitSecs);
+ ts.tv_sec = kPipeFenceWaitLimitSecs;
+ ts.tv_nsec = 0;
+ }
+ int ret = ::ppoll(&pfd, 1, &ts, nullptr);
+ if (ret >= 0) {
+ if (pfd.revents) {
+ if (pfd.revents & ~POLLIN) {
+ // Mostly this means the writing end fd was closed.
+ *hangUp = true;
+ mValid = false;
+ ALOGD("PipeFenceImpl: pipe fd hangup or err event returned");
+ }
+ *event = true;
+ return true;
+ }
+ // event not ready yet.
+ return true;
+ }
+ if (errno == EINTR) {
+ // poll() was cancelled by signal or inner kernel status.
+ return false;
+ }
+ // Since poll error happened here, treat the error is irrecoverable.
+ ALOGE("PipeFenceImpl: poll() error %d", errno);
+ *hangUp = true;
+ mValid = false;
+ return true;
+ }
+
+public:
+ virtual c2_status_t wait(c2_nsecs_t timeoutNs) {
+ if (!mValid) {
+ return C2_BAD_STATE;
+ }
+ bool hangUp = false;
+ bool event = false;
+ if (waitEvent(timeoutNs, &hangUp, &event)) {
+ if (hangUp) {
+ return C2_BAD_STATE;
+ }
+ if (event) {
+ return C2_OK;
+ }
+ return C2_TIMED_OUT;
+ } else {
+ return C2_CANCELED;
+ }
+ }
+
+ virtual bool valid() const {
+ if (!mValid) {
+ return false;
+ }
+ bool hangUp = false;
+ bool event = false;
+ if (waitEvent(0, &hangUp, &event)) {
+ if (hangUp) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ virtual bool ready() const {
+ if (!mValid) {
+ return false;
+ }
+ bool hangUp = false;
+ bool event = false;
+ if (waitEvent(0, &hangUp, &event)) {
+ if (event) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ virtual int fd() const {
+ if (!mValid) {
+ return -1;
+ }
+ return ::dup(mPipeFd.get());
+ }
+
+ virtual bool isHW() const {
+ return false;
+ }
+
+ virtual type_t type() const {
+ return PIPE_FENCE;
+ }
+
+ virtual native_handle_t *createNativeHandle() const {
+ // This is not supported.
+ return nullptr;
+ }
+
+ virtual ~PipeFenceImpl() = default;
+
+ PipeFenceImpl(int fd) : mPipeFd(fd) {
+ mValid = (mPipeFd.get() >= 0);
+ }
+
+private:
+ friend struct _C2FenceFactory;
+ static constexpr int kPipeFenceWaitLimitSecs = 5;
+
+ mutable std::atomic<bool> mValid;
+ ::android::base::unique_fd mPipeFd;
+};
+
+C2Fence _C2FenceFactory::CreatePipeFence(int fd) {
+ std::shared_ptr<_C2FenceFactory::PipeFenceImpl> impl =
+ std::make_shared<_C2FenceFactory::PipeFenceImpl>(fd);
+ std::shared_ptr<C2Fence::Impl> p = std::static_pointer_cast<C2Fence::Impl>(impl);
+ if (!p) {
+ ALOGE("PipeFence creation failure");
+ } else if (!impl->mValid) {
+ p.reset();
+ }
+ return C2Fence(p);
+}
+
native_handle_t* _C2FenceFactory::CreateNativeHandle(const C2Fence& fence) {
return fence.mImpl? fence.mImpl->createNativeHandle() : nullptr;
}
diff --git a/media/codec2/vndk/include/C2FenceFactory.h b/media/codec2/vndk/include/C2FenceFactory.h
index ef25c47..9b09980 100644
--- a/media/codec2/vndk/include/C2FenceFactory.h
+++ b/media/codec2/vndk/include/C2FenceFactory.h
@@ -39,6 +39,7 @@
class SurfaceFenceImpl;
class SyncFenceImpl;
+ class PipeFenceImpl;
/*
* Create C2Fence for BufferQueueBased blockpool.
@@ -66,6 +67,15 @@
*/
static C2Fence CreateMultipleFdSyncFence(const std::vector<int>& fenceFds);
+ /*
+ * Create C2Fence from an fd created by pipe()/pipe2() syscall.
+ *
+ * \param fd An fd representing the write end from a pair of
+ * file descriptors which are created by
+ * pipe()/pipe2() syscall.
+ */
+ static C2Fence CreatePipeFence(int fd);
+
/**
* Create a native handle from fence for marshalling
*
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index c058386..e74fc16 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -193,7 +193,7 @@
StreamDescriptor::Reply reply;
switch (state) {
case StreamDescriptor::State::ACTIVE:
- if (status_t status = pause(&reply); status != OK) return status;
+ RETURN_STATUS_IF_ERROR(pause(&reply));
if (reply.state != StreamDescriptor::State::PAUSED) {
ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
__func__, toString(reply.state).c_str());
@@ -203,7 +203,7 @@
case StreamDescriptor::State::PAUSED:
case StreamDescriptor::State::DRAIN_PAUSED:
if (mIsInput) return flush();
- if (status_t status = flush(&reply); status != OK) return status;
+ RETURN_STATUS_IF_ERROR(flush(&reply));
if (reply.state != StreamDescriptor::State::IDLE) {
ALOGE("%s: unexpected stream state: %s (expected IDLE)",
__func__, toString(reply.state).c_str());
@@ -211,10 +211,8 @@
}
FALLTHROUGH_INTENDED;
case StreamDescriptor::State::IDLE:
- if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
- &reply, true /*safeFromNonWorkerThread*/); status != OK) {
- return status;
- }
+ RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
+ &reply, true /*safeFromNonWorkerThread*/));
if (reply.state != StreamDescriptor::State::STANDBY) {
ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
__func__, toString(reply.state).c_str());
@@ -244,10 +242,7 @@
const auto state = getState();
StreamDescriptor::Reply reply;
if (state == StreamDescriptor::State::STANDBY) {
- if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true);
- status != OK) {
- return status;
- }
+ RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true));
return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), &reply, true);
}
@@ -264,10 +259,7 @@
ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
if (!mStream) return NO_INIT;
StreamDescriptor::Reply reply;
- if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
- return status;
- }
-
+ RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
*latency = std::clamp(std::max<int32_t>(0, reply.latencyMs), 1, 3000);
ALOGW_IF(reply.latencyMs != static_cast<int32_t>(*latency),
"Suspicious latency value reported by HAL: %d, clamped to %u", reply.latencyMs,
@@ -279,11 +271,9 @@
ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
if (!mStream) return NO_INIT;
StreamDescriptor::Reply reply;
- if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
- return status;
- }
- *frames = reply.observable.frames;
- *timestamp = reply.observable.timeNs;
+ RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
+ *frames = std::max<int64_t>(0, reply.observable.frames);
+ *timestamp = std::max<int64_t>(0, reply.observable.timeNs);
return OK;
}
@@ -292,12 +282,9 @@
if (!mStream) return NO_INIT;
StreamDescriptor::Reply reply;
// TODO: switch to updateCountersIfNeeded once we sort out mWorkerTid initialization
- if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true);
- status != OK) {
- return status;
- }
- *frames = reply.hardware.frames;
- *timestamp = reply.hardware.timeNs;
+ RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true));
+ *frames = std::max<int64_t>(0, reply.hardware.frames);
+ *timestamp = std::max<int64_t>(0, reply.hardware.timeNs);
return OK;
}
@@ -305,10 +292,8 @@
ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
if (!mStream) return NO_INIT;
StreamDescriptor::Reply reply;
- if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
- return status;
- }
- *frames = reply.xrunFrames;
+ RETURN_STATUS_IF_ERROR(updateCountersIfNeeded(&reply));
+ *frames = std::max<int32_t>(0, reply.xrunFrames);
return OK;
}
@@ -323,10 +308,7 @@
// stream state), however this scenario wasn't supported by the HIDL HAL.
if (getState() == StreamDescriptor::State::STANDBY) {
StreamDescriptor::Reply reply;
- if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply);
- status != OK) {
- return status;
- }
+ RETURN_STATUS_IF_ERROR(sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply));
if (reply.state != StreamDescriptor::State::IDLE) {
ALOGE("%s: failed to get the stream out of standby, actual state: %s",
__func__, toString(reply.state).c_str());
@@ -345,9 +327,7 @@
}
}
StreamDescriptor::Reply reply;
- if (status_t status = sendCommand(burst, &reply); status != OK) {
- return status;
- }
+ RETURN_STATUS_IF_ERROR(sendCommand(burst, &reply));
*transferred = reply.fmqByteCount;
if (mIsInput) {
LOG_ALWAYS_FATAL_IF(*transferred > bytes,
@@ -385,11 +365,8 @@
if (state == StreamDescriptor::State::IDLE) {
StreamDescriptor::Reply localReply{};
StreamDescriptor::Reply* innerReply = reply ?: &localReply;
- if (status_t status =
- sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply);
- status != OK) {
- return status;
- }
+ RETURN_STATUS_IF_ERROR(
+ sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), innerReply));
if (innerReply->state != StreamDescriptor::State::ACTIVE) {
ALOGE("%s: unexpected stream state: %s (expected ACTIVE)",
__func__, toString(innerReply->state).c_str());
@@ -452,10 +429,7 @@
return BAD_VALUE;
}
int64_t aidlPosition = 0, aidlTimestamp = 0;
- if (status_t status = getHardwarePosition(&aidlPosition, &aidlTimestamp); status != OK) {
- return status;
- }
-
+ RETURN_STATUS_IF_ERROR(getHardwarePosition(&aidlPosition, &aidlTimestamp));
position->time_nanoseconds = aidlTimestamp;
position->position_frames = static_cast<int32_t>(aidlPosition);
return OK;
@@ -503,6 +477,11 @@
}
{
std::lock_guard l(mLock);
+ // Not every command replies with 'latencyMs' field filled out, substitute the last
+ // returned value in that case.
+ if (reply->latencyMs <= 0) {
+ reply->latencyMs = mLastReply.latencyMs;
+ }
mLastReply = *reply;
}
switch (reply->status) {
@@ -608,10 +587,8 @@
return BAD_VALUE;
}
int64_t aidlFrames = 0, aidlTimestamp = 0;
- if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
- return OK;
- }
- *dspFrames = std::clamp<int64_t>(aidlFrames, 0, UINT32_MAX);
+ RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
+ *dspFrames = static_cast<uint32_t>(aidlFrames);
return OK;
}
@@ -680,10 +657,8 @@
return BAD_VALUE;
}
int64_t aidlFrames = 0, aidlTimestamp = 0;
- if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
- return status;
- }
- *frames = std::max<int64_t>(0, aidlFrames);
+ RETURN_STATUS_IF_ERROR(getObservablePosition(&aidlFrames, &aidlTimestamp));
+ *frames = aidlFrames;
timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
return OK;
@@ -901,9 +876,7 @@
return BAD_VALUE;
}
int32_t aidlXruns = 0;
- if (status_t status = getXruns(&aidlXruns); status != OK) {
- return status;
- }
+ RETURN_STATUS_IF_ERROR(getXruns(&aidlXruns));
*framesLost = std::max<int32_t>(0, aidlXruns);
return OK;
}
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index 3b369bd..4acc6ac 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -207,10 +207,13 @@
status_t getLatency(uint32_t *latency);
+ // Always returns non-negative values.
status_t getObservablePosition(int64_t *frames, int64_t *timestamp);
+ // Always returns non-negative values.
status_t getHardwarePosition(int64_t *frames, int64_t *timestamp);
+ // Always returns non-negative values.
status_t getXruns(int32_t *frames);
status_t transfer(void *buffer, size_t bytes, size_t *transferred);
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index b230df5..2fb5728 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -672,7 +672,7 @@
if (out_size != NULL) {
*out_size = abuf->capacity();
}
- return abuf->data();
+ return abuf->base();
}
android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
@@ -689,7 +689,7 @@
if (out_size != NULL) {
*out_size = abufs[idx]->capacity();
}
- return abufs[idx]->data();
+ return abufs[idx]->base();
}
ALOGE("couldn't get input buffers");
return NULL;
@@ -707,7 +707,7 @@
if (out_size != NULL) {
*out_size = abuf->capacity();
}
- return abuf->data();
+ return abuf->base();
}
android::Vector<android::sp<android::MediaCodecBuffer> > abufs;
@@ -720,7 +720,7 @@
if (out_size != NULL) {
*out_size = abufs[idx]->capacity();
}
- return abufs[idx]->data();
+ return abufs[idx]->base();
}
ALOGE("couldn't get output buffers");
return NULL;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 61b667b..8add05e 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -47,6 +47,7 @@
#include <binder/PermissionController.h>
#include <binder/IResultReceiver.h>
#include <binderthreadstate/CallerUtils.h>
+#include <com_android_internal_camera_flags.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <cutils/misc.h>
@@ -105,6 +106,7 @@
using hardware::camera2::ICameraInjectionSession;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
using hardware::camera2::utils::ConcurrentCameraIdCombination;
+namespace flags = com::android::internal::camera::flags;
// ----------------------------------------------------------------------------
// Logging support -- this is for debugging only
@@ -1648,7 +1650,6 @@
callingUid, procState);
}
-
// Automotive privileged client AID_AUTOMOTIVE_EVS using exterior system camera for use cases
// such as rear view and surround view cannot be disabled and are exempt from sensor privacy
// policy. In all other cases,if sensor privacy is enabled then prevent access to the camera.
@@ -1680,16 +1681,18 @@
clientUserId, cameraId.c_str());
}
- // If the System User tries to access the camera when the device is running in
- // headless system user mode, ensure that client has the required permission
- // CAMERA_HEADLESS_SYSTEM_USER.
- if (isHeadlessSystemUserMode() && (clientUserId == USER_SYSTEM) &&
- !hasPermissionsForCameraHeadlessSystemUser(cameraId, callingPid, callingUid)) {
- ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
- return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
- "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" as Headless System User\
- without camera headless system user permission",
- clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+ if (flags::camera_hsum_permission()) {
+ // If the System User tries to access the camera when the device is running in
+ // headless system user mode, ensure that client has the required permission
+ // CAMERA_HEADLESS_SYSTEM_USER.
+ if (isHeadlessSystemUserMode() && (clientUserId == USER_SYSTEM) &&
+ !hasPermissionsForCameraHeadlessSystemUser(cameraId, callingPid, callingUid)) {
+ ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
+ return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
+ "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" as Headless System \
+ User without camera headless system user permission",
+ clientName.c_str(), clientUid, clientPid, cameraId.c_str());
+ }
}
return Status::ok();
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 23051ef..6ce4d3a 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1487,6 +1487,56 @@
return res;
}
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupManualFlashStrengthControlTags() {
+ status_t res = OK;
+ auto& c = mCameraCharacteristics;
+ auto flashSingleStrengthMaxLevelEntry = c.find(ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL);
+ if (flashSingleStrengthMaxLevelEntry.count == 0) {
+ int32_t flashSingleStrengthMaxLevel = 1;
+ res = c.update(ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
+ &flashSingleStrengthMaxLevel, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL: %s (%d)",
+ __FUNCTION__,strerror(-res), res);
+ return res;
+ }
+ }
+ auto flashSingleStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL);
+ if (flashSingleStrengthDefaultLevelEntry.count == 0) {
+ int32_t flashSingleStrengthDefaultLevel = 1;
+ res = c.update(ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
+ &flashSingleStrengthDefaultLevel, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL: %s (%d)",
+ __FUNCTION__,strerror(-res), res);
+ return res;
+ }
+ }
+ auto flashTorchStrengthMaxLevelEntry = c.find(ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL);
+ if (flashTorchStrengthMaxLevelEntry.count == 0) {
+ int32_t flashTorchStrengthMaxLevel = 1;
+ res = c.update(ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
+ &flashTorchStrengthMaxLevel, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL: %s (%d)",
+ __FUNCTION__,strerror(-res), res);
+ return res;
+ }
+ }
+ auto flashTorchStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL);
+ if (flashTorchStrengthDefaultLevelEntry.count == 0) {
+ int32_t flashTorchStrengthDefaultLevel = 1;
+ res = c.update(ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
+ &flashTorchStrengthDefaultLevel, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL: %s (%d)",
+ __FUNCTION__,strerror(-res), res);
+ return res;
+ }
+ }
+ return res;
+}
+
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupMonochromeTags() {
status_t res = OK;
auto& c = mCameraCharacteristics;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 28be652..48c1134 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -683,6 +683,7 @@
SystemCameraKind getSystemCameraKind();
status_t fixupMonochromeTags();
status_t fixupTorchStrengthTags();
+ status_t fixupManualFlashStrengthControlTags();
status_t addDynamicDepthTags(bool maxResolution = false);
status_t deriveHeicTags(bool maxResolution = false);
status_t deriveJpegRTags(bool maxResolution = false);
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index 9659db8..085b012 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -494,6 +494,12 @@
__FUNCTION__, strerror(-res), res);
return;
}
+ res = fixupManualFlashStrengthControlTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
+ }
auto stat = addDynamicDepthTags();
if (OK != stat) {
ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index aeb0abc..56c0c90 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -613,6 +613,14 @@
__FUNCTION__, strerror(-res), res);
return;
}
+
+ res = fixupManualFlashStrengthControlTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
+ }
+
auto stat = addDynamicDepthTags();
if (OK != stat) {
ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),