Merge "Merge ab/6749736 in stage." into stage-aosp-master
diff --git a/media/OWNERS b/media/OWNERS
index bd83ad9..3e194f0 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -11,9 +11,11 @@
lajos@google.com
marcone@google.com
mnaganov@google.com
+nchalko@google.com
pawin@google.com
philburk@google.com
pmclean@google.com
+quxiangfang@google.com
rachad@google.com
rago@google.com
robertshih@google.com
diff --git a/media/codec2/core/include/C2Buffer.h b/media/codec2/core/include/C2Buffer.h
index 3d3587c..fe37b05 100644
--- a/media/codec2/core/include/C2Buffer.h
+++ b/media/codec2/core/include/C2Buffer.h
@@ -734,6 +734,22 @@
}
virtual ~C2Allocator() = default;
+
+ /**
+ * Returns a true if the handle looks valid for this allocator.
+ *
+ * It does not actually validate that the handle represents a valid allocation (by this
+ * allocator), only that the handle could have been returned by this allocator. As such,
+ * multiple allocators may return true for looksValid for the same handle.
+ *
+ * This method MUST be "non-blocking", MUST not access kernel and/or device drivers, and
+ * return within 1us.
+ *
+ * \param handle the handle for an existing allocation (possibly from another
+ * allocator)
+ */
+ virtual bool checkHandle(const C2Handle *const handle) const = 0;
+
protected:
C2Allocator() = default;
};
@@ -2156,9 +2172,12 @@
};
/**
- * An extension of C2Info objects that can contain arbitrary buffer data.
+ * A const metadata object that can contain arbitrary buffer data.
*
- * \note This object is not describable and contains opaque data.
+ * This object is not an actual C2Info and is not attached to buffers (C2Buffer), but rather to
+ * frames (C2FrameData). It is not describable via C2ParamDescriptor.
+ *
+ * C2InfoBuffer is a const object that can be allocated on stack and is copiable.
*/
class C2InfoBuffer {
public:
@@ -2167,14 +2186,65 @@
*
* \return the parameter index.
*/
- const C2Param::Index index() const;
+ const C2Param::Index index() const { return mIndex; }
/**
* Gets the buffer's data.
*
* \return the buffer's data.
*/
- const C2BufferData data() const;
+ const C2BufferData data() const { return mData; }
+
+ /// Returns a clone of this as a global info buffer.
+ C2InfoBuffer asGlobal() const {
+ C2Param::Index index = mIndex;
+ index.convertToGlobal();
+ return C2InfoBuffer(index, mData);
+ }
+
+ /// Returns a clone of this as a port info buffer.
+ C2InfoBuffer asPort(bool output) const {
+ C2Param::Index index = mIndex;
+ index.convertToPort(output);
+ return C2InfoBuffer(index, mData);
+ }
+
+ /// Returns a clone of this as a stream info buffer.
+ C2InfoBuffer asStream(bool output, unsigned stream) const {
+ C2Param::Index index = mIndex;
+ index.convertToStream(output, stream);
+ return C2InfoBuffer(index, mData);
+ }
+
+ /**
+ * Creates a global info buffer containing a single linear block.
+ *
+ * \param index the core parameter index of this info buffer.
+ * \param block the content of the info buffer.
+ *
+ * \return shared pointer to the created info buffer.
+ */
+ static C2InfoBuffer CreateLinearBuffer(C2Param::CoreIndex index, const C2ConstLinearBlock &block);
+
+ /**
+ * Creates a global info buffer containing a single graphic block.
+ *
+ * \param index the core parameter index of this info buffer.
+ * \param block the content of the info buffer.
+ *
+ * \return shared pointer to the created info buffer.
+ */
+ static C2InfoBuffer CreateGraphicBuffer(C2Param::CoreIndex index, const C2ConstGraphicBlock &block);
+
+protected:
+ // no public constructor
+ explicit C2InfoBuffer(C2Param::Index index, const std::vector<C2ConstLinearBlock> &blocks);
+ explicit C2InfoBuffer(C2Param::Index index, const std::vector<C2ConstGraphicBlock> &blocks);
+
+private:
+ C2Param::Index mIndex;
+ C2BufferData mData;
+ explicit C2InfoBuffer(C2Param::Index index, const C2BufferData &data);
};
/// @}
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 306c04c..ebe7b40 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -2239,8 +2239,8 @@
/**
* Configure tunneled mode
*/
-typedef C2PortParam<C2Setting, C2TunneledModeStruct, kParamIndexTunneledMode>
- C2PortTunneledModeSetting;
+typedef C2PortParam<C2Tuning, C2TunneledModeStruct, kParamIndexTunneledMode>
+ C2PortTunneledModeTuning;
constexpr char C2_PARAMKEY_TUNNELED_RENDER[] = "output.tunneled-render";
/**
@@ -2248,7 +2248,7 @@
* tunneled mode. If the tunneled mode is SIDEBAND, this is the
* sideband handle.
*/
-typedef C2PortParam<C2Setting, C2Int32Array, kParamIndexTunnelHandle> C2PortTunnelHandleSetting;
+typedef C2PortParam<C2Tuning, C2Int32Array, kParamIndexTunnelHandle> C2PortTunnelHandleTuning;
constexpr char C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE[] = "output.tunnel-handle";
/**
diff --git a/media/codec2/core/include/C2Param.h b/media/codec2/core/include/C2Param.h
index 436269a..e938f96 100644
--- a/media/codec2/core/include/C2Param.h
+++ b/media/codec2/core/include/C2Param.h
@@ -317,7 +317,8 @@
DEFINE_FIELD_BASED_COMPARISON_OPERATORS(Index, mIndex)
private:
- friend struct C2Param; // for setStream, MakeStreamId, isValid
+ friend class C2InfoBuffer; // for convertTo*
+ friend struct C2Param; // for setStream, MakeStreamId, isValid, convertTo*
friend struct _C2ParamInspector; // for testing
/**
diff --git a/media/codec2/core/include/C2Work.h b/media/codec2/core/include/C2Work.h
index 6923f3e..67084cc 100644
--- a/media/codec2/core/include/C2Work.h
+++ b/media/codec2/core/include/C2Work.h
@@ -161,7 +161,7 @@
//< for initial work item, these may also come from the parser - if provided
//< for output buffers, these are the responses to requestedInfos
std::vector<std::unique_ptr<C2Param>> configUpdate;
- std::vector<std::shared_ptr<C2InfoBuffer>> infoBuffers;
+ std::vector<C2InfoBuffer> infoBuffers;
};
struct C2Worklet {
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index c73cb52..1f0c856 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -943,14 +943,9 @@
d->infoBuffers.resize(s.infoBuffers.size());
i = 0;
- for (const std::shared_ptr<C2InfoBuffer>& sInfoBuffer : s.infoBuffers) {
+ for (const C2InfoBuffer& sInfoBuffer : s.infoBuffers) {
InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
- if (!sInfoBuffer) {
- LOG(ERROR) << "Null C2FrameData::infoBuffers["
- << i - 1 << "].";
- return false;
- }
- if (!objcpy(&dInfoBuffer, *sInfoBuffer,
+ if (!objcpy(&dInfoBuffer, sInfoBuffer,
bufferPoolSender, baseBlocks, baseBlockIndices)) {
LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
<< i - 1 << "].";
diff --git a/media/codec2/hidl/1.1/utils/Android.bp b/media/codec2/hidl/1.1/utils/Android.bp
index 386f6e2..ab8635b 100644
--- a/media/codec2/hidl/1.1/utils/Android.bp
+++ b/media/codec2/hidl/1.1/utils/Android.bp
@@ -44,6 +44,12 @@
"libstagefright_bufferpool@2.0.1",
"libui",
],
+
+ // Device does not boot when global ThinLTO is enabled for this library.
+ // http://b/170595429
+ lto: {
+ never: true,
+ },
}
diff --git a/media/codec2/tests/vndk/C2BufferTest.cpp b/media/codec2/tests/vndk/C2BufferTest.cpp
index 780994a..a9f8e17 100644
--- a/media/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/codec2/tests/vndk/C2BufferTest.cpp
@@ -765,4 +765,54 @@
}
}
+TEST_F(C2BufferTest, InfoBufferTest) {
+ constexpr size_t kCapacity = 524288u;
+
+ // allocate a linear block
+ std::shared_ptr<C2BlockPool> linearPool(makeLinearBlockPool());
+ std::shared_ptr<C2LinearBlock> linearBlock;
+ ASSERT_EQ(C2_OK, linearPool->fetchLinearBlock(
+ kCapacity,
+ { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
+ &linearBlock));
+
+ C2InfoBuffer info = C2InfoBuffer::CreateLinearBuffer(
+ kParamIndexNumber1, linearBlock->share(1024, kCapacity / 2, C2Fence()));
+ std::shared_ptr<C2InfoBuffer> spInfo(new C2InfoBuffer(info));
+ ASSERT_EQ(kParamIndexNumber1, spInfo->index().coreIndex());
+ ASSERT_TRUE(spInfo->index().isGlobal());
+ ASSERT_EQ(C2Param::INFO, spInfo->index().kind());
+ ASSERT_EQ(C2BufferData::LINEAR, spInfo->data().type());
+ ASSERT_EQ(1024, spInfo->data().linearBlocks()[0].offset());
+ ASSERT_EQ(kCapacity / 2, spInfo->data().linearBlocks()[0].size());
+ // handles must actually be identical after sharing into an info buffer
+ ASSERT_EQ(linearBlock->handle(), spInfo->data().linearBlocks()[0].handle());
+ ASSERT_EQ(linearPool->getAllocatorId(), spInfo->data().linearBlocks()[0].getAllocatorId());
+
+ C2InfoBuffer streamInfo = info.asStream(false /* output */, 1u);
+ ASSERT_EQ(kParamIndexNumber1, streamInfo.index().coreIndex());
+ ASSERT_TRUE(streamInfo.index().forStream());
+ ASSERT_TRUE(streamInfo.index().forInput());
+ ASSERT_EQ(1u, streamInfo.index().stream());
+ ASSERT_EQ(C2Param::INFO, streamInfo.index().kind());
+ ASSERT_EQ(C2BufferData::LINEAR, streamInfo.data().type());
+ ASSERT_EQ(1024, streamInfo.data().linearBlocks()[0].offset());
+ ASSERT_EQ(kCapacity / 2, streamInfo.data().linearBlocks()[0].size());
+ // handles must actually be identical after sharing into an info buffer
+ ASSERT_EQ(linearBlock->handle(), streamInfo.data().linearBlocks()[0].handle());
+ ASSERT_EQ(linearPool->getAllocatorId(), streamInfo.data().linearBlocks()[0].getAllocatorId());
+
+ C2InfoBuffer portInfo = streamInfo.asPort(true /* output */);
+ ASSERT_EQ(kParamIndexNumber1, portInfo.index().coreIndex());
+ ASSERT_TRUE(portInfo.index().forPort());
+ ASSERT_TRUE(portInfo.index().forOutput());
+ ASSERT_EQ(C2Param::INFO, portInfo.index().kind());
+ ASSERT_EQ(C2BufferData::LINEAR, portInfo.data().type());
+ ASSERT_EQ(1024, portInfo.data().linearBlocks()[0].offset());
+ ASSERT_EQ(kCapacity / 2, portInfo.data().linearBlocks()[0].size());
+ // handles must actually be identical after sharing into an info buffer
+ ASSERT_EQ(linearBlock->handle(), portInfo.data().linearBlocks()[0].handle());
+ ASSERT_EQ(linearPool->getAllocatorId(), portInfo.data().linearBlocks()[0].getAllocatorId());
+}
+
} // namespace android
diff --git a/media/codec2/vndk/C2AllocatorBlob.cpp b/media/codec2/vndk/C2AllocatorBlob.cpp
index 50c9e59..565137c 100644
--- a/media/codec2/vndk/C2AllocatorBlob.cpp
+++ b/media/codec2/vndk/C2AllocatorBlob.cpp
@@ -175,12 +175,12 @@
}
// static
-bool C2AllocatorBlob::isValid(const C2Handle* const o) {
+bool C2AllocatorBlob::CheckHandle(const C2Handle* const o) {
size_t capacity;
// Distinguish C2Handle purely allocated by C2AllocatorGralloc, or one allocated through
// C2AllocatorBlob, by checking the handle's height is 1, and its format is
// PixelFormat::BLOB by GetCapacityFromHandle().
- return C2AllocatorGralloc::isValid(o) && GetCapacityFromHandle(o, &capacity) == C2_OK;
+ return C2AllocatorGralloc::CheckHandle(o) && GetCapacityFromHandle(o, &capacity) == C2_OK;
}
} // namespace android
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index e1e1377..4d7e619 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -103,7 +103,7 @@
const static uint32_t MAGIC = '\xc2gr\x00';
static
- const ExtraData* getExtraData(const C2Handle *const handle) {
+ const ExtraData* GetExtraData(const C2Handle *const handle) {
if (handle == nullptr
|| native_handle_is_invalid(handle)
|| handle->numInts < NUM_INTS) {
@@ -114,23 +114,23 @@
}
static
- ExtraData *getExtraData(C2Handle *const handle) {
- return const_cast<ExtraData *>(getExtraData(const_cast<const C2Handle *const>(handle)));
+ ExtraData *GetExtraData(C2Handle *const handle) {
+ return const_cast<ExtraData *>(GetExtraData(const_cast<const C2Handle *const>(handle)));
}
public:
void getIgbpData(uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) const {
- const ExtraData *ed = getExtraData(this);
+ const ExtraData *ed = GetExtraData(this);
*generation = ed->generation;
*igbp_id = unsigned(ed->igbp_id_lo) | uint64_t(unsigned(ed->igbp_id_hi)) << 32;
*igbp_slot = ed->igbp_slot;
}
- static bool isValid(const C2Handle *const o) {
+ static bool IsValid(const C2Handle *const o) {
if (o == nullptr) { // null handle is always valid
return true;
}
- const ExtraData *xd = getExtraData(o);
+ const ExtraData *xd = GetExtraData(o);
// we cannot validate width/height/format/usage without accessing gralloc driver
return xd != nullptr && xd->magic == MAGIC;
}
@@ -152,7 +152,7 @@
native_handle_t *res = native_handle_create(handle->numFds, handle->numInts + NUM_INTS);
if (res != nullptr) {
memcpy(&res->data, &handle->data, sizeof(int) * (handle->numFds + handle->numInts));
- *getExtraData(res) = xd;
+ *GetExtraData(res) = xd;
}
return reinterpret_cast<C2HandleGralloc *>(res);
}
@@ -180,10 +180,10 @@
static bool MigrateNativeHandle(
native_handle_t *handle,
uint32_t generation, uint64_t igbp_id, uint32_t igbp_slot) {
- if (handle == nullptr || !isValid(handle)) {
+ if (handle == nullptr || !IsValid(handle)) {
return false;
}
- ExtraData *ed = getExtraData(handle);
+ ExtraData *ed = GetExtraData(handle);
if (!ed) return false;
ed->generation = generation;
ed->igbp_id_lo = uint32_t(igbp_id & 0xFFFFFFFF);
@@ -195,7 +195,7 @@
static native_handle_t* UnwrapNativeHandle(
const C2Handle *const handle) {
- const ExtraData *xd = getExtraData(handle);
+ const ExtraData *xd = GetExtraData(handle);
if (xd == nullptr || xd->magic != MAGIC) {
return nullptr;
}
@@ -211,7 +211,7 @@
uint32_t *width, uint32_t *height, uint32_t *format,
uint64_t *usage, uint32_t *stride,
uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) {
- const ExtraData *xd = getExtraData(handle);
+ const ExtraData *xd = GetExtraData(handle);
if (xd == nullptr) {
return nullptr;
}
@@ -784,8 +784,9 @@
return mImpl->status();
}
-bool C2AllocatorGralloc::isValid(const C2Handle* const o) {
- return C2HandleGralloc::isValid(o);
+// static
+bool C2AllocatorGralloc::CheckHandle(const C2Handle* const o) {
+ return C2HandleGralloc::IsValid(o);
}
} // namespace android
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
index 6d27a02..85623b8 100644
--- a/media/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -73,7 +73,7 @@
};
// static
-bool C2HandleIon::isValid(const C2Handle * const o) {
+bool C2HandleIon::IsValid(const C2Handle * const o) {
if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
return false;
}
@@ -579,7 +579,7 @@
return mInit;
}
- if (!C2HandleIon::isValid(handle)) {
+ if (!C2HandleIon::IsValid(handle)) {
return C2_BAD_VALUE;
}
@@ -596,9 +596,8 @@
return ret;
}
-bool C2AllocatorIon::isValid(const C2Handle* const o) {
- return C2HandleIon::isValid(o);
+bool C2AllocatorIon::CheckHandle(const C2Handle* const o) {
+ return C2HandleIon::IsValid(o);
}
} // namespace android
-
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
index 0b08f31..143355f 100644
--- a/media/codec2/vndk/C2Buffer.cpp
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -106,6 +106,7 @@
class BufferDataBuddy : public C2BufferData {
using C2BufferData::C2BufferData;
friend class ::C2Buffer;
+ friend class ::C2InfoBuffer;
};
} // namespace
@@ -396,26 +397,18 @@
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
const C2Handle *handle) {
// TODO: get proper allocator? and mutex?
- static std::unique_ptr<C2Allocator> sAllocator = []{
- std::unique_ptr<C2Allocator> allocator;
- if (android::GetPreferredLinearAllocatorId(android::GetCodec2PoolMask()) ==
- android::C2PlatformAllocatorStore::BLOB) {
- allocator = std::make_unique<C2AllocatorBlob>(android::C2PlatformAllocatorStore::BLOB);
- } else {
- allocator = std::make_unique<C2AllocatorIon>(android::C2PlatformAllocatorStore::ION);
- }
+ static std::shared_ptr<C2Allocator> sAllocator = []{
+ std::shared_ptr<C2Allocator> allocator;
+ std::shared_ptr<C2AllocatorStore> allocatorStore = android::GetCodec2PlatformAllocatorStore();
+ allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+
return allocator;
}();
if (sAllocator == nullptr)
return nullptr;
- bool isValidHandle = false;
- if (sAllocator->getId() == android::C2PlatformAllocatorStore::BLOB) {
- isValidHandle = C2AllocatorBlob::isValid(handle);
- } else {
- isValidHandle = C2AllocatorIon::isValid(handle);
- }
+ bool isValidHandle = sAllocator->checkHandle(handle);
std::shared_ptr<C2LinearAllocation> alloc;
if (isValidHandle) {
@@ -431,26 +424,18 @@
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
const C2Handle *cHandle, const std::shared_ptr<BufferPoolData> &data) {
// TODO: get proper allocator? and mutex?
- static std::unique_ptr<C2Allocator> sAllocator = []{
- std::unique_ptr<C2Allocator> allocator;
- if (android::GetPreferredLinearAllocatorId(android::GetCodec2PoolMask()) ==
- android::C2PlatformAllocatorStore::BLOB) {
- allocator = std::make_unique<C2AllocatorBlob>(android::C2PlatformAllocatorStore::BLOB);
- } else {
- allocator = std::make_unique<C2AllocatorIon>(android::C2PlatformAllocatorStore::ION);
- }
+ static std::shared_ptr<C2Allocator> sAllocator = []{
+ std::shared_ptr<C2Allocator> allocator;
+ std::shared_ptr<C2AllocatorStore> allocatorStore = android::GetCodec2PlatformAllocatorStore();
+ allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+
return allocator;
}();
if (sAllocator == nullptr)
return nullptr;
- bool isValidHandle = false;
- if (sAllocator->getId() == android::C2PlatformAllocatorStore::BLOB) {
- isValidHandle = C2AllocatorBlob::isValid(cHandle);
- } else {
- isValidHandle = C2AllocatorIon::isValid(cHandle);
- }
+ bool isValidHandle = sAllocator->checkHandle(cHandle);
std::shared_ptr<C2LinearAllocation> alloc;
if (isValidHandle) {
@@ -1148,7 +1133,7 @@
static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
std::shared_ptr<C2GraphicAllocation> alloc;
- if (C2AllocatorGralloc::isValid(cHandle)) {
+ if (sAllocator->isValid(cHandle)) {
c2_status_t err = sAllocator->priorGraphicAllocation(cHandle, &alloc);
const std::shared_ptr<C2PooledBlockPoolData> poolData =
std::make_shared<C2PooledBlockPoolData>(data);
@@ -1185,6 +1170,7 @@
type_t mType;
std::vector<C2ConstLinearBlock> mLinearBlocks;
std::vector<C2ConstGraphicBlock> mGraphicBlocks;
+ friend class C2InfoBuffer;
};
C2BufferData::C2BufferData(const std::vector<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
@@ -1200,6 +1186,35 @@
return mImpl->graphicBlocks();
}
+C2InfoBuffer::C2InfoBuffer(
+ C2Param::Index index, const std::vector<C2ConstLinearBlock> &blocks)
+ : mIndex(index), mData(BufferDataBuddy(blocks)) {
+}
+
+C2InfoBuffer::C2InfoBuffer(
+ C2Param::Index index, const std::vector<C2ConstGraphicBlock> &blocks)
+ : mIndex(index), mData(BufferDataBuddy(blocks)) {
+}
+
+C2InfoBuffer::C2InfoBuffer(
+ C2Param::Index index, const C2BufferData &data)
+ : mIndex(index), mData(data) {
+}
+
+// static
+C2InfoBuffer C2InfoBuffer::CreateLinearBuffer(
+ C2Param::CoreIndex index, const C2ConstLinearBlock &block) {
+ return C2InfoBuffer(index.coreIndex() | C2Param::Index::KIND_INFO | C2Param::Index::DIR_GLOBAL,
+ { block });
+}
+
+// static
+C2InfoBuffer C2InfoBuffer::CreateGraphicBuffer(
+ C2Param::CoreIndex index, const C2ConstGraphicBlock &block) {
+ return C2InfoBuffer(index.coreIndex() | C2Param::Index::KIND_INFO | C2Param::Index::DIR_GLOBAL,
+ { block });
+}
+
class C2Buffer::Impl {
public:
Impl(C2Buffer *thiz, const std::vector<C2ConstLinearBlock> &blocks)
@@ -1330,4 +1345,3 @@
std::shared_ptr<C2Buffer> C2Buffer::CreateGraphicBuffer(const C2ConstGraphicBlock &block) {
return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
}
-
diff --git a/media/codec2/vndk/include/C2AllocatorBlob.h b/media/codec2/vndk/include/C2AllocatorBlob.h
index 89ce949..fc67af7 100644
--- a/media/codec2/vndk/include/C2AllocatorBlob.h
+++ b/media/codec2/vndk/include/C2AllocatorBlob.h
@@ -44,7 +44,12 @@
virtual ~C2AllocatorBlob() override;
- static bool isValid(const C2Handle* const o);
+ virtual bool checkHandle(const C2Handle* const o) const override { return CheckHandle(o); }
+
+ static bool CheckHandle(const C2Handle* const o);
+
+ // deprecated
+ static bool isValid(const C2Handle* const o) { return CheckHandle(o); }
private:
std::shared_ptr<const Traits> mTraits;
diff --git a/media/codec2/vndk/include/C2AllocatorGralloc.h b/media/codec2/vndk/include/C2AllocatorGralloc.h
index ee7524e..578cf76 100644
--- a/media/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/codec2/vndk/include/C2AllocatorGralloc.h
@@ -84,7 +84,12 @@
virtual ~C2AllocatorGralloc() override;
- static bool isValid(const C2Handle* const o);
+ virtual bool checkHandle(const C2Handle* const o) const override { return CheckHandle(o); }
+
+ static bool CheckHandle(const C2Handle* const o);
+
+ // deprecated
+ static bool isValid(const C2Handle* const o) { return CheckHandle(o); }
private:
class Impl;
diff --git a/media/codec2/vndk/include/C2AllocatorIon.h b/media/codec2/vndk/include/C2AllocatorIon.h
index 1b2051f..6a49b7d 100644
--- a/media/codec2/vndk/include/C2AllocatorIon.h
+++ b/media/codec2/vndk/include/C2AllocatorIon.h
@@ -57,7 +57,12 @@
virtual ~C2AllocatorIon() override;
- static bool isValid(const C2Handle* const o);
+ virtual bool checkHandle(const C2Handle* const o) const override { return CheckHandle(o); }
+
+ static bool CheckHandle(const C2Handle* const o);
+
+ // deprecated
+ static bool isValid(const C2Handle* const o) { return CheckHandle(o); }
/**
* Updates the usage mapper for subsequent new allocations, as well as the supported
diff --git a/media/codec2/vndk/internal/C2HandleIonInternal.h b/media/codec2/vndk/internal/C2HandleIonInternal.h
index c0e1d83..c67698c 100644
--- a/media/codec2/vndk/internal/C2HandleIonInternal.h
+++ b/media/codec2/vndk/internal/C2HandleIonInternal.h
@@ -28,7 +28,10 @@
mFds{ bufferFd },
mInts{ int(size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } { }
- static bool isValid(const C2Handle * const o);
+ static bool IsValid(const C2Handle * const o);
+
+ // deprecated
+ static bool isValid(const C2Handle * const o) { return IsValid(o); }
int bufferFd() const { return mFds.mBuffer; }
size_t size() const {
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 62936f6..fff12c4 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -223,7 +223,7 @@
static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
std::shared_ptr<C2GraphicAllocation> alloc;
- if (C2AllocatorGralloc::isValid(handle)) {
+ if (C2AllocatorGralloc::CheckHandle(handle)) {
uint32_t width;
uint32_t height;
uint32_t format;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 6e2d22f..d677744 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -8268,17 +8268,38 @@
FALLTHROUGH_INTENDED;
}
case kWhatResume:
- case kWhatSetParameters:
{
- if (msg->what() == kWhatResume) {
- ALOGV("[%s] Deferring resume", mCodec->mComponentName.c_str());
- }
+ ALOGV("[%s] Deferring resume", mCodec->mComponentName.c_str());
mCodec->deferMessage(msg);
handled = true;
break;
}
+ case kWhatSetParameters:
+ {
+ sp<AMessage> params;
+ CHECK(msg->findMessage("params", ¶ms));
+
+ sp<ABuffer> hdr10PlusInfo;
+ if (params->findBuffer("hdr10-plus-info", &hdr10PlusInfo)) {
+ if (hdr10PlusInfo != nullptr && hdr10PlusInfo->size() > 0) {
+ (void)mCodec->setHdr10PlusInfo(hdr10PlusInfo);
+ }
+ params->removeEntryAt(params->findEntryByName("hdr10-plus-info"));
+
+ if (params->countEntries() == 0) {
+ msg->removeEntryAt(msg->findEntryByName("params"));
+ }
+ }
+
+ if (msg->countEntries() > 0) {
+ mCodec->deferMessage(msg);
+ }
+ handled = true;
+ break;
+ }
+
case kWhatForceStateTransition:
{
int32_t generation = 0;
@@ -8389,6 +8410,15 @@
return false;
}
+ case OMX_EventConfigUpdate:
+ {
+ CHECK_EQ(data1, (OMX_U32)kPortIndexOutput);
+
+ mCodec->onConfigUpdate((OMX_INDEXTYPE)data2);
+
+ return true;
+ }
+
default:
return BaseState::onOMXEvent(event, data1, data2);
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7a6112f..c38de64 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2131,6 +2131,8 @@
}
bool sendErrorResponse = true;
+ std::string origin{"kWhatError:"};
+ origin += stateString(mState);
switch (mState) {
case INITIALIZING:
@@ -2182,14 +2184,14 @@
// be a shutdown complete notification after
// all.
- // note that we're directly going from
+ // note that we may be directly going from
// STOPPING->UNINITIALIZED, instead of the
// usual STOPPING->INITIALIZED state.
setState(UNINITIALIZED);
if (mState == RELEASING) {
mComponentName.clear();
}
- postPendingRepliesAndDeferredMessages();
+ postPendingRepliesAndDeferredMessages(origin + ":dead");
sendErrorResponse = false;
}
break;
@@ -2280,7 +2282,7 @@
// released by ResourceManager.
finalErr = DEAD_OBJECT;
}
- postPendingRepliesAndDeferredMessages(finalErr);
+ postPendingRepliesAndDeferredMessages(origin, finalErr);
}
break;
}
@@ -2328,7 +2330,7 @@
MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
}
- postPendingRepliesAndDeferredMessages();
+ postPendingRepliesAndDeferredMessages("kWhatComponentAllocated");
break;
}
@@ -2367,7 +2369,7 @@
mFlags |= kFlagUsesSoftwareRenderer;
}
setState(CONFIGURED);
- postPendingRepliesAndDeferredMessages();
+ postPendingRepliesAndDeferredMessages("kWhatComponentConfigured");
// augment our media metrics info, now that we know more things
// such as what the codec extracted from any CSD passed in.
@@ -2436,7 +2438,7 @@
} else {
response->setInt32("err", err);
}
- postPendingRepliesAndDeferredMessages(response);
+ postPendingRepliesAndDeferredMessages("kWhatInputSurfaceCreated", response);
break;
}
@@ -2458,7 +2460,7 @@
} else {
response->setInt32("err", err);
}
- postPendingRepliesAndDeferredMessages(response);
+ postPendingRepliesAndDeferredMessages("kWhatInputSurfaceAccepted", response);
break;
}
@@ -2476,7 +2478,7 @@
if (msg->findInt32("err", &err)) {
response->setInt32("err", err);
}
- postPendingRepliesAndDeferredMessages(response);
+ postPendingRepliesAndDeferredMessages("kWhatSignaledInputEOS", response);
break;
}
@@ -2495,7 +2497,7 @@
MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
}
setState(STARTED);
- postPendingRepliesAndDeferredMessages();
+ postPendingRepliesAndDeferredMessages("kWhatStartCompleted");
break;
}
@@ -2725,7 +2727,13 @@
break;
}
setState(INITIALIZED);
- postPendingRepliesAndDeferredMessages();
+ if (mReplyID) {
+ postPendingRepliesAndDeferredMessages("kWhatStopCompleted");
+ } else {
+ ALOGW("kWhatStopCompleted: presumably an error occurred earlier, "
+ "but the operation completed anyway. (last reply origin=%s)",
+ mLastReplyOrigin.c_str());
+ }
break;
}
@@ -2749,7 +2757,7 @@
mReleaseSurface.reset();
if (mReplyID != nullptr) {
- postPendingRepliesAndDeferredMessages();
+ postPendingRepliesAndDeferredMessages("kWhatReleaseCompleted");
}
if (mAsyncReleaseCompleteNotification != nullptr) {
flushMediametrics();
@@ -2774,7 +2782,7 @@
mCodec->signalResume();
}
- postPendingRepliesAndDeferredMessages();
+ postPendingRepliesAndDeferredMessages("kWhatFlushCompleted");
break;
}
@@ -3163,7 +3171,8 @@
if (mState == FLUSHING || mState == STOPPING
|| mState == CONFIGURING || mState == STARTING) {
// mReply is always set if in these states.
- postPendingRepliesAndDeferredMessages();
+ postPendingRepliesAndDeferredMessages(
+ std::string("kWhatRelease:") + stateString(mState));
}
if (mFlags & kFlagSawMediaServerDie) {
@@ -3212,7 +3221,7 @@
// State transition replies are handled above, so this reply
// would not be related to state transition. As we are
// shutting down the component, just fail the operation.
- postPendingRepliesAndDeferredMessages(UNKNOWN_ERROR);
+ postPendingRepliesAndDeferredMessages("kWhatRelease:reply", UNKNOWN_ERROR);
}
mReplyID = replyID;
setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
@@ -3228,7 +3237,7 @@
if (asyncNotify != nullptr) {
mResourceManagerProxy->markClientForPendingRemoval();
- postPendingRepliesAndDeferredMessages();
+ postPendingRepliesAndDeferredMessages("kWhatRelease:async");
asyncNotifyPost.clear();
mAsyncReleaseCompleteNotification = asyncNotify;
}
@@ -4303,16 +4312,23 @@
return OK;
}
-void MediaCodec::postPendingRepliesAndDeferredMessages(status_t err /* = OK */) {
+void MediaCodec::postPendingRepliesAndDeferredMessages(
+ std::string origin, status_t err /* = OK */) {
sp<AMessage> response{new AMessage};
if (err != OK) {
response->setInt32("err", err);
}
- postPendingRepliesAndDeferredMessages(response);
+ postPendingRepliesAndDeferredMessages(origin, response);
}
-void MediaCodec::postPendingRepliesAndDeferredMessages(const sp<AMessage> &response) {
- CHECK(mReplyID);
+void MediaCodec::postPendingRepliesAndDeferredMessages(
+ std::string origin, const sp<AMessage> &response) {
+ LOG_ALWAYS_FATAL_IF(
+ !mReplyID,
+ "postPendingRepliesAndDeferredMessages: mReplyID == null, from %s following %s",
+ origin.c_str(),
+ mLastReplyOrigin.c_str());
+ mLastReplyOrigin = origin;
response->postReply(mReplyID);
mReplyID.clear();
ALOGV_IF(!mDeferredMessages.empty(),
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index e97f6eb..5509512 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -813,10 +813,6 @@
baseSize = U32_AT(&mParent.mData[mOffset + 4]);
}
- if (baseSize == 0) {
- return;
- }
-
// Prevent integer overflow when adding
if (SIZE_MAX - 10 <= baseSize) {
return;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index c9109f5..a4836cd 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -366,6 +366,7 @@
AString mOwnerName;
sp<MediaCodecInfo> mCodecInfo;
sp<AReplyToken> mReplyID;
+ std::string mLastReplyOrigin;
std::vector<sp<AMessage>> mDeferredMessages;
uint32_t mFlags;
status_t mStickyError;
@@ -489,8 +490,8 @@
bool hasPendingBuffer(int portIndex);
bool hasPendingBuffer();
- void postPendingRepliesAndDeferredMessages(status_t err = OK);
- void postPendingRepliesAndDeferredMessages(const sp<AMessage> &response);
+ void postPendingRepliesAndDeferredMessages(std::string origin, status_t err = OK);
+ void postPendingRepliesAndDeferredMessages(std::string origin, const sp<AMessage> &response);
/* called to get the last codec error when the sticky flag is set.
* if no such codec error is found, returns UNKNOWN_ERROR.
diff --git a/media/libstagefright/tests/mediacodec/Android.bp b/media/libstagefright/tests/mediacodec/Android.bp
index 006864e..0bd0639 100644
--- a/media/libstagefright/tests/mediacodec/Android.bp
+++ b/media/libstagefright/tests/mediacodec/Android.bp
@@ -23,7 +23,12 @@
"MediaTestHelper.cpp",
],
+ header_libs: [
+ "libmediadrm_headers",
+ ],
+
shared_libs: [
+ "libgui",
"libmedia",
"libmedia_codeclist",
"libmediametrics",
diff --git a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
index baa86c1..d00a50f 100644
--- a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
+++ b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
@@ -20,6 +20,8 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <gui/Surface.h>
+#include <mediadrm/ICrypto.h>
#include <media/stagefright/CodecBase.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecListWriter.h>
@@ -152,6 +154,37 @@
using namespace android;
using ::testing::_;
+static sp<MediaCodec> SetupMediaCodec(
+ const AString &owner,
+ const AString &codecName,
+ const AString &mediaType,
+ const sp<ALooper> &looper,
+ std::function<sp<CodecBase>(const AString &name, const char *owner)> getCodecBase) {
+ std::shared_ptr<MediaCodecListWriter> listWriter =
+ MediaTestHelper::CreateCodecListWriter();
+ std::unique_ptr<MediaCodecInfoWriter> infoWriter = listWriter->addMediaCodecInfo();
+ infoWriter->setName(codecName.c_str());
+ infoWriter->setOwner(owner.c_str());
+ infoWriter->addMediaType(mediaType.c_str());
+ std::vector<sp<MediaCodecInfo>> codecInfos;
+ MediaTestHelper::WriteCodecInfos(listWriter, &codecInfos);
+ std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo =
+ [codecInfos](const AString &name, sp<MediaCodecInfo> *info) -> status_t {
+ auto it = std::find_if(
+ codecInfos.begin(), codecInfos.end(),
+ [&name](const sp<MediaCodecInfo> &info) {
+ return name.equalsIgnoreCase(info->getCodecName());
+ });
+
+ *info = (it == codecInfos.end()) ? nullptr : *it;
+ return (*info) ? OK : NAME_NOT_FOUND;
+ };
+
+ looper->start();
+ return MediaTestHelper::CreateCodec(
+ codecName, looper, getCodecBase, getCodecInfo);
+}
+
TEST(MediaCodecTest, ReclaimReleaseRace) {
// Test scenario:
//
@@ -202,30 +235,9 @@
return mockCodec;
};
- std::shared_ptr<MediaCodecListWriter> listWriter =
- MediaTestHelper::CreateCodecListWriter();
- std::unique_ptr<MediaCodecInfoWriter> infoWriter = listWriter->addMediaCodecInfo();
- infoWriter->setName(kCodecName.c_str());
- infoWriter->setOwner(kCodecOwner.c_str());
- infoWriter->addMediaType(kMediaType.c_str());
- std::vector<sp<MediaCodecInfo>> codecInfos;
- MediaTestHelper::WriteCodecInfos(listWriter, &codecInfos);
- std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo =
- [codecInfos](const AString &name, sp<MediaCodecInfo> *info) -> status_t {
- auto it = std::find_if(
- codecInfos.begin(), codecInfos.end(),
- [&name](const sp<MediaCodecInfo> &info) {
- return name.equalsIgnoreCase(info->getCodecName());
- });
-
- *info = (it == codecInfos.end()) ? nullptr : *it;
- return (*info) ? OK : NAME_NOT_FOUND;
- };
-
sp<ALooper> looper{new ALooper};
- looper->start();
- sp<MediaCodec> codec = MediaTestHelper::CreateCodec(
- kCodecName, looper, getCodecBase, getCodecInfo);
+ sp<MediaCodec> codec = SetupMediaCodec(
+ kCodecOwner, kCodecName, kMediaType, looper, getCodecBase);
ASSERT_NE(nullptr, codec) << "Codec must not be null";
ASSERT_NE(nullptr, mockCodec) << "MockCodec must not be null";
std::promise<void> reclaimCompleted;
@@ -266,3 +278,73 @@
<< "release timed out";
looper->stop();
}
+
+TEST(MediaCodecTest, ErrorWhileStopping) {
+ // Test scenario:
+ //
+ // 1) Client thread calls stop(); MediaCodec looper thread calls
+ // initiateShutdown(); shutdown is being handled at the component thread.
+ // 2) Error occurred, but the shutdown operation is still being done.
+ // 3) MediaCodec looper thread handles the error.
+ // 4) Component thread completes shutdown and posts onStopCompleted()
+
+ static const AString kCodecName{"test.codec"};
+ static const AString kCodecOwner{"nobody"};
+ static const AString kMediaType{"video/x-test"};
+
+ std::promise<void> errorOccurred;
+ sp<MockCodec> mockCodec;
+ std::function<sp<CodecBase>(const AString &name, const char *owner)> getCodecBase =
+ [&mockCodec, &errorOccurred](const AString &, const char *) {
+ mockCodec = new MockCodec([](const std::shared_ptr<MockBufferChannel> &) {
+ // No mock setup, as we don't expect any buffer operations
+ // in this scenario.
+ });
+ ON_CALL(*mockCodec, initiateAllocateComponent(_))
+ .WillByDefault([mockCodec](const sp<AMessage> &) {
+ mockCodec->callback()->onComponentAllocated(kCodecName.c_str());
+ });
+ ON_CALL(*mockCodec, initiateConfigureComponent(_))
+ .WillByDefault([mockCodec](const sp<AMessage> &msg) {
+ mockCodec->callback()->onComponentConfigured(
+ msg->dup(), msg->dup());
+ });
+ ON_CALL(*mockCodec, initiateStart())
+ .WillByDefault([mockCodec]() {
+ mockCodec->callback()->onStartCompleted();
+ });
+ ON_CALL(*mockCodec, initiateShutdown(true))
+ .WillByDefault([mockCodec, &errorOccurred](bool) {
+ mockCodec->callback()->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
+ // Mark that 1) and 2) are complete.
+ errorOccurred.set_value();
+ });
+ ON_CALL(*mockCodec, initiateShutdown(false))
+ .WillByDefault([mockCodec](bool) {
+ mockCodec->callback()->onReleaseCompleted();
+ });
+ return mockCodec;
+ };
+
+ sp<ALooper> looper{new ALooper};
+ sp<MediaCodec> codec = SetupMediaCodec(
+ kCodecOwner, kCodecName, kMediaType, looper, getCodecBase);
+ ASSERT_NE(nullptr, codec) << "Codec must not be null";
+ ASSERT_NE(nullptr, mockCodec) << "MockCodec must not be null";
+
+ std::thread([mockCodec, &errorOccurred]{
+ // Simulate component thread that handles stop()
+ errorOccurred.get_future().wait();
+ // Error occurred but shutdown request still got processed.
+ mockCodec->callback()->onStopCompleted();
+ }).detach();
+
+ codec->configure(new AMessage, nullptr, nullptr, 0);
+ codec->start();
+ codec->stop();
+ // Sleep here to give time for the MediaCodec looper thread
+ // to process the messages.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ codec->release();
+ looper->stop();
+}
diff --git a/services/OWNERS b/services/OWNERS
index 66a4bcb..f0b5e2f 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -5,3 +5,5 @@
gkasten@google.com
hunga@google.com
marcone@google.com
+nchalko@google.com
+quxiangfang@google.com