Merge "Camera: fix FlashLightTest"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 34d040e..46a95c5 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -65,6 +65,8 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/liboboe*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj_arm/STATIC_LIBRARIES/liboboe*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/liboboe*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/mediacodec)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/mediacodec.rc)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 60effe2..c53e6c3 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -56,17 +56,19 @@
}
status_t CameraStatus::writeToParcel(android::Parcel* parcel) const {
- status_t res;
- res = parcel->writeString8(cameraId);
+ auto res = parcel->writeString16(String16(cameraId));
if (res != OK) return res;
+
res = parcel->writeInt32(status);
return res;
}
status_t CameraStatus::readFromParcel(const android::Parcel* parcel) {
- status_t res;
- res = parcel->readString8(&cameraId);
+ String16 tempCameraId;
+ auto res = parcel->readString16(&tempCameraId);
if (res != OK) return res;
+ cameraId = String8(tempCameraId);
+
res = parcel->readInt32(&status);
return res;
}
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/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index a63f39a..637bf9b 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -179,6 +179,78 @@
media_status_t AMediaCodec_releaseOutputBufferAtTime(
AMediaCodec *mData, size_t idx, int64_t timestampNs);
+/**
+ * Creates a Surface that can be used as the input to encoder, in place of input buffers
+ *
+ * This can only be called after the codec has been configured via
+ * AMediaCodec_configure(..); and before AMediaCodec_start() has been called.
+ *
+ * The application is responsible for releasing the surface by calling
+ * ANativeWindow_release() when done.
+ *
+ * For more details, see the Java documentation for MediaCodec.createInputSurface.
+ */
+media_status_t AMediaCodec_createInputSurface(
+ AMediaCodec *mData, ANativeWindow **surface);
+
+/**
+ * Creates a persistent Surface that can be used as the input to encoder
+ *
+ * Persistent surface can be reused by MediaCodec instances and can be set
+ * on a new instance via AMediaCodec_setInputSurface().
+ * A persistent surface can be connected to at most one instance of MediaCodec
+ * at any point in time.
+ *
+ * The application is responsible for releasing the surface by calling
+ * ANativeWindow_release() when done.
+ *
+ * For more details, see the Java documentation for MediaCodec.createPersistentInputSurface.
+ */
+media_status_t AMediaCodec_createPersistentInputSurface(
+ ANativeWindow **surface);
+
+/**
+ * Set a persistent-surface that can be used as the input to encoder, in place of input buffers
+ *
+ * The surface provided *must* be a persistent surface created via
+ * AMediaCodec_createPersistentInputSurface()
+ * This can only be called after the codec has been configured by calling
+ * AMediaCodec_configure(..); and before AMediaCodec_start() has been called.
+ *
+ * For more details, see the Java documentation for MediaCodec.setInputSurface.
+ */
+media_status_t AMediaCodec_setInputSurface(
+ AMediaCodec *mData, ANativeWindow *surface);
+
+/**
+ * Signal additional parameters to the codec instance.
+ *
+ * Parameters can be communicated only when the codec is running, i.e
+ * after AMediaCodec_start() has been called.
+ *
+ * NOTE: Some of these parameter changes may silently fail to apply.
+ */
+media_status_t AMediaCodec_setParameters(
+ AMediaCodec *mData, const AMediaFormat* params);
+
+/**
+ * Signals end-of-stream on input. Equivalent to submitting an empty buffer with
+ * AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM set.
+ *
+ * Returns AMEDIA_ERROR_INVALID_OPERATION when used with an encoder not in executing state
+ * or not receiving input from a Surface created by AMediaCodec_createInputSurface or
+ * AMediaCodec_createPersistentInputSurface.
+ *
+ * Returns the previous codec error if one exists.
+ *
+ * Returns AMEDIA_OK when completed succesfully.
+ *
+ * For more details, see the Java documentation for MediaCodec.signalEndOfInputStream.
+ */
+media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData);
+
+
+
typedef enum {
AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1,
diff --git a/include/ndk/NdkMediaError.h b/include/ndk/NdkMediaError.h
index 9709a6f..1b51364 100644
--- a/include/ndk/NdkMediaError.h
+++ b/include/ndk/NdkMediaError.h
@@ -45,6 +45,7 @@
AMEDIA_ERROR_UNSUPPORTED = AMEDIA_ERROR_BASE - 2,
AMEDIA_ERROR_INVALID_OBJECT = AMEDIA_ERROR_BASE - 3,
AMEDIA_ERROR_INVALID_PARAMETER = AMEDIA_ERROR_BASE - 4,
+ AMEDIA_ERROR_INVALID_OPERATION = AMEDIA_ERROR_BASE - 5,
AMEDIA_DRM_ERROR_BASE = -20000,
AMEDIA_DRM_NOT_PROVISIONED = AMEDIA_DRM_ERROR_BASE - 1,
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/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 0d8142d..8028969 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1345,6 +1345,7 @@
case AUDIO_DEVICE_OUT_WIRED_HEADSET:
case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ case AUDIO_DEVICE_OUT_USB_HEADSET:
return 0;
default :
return -EINVAL;
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index ccfd29c..f2844ed 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -531,6 +531,7 @@
break;
case AUDIO_DEVICE_OUT_WIRED_HEADSET:
case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ case AUDIO_DEVICE_OUT_USB_HEADSET:
default:
break;
}
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/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index c00a951..638eec3 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -465,6 +465,10 @@
} else {
// Legacy IOMX
binder = sm->getService(String16("media.codec"));
+ if (binder == NULL) {
+ ALOGE("Unable to connect to media codec service");
+ return NO_INIT;
+ }
mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
binder->linkToDeath(mCodecDeathListener);
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/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index 7936ad2..de38e7f 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -68,24 +68,32 @@
NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const {
auto it = begin();
- // Second entry can be author or timestamp. Skip author if present
- if ((++it)->type == EVENT_AUTHOR) {
+ // skip start fmt
+ ++it;
+ // skip timestamp
+ ++it;
+ // Skip author if present
+ if (it->type == EVENT_AUTHOR) {
++it;
}
- return ++it;
+ return it;
}
timespec NBLog::FormatEntry::timestamp() const {
auto it = begin();
- if ((++it)->type != EVENT_TIMESTAMP) {
- ++it;
- }
+ // skip start fmt
+ ++it;
return it.payload<timespec>();
}
pid_t NBLog::FormatEntry::author() const {
auto it = begin();
- if ((++it)->type == EVENT_AUTHOR) {
+ // skip start fmt
+ ++it;
+ // skip timestamp
+ ++it;
+ // if there is an author entry, return it, return -1 otherwise
+ if (it->type == EVENT_AUTHOR) {
return it.payload<int>();
}
return -1;
@@ -96,6 +104,8 @@
auto it = begin();
// copy fmt start entry
it.copyTo(dst);
+ // copy timestamp
+ (++it).copyTo(dst);
// insert author entry
size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
uint8_t authorEntry[authorEntrySize];
diff --git a/media/libnbaio/include/NBLog.h b/media/libnbaio/include/NBLog.h
index 7aaf298..59b77bd 100644
--- a/media/libnbaio/include/NBLog.h
+++ b/media/libnbaio/include/NBLog.h
@@ -59,8 +59,8 @@
// a formatted entry has the following structure:
// * START_FMT entry, containing the format string
-// * author entry of the thread that generated it (optional, present in merged log)
// * TIMESTAMP entry
+// * author entry of the thread that generated it (optional, present in merged log)
// * format arg1
// * format arg2
// * ...
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 81eecaf..37e1546 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -551,7 +551,8 @@
mCreateInputBuffersSuspended(false),
mTunneled(false),
mDescribeColorAspectsIndex((OMX_INDEXTYPE)0),
- mDescribeHDRStaticInfoIndex((OMX_INDEXTYPE)0) {
+ mDescribeHDRStaticInfoIndex((OMX_INDEXTYPE)0),
+ mVendorExtensionsStatus(kExtensionsUnchecked) {
mUninitializedState = new UninitializedState(this);
mLoadedState = new LoadedState(this);
mLoadedToIdleState = new LoadedToIdleState(this);
@@ -2216,13 +2217,16 @@
int32_t maxInputSize;
if (msg->findInt32("max-input-size", &maxInputSize)) {
err = setMinBufferSize(kPortIndexInput, (size_t)maxInputSize);
+ err = OK; // ignore error
} else if (!strcmp("OMX.Nvidia.aac.decoder", mComponentName.c_str())) {
err = setMinBufferSize(kPortIndexInput, 8192); // XXX
+ err = OK; // ignore error
}
int32_t priority;
if (msg->findInt32("priority", &priority)) {
err = setPriority(priority);
+ err = OK; // ignore error
}
int32_t rateInt = -1;
@@ -2233,6 +2237,14 @@
}
if (rateFloat > 0) {
err = setOperatingRate(rateFloat, video);
+ err = OK; // ignore errors
+ }
+
+ if (err == OK) {
+ err = setVendorParameters(msg);
+ if (err != OK) {
+ return err;
+ }
}
// NOTE: both mBaseOutputFormat and mOutputFormat are outputFormat to signal first frame.
@@ -5106,7 +5118,7 @@
return BAD_TYPE;
}
- return OK;
+ return getVendorParameters(portIndex, notify);
}
void ACodec::onDataSpaceChanged(android_dataspace dataSpace, const ColorAspects &aspects) {
@@ -7176,7 +7188,362 @@
err = OK; // ignore failure
}
- return err;
+ return setVendorParameters(params);
+}
+
+// Removes trailing tags matching |tag| from |key| (e.g. a settings name). |minLength| specifies
+// the minimum number of characters to keep in |key| (even if it has trailing tags).
+// (Used to remove trailing 'value' tags in settings names, e.g. to normalize
+// 'vendor.settingsX.value' to 'vendor.settingsX')
+static void removeTrailingTags(char *key, size_t minLength, const char *tag) {
+ size_t length = strlen(key);
+ size_t tagLength = strlen(tag);
+ while (length > minLength + tagLength
+ && !strcmp(key + length - tagLength, tag)
+ && key[length - tagLength - 1] == '.') {
+ length -= tagLength + 1;
+ key[length] = '\0';
+ }
+}
+
+/**
+ * Struct encompassing a vendor extension config structure and a potential error status (in case
+ * the structure is null). Used to iterate through vendor extensions.
+ */
+struct VendorExtension {
+ OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE *config; // structure does not own config
+ status_t status;
+
+ // create based on an error status
+ VendorExtension(status_t s_ = NO_INIT) : config(nullptr), status(s_) { }
+
+ // create based on a successfully retrieved config structure
+ VendorExtension(OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE *c_) : config(c_), status(OK) { }
+};
+
+// class VendorExtensions;
+/**
+ * Forward iterator to enumerate vendor extensions supported by an OMX component.
+ */
+class VendorExtensionIterator {
+//private:
+ static constexpr size_t kLastIndex = ~(size_t)0; // last index marker
+
+ sp<IOMXNode> mNode; // component
+ size_t mIndex; // current android extension index
+ std::unique_ptr<uint8_t[]> mBacking; // current extension's backing
+ VendorExtension mCurrent; // current extension
+
+ VendorExtensionIterator(const sp<IOMXNode> &node, size_t index)
+ : mNode(node),
+ mIndex(index) {
+ mCurrent = retrieve();
+ }
+
+ friend class VendorExtensions;
+
+public:
+ // copy constructor
+ VendorExtensionIterator(const VendorExtensionIterator &it)
+ : VendorExtensionIterator(it.mNode, it.mIndex) { }
+
+ // retrieves the current extension pointed to by this iterator
+ VendorExtension retrieve() {
+ if (mIndex == kLastIndex) {
+ return NO_INIT;
+ }
+
+ // try with one param first, then retry if extension needs more than 1 param
+ for (size_t paramSizeUsed = 1;; ) {
+ if (paramSizeUsed > OMX_MAX_ANDROID_VENDOR_PARAMCOUNT) {
+ return BAD_VALUE; // this prevents overflow in the following formula
+ }
+
+ size_t size = sizeof(OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE) +
+ (paramSizeUsed - 1) * sizeof(OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE::param);
+ mBacking.reset(new uint8_t[size]);
+ if (!mBacking) {
+ return NO_MEMORY;
+ }
+
+ OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE *config =
+ reinterpret_cast<OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE *>(mBacking.get());
+
+ InitOMXParams(config);
+ config->nSize = size;
+ config->nIndex = mIndex;
+ config->nParamSizeUsed = paramSizeUsed;
+ status_t err = mNode->getConfig(
+ (OMX_INDEXTYPE)OMX_IndexConfigAndroidVendorExtension, config, size);
+ if (err == OK && config->nParamCount > paramSizeUsed && paramSizeUsed == 1) {
+ // reallocate if we need a bigger config
+ paramSizeUsed = config->nParamCount;
+ continue;
+ } else if (err == NOT_ENOUGH_DATA
+ || (err != OK && mIndex == 0)) {
+ // stop iterator on no-more signal, or if index is not at all supported
+ mIndex = kLastIndex;
+ return NO_INIT;
+ } else if (err != OK) {
+ return err;
+ } else if (paramSizeUsed != config->nParamSizeUsed) {
+ return BAD_VALUE; // component shall not modify size of nParam
+ }
+
+ return config;
+ }
+ }
+
+ // returns extension pointed to by this iterator
+ VendorExtension operator*() {
+ return mCurrent;
+ }
+
+ // prefix increment: move to next extension
+ VendorExtensionIterator &operator++() { // prefix
+ if (mIndex != kLastIndex) {
+ ++mIndex;
+ mCurrent = retrieve();
+ }
+ return *this;
+ }
+
+ // iterator equality operators
+ bool operator==(const VendorExtensionIterator &o) {
+ return mNode == o.mNode && mIndex == o.mIndex;
+ }
+
+ bool operator!=(const VendorExtensionIterator &o) {
+ return !(*this == o);
+ }
+};
+
+/**
+ * Iterable container for vendor extensions provided by a component
+ */
+class VendorExtensions {
+//private:
+ sp<IOMXNode> mNode;
+
+public:
+ VendorExtensions(const sp<IOMXNode> &node)
+ : mNode(node) {
+ }
+
+ VendorExtensionIterator begin() {
+ return VendorExtensionIterator(mNode, 0);
+ }
+
+ VendorExtensionIterator end() {
+ return VendorExtensionIterator(mNode, VendorExtensionIterator::kLastIndex);
+ }
+};
+
+status_t ACodec::setVendorParameters(const sp<AMessage> ¶ms) {
+ std::map<std::string, std::string> vendorKeys; // maps reduced name to actual name
+ constexpr char prefix[] = "vendor.";
+ constexpr size_t prefixLength = sizeof(prefix) - 1;
+ // longest possible vendor param name
+ char reducedKey[OMX_MAX_STRINGNAME_SIZE + OMX_MAX_STRINGVALUE_SIZE];
+
+ // identify all vendor keys to speed up search later and to detect vendor keys
+ for (size_t i = params->countEntries(); i; --i) {
+ AMessage::Type keyType;
+ const char* key = params->getEntryNameAt(i - 1, &keyType);
+ if (key != nullptr && !strncmp(key, prefix, prefixLength)
+ // it is safe to limit format keys to the max vendor param size as we only
+ // shorten parameter names by removing any trailing 'value' tags, and we
+ // already remove the vendor prefix.
+ && strlen(key + prefixLength) < sizeof(reducedKey)
+ && (keyType == AMessage::kTypeInt32
+ || keyType == AMessage::kTypeInt64
+ || keyType == AMessage::kTypeString)) {
+ strcpy(reducedKey, key + prefixLength);
+ removeTrailingTags(reducedKey, 0, "value");
+ auto existingKey = vendorKeys.find(reducedKey);
+ if (existingKey != vendorKeys.end()) {
+ ALOGW("[%s] vendor parameter '%s' aliases parameter '%s'",
+ mComponentName.c_str(), key, existingKey->second.c_str());
+ // ignore for now
+ }
+ vendorKeys.emplace(reducedKey, key);
+ }
+ }
+
+ // don't bother component if we don't have vendor extensions as they may not have implemented
+ // the android vendor extension support, which will lead to unnecessary OMX failure logs.
+ if (vendorKeys.empty()) {
+ return OK;
+ }
+
+ char key[sizeof(OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE::cName) +
+ sizeof(OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE::cKey)];
+
+ status_t finalError = OK;
+
+ // don't try again if component does not have vendor extensions
+ if (mVendorExtensionsStatus == kExtensionsNone) {
+ return OK;
+ }
+
+ for (VendorExtension ext : VendorExtensions(mOMXNode)) {
+ OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE *config = ext.config;
+ if (config == nullptr) {
+ return ext.status;
+ }
+
+ mVendorExtensionsStatus = kExtensionsExist;
+
+ config->cName[sizeof(config->cName) - 1] = '\0'; // null-terminate name
+ strcpy(key, (const char *)config->cName);
+ size_t nameLength = strlen(key);
+ key[nameLength] = '.';
+
+ // don't set vendor extension if client has not provided any of its parameters
+ // or if client simply unsets parameters that are already unset
+ bool needToSet = false;
+ for (size_t paramIndex = 0; paramIndex < config->nParamCount; ++paramIndex) {
+ // null-terminate param key
+ config->param[paramIndex].cKey[sizeof(config->param[0].cKey) - 1] = '\0';
+ strcpy(key + nameLength + 1, (const char *)config->param[paramIndex].cKey);
+ removeTrailingTags(key, nameLength, "value");
+ auto existingKey = vendorKeys.find(key);
+
+ // don't touch (e.g. change) parameters that are not specified by client
+ if (existingKey == vendorKeys.end()) {
+ continue;
+ }
+
+ bool wasSet = config->param[paramIndex].bSet;
+ switch (config->param[paramIndex].eValueType) {
+ case OMX_AndroidVendorValueInt32:
+ {
+ int32_t value;
+ config->param[paramIndex].bSet =
+ (OMX_BOOL)params->findInt32(existingKey->second.c_str(), &value);
+ if (config->param[paramIndex].bSet) {
+ config->param[paramIndex].nInt32 = value;
+ }
+ break;
+ }
+ case OMX_AndroidVendorValueInt64:
+ {
+ int64_t value;
+ config->param[paramIndex].bSet =
+ (OMX_BOOL)params->findAsInt64(existingKey->second.c_str(), &value);
+ if (config->param[paramIndex].bSet) {
+ config->param[paramIndex].nInt64 = value;
+ }
+ break;
+ }
+ case OMX_AndroidVendorValueString:
+ {
+ AString value;
+ config->param[paramIndex].bSet =
+ (OMX_BOOL)params->findString(existingKey->second.c_str(), &value);
+ if (config->param[paramIndex].bSet) {
+ strncpy((char *)config->param[paramIndex].cString, value.c_str(),
+ sizeof(OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE::cString));
+ }
+ break;
+ }
+ default:
+ ALOGW("[%s] vendor parameter '%s' is not a supported value",
+ mComponentName.c_str(), key);
+ continue;
+ }
+ if (config->param[paramIndex].bSet || wasSet) {
+ needToSet = true;
+ }
+ }
+
+ if (needToSet) {
+ status_t err = mOMXNode->setConfig(
+ (OMX_INDEXTYPE)OMX_IndexConfigAndroidVendorExtension,
+ config, config->nSize);
+ if (err != OK) {
+ key[nameLength] = '\0';
+ ALOGW("[%s] failed to set vendor extension '%s'", mComponentName.c_str(), key);
+ // try to set each extension, and return first failure
+ if (finalError == OK) {
+ finalError = err;
+ }
+ }
+ }
+ }
+
+ if (mVendorExtensionsStatus == kExtensionsUnchecked) {
+ mVendorExtensionsStatus = kExtensionsNone;
+ }
+
+ return finalError;
+}
+
+status_t ACodec::getVendorParameters(OMX_U32 portIndex, sp<AMessage> &format) {
+ constexpr char prefix[] = "vendor.";
+ constexpr size_t prefixLength = sizeof(prefix) - 1;
+ char key[sizeof(OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE::cName) +
+ sizeof(OMX_CONFIG_ANDROID_VENDOR_PARAMTYPE::cKey) + prefixLength];
+ strcpy(key, prefix);
+
+ // don't try again if component does not have vendor extensions
+ if (mVendorExtensionsStatus == kExtensionsNone) {
+ return OK;
+ }
+
+ for (VendorExtension ext : VendorExtensions(mOMXNode)) {
+ OMX_CONFIG_ANDROID_VENDOR_EXTENSIONTYPE *config = ext.config;
+ if (config == nullptr) {
+ return ext.status;
+ }
+
+ mVendorExtensionsStatus = kExtensionsExist;
+
+ if (config->eDir != (portIndex == kPortIndexInput ? OMX_DirInput : OMX_DirOutput)) {
+ continue;
+ }
+
+ config->cName[sizeof(config->cName) - 1] = '\0'; // null-terminate name
+ strcpy(key + prefixLength, (const char *)config->cName);
+ size_t nameLength = strlen(key);
+ key[nameLength] = '.';
+
+ for (size_t paramIndex = 0; paramIndex < config->nParamCount; ++paramIndex) {
+ // null-terminate param key
+ config->param[paramIndex].cKey[sizeof(config->param[0].cKey) - 1] = '\0';
+ strcpy(key + nameLength + 1, (const char *)config->param[paramIndex].cKey);
+ removeTrailingTags(key, nameLength, "value");
+ if (config->param[paramIndex].bSet) {
+ switch (config->param[paramIndex].eValueType) {
+ case OMX_AndroidVendorValueInt32:
+ {
+ format->setInt32(key, config->param[paramIndex].nInt32);
+ break;
+ }
+ case OMX_AndroidVendorValueInt64:
+ {
+ format->setInt64(key, config->param[paramIndex].nInt64);
+ break;
+ }
+ case OMX_AndroidVendorValueString:
+ {
+ config->param[paramIndex].cString[OMX_MAX_STRINGVALUE_SIZE - 1] = '\0';
+ format->setString(key, (const char *)config->param[paramIndex].cString);
+ break;
+ }
+ default:
+ ALOGW("vendor parameter %s is not a supported value", key);
+ continue;
+ }
+ }
+ }
+ }
+
+ if (mVendorExtensionsStatus == kExtensionsUnchecked) {
+ mVendorExtensionsStatus = kExtensionsNone;
+ }
+
+ return OK;
}
void ACodec::onSignalEndOfInputStream() {
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 9cb0cdc..ecbbd03 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) {
@@ -81,6 +75,9 @@
}
status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
+ if (mDealer != nullptr) {
+ return -ENOSYS;
+ }
std::shared_ptr<const std::vector<const BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
@@ -100,7 +97,7 @@
const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
AString *errorDetailMsg) {
- if (!hasCryptoOrDescrambler()) {
+ if (!hasCryptoOrDescrambler() || mDealer == nullptr) {
return -ENOSYS;
}
std::shared_ptr<const std::vector<const BufferInfo>> array(
@@ -257,18 +254,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 +268,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/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 1b0db33..b78aa75 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -240,6 +240,24 @@
return false;
}
+bool AMessage::findAsInt64(const char *name, int64_t *value) const {
+ size_t i = findItemIndex(name, strlen(name));
+ if (i < mNumItems) {
+ const Item *item = &mItems[i];
+ switch (item->mType) {
+ case kTypeInt64:
+ *value = (float)item->u.int64Value;
+ return true;
+ case kTypeInt32:
+ *value = (float)item->u.int32Value;
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
bool AMessage::contains(const char *name) const {
size_t i = findItemIndex(name, strlen(name));
return i < mNumItems;
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 3548f96..9b2e7fa 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -50,5 +50,9 @@
"unsigned-integer-overflow",
"signed-integer-overflow",
],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
},
}
diff --git a/media/libstagefright/include/ACodec.h b/media/libstagefright/include/ACodec.h
index 998716f..c57005d 100644
--- a/media/libstagefright/include/ACodec.h
+++ b/media/libstagefright/include/ACodec.h
@@ -304,6 +304,12 @@
std::shared_ptr<ACodecBufferChannel> mBufferChannel;
+ enum {
+ kExtensionsUnchecked,
+ kExtensionsNone,
+ kExtensionsExist,
+ } mVendorExtensionsStatus;
+
status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
status_t allocateBuffersOnPort(OMX_U32 portIndex);
status_t freeBuffersOnPort(OMX_U32 portIndex);
@@ -549,6 +555,13 @@
status_t requestIDRFrame();
status_t setParameters(const sp<AMessage> ¶ms);
+ // set vendor extension parameters specified in params that are supported by the codec
+ status_t setVendorParameters(const sp<AMessage> ¶ms);
+
+ // get vendor extension parameters supported by the codec for a specific port and add it to
+ // |format|
+ status_t getVendorParameters(OMX_U32 portIndex, sp<AMessage> &format);
+
// Send EOS on input stream.
void onSignalEndOfInputStream();
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/include/foundation/AMessage.h b/media/libstagefright/include/foundation/AMessage.h
index 782f8e6..8580eb5 100644
--- a/media/libstagefright/include/foundation/AMessage.h
+++ b/media/libstagefright/include/foundation/AMessage.h
@@ -123,6 +123,9 @@
bool findBuffer(const char *name, sp<ABuffer> *buffer) const;
bool findMessage(const char *name, sp<AMessage> *obj) const;
+ // finds signed integer types cast to int64_t
+ bool findAsInt64(const char *name, int64_t *value) const;
+
// finds any numeric type cast to a float
bool findAsFloat(const char *name, float *value) const;
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/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index 38aad39..ee6d1d5 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -32,9 +32,13 @@
switch (err) {
case OMX_ErrorNone:
return OK;
+ case OMX_ErrorNoMore:
+ return NOT_ENOUGH_DATA;
case OMX_ErrorUnsupportedSetting:
case OMX_ErrorUnsupportedIndex:
return ERROR_UNSUPPORTED; // this is a media specific error
+ case OMX_ErrorBadParameter:
+ return BAD_VALUE;
case OMX_ErrorInsufficientResources:
return NO_MEMORY;
case OMX_ErrorInvalidComponentName:
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 67b0ab1..0984ca4 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -38,6 +38,8 @@
frameworks/base/core/jni \
frameworks/base/media/jni \
frameworks/av/include/ndk \
+ frameworks/native/include \
+ frameworks/native/include/media/openmax \
system/media/camera/include \
$(call include-path-for, libhardware)/hardware \
@@ -56,10 +58,12 @@
liblog \
libutils \
libcutils \
+ libandroid \
libandroid_runtime \
libbinder \
libgui \
libui \
+ libandroid \
include $(BUILD_SHARED_LIBRARY)
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/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 22c90e2..6d02cf1 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -31,9 +31,11 @@
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/PersistentSurface.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaErrors.h>
#include <media/MediaCodecBuffer.h>
+#include <android/native_window.h>
using namespace android;
@@ -54,6 +56,18 @@
kWhatStopActivityNotifications,
};
+struct AMediaCodecPersistentSurface : public Surface {
+ sp<PersistentSurface> mPersistentSurface;
+ AMediaCodecPersistentSurface(
+ const sp<IGraphicBufferProducer>& igbp,
+ const sp<PersistentSurface>& ps)
+ : Surface(igbp) {
+ mPersistentSurface = ps;
+ }
+ virtual ~AMediaCodecPersistentSurface() {
+ //mPersistentSurface ref will be let go off here
+ }
+};
class CodecHandler: public AHandler {
private:
@@ -377,6 +391,94 @@
return translate_error(mData->mCodec->setSurface(surface));
}
+EXPORT
+media_status_t AMediaCodec_createInputSurface(AMediaCodec *mData, ANativeWindow **surface) {
+ if (surface == NULL || mData == NULL) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *surface = NULL;
+
+ sp<IGraphicBufferProducer> igbp = NULL;
+ status_t err = mData->mCodec->createInputSurface(&igbp);
+ if (err != NO_ERROR) {
+ return translate_error(err);
+ }
+
+ *surface = new Surface(igbp);
+ ANativeWindow_acquire(*surface);
+ return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AMediaCodec_createPersistentInputSurface(ANativeWindow **surface) {
+ if (surface == NULL) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ *surface = NULL;
+
+ sp<PersistentSurface> ps = MediaCodec::CreatePersistentInputSurface();
+ if (ps == NULL) {
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ sp<IGraphicBufferProducer> igbp = ps->getBufferProducer();
+ if (igbp == NULL) {
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ *surface = new AMediaCodecPersistentSurface(igbp, ps);
+ ANativeWindow_acquire(*surface);
+
+ return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AMediaCodec_setInputSurface(
+ AMediaCodec *mData, ANativeWindow *surface) {
+
+ if (surface == NULL || mData == NULL) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ AMediaCodecPersistentSurface *aMediaPersistentSurface =
+ static_cast<AMediaCodecPersistentSurface *>(surface);
+ if (aMediaPersistentSurface->mPersistentSurface == NULL) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ return translate_error(mData->mCodec->setInputSurface(
+ aMediaPersistentSurface->mPersistentSurface));
+}
+
+EXPORT
+media_status_t AMediaCodec_setParameters(
+ AMediaCodec *mData, const AMediaFormat* params) {
+ if (params == NULL || mData == NULL) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ sp<AMessage> nativeParams;
+ AMediaFormat_getFormat(params, &nativeParams);
+ ALOGV("setParameters: %s", nativeParams->debugString(0).c_str());
+
+ return translate_error(mData->mCodec->setParameters(nativeParams));
+}
+
+EXPORT
+media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) {
+
+ if (mData == NULL) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ status_t err = mData->mCodec->signalEndOfInputStream();
+ if (err == INVALID_OPERATION) {
+ return AMEDIA_ERROR_INVALID_OPERATION;
+ }
+
+ return translate_error(err);
+
+}
+
//EXPORT
media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
void *userdata) {
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 7db4d06..d7ad370 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
@@ -69,6 +75,11 @@
AMediaCodec_releaseOutputBuffer;
AMediaCodec_releaseOutputBufferAtTime;
AMediaCodec_setOutputSurface; # introduced=24
+ AMediaCodec_setParameters; # introduced=26
+ AMediaCodec_setInputSurface; # introduced=26
+ AMediaCodec_createInputSurface; # introduced=26
+ AMediaCodec_signalEndOfInputStream; # introduced=26
+ AMediaCodec_createPersistentInputSurface; # introduced=26
AMediaCodec_start;
AMediaCodec_stop;
AMediaCrypto_delete;
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index d091179..1239fe0 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -124,16 +124,16 @@
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ case AUDIO_DEVICE_OUT_USB_HEADSET:
return DEVICE_CATEGORY_HEADSET;
case AUDIO_DEVICE_OUT_LINE:
case AUDIO_DEVICE_OUT_AUX_DIGITAL:
- /*USB? Remote submix?*/
+ case AUDIO_DEVICE_OUT_USB_DEVICE:
return DEVICE_CATEGORY_EXT_MEDIA;
case AUDIO_DEVICE_OUT_SPEAKER:
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
case AUDIO_DEVICE_OUT_USB_ACCESSORY:
- case AUDIO_DEVICE_OUT_USB_DEVICE:
case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
default:
return DEVICE_CATEGORY_SPEAKER;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 4ab7604..096ffd1 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -356,6 +356,8 @@
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
if (device) break;
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
+ if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
if (device) break;
if (!isInCall()) {
@@ -509,6 +511,9 @@
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
}
if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
}
if (device2 == AUDIO_DEVICE_NONE) {
@@ -591,6 +596,8 @@
device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
+ device = AUDIO_DEVICE_IN_USB_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
device = AUDIO_DEVICE_IN_USB_DEVICE;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
@@ -621,6 +628,8 @@
default: // FORCE_NONE
if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
+ device = AUDIO_DEVICE_IN_USB_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
device = AUDIO_DEVICE_IN_USB_DEVICE;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
@@ -646,6 +655,8 @@
device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
+ device = AUDIO_DEVICE_IN_USB_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
device = AUDIO_DEVICE_IN_USB_DEVICE;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 7634664..ce6354d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5160,7 +5160,8 @@
if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AUDIO_DEVICE_OUT_WIRED_HEADSET |
- AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) &&
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_USB_HEADSET)) &&
((stream_strategy == STRATEGY_SONIFICATION)
|| (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
|| (stream == AUDIO_STREAM_SYSTEM)
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 4428f75..a77a90b7 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -867,23 +867,22 @@
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
- if (dataSpace != streamInfo.dataSpace) {
- String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d",
- mCameraIdStr.string(), dataSpace, streamInfo.dataSpace);
- ALOGE("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
- }
- //At the native side, there isn't a way to check whether 2 surfaces come from the same
- //surface class type. Use usage flag to approximate the comparison. Treat
- //different preview surface usage flags as the same.
- int32_t previewUsageMask =
- GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_HW_COMPOSER;
- if ((consumerUsage & ~previewUsageMask) != (streamInfo.consumerUsage & ~previewUsageMask)) {
- String8 msg = String8::format(
- "Camera %s:Surface usage flag doesn't match 0x%x vs 0x%x",
- mCameraIdStr.string(), consumerUsage, streamInfo.consumerUsage);
- ALOGE("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ if (dataSpace != streamInfo.dataSpace) {
+ String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d",
+ mCameraIdStr.string(), dataSpace, streamInfo.dataSpace);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+ //At the native side, there isn't a way to check whether 2 surfaces come from the same
+ //surface class type. Use usage flag to approximate the comparison.
+ if (consumerUsage != streamInfo.consumerUsage) {
+ String8 msg = String8::format(
+ "Camera %s:Surface usage flag doesn't match 0x%x vs 0x%x",
+ mCameraIdStr.string(), consumerUsage, streamInfo.consumerUsage);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
}
return binder::Status::ok();
}
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index bf6af86..869e93a 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -461,9 +461,9 @@
} else if (res == NO_MEMORY) {
SP_LOGV("%s: No free buffers", __FUNCTION__);
return;
- } else {
- LOG_ALWAYS_FATAL_IF(res != NO_ERROR,
- "detaching buffer from output failed (%d)", res);
+ } else if (res != OK) {
+ SP_LOGE("%s: detaching buffer from output failed (%d)", __FUNCTION__, res);
+ return;
}
BufferTracker& tracker = *(mBuffers[buffer->getId()]);
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 5cb7f92..8eb4aa0 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -41,9 +41,11 @@
$(TOP)/frameworks/av/media/libstagefright \
$(TOP)/frameworks/av/media/libstagefright/include \
$(TOP)/frameworks/native/include/media/openmax
-LOCAL_MODULE := mediacodec
+LOCAL_MODULE := android.hardware.media.omx@1.0-service
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
LOCAL_32_BIT_ONLY := true
-LOCAL_INIT_RC := mediacodec.rc
+LOCAL_INIT_RC := android.hardware.media.omx@1.0-service.rc
include $(BUILD_EXECUTABLE)
# service seccomp policy
diff --git a/services/mediacodec/mediacodec.rc b/services/mediacodec/android.hardware.media.omx@1.0-service.rc
similarity index 63%
rename from services/mediacodec/mediacodec.rc
rename to services/mediacodec/android.hardware.media.omx@1.0-service.rc
index d78e0a4..ec51d65 100644
--- a/services/mediacodec/mediacodec.rc
+++ b/services/mediacodec/android.hardware.media.omx@1.0-service.rc
@@ -1,4 +1,4 @@
-service mediacodec /system/bin/mediacodec
+service mediacodec /vendor/bin/hw/android.hardware.media.omx@1.0-service
class main
user mediacodec
group camera drmrpc mediadrm
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