Merge "Move mediacodec to vendor partition."
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 9f41403..1466222 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -228,11 +228,11 @@
void CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
native_handle_t* nativeHandle = native_handle_create(1, 0);
if (!nativeHandle) {
- ALOGE("setHeapBase(), failed to create native handle");
+ ALOGE("setSharedBufferBase(), failed to create native handle");
return;
}
if (heap == NULL) {
- ALOGE("setHeapBase(): heap is NULL");
+ ALOGE("setSharedBufferBase(): heap is NULL");
return;
}
int fd = heap->getHeapID();
@@ -244,10 +244,6 @@
ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
}
-void CryptoHal::clearHeapBase(const sp<IMemoryHeap>& heap) {
- mHeapBases.removeItem(heap->getBase());
-}
-
status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, ::SharedBuffer* buffer) {
ssize_t offset;
size_t size;
@@ -261,8 +257,9 @@
return UNEXPECTED_NULL;
}
- // memory must be in the declared heap
- CHECK(mHeapBases.indexOfKey(heap->getBase()) >= 0);
+ if (mHeapBases.indexOfKey(heap->getBase()) < 0) {
+ setHeapBase(heap);
+ }
buffer->bufferId = mHeapBases.valueFor(heap->getBase());
buffer->offset = offset >= 0 ? offset : 0;
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 7b70205..92c9548 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -36,8 +36,6 @@
DECRYPT,
NOTIFY_RESOLUTION,
SET_MEDIADRM_SESSION,
- SET_HEAP,
- UNSET_HEAP,
};
struct BpCrypto : public BpInterface<ICrypto> {
@@ -179,23 +177,6 @@
return reply.readInt32();
}
- virtual void setHeap(const sp<IMemoryHeap> &heap) {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(heap));
- remote()->transact(SET_HEAP, data, &reply);
- return;
- }
-
- virtual void unsetHeap(const sp<IMemoryHeap>& heap) {
- Parcel data, reply;
- data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(heap));
- remote()->transact(UNSET_HEAP, data, &reply);
- return;
- }
-
-
private:
void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
uint32_t size = reply.readInt32();
@@ -423,24 +404,6 @@
return OK;
}
- case SET_HEAP:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
- sp<IMemoryHeap> heap =
- interface_cast<IMemoryHeap>(data.readStrongBinder());
- setHeap(heap);
- return OK;
- }
-
- case UNSET_HEAP:
- {
- CHECK_INTERFACE(ICrypto, data, reply);
- sp<IMemoryHeap> heap =
- interface_cast<IMemoryHeap>(data.readStrongBinder());
- unsetHeap(heap);
- return OK;
- }
-
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/include/ndk/NdkImage.h b/include/ndk/NdkImage.h
index 40c1699..3d1bacc 100644
--- a/include/ndk/NdkImage.h
+++ b/include/ndk/NdkImage.h
@@ -40,6 +40,10 @@
#include "NdkMediaError.h"
+#if __ANDROID_API__ >= 26
+#include <android/hardware_buffer.h>
+#endif /* __ANDROID_API__ >= 26 */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -707,6 +711,53 @@
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 26
+
+/*
+ * Return the image back the the system and delete the AImage object from memory asynchronously.
+ *
+ * <p>Similar to {@link AImage_delete}, do NOT use the image pointer after this method returns.
+ * However, the caller can still hold on to the {@link AHardwareBuffer} returned from this image and
+ * signal the release of the hardware buffer back to the {@link AImageReader}'s queue using
+ * releaseFenceFd.</p>
+ *
+ * @param image The {@link AImage} to be deleted.
+ * @param releaseFenceFd A sync fence fd defined in {@link sync.h}, which signals the release of
+ * underlying {@link AHardwareBuffer}.
+ *
+ * @see sync.h
+ */
+void AImage_deleteAsync(AImage* image, int releaseFenceFd);
+
+/**
+ * Get the hardware buffer handle of the input image intended for GPU and/or hardware access.
+ *
+ * <p>Note that no reference on the returned {@link AHardwareBuffer} handle is acquired
+ * automatically. Once the {@link AImage} or the parent {@link AImageReader} is deleted, the
+ * {@link AHardwareBuffer} handle from previous {@link AImage_getHardwareBuffer} becomes
+ * invalid.</p>
+ *
+ * <p>If the caller ever needs to hold on a reference to the {@link AHardwareBuffer} handle after
+ * the {@link AImage} or the parent {@link AImageReader} is deleted, it must call {@link
+ * AHardwareBuffer_acquire} to acquire an extra reference, and call {@link AHardwareBuffer_release}
+ * once it has finished using it in order to properly deallocate the underlying memory managed by
+ * {@link AHardwareBuffer}. If the caller has acquired extra reference on an {@link AHardwareBuffer}
+ * returned from this function, it must also listen to {@link onBufferFreed} callback to be
+ * notified when the buffer is no longer used by {@link AImageReader}.</p>
+ *
+ * @param image the {@link AImage} of interest.
+ * @param outBuffer The memory area pointed to by buffer will contain the acquired AHardwareBuffer
+ * handle.
+ * @return <ul>
+ * <li>{@link AMEDIA_OK} if the method call succeeds.</li>
+ * <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if image or buffer is NULL</li></ul>
+ *
+ * @see AImageReader_ImageCallback
+ */
+media_status_t AImage_getHardwareBuffer(const AImage* image, /*out*/AHardwareBuffer** buffer);
+
+#endif /* __ANDROID_API__ >= 26 */
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/include/ndk/NdkImageReader.h b/include/ndk/NdkImageReader.h
index 8d72c28..a158da9 100644
--- a/include/ndk/NdkImageReader.h
+++ b/include/ndk/NdkImageReader.h
@@ -300,6 +300,127 @@
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 26
+
+/**
+ * AImageReader constructor similar to {@link AImageReader_new} that takes an additional parameter
+ * for the consumer usage. All other parameters and the return values are identical to those passed
+ * to {@line AImageReader_new}.
+ *
+ * @param usage0 specifies how the consumer will access the AImage, using combination of the
+ * AHARDWAREBUFFER_USAGE0 flags described in {@link hardware_buffer.h}.
+ * Passing {@link AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN} is equivalent to calling
+ * {@link AImageReader_new} with the same parameters. Note that consumers that do not
+ * require CPU access to the buffer should omit {@link
+ * AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN} to improve performance.
+ * @param usage1 specifies how the consumer will access the AImage, using combination of the
+ * AHARDWAREBUFFER_USAGE1 flags described in {@link hardware_buffer.h}.
+ *
+ * @see AImage
+ * @see AImageReader_new
+ * @see AHardwareBuffer
+ */
+media_status_t AImageReader_newWithUsage(
+ int32_t width, int32_t height, int32_t format, uint64_t usage0,
+ uint64_t usage1, int32_t maxImages, /*out*/ AImageReader** reader);
+
+/*
+ * Acquire the next {@link AImage} from the image reader's queue asynchronously.
+ *
+ * <p>AImageReader acquire method similar to {@link AImageReader_acquireNextImage} that takes an
+ * additional parameter for the sync fence. All other parameters and the return values are
+ * identical to those passed to {@link AImageReader_acquireNextImage}.</p>
+ *
+ * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
+ * buffer is ready to consume. When synchronization fence is not needed, fence will be set
+ * to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
+ * use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ * fence fd to change status before attempting to access the {@link AImage} returned.
+ *
+ * @see sync.h
+ * @see sync_get_fence_info
+ */
+media_status_t AImageReader_acquireNextImageAsync(
+ AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd);
+
+/*
+ * Acquire the latest {@link AImage} from the image reader's queue asynchronously, dropping older
+ * images.
+ *
+ * <p>AImageReader acquire method similar to {@link AImageReader_acquireLatestImage} that takes an
+ * additional parameter for the sync fence. All other parameters and the return values are
+ * identical to those passed to {@link AImageReader_acquireLatestImage}.</p>
+ *
+ * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
+ * buffer is ready to consume. When synchronization fence is not needed, fence will be set
+ * to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
+ * use syscalls such as {@code poll()}, {@code epoll()}, {@code select()} to wait for the
+ * fence fd to change status before attempting to access the {@link AImage} returned.
+ *
+ * @see sync.h
+ * @see sync_get_fence_info
+ */
+media_status_t AImageReader_acquireLatestImageAsync(
+ AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd);
+/**
+ * The definition of {@link AImageReader} buffer removed callback.
+ *
+ * @param context The optional application context provided by user in
+ * {@link AImageReader_setBufferRemovedListener}.
+ * @param reader The {@link AImageReader} of interest.
+ * @param buffer The {@link AHardwareBuffer} that is being removed from this image reader.
+ */
+typedef void (*AImageReader_BufferRemovedCallback)(void* context,
+ AImageReader* reader,
+ AHardwareBuffer* buffer);
+
+typedef struct AImageReader_BufferRemovedListener {
+ /// optional application context.
+ void* context;
+
+ /**
+ * This callback is called when an old {@link AHardwareBuffer} is about to be removed from the
+ * image reader.
+ *
+ * <p>Note that registering this callback is optional unless the user holds on extra reference
+ * to {@link AHardwareBuffer} returned from {@link AImage_getHardwareBuffer} by calling {@link
+ * AHardwareBuffer_acquire} or creating external graphic objects, such as EglImage, from it.</p>
+ *
+ * <p>If the callback is registered, the {@link AImageReader} will hold on the last of its
+ * references to the {@link AHardwareBuffer} until this callback returns. User can use the
+ * callback to get notified that it becomes the last owner of the buffer. It is up to the user
+ * to decide to either 1) immediately release all of its references to the buffer; or 2) keep
+ * using the buffer and release it in future. Note that, if option 2 if used, user of this API
+ * is responsible to deallocate the buffer properly by calling {@link AHardwareBuffer_release}.
+ * </p>
+ *
+ * @see AHardwareBuffer_release
+ * @see AImage_getHardwareBuffer
+ */
+ AImageReader_BufferRemovedCallback onBufferRemoved;
+} AImageReader_BufferRemovedListener;
+
+/**
+ * Set the onBufferRemoved listener of this image reader.
+ *
+ * <p>Note that calling this method will replace previously registered listeners.</p>
+ *
+ * @param reader The image reader of interest.
+ * @param listener the {@link AImageReader_BufferRemovedListener} to be registered. Set this to
+ * NULL if application no longer needs to listen to buffer removed events.
+ *
+ * @return <ul>
+ * <li>{@link AMEDIA_OK} if the method call succeeds.</li>
+ * <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL.</li></ul>
+ *
+ * @see AImage_getHardwareBuffer
+ */
+media_status_t AImageReader_setBufferRemovedListener(
+ AImageReader* reader, AImageReader_BufferRemovedListener* listener);
+
+#endif /* __ANDROID_API__ >= 26 */
+
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.cpp b/media/libaudiohal/DevicesFactoryHalHidl.cpp
index 758a5805..fc2645e 100644
--- a/media/libaudiohal/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHidl.cpp
@@ -45,7 +45,8 @@
// and thus have the same lifespan.
mDevicesFactory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
} else {
- LOG_ALWAYS_FATAL("Failed to obtain IDevicesFactory service");
+ ALOGE("Failed to obtain IDevicesFactory service, terminating process.");
+ exit(1);
}
}
diff --git a/media/libaudiohal/EffectsFactoryHalHidl.cpp b/media/libaudiohal/EffectsFactoryHalHidl.cpp
index f7dbb9c..605c059 100644
--- a/media/libaudiohal/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/EffectsFactoryHalHidl.cpp
@@ -44,7 +44,10 @@
EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory") {
mEffectsFactory = IEffectsFactory::getService();
- LOG_ALWAYS_FATAL_IF(mEffectsFactory == 0, "Failed to obtain IEffectsFactory service");
+ if (mEffectsFactory == 0) {
+ ALOGE("Failed to obtain IEffectsFactory service, terminating process.");
+ exit(1);
+ }
}
EffectsFactoryHalHidl::~EffectsFactoryHalHidl() {
diff --git a/media/libmedia/include/Crypto.h b/media/libmedia/include/Crypto.h
index b68413d..ce08f98 100644
--- a/media/libmedia/include/Crypto.h
+++ b/media/libmedia/include/Crypto.h
@@ -55,9 +55,6 @@
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
const DestinationBuffer &destination, AString *errorDetailMsg);
- virtual void setHeap(const sp<IMemoryHeap>&) {}
- virtual void unsetHeap(const sp<IMemoryHeap>&) {}
-
private:
mutable Mutex mLock;
diff --git a/media/libmedia/include/CryptoHal.h b/media/libmedia/include/CryptoHal.h
index d6214c2..28ade20 100644
--- a/media/libmedia/include/CryptoHal.h
+++ b/media/libmedia/include/CryptoHal.h
@@ -60,9 +60,6 @@
const ICrypto::DestinationBuffer &destination,
AString *errorDetailMsg);
- virtual void setHeap(const sp<IMemoryHeap>& heap) { setHeapBase(heap); }
- virtual void unsetHeap(const sp<IMemoryHeap>& heap) { clearHeapBase(heap); }
-
private:
mutable Mutex mLock;
@@ -85,7 +82,6 @@
const uint8_t uuid[16], const void *initData, size_t size);
void setHeapBase(const sp<IMemoryHeap>& heap);
- void clearHeapBase(const sp<IMemoryHeap>& heap);
status_t toSharedBuffer(const sp<IMemory>& memory, ::SharedBuffer* buffer);
diff --git a/media/libmedia/include/ICrypto.h b/media/libmedia/include/ICrypto.h
index f83c846..8990f4b 100644
--- a/media/libmedia/include/ICrypto.h
+++ b/media/libmedia/include/ICrypto.h
@@ -27,7 +27,6 @@
struct AString;
class IMemory;
-class IMemoryHeap;
struct ICrypto : public IInterface {
DECLARE_META_INTERFACE(Crypto);
@@ -65,13 +64,6 @@
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
const DestinationBuffer &destination, AString *errorDetailMsg) = 0;
- /**
- * Declare the heap that the shared memory source buffers passed
- * to decrypt will be allocated from.
- */
- virtual void setHeap(const sp<IMemoryHeap>& heap) = 0;
- virtual void unsetHeap(const sp<IMemoryHeap>& heap) = 0;
-
private:
DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 621347d..66b64f8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -93,7 +93,7 @@
mLooper->stop();
// finalize any pending metrics, usually a no-op.
- finalizeMetrics("destructor");
+ updateMetrics("destructor");
logMetrics("destructor");
if (mAnalyticsItem != NULL) {
@@ -511,11 +511,11 @@
return OK;
}
-void NuPlayerDriver::finalizeMetrics(const char *where) {
+void NuPlayerDriver::updateMetrics(const char *where) {
if (where == NULL) {
where = "unknown";
}
- ALOGV("finalizeMetrics(%p) from %s at state %d", this, where, mState);
+ ALOGV("updateMetrics(%p) from %s at state %d", this, where, mState);
// gather the final stats for this record
Vector<sp<AMessage>> trackStats;
@@ -560,18 +560,16 @@
}
}
}
-
- // getDuration() uses mLock for mutex -- careful where we use it.
- int duration_ms = -1;
- getDuration(&duration_ms);
- if (duration_ms != -1) {
- mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
- }
-
- if (mPlayingTimeUs > 0) {
- mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
- }
}
+
+ // always provide duration and playing time, even if they have 0/unknown values.
+
+ // getDuration() uses mLock for mutex -- careful where we use it.
+ int duration_ms = -1;
+ getDuration(&duration_ms);
+ mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
+
+ mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
}
@@ -605,7 +603,7 @@
status_t NuPlayerDriver::reset() {
ALOGD("reset(%p) at state %d", this, mState);
- finalizeMetrics("reset");
+ updateMetrics("reset");
logMetrics("reset");
Mutex::Autolock autoLock(mLock);
@@ -731,7 +729,7 @@
if (key == FOURCC('m','t','r','X')) {
// mtrX -- a play on 'metrics' (not matrix)
// gather current info all together, parcel it, and send it back
- finalizeMetrics("api");
+ updateMetrics("api");
mAnalyticsItem->writeToParcel(reply);
return OK;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 082f71a..c5ddcb0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -137,7 +137,7 @@
bool mLooping;
bool mAutoLoop;
- void finalizeMetrics(const char *where);
+ void updateMetrics(const char *where);
void logMetrics(const char *where);
status_t prepare_l();
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 9cb0cdc..259e134 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -39,12 +39,6 @@
using BufferInfo = ACodecBufferChannel::BufferInfo;
using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
-ACodecBufferChannel::~ACodecBufferChannel() {
- if (mCrypto != nullptr && mDealer != nullptr) {
- mCrypto->unsetHeap(mDealer->getMemoryHeap());
- }
-}
-
static BufferInfoIterator findClientBuffer(
const std::shared_ptr<const std::vector<const BufferInfo>> &array,
const sp<MediaCodecBuffer> &buffer) {
@@ -257,18 +251,6 @@
}
}
-sp<MemoryDealer> ACodecBufferChannel::makeMemoryDealer(size_t heapSize) {
- sp<MemoryDealer> dealer;
- if (mDealer != nullptr && mCrypto != nullptr) {
- mCrypto->unsetHeap(mDealer->getMemoryHeap());
- }
- dealer = new MemoryDealer(heapSize, "ACodecBufferChannel");
- if (mCrypto != nullptr) {
- mCrypto->setHeap(dealer->getMemoryHeap());
- }
- return dealer;
-}
-
void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
if (hasCryptoOrDescrambler()) {
size_t totalSize = std::accumulate(
@@ -283,10 +265,8 @@
(size_t max, const BufferAndId& elem) {
return std::max(max, align(elem.mBuffer->capacity(), alignment));
});
- size_t destinationBufferSize = maxSize;
- size_t heapSize = totalSize + destinationBufferSize;
- mDealer = makeMemoryDealer(heapSize);
- mDecryptDestination = mDealer->allocate(destinationBufferSize);
+ mDealer = new MemoryDealer(totalSize + maxSize, "ACodecBufferChannel");
+ mDecryptDestination = mDealer->allocate(maxSize);
}
std::vector<const BufferInfo> inputBuffers;
for (const BufferAndId &elem : array) {
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index b731666..02468c1 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -60,7 +60,7 @@
ACodecBufferChannel(
const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained);
- virtual ~ACodecBufferChannel();
+ virtual ~ACodecBufferChannel() = default;
// BufferChannelBase interface
virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
@@ -127,8 +127,6 @@
std::shared_ptr<const std::vector<const BufferInfo>> mInputBuffers;
std::shared_ptr<const std::vector<const BufferInfo>> mOutputBuffers;
- sp<MemoryDealer> makeMemoryDealer(size_t heapSize);
-
bool hasCryptoOrDescrambler() {
return mCrypto != NULL || mDescrambler != NULL;
}
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 793ecb8..dae1ee9 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -379,7 +379,7 @@
// the action are overridden by the last action. For the other cases, traverse
// the Queue to find the newest action that with timestamp smaller or equal to
// the buffer's timestamp. For example, an action queue like
- // [pause, 1s], [resume 2us], [pause 3us], [resume 4us], [pause 5us].... Upon
+ // [pause 1us], [resume 2us], [pause 3us], [resume 4us], [pause 5us].... Upon
// receiving a buffer with timestamp 3.5us, only the action [pause, 3us] needs
// to be handled and [pause, 1us], [resume 2us] will be discarded.
bool dropped = false;
@@ -398,15 +398,14 @@
}
if (!done) {
+ // Find the newest action that with timestamp smaller than itemTimeUs. Then
+ // remove all the actions before and include the newest action.
List<ActionItem>::iterator it = mActionQueue.begin();
- while(it != mActionQueue.end()) {
+ while (it != mActionQueue.end() && it->mActionTimeUs <= itemTimeUs) {
nextAction = *it;
- mActionQueue.erase(it);
- if (nextAction.mActionTimeUs > itemTimeUs) {
- break;
- }
++it;
}
+ mActionQueue.erase(mActionQueue.begin(), it);
CHECK(itemTimeUs >= nextAction.mActionTimeUs);
switch (nextAction.mAction) {
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 67b0ab1..bd4a968 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -56,6 +56,7 @@
liblog \
libutils \
libcutils \
+ libandroid \
libandroid_runtime \
libbinder \
libgui \
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 6c9a644..95fdf36 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -31,10 +31,10 @@
#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
-AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage,
+AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage0, uint64_t usage1,
BufferItem* buffer, int64_t timestamp,
int32_t width, int32_t height, int32_t numPlanes) :
- mReader(reader), mFormat(format), mUsage(usage),
+ mReader(reader), mFormat(format), mUsage0(usage0), mUsage1(usage1),
mBuffer(buffer), mLockedBuffer(nullptr), mTimestamp(timestamp),
mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
}
@@ -54,7 +54,7 @@
}
void
-AImage::close() {
+AImage::close(int releaseFenceFd) {
Mutex::Autolock _l(mLock);
if (mIsClosed) {
return;
@@ -64,7 +64,7 @@
LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
return;
}
- reader->releaseImageLocked(this);
+ reader->releaseImageLocked(this, releaseFenceFd);
// Should have been set to nullptr in releaseImageLocked
// Set to nullptr here for extra safety only
mBuffer = nullptr;
@@ -178,9 +178,9 @@
return AMEDIA_ERROR_INVALID_OBJECT;
}
- if ((mUsage & AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN) == 0) {
+ if ((mUsage0 & AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN) == 0) {
ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "",
- __FUNCTION__, this, mUsage);
+ __FUNCTION__, this, mUsage0);
return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
}
@@ -194,7 +194,7 @@
uint64_t producerUsage;
uint64_t consumerUsage;
android_hardware_HardwareBuffer_convertToGrallocUsageBits(
- &producerUsage, &consumerUsage, mUsage, 0);
+ &producerUsage, &consumerUsage, mUsage0, mUsage1);
status_t ret =
lockImageFromBuffer(mBuffer, consumerUsage, mBuffer->mFence->dup(), lockedBuffer.get());
@@ -600,12 +600,31 @@
return AMEDIA_OK;
}
+media_status_t
+AImage::getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const {
+ if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
+ ALOGE("%s: AImage %p has no buffer.", __FUNCTION__, this);
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+
+ // TODO(jwcai) Someone from Android graphics team stating this should just be a static_cast.
+ *buffer = reinterpret_cast<AHardwareBuffer*>(mBuffer->mGraphicBuffer.get());
+ return AMEDIA_OK;
+}
+
EXPORT
void AImage_delete(AImage* image) {
ALOGV("%s", __FUNCTION__);
+ AImage_deleteAsync(image, -1);
+ return;
+}
+
+EXPORT
+void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
+ ALOGV("%s", __FUNCTION__);
if (image != nullptr) {
image->lockReader();
- image->close();
+ image->close(releaseFenceFd);
image->unlockReader();
if (!image->isClosed()) {
LOG_ALWAYS_FATAL("Image close failed!");
@@ -750,3 +769,15 @@
}
return image->getPlaneData(planeIdx, data, dataLength);
}
+
+EXPORT
+media_status_t AImage_getHardwareBuffer(
+ const AImage* image, /*out*/AHardwareBuffer** buffer) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (image == nullptr || buffer == nullptr) {
+ ALOGE("%s: bad argument. image %p buffer %p", __FUNCTION__, image, buffer);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return image->getHardwareBuffer(buffer);
+}
diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h
index e01dcc7..1fcb495 100644
--- a/media/ndk/NdkImagePriv.h
+++ b/media/ndk/NdkImagePriv.h
@@ -32,12 +32,13 @@
// TODO: this only supports ImageReader
struct AImage {
- AImage(AImageReader* reader, int32_t format, uint64_t usage,
+ AImage(AImageReader* reader, int32_t format, uint64_t usage0, uint64_t usage1,
BufferItem* buffer, int64_t timestamp,
int32_t width, int32_t height, int32_t numPlanes);
// free all resources while keeping object alive. Caller must obtain reader lock
- void close();
+ void close() { close(-1); }
+ void close(int releaseFenceFd);
// Remove from object memory. Must be called after close
void free();
@@ -61,6 +62,7 @@
media_status_t getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const;
media_status_t getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const;
media_status_t getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const;
+ media_status_t getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const;
private:
// AImage should be deleted through free() API.
@@ -73,7 +75,8 @@
// When reader is close, AImage will only accept close API call
wp<AImageReader> mReader;
const int32_t mFormat;
- const uint64_t mUsage; // AHARDWAREBUFFER_USAGE0* flags.
+ const uint64_t mUsage0; // AHARDWAREBUFFER_USAGE0* flags.
+ const uint64_t mUsage1; // AHARDWAREBUFFER_USAGE1* flags.
BufferItem* mBuffer;
std::unique_ptr<CpuConsumer::LockedBuffer> mLockedBuffer;
const int64_t mTimestamp;
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index e580dae..c0aee90 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -38,9 +38,9 @@
}
}
-const int32_t AImageReader::kDefaultUsage = AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
const char* AImageReader::kCallbackFpKey = "Callback";
const char* AImageReader::kContextKey = "Context";
+const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
bool
AImageReader::isSupportedFormat(int32_t format) {
@@ -117,6 +117,45 @@
return AMEDIA_OK;
}
+void
+AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
+ Mutex::Autolock _l(mLock);
+ sp<AImageReader> reader = mReader.promote();
+ if (reader == nullptr) {
+ ALOGW("A frame is available after AImageReader closed!");
+ return; // reader has been closed
+ }
+ if (mListener.onBufferRemoved == nullptr) {
+ return; // No callback registered
+ }
+
+ sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
+ if (gBuffer == nullptr) {
+ ALOGW("A buffer being freed has gone away!");
+ return; // buffer is already destroyed
+ }
+
+ sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
+ msg->setPointer(
+ AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
+ msg->setPointer(AImageReader::kContextKey, mListener.context);
+ msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
+ msg->post();
+}
+
+media_status_t
+AImageReader::BufferRemovedListener::setBufferRemovedListener(
+ AImageReader_BufferRemovedListener* listener) {
+ Mutex::Autolock _l(mLock);
+ if (listener == nullptr) {
+ mListener.context = nullptr;
+ mListener.onBufferRemoved = nullptr;
+ } else {
+ mListener = *listener;
+ }
+ return AMEDIA_OK;
+}
+
media_status_t
AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
return mFrameListener->setImageListener(listener);
@@ -128,9 +167,50 @@
return setImageListenerLocked(listener);
}
+media_status_t
+AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
+ return mBufferRemovedListener->setBufferRemovedListener(listener);
+}
+
+media_status_t
+AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
+ Mutex::Autolock _l(mLock);
+ return setBufferRemovedListenerLocked(listener);
+}
+
void AImageReader::CallbackHandler::onMessageReceived(
const sp<AMessage> &msg) {
switch (msg->what()) {
+ case kWhatBufferRemoved:
+ {
+ AImageReader_BufferRemovedCallback onBufferRemoved;
+ void* context;
+ bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
+ if (!found || onBufferRemoved == nullptr) {
+ ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
+ return;
+ }
+ found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ sp<RefBase> bufferToFree;
+ found = msg->findObject(kGraphicBufferKey, &bufferToFree);
+ if (!found || bufferToFree == nullptr) {
+ ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
+ return;
+ }
+
+ // TODO(jwcai) Someone from Android graphics team stating this should just be a
+ // static_cast.
+ AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
+
+ // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
+ // this AImageReader, and the reference will be gone once this function returns.
+ (*onBufferRemoved)(context, mReader, outBuffer);
+ break;
+ }
case kWhatImageAvailable:
{
AImageReader_ImageCallback onImageAvailable;
@@ -157,15 +237,18 @@
AImageReader::AImageReader(int32_t width,
int32_t height,
int32_t format,
- uint64_t usage,
+ uint64_t usage0,
+ uint64_t usage1,
int32_t maxImages)
: mWidth(width),
mHeight(height),
mFormat(format),
- mUsage(usage),
+ mUsage0(usage0),
+ mUsage1(usage1),
mMaxImages(maxImages),
mNumPlanes(getNumPlanesForFormat(format)),
- mFrameListener(new FrameListener(this)) {}
+ mFrameListener(new FrameListener(this)),
+ mBufferRemovedListener(new BufferRemovedListener(this)) {}
media_status_t
AImageReader::init() {
@@ -176,18 +259,19 @@
uint64_t producerUsage;
uint64_t consumerUsage;
android_hardware_HardwareBuffer_convertToGrallocUsageBits(
- &producerUsage, &consumerUsage, mUsage, 0);
+ &producerUsage, &consumerUsage, mUsage0, mUsage1);
+ mHalUsage = consumerUsage;
sp<IGraphicBufferProducer> gbProducer;
sp<IGraphicBufferConsumer> gbConsumer;
BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
- String8 consumerName = String8::format(
- "ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d", mWidth, mHeight, mFormat, mUsage,
- mMaxImages, getpid(), createProcessUniqueId());
+ String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "u%" PRIu64 "m%d-%d-%d",
+ mWidth, mHeight, mFormat, mUsage0, mUsage1, mMaxImages, getpid(),
+ createProcessUniqueId());
mBufferItemConsumer =
- new BufferItemConsumer(gbConsumer, consumerUsage, mMaxImages, /*controlledByApp*/ true);
+ new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
if (mBufferItemConsumer == nullptr) {
ALOGE("Failed to allocate BufferItemConsumer");
return AMEDIA_ERROR_UNKNOWN;
@@ -196,6 +280,7 @@
mProducer = gbProducer;
mBufferItemConsumer->setName(consumerName);
mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
+ mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
status_t res;
res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
@@ -247,6 +332,9 @@
AImageReader_ImageListener nullListener = {nullptr, nullptr};
setImageListenerLocked(&nullListener);
+ AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
+ setBufferRemovedListenerLocked(&nullBufferRemovedListener);
+
if (mCbLooper != nullptr) {
mCbLooper->unregisterHandler(mHandler->id());
mCbLooper->stop();
@@ -274,7 +362,7 @@
}
media_status_t
-AImageReader::acquireImageLocked(/*out*/AImage** image) {
+AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
*image = nullptr;
BufferItem* buffer = getBufferItemLocked();
if (buffer == nullptr) {
@@ -283,7 +371,10 @@
return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
}
- status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0);
+ // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
+ bool waitForFence = acquireFenceFd == nullptr;
+ status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
+
if (res != NO_ERROR) {
returnBufferItemLocked(buffer);
if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
@@ -301,10 +392,12 @@
const int bufferWidth = getBufferWidth(buffer);
const int bufferHeight = getBufferHeight(buffer);
const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
+ const int bufferUsage = buffer->mGraphicBuffer->getUsage();
const int readerWidth = mWidth;
const int readerHeight = mHeight;
const int readerFmt = mHalFormat;
+ const int readerUsage = mHalUsage;
// Check if the producer buffer configurations match what AImageReader configured. Add some
// extra checks for non-opaque formats.
@@ -324,6 +417,13 @@
__FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
}
+ // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
+ // ImageReader requested has been supported from the producer side.
+ ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
+ "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
+ "configured: %x",
+ __FUNCTION__, bufferUsage, readerUsage);
+
if (readerFmt != bufferFmt) {
if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
// Special casing for when producer switches to a format compatible with flexible
@@ -345,13 +445,19 @@
}
if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
- *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
- readerWidth, readerHeight, mNumPlanes);
+ *image = new AImage(this, mFormat, mUsage0, mUsage1, buffer, buffer->mTimestamp,
+ readerWidth, readerHeight, mNumPlanes);
} else {
- *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
- bufferWidth, bufferHeight, mNumPlanes);
+ *image = new AImage(this, mFormat, mUsage0, mUsage1, buffer, buffer->mTimestamp,
+ bufferWidth, bufferHeight, mNumPlanes);
}
mAcquiredImages.push_back(*image);
+
+ // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
+ if (acquireFenceFd != nullptr) {
+ *acquireFenceFd = buffer->mFence->dup();
+ }
+
return AMEDIA_OK;
}
@@ -373,7 +479,7 @@
}
void
-AImageReader::releaseImageLocked(AImage* image) {
+AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd) {
BufferItem* buffer = image->mBuffer;
if (buffer == nullptr) {
// This should not happen, but is not fatal
@@ -381,15 +487,17 @@
return;
}
- int fenceFd = -1;
- media_status_t ret = image->unlockImageIfLocked(&fenceFd);
+ int unlockFenceFd = -1;
+ media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
if (ret < 0) {
ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
return;
}
- sp<Fence> releaseFence = fenceFd > 0 ? new Fence(fenceFd) : Fence::NO_FENCE;
- mBufferItemConsumer->releaseBuffer(*buffer, releaseFence);
+ sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
+ sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
+ sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
+ mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
returnBufferItemLocked(buffer);
image->mBuffer = nullptr;
@@ -433,13 +541,13 @@
}
media_status_t
-AImageReader::acquireNextImage(/*out*/AImage** image) {
+AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
Mutex::Autolock _l(mLock);
- return acquireImageLocked(image);
+ return acquireImageLocked(image, acquireFenceFd);
}
media_status_t
-AImageReader::acquireLatestImage(/*out*/AImage** image) {
+AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
if (image == nullptr) {
return AMEDIA_ERROR_INVALID_PARAMETER;
}
@@ -447,17 +555,26 @@
*image = nullptr;
AImage* prevImage = nullptr;
AImage* nextImage = nullptr;
- media_status_t ret = acquireImageLocked(&prevImage);
+ media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
if (prevImage == nullptr) {
return ret;
}
for (;;) {
- ret = acquireImageLocked(&nextImage);
+ ret = acquireImageLocked(&nextImage, acquireFenceFd);
if (nextImage == nullptr) {
*image = prevImage;
return AMEDIA_OK;
}
- prevImage->close();
+
+ if (acquireFenceFd == nullptr) {
+ // No need for release fence here since the prevImage is unused and acquireImageLocked
+ // has already waited for acquired fence to be signaled.
+ prevImage->close();
+ } else {
+ // Use the acquire fence as release fence, so that producer can wait before trying to
+ // refill the buffer.
+ prevImage->close(*acquireFenceFd);
+ }
prevImage->free();
prevImage = nextImage;
nextImage = nullptr;
@@ -469,6 +586,15 @@
int32_t width, int32_t height, int32_t format, int32_t maxImages,
/*out*/AImageReader** reader) {
ALOGV("%s", __FUNCTION__);
+ return AImageReader_newWithUsage(
+ width, height, format, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN, 0, maxImages, reader);
+}
+
+EXPORT
+media_status_t AImageReader_newWithUsage(
+ int32_t width, int32_t height, int32_t format, uint64_t usage0, uint64_t usage1,
+ int32_t maxImages, /*out*/ AImageReader** reader) {
+ ALOGV("%s", __FUNCTION__);
if (width < 1 || height < 1) {
ALOGE("%s: image dimension must be positive: w:%d h:%d",
@@ -499,10 +625,8 @@
return AMEDIA_ERROR_INVALID_PARAMETER;
}
- // Set consumer usage to AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN by default so that
- // AImageReader_new behaves as if it's backed by CpuConsumer.
AImageReader* tmpReader = new AImageReader(
- width, height, format, AImageReader::kDefaultUsage, maxImages);
+ width, height, format, usage0, usage1, maxImages);
if (tmpReader == nullptr) {
ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
return AMEDIA_ERROR_UNKNOWN;
@@ -590,23 +714,37 @@
EXPORT
media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
ALOGV("%s", __FUNCTION__);
- if (reader == nullptr || image == nullptr) {
- ALOGE("%s: invalid argument. reader %p, image %p",
- __FUNCTION__, reader, image);
- return AMEDIA_ERROR_INVALID_PARAMETER;
- }
- return reader->acquireNextImage(image);
+ return AImageReader_acquireNextImageAsync(reader, image, nullptr);
}
EXPORT
media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
ALOGV("%s", __FUNCTION__);
+ return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
+}
+
+EXPORT
+media_status_t AImageReader_acquireNextImageAsync(
+ AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
+ ALOGV("%s", __FUNCTION__);
if (reader == nullptr || image == nullptr) {
ALOGE("%s: invalid argument. reader %p, image %p",
__FUNCTION__, reader, image);
return AMEDIA_ERROR_INVALID_PARAMETER;
}
- return reader->acquireLatestImage(image);
+ return reader->acquireNextImage(image, acquireFenceFd);
+}
+
+EXPORT
+media_status_t AImageReader_acquireLatestImageAsync(
+ AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr || image == nullptr) {
+ ALOGE("%s: invalid argument. reader %p, image %p",
+ __FUNCTION__, reader, image);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return reader->acquireLatestImage(image, acquireFenceFd);
}
EXPORT
@@ -621,3 +759,16 @@
reader->setImageListener(listener);
return AMEDIA_OK;
}
+
+EXPORT
+media_status_t AImageReader_setBufferRemovedListener(
+ AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr) {
+ ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ reader->setBufferRemovedListener(listener);
+ return AMEDIA_OK;
+}
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 8becb1d..a233ec8 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -49,15 +49,14 @@
struct AImageReader : public RefBase {
public:
- static const int32_t kDefaultUsage;
-
static bool isSupportedFormat(int32_t format);
static int getNumPlanesForFormat(int32_t format);
AImageReader(int32_t width,
int32_t height,
int32_t format,
- uint64_t usage,
+ uint64_t usage0,
+ uint64_t usage1,
int32_t maxImages);
~AImageReader();
@@ -66,15 +65,15 @@
media_status_t init();
media_status_t setImageListener(AImageReader_ImageListener* listener);
+ media_status_t setBufferRemovedListener(AImageReader_BufferRemovedListener* listener);
- media_status_t acquireNextImage(/*out*/AImage** image);
- media_status_t acquireLatestImage(/*out*/AImage** image);
+ media_status_t acquireNextImage(/*out*/AImage** image, /*out*/int* fenceFd);
+ media_status_t acquireLatestImage(/*out*/AImage** image, /*out*/int* fenceFd);
ANativeWindow* getWindow() const { return mWindow.get(); };
int32_t getWidth() const { return mWidth; };
int32_t getHeight() const { return mHeight; };
int32_t getFormat() const { return mFormat; };
- uint64_t getUsage() const { return mUsage; };
int32_t getMaxImages() const { return mMaxImages; };
private:
@@ -85,22 +84,25 @@
void returnBufferItemLocked(BufferItem* buffer);
// Called by AImageReader_acquireXXX to acquire a Buffer and setup AImage.
- media_status_t acquireImageLocked(/*out*/AImage** image);
+ media_status_t acquireImageLocked(/*out*/AImage** image, /*out*/int* fenceFd);
// Called by AImage to close image
- void releaseImageLocked(AImage* image);
+ void releaseImageLocked(AImage* image, int releaseFenceFd);
static int getBufferWidth(BufferItem* buffer);
static int getBufferHeight(BufferItem* buffer);
media_status_t setImageListenerLocked(AImageReader_ImageListener* listener);
+ media_status_t setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener);
// definition of handler and message
enum {
- kWhatImageAvailable
+ kWhatBufferRemoved,
+ kWhatImageAvailable,
};
static const char* kCallbackFpKey;
static const char* kContextKey;
+ static const char* kGraphicBufferKey;
class CallbackHandler : public AHandler {
public:
CallbackHandler(AImageReader* reader) : mReader(reader) {}
@@ -115,7 +117,8 @@
const int32_t mWidth;
const int32_t mHeight;
const int32_t mFormat;
- const uint64_t mUsage;
+ const uint64_t mUsage0; // AHARDWAREBUFFER_USAGE0* flags.
+ const uint64_t mUsage1; // AHARDWAREBUFFER_USAGE1* flags.
const int32_t mMaxImages;
// TODO(jwcai) Seems completely unused in AImageReader class.
@@ -136,8 +139,24 @@
};
sp<FrameListener> mFrameListener;
+ struct BufferRemovedListener : public BufferItemConsumer::BufferFreedListener {
+ public:
+ explicit BufferRemovedListener(AImageReader* parent) : mReader(parent) {}
+
+ void onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) override;
+
+ media_status_t setBufferRemovedListener(AImageReader_BufferRemovedListener* listener);
+
+ private:
+ AImageReader_BufferRemovedListener mListener = {nullptr, nullptr};
+ wp<AImageReader> mReader;
+ Mutex mLock;
+ };
+ sp<BufferRemovedListener> mBufferRemovedListener;
+
int mHalFormat;
android_dataspace mHalDataSpace;
+ uint64_t mHalUsage;
sp<IGraphicBufferProducer> mProducer;
sp<Surface> mSurface;
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 7db4d06..74c23d3 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -1,7 +1,9 @@
LIBMEDIANDK {
global:
AImageReader_acquireLatestImage; # introduced=24
+ AImageReader_acquireLatestImageAsync; # introduced=26
AImageReader_acquireNextImage; # introduced=24
+ AImageReader_acquireNextImageAsync; # introduced=26
AImageReader_delete; # introduced=24
AImageReader_getFormat; # introduced=24
AImageReader_getHeight; # introduced=24
@@ -9,10 +11,14 @@
AImageReader_getWidth; # introduced=24
AImageReader_getWindow; # introduced=24
AImageReader_new; # introduced=24
+ AImageReader_newWithUsage; # introduced=26
+ AImageReader_setBufferRemovedListener; # introduced=26
AImageReader_setImageListener; # introduced=24
AImage_delete; # introduced=24
+ AImage_deleteAsync; # introduced=26
AImage_getCropRect; # introduced=24
AImage_getFormat; # introduced=24
+ AImage_getHardwareBuffer; # introduced=26
AImage_getHeight; # introduced=24
AImage_getNumberOfPlanes; # introduced=24
AImage_getPlaneData; # introduced=24
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index f8b2908..562e6c9 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -22,6 +22,7 @@
#include <chrono>
#include <inttypes.h>
+#include <set>
#include <hidl/ServiceManagement.h>
namespace android {
@@ -75,7 +76,7 @@
std::lock_guard<std::mutex> lock(mInterfaceMutex);
int count = 0;
for (auto& provider : mProviders) {
- count += provider->mDevices.size();
+ count += provider->mUniqueDeviceCount;
}
return count;
}
@@ -85,7 +86,7 @@
int count = 0;
for (auto& provider : mProviders) {
if (kStandardProviderTypes.find(provider->getType()) != std::string::npos) {
- count += provider->mDevices.size();
+ count += provider->mUniqueDeviceCount;
}
}
return count;
@@ -471,6 +472,12 @@
}
}
+ std::set<std::string> uniqueCameraIds;
+ for (auto& device : mDevices) {
+ uniqueCameraIds.insert(device->mId);
+ }
+ mUniqueDeviceCount = uniqueCameraIds.size();
+
ALOGI("Camera provider %s ready with %zu camera devices",
mProviderName.c_str(), mDevices.size());
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index b1da831..04b9597 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -292,6 +292,7 @@
static status_t setTorchMode(InterfaceT& interface, bool enabled);
};
std::vector<std::unique_ptr<DeviceInfo>> mDevices;
+ int mUniqueDeviceCount;
// HALv1-specific camera fields, including the actual device interface
struct DeviceInfo1 : public DeviceInfo {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 71e52af..eccaddb 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -933,8 +933,18 @@
return res;
}
+
hardware::Return<void> Camera3Device::processCaptureResult(
- const device::V3_2::CaptureResult& result) {
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) {
+ for (const auto& result : results) {
+ processOneCaptureResult(result);
+ }
+ return hardware::Void();
+}
+
+void Camera3Device::processOneCaptureResult(
+ const hardware::camera::device::V3_2::CaptureResult& result) {
camera3_capture_result r;
status_t res;
r.frame_number = result.frameNumber;
@@ -944,7 +954,7 @@
if ((res = validate_camera_metadata_structure(r.result, &expected_metadata_size)) != OK) {
ALOGE("%s: Frame %d: Invalid camera metadata received by camera service from HAL: %s (%d)",
__FUNCTION__, result.frameNumber, strerror(-res), res);
- return hardware::Void();
+ return;
}
} else {
r.result = nullptr;
@@ -960,7 +970,7 @@
if (idx == -1) {
ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
__FUNCTION__, result.frameNumber, i, bSrc.streamId);
- return hardware::Void();
+ return;
}
bDst.stream = mOutputStreams.valueAt(idx)->asHalStream();
@@ -969,7 +979,7 @@
if (res != OK) {
ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
__FUNCTION__, result.frameNumber, i, bSrc.streamId);
- return hardware::Void();
+ return;
}
bDst.buffer = buffer;
bDst.status = mapHidlBufferStatus(bSrc.status);
@@ -981,7 +991,7 @@
} else {
ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
__FUNCTION__, result.frameNumber, i, bSrc.releaseFence->numFds);
- return hardware::Void();
+ return;
}
}
r.num_output_buffers = outputBuffers.size();
@@ -994,7 +1004,7 @@
if (mInputStream->getId() != result.inputBuffer.streamId) {
ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
result.frameNumber, result.inputBuffer.streamId);
- return hardware::Void();
+ return;
}
inputBuffer.stream = mInputStream->asHalStream();
buffer_handle_t *buffer;
@@ -1003,7 +1013,7 @@
if (res != OK) {
ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
__FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
- return hardware::Void();
+ return;
}
inputBuffer.buffer = buffer;
inputBuffer.status = mapHidlBufferStatus(result.inputBuffer.status);
@@ -1015,7 +1025,7 @@
} else {
ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
__FUNCTION__, result.frameNumber, result.inputBuffer.releaseFence->numFds);
- return hardware::Void();
+ return;
}
r.input_buffer = &inputBuffer;
}
@@ -1023,12 +1033,19 @@
r.partial_result = result.partialResult;
processCaptureResult(&r);
-
- return hardware::Void();
}
hardware::Return<void> Camera3Device::notify(
- const NotifyMsg& msg) {
+ const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+ for (const auto& msg : msgs) {
+ notify(msg);
+ }
+ return hardware::Void();
+}
+
+void Camera3Device::notify(
+ const hardware::camera::device::V3_2::NotifyMsg& msg) {
+
camera3_notify_msg m;
switch (msg.type) {
case MsgType::ERROR:
@@ -1039,7 +1056,7 @@
if (idx == -1) {
ALOGE("%s: Frame %d: Invalid error stream id %d",
__FUNCTION__, m.message.error.frame_number, msg.msg.error.errorStreamId);
- return hardware::Void();
+ return;
}
m.message.error.error_stream = mOutputStreams.valueAt(idx)->asHalStream();
} else {
@@ -1067,8 +1084,6 @@
break;
}
notify(&m);
-
- return hardware::Void();
}
status_t Camera3Device::captureList(const List<const CameraMetadata> &requests,
@@ -3036,7 +3051,8 @@
mHal3Device(nullptr) {}
Camera3Device::HalInterface::HalInterface(const HalInterface& other) :
- mHal3Device(other.mHal3Device), mHidlSession(other.mHidlSession) {}
+ mHal3Device(other.mHal3Device),
+ mHidlSession(other.mHidlSession) {}
bool Camera3Device::HalInterface::valid() {
return (mHal3Device != nullptr) || (mHidlSession != nullptr);
@@ -3047,6 +3063,10 @@
mHidlSession.clear();
}
+bool Camera3Device::HalInterface::supportBatchRequest() {
+ return mHidlSession != nullptr;
+}
+
status_t Camera3Device::HalInterface::constructDefaultRequestSettings(
camera3_request_template_t templateId,
/*out*/ camera_metadata_t **requestTemplate) {
@@ -3251,6 +3271,114 @@
return res;
}
+void Camera3Device::HalInterface::wrapAsHidlRequest(camera3_capture_request_t* request,
+ /*out*/device::V3_2::CaptureRequest* captureRequest,
+ /*out*/std::vector<native_handle_t*>* handlesCreated) {
+
+ if (captureRequest == nullptr || handlesCreated == nullptr) {
+ ALOGE("%s: captureRequest (%p) and handlesCreated (%p) must not be null",
+ __FUNCTION__, captureRequest, handlesCreated);
+ return;
+ }
+
+ captureRequest->frameNumber = request->frame_number;
+ // A null request settings maps to a size-0 CameraMetadata
+ if (request->settings != nullptr) {
+ captureRequest->settings.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(request->settings)),
+ get_camera_metadata_size(request->settings));
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mInflightLock);
+ if (request->input_buffer != nullptr) {
+ int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
+ buffer_handle_t buf = *(request->input_buffer->buffer);
+ auto pair = getBufferId(buf, streamId);
+ bool isNewBuffer = pair.first;
+ uint64_t bufferId = pair.second;
+ captureRequest->inputBuffer.streamId = streamId;
+ captureRequest->inputBuffer.bufferId = bufferId;
+ captureRequest->inputBuffer.buffer = (isNewBuffer) ? buf : nullptr;
+ captureRequest->inputBuffer.status = BufferStatus::OK;
+ native_handle_t *acquireFence = nullptr;
+ if (request->input_buffer->acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = request->input_buffer->acquire_fence;
+ handlesCreated->push_back(acquireFence);
+ }
+ captureRequest->inputBuffer.acquireFence = acquireFence;
+ captureRequest->inputBuffer.releaseFence = nullptr;
+
+ pushInflightBufferLocked(captureRequest->frameNumber, streamId,
+ request->input_buffer->buffer,
+ request->input_buffer->acquire_fence);
+ } else {
+ captureRequest->inputBuffer.streamId = -1;
+ captureRequest->inputBuffer.bufferId = BUFFER_ID_NO_BUFFER;
+ }
+
+ captureRequest->outputBuffers.resize(request->num_output_buffers);
+ for (size_t i = 0; i < request->num_output_buffers; i++) {
+ const camera3_stream_buffer_t *src = request->output_buffers + i;
+ StreamBuffer &dst = captureRequest->outputBuffers[i];
+ int32_t streamId = Camera3Stream::cast(src->stream)->getId();
+ buffer_handle_t buf = *(src->buffer);
+ auto pair = getBufferId(buf, streamId);
+ bool isNewBuffer = pair.first;
+ dst.streamId = streamId;
+ dst.bufferId = pair.second;
+ dst.buffer = isNewBuffer ? buf : nullptr;
+ dst.status = BufferStatus::OK;
+ native_handle_t *acquireFence = nullptr;
+ if (src->acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = src->acquire_fence;
+ handlesCreated->push_back(acquireFence);
+ }
+ dst.acquireFence = acquireFence;
+ dst.releaseFence = nullptr;
+
+ pushInflightBufferLocked(captureRequest->frameNumber, streamId,
+ src->buffer, src->acquire_fence);
+ }
+ }
+}
+
+status_t Camera3Device::HalInterface::processBatchCaptureRequests(
+ std::vector<camera3_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
+ ATRACE_NAME("CameraHal::processBatchCaptureRequests");
+ if (!valid()) return INVALID_OPERATION;
+
+ hardware::hidl_vec<device::V3_2::CaptureRequest> captureRequests;
+ size_t batchSize = requests.size();
+ captureRequests.resize(batchSize);
+ std::vector<native_handle_t*> handlesCreated;
+
+ for (size_t i = 0; i < batchSize; i++) {
+ wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i], /*out*/&handlesCreated);
+ }
+
+ common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
+ *numRequestProcessed = 0;
+ mHidlSession->processCaptureRequest(captureRequests,
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ *numRequestProcessed = n;
+ });
+
+ if (status == common::V1_0::Status::OK && *numRequestProcessed != batchSize) {
+ ALOGE("%s: processCaptureRequest returns OK but processed %d/%zu requests",
+ __FUNCTION__, *numRequestProcessed, batchSize);
+ status = common::V1_0::Status::INTERNAL_ERROR;
+ }
+
+ for (auto& handle : handlesCreated) {
+ native_handle_delete(handle);
+ }
+ return CameraProviderManager::mapToStatusT(status);
+}
+
status_t Camera3Device::HalInterface::processCaptureRequest(
camera3_capture_request_t *request) {
ATRACE_NAME("CameraHal::processCaptureRequest");
@@ -3260,76 +3388,10 @@
if (mHal3Device != nullptr) {
res = mHal3Device->ops->process_capture_request(mHal3Device, request);
} else {
- device::V3_2::CaptureRequest captureRequest;
- captureRequest.frameNumber = request->frame_number;
- std::vector<native_handle_t*> handlesCreated;
- // A null request settings maps to a size-0 CameraMetadata
- if (request->settings != nullptr) {
- captureRequest.settings.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(request->settings)),
- get_camera_metadata_size(request->settings));
- }
-
- {
- std::lock_guard<std::mutex> lock(mInflightLock);
- if (request->input_buffer != nullptr) {
- int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
- buffer_handle_t buf = *(request->input_buffer->buffer);
- auto pair = getBufferId(buf, streamId);
- bool isNewBuffer = pair.first;
- uint64_t bufferId = pair.second;
- captureRequest.inputBuffer.streamId = streamId;
- captureRequest.inputBuffer.bufferId = bufferId;
- captureRequest.inputBuffer.buffer = (isNewBuffer) ? buf : nullptr;
- captureRequest.inputBuffer.status = BufferStatus::OK;
- native_handle_t *acquireFence = nullptr;
- if (request->input_buffer->acquire_fence != -1) {
- acquireFence = native_handle_create(1,0);
- acquireFence->data[0] = request->input_buffer->acquire_fence;
- handlesCreated.push_back(acquireFence);
- }
- captureRequest.inputBuffer.acquireFence = acquireFence;
- captureRequest.inputBuffer.releaseFence = nullptr;
-
- pushInflightBufferLocked(captureRequest.frameNumber, streamId,
- request->input_buffer->buffer,
- request->input_buffer->acquire_fence);
- } else {
- captureRequest.inputBuffer.streamId = -1;
- captureRequest.inputBuffer.bufferId = BUFFER_ID_NO_BUFFER;
- }
-
- captureRequest.outputBuffers.resize(request->num_output_buffers);
- for (size_t i = 0; i < request->num_output_buffers; i++) {
- const camera3_stream_buffer_t *src = request->output_buffers + i;
- StreamBuffer &dst = captureRequest.outputBuffers[i];
- int32_t streamId = Camera3Stream::cast(src->stream)->getId();
- buffer_handle_t buf = *(src->buffer);
- auto pair = getBufferId(buf, streamId);
- bool isNewBuffer = pair.first;
- dst.streamId = streamId;
- dst.bufferId = pair.second;
- dst.buffer = isNewBuffer ? buf : nullptr;
- dst.status = BufferStatus::OK;
- native_handle_t *acquireFence = nullptr;
- if (src->acquire_fence != -1) {
- acquireFence = native_handle_create(1,0);
- acquireFence->data[0] = src->acquire_fence;
- handlesCreated.push_back(acquireFence);
- }
- dst.acquireFence = acquireFence;
- dst.releaseFence = nullptr;
-
- pushInflightBufferLocked(captureRequest.frameNumber, streamId,
- src->buffer, src->acquire_fence);
- }
- }
- common::V1_0::Status status = mHidlSession->processCaptureRequest(captureRequest);
-
- for (auto& handle : handlesCreated) {
- native_handle_delete(handle);
- }
- res = CameraProviderManager::mapToStatusT(status);
+ uint32_t numRequestProcessed = 0;
+ std::vector<camera3_capture_request_t*> requests(1);
+ requests[0] = request;
+ res = processBatchCaptureRequests(requests, &numRequestProcessed);
}
return res;
}
@@ -3757,6 +3819,128 @@
}
}
+bool Camera3Device::RequestThread::sendRequestsBatch() {
+ status_t res;
+ size_t batchSize = mNextRequests.size();
+ std::vector<camera3_capture_request_t*> requests(batchSize);
+ uint32_t numRequestProcessed = 0;
+ for (size_t i = 0; i < batchSize; i++) {
+ requests[i] = &mNextRequests.editItemAt(i).halRequest;
+ }
+
+ ATRACE_ASYNC_BEGIN("batch frame capture", mNextRequests[0].halRequest.frame_number);
+ res = mInterface->processBatchCaptureRequests(requests, &numRequestProcessed);
+
+ bool triggerRemoveFailed = false;
+ NextRequest& triggerFailedRequest = mNextRequests.editItemAt(0);
+ for (size_t i = 0; i < numRequestProcessed; i++) {
+ NextRequest& nextRequest = mNextRequests.editItemAt(i);
+ nextRequest.submitted = true;
+
+
+ // Update the latest request sent to HAL
+ if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged
+ Mutex::Autolock al(mLatestRequestMutex);
+
+ camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings);
+ mLatestRequest.acquire(cloned);
+
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent != NULL) {
+ parent->monitorMetadata(TagMonitor::REQUEST,
+ nextRequest.halRequest.frame_number,
+ 0, mLatestRequest);
+ }
+ }
+
+ if (nextRequest.halRequest.settings != NULL) {
+ nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings);
+ }
+
+ if (!triggerRemoveFailed) {
+ // Remove any previously queued triggers (after unlock)
+ status_t removeTriggerRes = removeTriggers(mPrevRequest);
+ if (removeTriggerRes != OK) {
+ triggerRemoveFailed = true;
+ triggerFailedRequest = nextRequest;
+ }
+ }
+ }
+
+ if (triggerRemoveFailed) {
+ SET_ERR("RequestThread: Unable to remove triggers "
+ "(capture request %d, HAL device: %s (%d)",
+ triggerFailedRequest.halRequest.frame_number, strerror(-res), res);
+ cleanUpFailedRequests(/*sendRequestError*/ false);
+ return false;
+ }
+
+ if (res != OK) {
+ // Should only get a failure here for malformed requests or device-level
+ // errors, so consider all errors fatal. Bad metadata failures should
+ // come through notify.
+ SET_ERR("RequestThread: Unable to submit capture request %d to HAL device: %s (%d)",
+ mNextRequests[numRequestProcessed].halRequest.frame_number,
+ strerror(-res), res);
+ cleanUpFailedRequests(/*sendRequestError*/ false);
+ return false;
+ }
+ return true;
+}
+
+bool Camera3Device::RequestThread::sendRequestsOneByOne() {
+ status_t res;
+
+ for (auto& nextRequest : mNextRequests) {
+ // Submit request and block until ready for next one
+ ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number);
+ res = mInterface->processCaptureRequest(&nextRequest.halRequest);
+
+ if (res != OK) {
+ // Should only get a failure here for malformed requests or device-level
+ // errors, so consider all errors fatal. Bad metadata failures should
+ // come through notify.
+ SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
+ " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res),
+ res);
+ cleanUpFailedRequests(/*sendRequestError*/ false);
+ return false;
+ }
+
+ // Mark that the request has be submitted successfully.
+ nextRequest.submitted = true;
+
+ // Update the latest request sent to HAL
+ if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged
+ Mutex::Autolock al(mLatestRequestMutex);
+
+ camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings);
+ mLatestRequest.acquire(cloned);
+
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent != NULL) {
+ parent->monitorMetadata(TagMonitor::REQUEST, nextRequest.halRequest.frame_number,
+ 0, mLatestRequest);
+ }
+ }
+
+ if (nextRequest.halRequest.settings != NULL) {
+ nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings);
+ }
+
+ // Remove any previously queued triggers (after unlock)
+ res = removeTriggers(mPrevRequest);
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to remove triggers "
+ "(capture request %d, HAL device: %s (%d)",
+ nextRequest.halRequest.frame_number, strerror(-res), res);
+ cleanUpFailedRequests(/*sendRequestError*/ false);
+ return false;
+ }
+ }
+ return true;
+}
+
bool Camera3Device::RequestThread::threadLoop() {
ATRACE_CALL();
status_t res;
@@ -3819,58 +4003,12 @@
ALOGVV("%s: %d: submitting %zu requests in a batch.", __FUNCTION__, __LINE__,
mNextRequests.size());
- for (auto& nextRequest : mNextRequests) {
- // Submit request and block until ready for next one
- ATRACE_ASYNC_BEGIN("frame capture", nextRequest.halRequest.frame_number);
- res = mInterface->processCaptureRequest(&nextRequest.halRequest);
- if (res != OK) {
- // Should only get a failure here for malformed requests or device-level
- // errors, so consider all errors fatal. Bad metadata failures should
- // come through notify.
- SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
- " device: %s (%d)", nextRequest.halRequest.frame_number, strerror(-res),
- res);
- cleanUpFailedRequests(/*sendRequestError*/ false);
- if (useFlushLock) {
- mFlushLock.unlock();
- }
- return false;
- }
-
- // Mark that the request has be submitted successfully.
- nextRequest.submitted = true;
-
- // Update the latest request sent to HAL
- if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged
- Mutex::Autolock al(mLatestRequestMutex);
-
- camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings);
- mLatestRequest.acquire(cloned);
-
- sp<Camera3Device> parent = mParent.promote();
- if (parent != NULL) {
- parent->monitorMetadata(TagMonitor::REQUEST, nextRequest.halRequest.frame_number,
- 0, mLatestRequest);
- }
- }
-
- if (nextRequest.halRequest.settings != NULL) {
- nextRequest.captureRequest->mSettings.unlock(nextRequest.halRequest.settings);
- }
-
- // Remove any previously queued triggers (after unlock)
- res = removeTriggers(mPrevRequest);
- if (res != OK) {
- SET_ERR("RequestThread: Unable to remove triggers "
- "(capture request %d, HAL device: %s (%d)",
- nextRequest.halRequest.frame_number, strerror(-res), res);
- cleanUpFailedRequests(/*sendRequestError*/ false);
- if (useFlushLock) {
- mFlushLock.unlock();
- }
- return false;
- }
+ bool submitRequestSuccess = false;
+ if (mInterface->supportBatchRequest()) {
+ submitRequestSuccess = sendRequestsBatch();
+ } else {
+ submitRequestSuccess = sendRequestsOneByOne();
}
if (useFlushLock) {
@@ -3883,7 +4021,7 @@
mNextRequests.clear();
}
- return true;
+ return submitRequestSuccess;
}
status_t Camera3Device::RequestThread::prepareHalRequests() {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index c10b1b4..d873b27 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -241,6 +241,9 @@
// Reset this HalInterface object (does not call close())
void clear();
+ // Check if HalInterface support sending requests in batch
+ bool supportBatchRequest();
+
// Calls into the HAL interface
// Caller takes ownership of requestTemplate
@@ -248,6 +251,9 @@
/*out*/ camera_metadata_t **requestTemplate);
status_t configureStreams(/*inout*/ camera3_stream_configuration *config);
status_t processCaptureRequest(camera3_capture_request_t *request);
+ status_t processBatchCaptureRequests(
+ std::vector<camera3_capture_request_t*>& requests,
+ /*out*/uint32_t* numRequestProcessed);
status_t flush();
status_t dump(int fd);
status_t close();
@@ -262,6 +268,12 @@
std::mutex mInflightLock;
+ // The output HIDL request still depends on input camera3_capture_request_t
+ // Do not free input camera3_capture_request_t before output HIDL request
+ void wrapAsHidlRequest(camera3_capture_request_t* in,
+ /*out*/hardware::camera::device::V3_2::CaptureRequest* out,
+ /*out*/std::vector<native_handle_t*>* handlesCreated);
+
status_t pushInflightBufferLocked(int32_t frameNumber, int32_t streamId,
buffer_handle_t *buffer, int acquireFence);
// Cache of buffer handles keyed off (frameNumber << 32 | streamId)
@@ -438,9 +450,17 @@
*/
hardware::Return<void> processCaptureResult(
- const hardware::camera::device::V3_2::CaptureResult& result) override;
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) override;
hardware::Return<void> notify(
- const hardware::camera::device::V3_2::NotifyMsg& msg) override;
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+ // Handle one capture result
+ void processOneCaptureResult(
+ const hardware::camera::device::V3_2::CaptureResult& results);
+ // Handle one notify message
+ void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
/**
* Common initialization code shared by both HAL paths
@@ -759,6 +779,12 @@
// Clear repeating requests. Must be called with mRequestLock held.
status_t clearRepeatingRequestsLocked(/*out*/ int64_t *lastFrameNumber = NULL);
+ // send request in mNextRequests to HAL one by one. Return true = sucssess
+ bool sendRequestsOneByOne();
+
+ // send request in mNextRequests to HAL in a batch. Return true = sucssess
+ bool sendRequestsBatch();
+
wp<Camera3Device> mParent;
wp<camera3::StatusTracker> mStatusTracker;
HalInterface* mInterface;
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 19016cd..2ce6cf8 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -51,3 +51,7 @@
getdents64: 1
pipe2: 1
ppoll: 1
+
+# Required by AddressSanitizer
+gettid: 1
+sched_yield: 1