Merge "Codec2: C2Block2D rework"
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 5240f7b..2ec30dd 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -106,6 +106,10 @@
"VideoFrameScheduler.cpp",
],
+ header_libs: [
+ "libstagefright_codec2_internal",
+ ],
+
shared_libs: [
"libaudioutils",
"libbinder",
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index ca4ddc8..27060e1 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -23,6 +23,7 @@
#include <C2AllocatorGralloc.h>
#include <C2PlatformSupport.h>
+#include <C2BlockInternal.h>
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <binder/MemoryDealer.h>
@@ -819,7 +820,7 @@
std::shared_ptr<C2Allocator> allocator = mAllocator.lock();
if (!allocator) {
c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
- C2AllocatorStore::PLATFORM_START + 1, // GRALLOC
+ C2PlatformAllocatorStore::GRALLOC,
&allocator);
if (err != OK) {
return UNKNOWN_ERROR;
@@ -835,7 +836,8 @@
if (err != OK) {
return UNKNOWN_ERROR;
}
- std::shared_ptr<C2GraphicBlock> block(new GraphicBlock(alloc));
+
+ std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
std::unique_ptr<C2Work> work(new C2Work);
work->input.flags = (C2FrameData::flags_t)0;
diff --git a/media/libstagefright/codec2/include/C2.h b/media/libstagefright/codec2/include/C2.h
index ab81cdc..00e3924 100644
--- a/media/libstagefright/codec2/include/C2.h
+++ b/media/libstagefright/codec2/include/C2.h
@@ -534,6 +534,18 @@
});
}
+/**
+ * \ingroup utils_internal
+ */
+template<typename T, typename U, typename V>
+inline constexpr typename c2_types<T, V>::wide_type c2_clamp(const T a, const U b, const V c) {
+ typedef typename c2_types<T, U, V>::wide_type wide_type;
+ return ({
+ wide_type a_(a), b_(b), c_(c);
+ static_cast<typename c2_types<T, V>::wide_type>(b_ < a_ ? a_ : b_ > c_ ? c_ : b_);
+ });
+}
+
/// @}
#ifdef __ANDROID__
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index 45ad17f..034075f 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -134,7 +134,7 @@
private:
class Impl;
std::shared_ptr<Impl> mImpl;
- C2Fence(const std::shared_ptr<Impl> &impl);
+ C2Fence(std::shared_ptr<Impl> impl);
friend struct _C2FenceFactory;
};
@@ -324,15 +324,20 @@
C2_ALLOW_OVERFLOW
inline constexpr C2Segment intersect(const C2Segment &other) const {
- if (!isValid()) {
- return *this;
- } else if (!other.isValid()) {
- return other;
- } else {
- return C2Segment(c2_max(offset, other.offset),
- c2_min(end(), other.end()) - c2_max(offset, other.offset));
- }
+ return C2Segment(c2_max(offset, other.offset),
+ c2_min(end(), other.end()) - c2_max(offset, other.offset));
}
+
+ /** clamps end to offset if it overflows */
+ inline constexpr C2Segment normalize() const {
+ return C2Segment(offset, c2_max(offset, end()) - offset);
+ }
+
+ /** clamps end to max if it overflows */
+ inline constexpr C2Segment saturate() const {
+ return C2Segment(offset, c2_min(size, ~offset));
+ }
+
};
/**
@@ -370,7 +375,7 @@
};
/**
- * Aspect for objects that have a linear range.
+ * Aspect for objects that have a linear range inside a linear capacity.
*
* This class is copiable.
*/
@@ -386,33 +391,52 @@
return C2Segment(mOffset, mSize);
}
-protected:
- // capacity range [0, capacity]
- inline constexpr explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
- : _C2LinearCapacityAspect(parent),
- mOffset(0),
- mSize(capacity()) { }
+private:
+ // subrange of capacity [0, capacity] & [size, size + offset]
+ inline constexpr _C2LinearRangeAspect(uint32_t capacity_, size_t offset, size_t size)
+ : _C2LinearCapacityAspect(capacity_),
+ mOffset(c2_min(offset, capacity())),
+ mSize(c2_min(size, capacity() - mOffset)) {
+ }
+protected:
// copy constructor (no error check)
inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect &other)
: _C2LinearCapacityAspect(other.capacity()),
mOffset(other.offset()),
- mSize(other.size()) { }
+ mSize(other.size()) {
+ }
- // subrange of capacity [0, capacity] & [size, size + offset]
+ // parent capacity range [0, capacity]
+ inline constexpr explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
+ : _C2LinearCapacityAspect(parent),
+ mOffset(0),
+ mSize(capacity()) {
+ }
+
+ // subrange of parent capacity [0, capacity] & [size, size + offset]
inline constexpr _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
: _C2LinearCapacityAspect(parent),
mOffset(c2_min(offset, capacity())),
- mSize(c2_min(size, capacity() - mOffset)) { }
+ mSize(c2_min(size, capacity() - mOffset)) {
+ }
- // subsection of the two [offset, offset + size] ranges
+ // subsection of the parent's and [offset, offset + size] ranges
inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
- : _C2LinearCapacityAspect(parent == nullptr ? 0 : parent->capacity()),
+ : _C2LinearCapacityAspect(parent),
mOffset(c2_min(c2_max(offset, parent == nullptr ? 0 : parent->offset()), capacity())),
- mSize(c2_min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) { }
+ mSize(std::min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) {
+ }
-private:
- friend class _C2EditableLinearRange;
+public:
+ inline constexpr _C2LinearRangeAspect childRange(size_t offset, size_t size) const {
+ return _C2LinearRangeAspect(
+ mSize,
+ c2_min(c2_max(offset, mOffset), capacity()) - mOffset,
+ c2_min(c2_min(size, mSize), capacity() - c2_min(c2_max(offset, mOffset), capacity())));
+ }
+
+ friend class _C2EditableLinearRangeAspect;
// invariants 0 <= mOffset <= mOffset + mSize <= capacity()
uint32_t mOffset;
uint32_t mSize;
@@ -420,7 +444,7 @@
};
/**
- * Utility class for safe range calculations.
+ * Utility class for safe range calculations using size_t-s.
*/
class C2LinearRange : public _C2LinearRangeAspect {
public:
@@ -436,7 +460,7 @@
};
/**
- * Utility class for simple capacity and range construction.
+ * Utility class for simple and safe capacity and range construction.
*/
class C2LinearCapacity : public _C2LinearCapacityAspect {
public:
@@ -453,21 +477,10 @@
*
* This class is copiable.
*/
-class _C2EditableLinearRange : public _C2LinearRangeAspect {
-protected:
- inline explicit _C2EditableLinearRange(const _C2LinearCapacityAspect *parent)
- : _C2LinearRangeAspect(parent) { }
+class _C2EditableLinearRangeAspect : public _C2LinearRangeAspect {
+ using _C2LinearRangeAspect::_C2LinearRangeAspect;
- inline _C2EditableLinearRange(const _C2LinearRangeAspect &other)
- : _C2LinearRangeAspect(other) { }
-
- inline _C2EditableLinearRange(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
- : _C2LinearRangeAspect(parent, offset, size) { }
-
- // subsection of the two [offset, offset + size] ranges
- inline _C2EditableLinearRange(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
- : _C2LinearRangeAspect(parent, offset, size) { }
-
+public:
/// \name Editable linear range interface
/// @{
@@ -1086,7 +1099,7 @@
*
* This class is copiable. \todo movable only?
*/
-class C2WriteView : public _C2EditableLinearRange {
+class C2WriteView : public _C2EditableLinearRangeAspect {
public:
/**
* Start of the block.
@@ -1354,30 +1367,6 @@
/// @{
/**
- * Interface for objects that have a width and height (planar capacity).
- */
-class _C2PlanarCapacityAspect {
-/// \name Planar capacity interface
-/// @{
-public:
- inline uint32_t width() const { return _mWidth; }
- inline uint32_t height() const { return _mHeight; }
-
-protected:
- inline _C2PlanarCapacityAspect(uint32_t width, uint32_t height)
- : _mWidth(width), _mHeight(height) { }
-
- inline _C2PlanarCapacityAspect(const _C2PlanarCapacityAspect *parent)
- : _mWidth(parent == nullptr ? 0 : parent->width()),
- _mHeight(parent == nullptr ? 0 : parent->height()) { }
-
-private:
- const uint32_t _mWidth;
- const uint32_t _mHeight;
-/// @}
-};
-
-/**
* C2Rect: rectangle type with non-negative coordinates.
*
* \note This struct has public fields without getters/setters. All methods are inline.
@@ -1465,17 +1454,44 @@
C2_ALLOW_OVERFLOW
inline constexpr C2Rect intersect(const C2Rect &other) const {
- if (!isValid()) {
- return *this;
- } else if (!other.isValid()) {
- return other;
- } else {
- return C2Rect(c2_min(right(), other.right()) - c2_max(left, other.left),
- c2_min(bottom(), other.bottom()) - c2_max(top, other.top),
- c2_max(left, other.left),
- c2_max(top, other.top));
- }
+ return C2Rect(c2_min(right(), other.right()) - c2_max(left, other.left),
+ c2_min(bottom(), other.bottom()) - c2_max(top, other.top),
+ c2_max(left, other.left),
+ c2_max(top, other.top));
}
+
+ /** clamps right and bottom to top, left if they overflow */
+ inline constexpr C2Rect normalize() const {
+ return C2Rect(c2_max(left, right()) - left, c2_max(top, bottom()) - top, left, top);
+ }
+};
+
+/**
+ * Interface for objects that have a width and height (planar capacity).
+ */
+class _C2PlanarCapacityAspect {
+/// \name Planar capacity interface
+/// @{
+public:
+ inline constexpr uint32_t width() const { return _mWidth; }
+ inline constexpr uint32_t height() const { return _mHeight; }
+
+ inline constexpr operator C2Rect() const {
+ return C2Rect(_mWidth, _mHeight);
+ }
+
+protected:
+ inline constexpr _C2PlanarCapacityAspect(uint32_t width, uint32_t height)
+ : _mWidth(width), _mHeight(height) { }
+
+ inline explicit constexpr _C2PlanarCapacityAspect(const _C2PlanarCapacityAspect *parent)
+ : _mWidth(parent == nullptr ? 0 : parent->width()),
+ _mHeight(parent == nullptr ? 0 : parent->height()) { }
+
+private:
+ uint32_t _mWidth;
+ uint32_t _mHeight;
+/// @}
};
/**
@@ -1497,6 +1513,7 @@
int32_t colInc; ///< column increment in bytes. may be negative
int32_t rowInc; ///< row increment in bytes. may be negative
+
uint32_t colSampling; ///< subsampling compared to width (must be a power of 2)
uint32_t rowSampling; ///< subsampling compared to height (must be a power of 2)
@@ -1529,7 +1546,7 @@
BIG_END, // BIG_ENDIAN is a reserved macro
} endianness; ///< endianness of the samples
- inline ssize_t minOffset(uint32_t width, uint32_t height) {
+ inline constexpr ssize_t minOffset(uint32_t width, uint32_t height) const {
ssize_t offs = 0;
if (width > 0 && colInc < 0) {
offs += colInc * (ssize_t)(width - 1);
@@ -1540,7 +1557,7 @@
return offs;
}
- inline ssize_t maxOffset(uint32_t width, uint32_t height, uint32_t allocatedDepth) {
+ inline constexpr ssize_t maxOffset(uint32_t width, uint32_t height) const {
ssize_t offs = (allocatedDepth + 7) >> 3;
if (width > 0 && colInc > 0) {
offs += colInc * (ssize_t)(width - 1);
@@ -1550,20 +1567,20 @@
}
return offs;
}
-};
+} C2_PACK;
struct C2PlanarLayout {
//public:
enum type_t : uint32_t {
TYPE_UNKNOWN = 0,
- TYPE_YUV = 0x100,
- TYPE_YUVA,
- TYPE_RGB,
- TYPE_RGBA,
+ TYPE_YUV = 0x100, ///< YUV image with 3 planes
+ TYPE_YUVA, ///< YUVA image with 4 planes
+ TYPE_RGB, ///< RGB image with 3 planes
+ TYPE_RGBA, ///< RBGA image with 4 planes
};
- type_t type;
- uint32_t numPlanes; // number of planes
+ type_t type; // image type
+ uint32_t numPlanes; // number of planes
enum plane_index_t : uint32_t {
PLANE_Y = 0,
@@ -1584,13 +1601,68 @@
*
* This class is copiable.
*/
-class _C2PlanarSection : public _C2PlanarCapacityAspect {
+class _C2PlanarSectionAspect : public _C2PlanarCapacityAspect {
/// \name Planar section interface
/// @{
+private:
+ inline constexpr _C2PlanarSectionAspect(uint32_t width, uint32_t height, const C2Rect &crop)
+ : _C2PlanarCapacityAspect(width, height),
+ mCrop(std::min(width - std::min(crop.left, width), crop.width),
+ std::min(height - std::min(crop.top, height), crop.height),
+ std::min(crop.left, width),
+ std::min(crop.height, height)) {
+ }
+
public:
// crop can be an empty rect, does not have to line up with subsampling
// NOTE: we do not support floating-point crop
- inline const C2Rect crop() const { return mCrop; }
+ inline constexpr C2Rect crop() const { return mCrop; }
+
+ /**
+ * Returns a child planar section for |crop|, where the capacity represents this section.
+ */
+ inline constexpr _C2PlanarSectionAspect childSection(const C2Rect &crop) const {
+ return _C2PlanarSectionAspect(
+ mCrop.width, mCrop.height,
+ // crop and translate |crop| rect
+ C2Rect(c2_min(mCrop.right() - c2_clamp(mCrop.left, crop.left, mCrop.right()), crop.width),
+ c2_min(mCrop.bottom() - c2_clamp(mCrop.top, crop.top, mCrop.bottom()), crop.height),
+ c2_clamp(mCrop.left, crop.left, mCrop.right()) - mCrop.left,
+ c2_clamp(mCrop.top, crop.top, mCrop.bottom()) - mCrop.top));
+ }
+
+protected:
+ inline constexpr _C2PlanarSectionAspect(const _C2PlanarCapacityAspect *parent)
+ : _C2PlanarCapacityAspect(parent), mCrop(width(), height()) {}
+
+ inline constexpr _C2PlanarSectionAspect(const _C2PlanarCapacityAspect *parent, const C2Rect &crop)
+ : _C2PlanarCapacityAspect(parent),
+ mCrop(parent == nullptr ? C2Rect(0, 0) : ((C2Rect)*parent).intersect(crop).normalize()) { }
+
+ inline constexpr _C2PlanarSectionAspect(const _C2PlanarSectionAspect *parent, const C2Rect &crop)
+ : _C2PlanarCapacityAspect(parent),
+ mCrop(parent == nullptr ? C2Rect(0, 0) : parent->crop().intersect(crop).normalize()) { }
+
+private:
+ friend class _C2EditablePlanarSectionAspect;
+ C2Rect mCrop;
+/// @}
+};
+
+/**
+ * Aspect for objects that have an editable planar section (crop rectangle).
+ *
+ * This class is copiable.
+ */
+class _C2EditablePlanarSectionAspect : public _C2PlanarSectionAspect {
+/// \name Planar section interface
+/// @{
+ using _C2PlanarSectionAspect::_C2PlanarSectionAspect;
+
+public:
+ // crop can be an empty rect, does not have to line up with subsampling
+ // NOTE: we do not support floating-point crop
+ inline constexpr C2Rect crop() const { return mCrop; }
/**
* Sets crop to crop intersected with [(0,0) .. (width, height)]
@@ -1616,17 +1688,41 @@
mCrop = crop;
return true;
}
-
-protected:
- inline _C2PlanarSection(const _C2PlanarCapacityAspect *parent)
- : _C2PlanarCapacityAspect(parent), mCrop(width(), height()) {}
-
-private:
- C2Rect mCrop;
/// @}
};
/**
+ * Utility class for safe range calculations using size_t-s.
+ */
+class C2PlanarSection : public _C2PlanarSectionAspect {
+public:
+ inline constexpr C2PlanarSection(const _C2PlanarCapacityAspect &parent, const C2Rect &crop)
+ : _C2PlanarSectionAspect(&parent, crop) { }
+
+ inline constexpr C2PlanarSection(const _C2PlanarSectionAspect &parent, const C2Rect &crop)
+ : _C2PlanarSectionAspect(&parent, crop) { }
+
+ inline constexpr C2PlanarSection intersect(const C2Rect &crop) const {
+ return C2PlanarSection(*this, crop);
+ }
+};
+
+/**
+ * Utility class for simple and safe planar capacity and section construction.
+ */
+class C2PlanarCapacity : public _C2PlanarCapacityAspect {
+public:
+ inline constexpr explicit C2PlanarCapacity(size_t width, size_t height)
+ : _C2PlanarCapacityAspect(c2_min(width, std::numeric_limits<uint32_t>::max()),
+ c2_min(height, std::numeric_limits<uint32_t>::max())) { }
+
+ inline constexpr C2PlanarSection section(const C2Rect &crop) const {
+ return C2PlanarSection(*this, crop);
+ }
+};
+
+
+/**
* \ingroup graphic allocator
* 2D allocation interface.
*/
@@ -1640,19 +1736,22 @@
* descriptor referring to an acquire sync fence object. If it is already safe to access the
* buffer contents, then -1.
*
+ * Safe regions for the pointer addresses returned can be gotten via C2LayoutInfo.minOffse()/
+ * maxOffset().
+ *
* \note Only one portion of the graphic allocation can be mapped at the same time. (This is
* from gralloc1 limitation.)
*
- * \param rect section to be mapped (this does not have to be aligned)
- * \param usage the desired usage. \todo this must be kSoftwareRead and/or
+ * \param rect section to be mapped (this does not have to be aligned)
+ * \param usage the desired usage. \todo this must be kSoftwareRead and/or
* kSoftwareWrite.
- * \param fenceFd a pointer to a file descriptor if an async mapping is requested. If
+ * \param fenceFd a pointer to a file descriptor if an async mapping is requested. If
* not-null, and acquire fence FD will be stored here on success, or -1
* on failure. If null, the mapping will be synchronous.
- * \param layout a pointer to where the mapped planes' descriptors will be
+ * \param layout a pointer to where the mapped planes' descriptors will be
* stored. On failure, nullptr will be stored here.
- *
- * \todo Do we need to support sync operation as we could just wait for the fence?
+ * \param addr pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
+ * elements. Only layout.numPlanes elements will be modified on success.
*
* \retval C2_OK the operation was successful
* \retval C2_REFUSED no permission to map the section
@@ -1666,7 +1765,6 @@
*/
virtual c2_status_t map(
C2Rect rect, C2MemoryUsage usage, int *fenceFd,
- // TODO: return <addr, size> buffers with plane sizes
C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
/**
@@ -1687,11 +1785,9 @@
virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
/**
- * Returns true if this is a valid allocation.
- *
- * \todo remove?
+ * Returns the allocator ID for this allocation. This is useful to put the handle into context.
*/
- virtual bool isValid() const = 0;
+ virtual C2Allocator::id_t getAllocatorId() const = 0;
/**
* Returns a pointer to the allocation handle.
@@ -1710,15 +1806,36 @@
class C2GraphicAllocation;
-class C2Block2D : public _C2PlanarSection {
+/**
+ * A 2D block.
+ *
+ * \note width()/height() is not meaningful for users of blocks; instead, crop().width() and
+ * crop().height() is the capacity of the usable portion. Use and crop() if accessing the block
+ * directly through its handle to represent the allotted region of the underlying allocation to this
+ * block.
+ */
+class C2Block2D : public _C2PlanarSectionAspect {
public:
+ /**
+ * Returns the underlying handle for this allocation.
+ *
+ * \note that the block and its block pool has shared ownership of the handle
+ * and if all references to the block are released, the underlying block
+ * allocation may get reused even if a client keeps a clone of this handle.
+ */
const C2Handle *handle() const;
-protected:
- C2Block2D(const std::shared_ptr<C2GraphicAllocation> &alloc);
+ /**
+ * Returns the allocator's ID that created the underlying allocation for this block. This
+ * provides the context for understanding the handle.
+ */
+ C2Allocator::id_t getAllocatorId() const;
-private:
+protected:
class Impl;
+ C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion);
+
+ friend struct _C2BlockFactory;
std::shared_ptr<Impl> mImpl;
};
@@ -1731,21 +1848,19 @@
* to ensure subsampling is followed. This results in nearly identical interface between read and
* write views, so C2GraphicView can encompass both of them.
*/
-class C2GraphicView : public _C2PlanarSection {
+class C2GraphicView : public _C2EditablePlanarSectionAspect {
public:
/**
- * \return array of pointers to the start of the planes or nullptr on error.
- * Regardless of crop rect, they always point to the top-left corner of
- * each plane. Access outside of the crop rect results in an undefined
- * behavior.
+ * \return array of pointers (of layout().numPlanes elements) to the start of the planes or
+ * nullptr on error. Regardless of crop rect, they always point to the top-left corner of each
+ * plane. Access outside of the crop rect results in an undefined behavior.
*/
const uint8_t *const *data() const;
/**
- * \return array of pointers to the start of the planes or nullptr on error.
- * Regardless of crop rect, they always point to the top-left corner of
- * each plane. Access outside of the crop rect results in an undefined
- * behavior.
+ * \return array of pointers (of layout().numPlanes elements) to the start of the planes or
+ * nullptr on error. Regardless of crop rect, they always point to the top-left corner of each
+ * plane. Access outside of the crop rect results in an undefined behavior.
*/
uint8_t *const *data();
@@ -1770,14 +1885,12 @@
c2_status_t error() const;
protected:
- C2GraphicView(
- const _C2PlanarCapacityAspect *parent,
- uint8_t *const *data,
- const C2PlanarLayout& layout);
+ class Impl;
+ C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion);
explicit C2GraphicView(c2_status_t error);
private:
- class Impl;
+ friend struct _C2BlockFactory;
std::shared_ptr<Impl> mImpl;
};
@@ -1814,11 +1927,11 @@
C2Fence fence() const { return mFence; }
protected:
- C2ConstGraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc, C2Fence fence);
+ C2ConstGraphicBlock(
+ std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion, C2Fence fence);
private:
- class Impl;
- std::shared_ptr<Impl> mImpl;
+ friend struct _C2BlockFactory;
C2Fence mFence;
};
@@ -1848,11 +1961,9 @@
C2ConstGraphicBlock share(const C2Rect &crop, C2Fence fence);
protected:
- explicit C2GraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc);
+ C2GraphicBlock(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion);
-private:
- class Impl;
- std::shared_ptr<Impl> mImpl;
+ friend struct _C2BlockFactory;
};
/// @}
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index 2de43c8..f0e57e2 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -26,6 +26,209 @@
namespace android {
+class C2BufferUtilsTest : public ::testing::Test {
+ static void StaticSegmentTest() {
+ // constructor
+ static_assert(C2Segment(123u, 456u).offset == 123, "");
+ static_assert(C2Segment(123u, 456u).size == 456, "");
+
+ // empty
+ static_assert(!C2Segment(123u, 456u).isEmpty(), "");
+ static_assert(C2Segment(123u, 0u).isEmpty(), "");
+
+ // valid
+ static_assert(C2Segment(123u, 456u).isValid(), "");
+ static_assert(C2Segment(123u, ~123u).isValid(), "");
+ static_assert(!C2Segment(123u, 1 + ~123u).isValid(), "");
+
+ // bool()
+ static_assert(C2Segment(123u, 456u), "");
+ static_assert((bool)C2Segment(123u, ~123u), "");
+ static_assert(!bool(C2Segment(123u, 1 + ~123u)), "");
+ static_assert(!bool(C2Segment(123u, 0)), "");
+
+ // !
+ static_assert(!!C2Segment(123u, 456u), "");
+ static_assert(!!C2Segment(123u, ~123u), "");
+ static_assert(!C2Segment(123u, 1 + ~123u), "");
+ static_assert(!C2Segment(123u, 0), "");
+
+ // contains
+ static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, 0)), "");
+ static_assert(!C2Segment(123u, 1 + ~123u).contains(C2Segment(123u, 0)), "");
+ static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, ~123u)), "");
+ static_assert(!C2Segment(123u, ~123u).contains(C2Segment(123u, 1 + ~123u)), "");
+ static_assert(!C2Segment(123u, 1 + ~123u).contains(C2Segment(123u, 1 + ~123u)), "");
+ static_assert(!C2Segment(123u, ~123u).contains(C2Segment(122u, 2u)), "");
+ static_assert(C2Segment(123u, ~123u).contains(C2Segment(123u, 2u)), "");
+ static_assert(C2Segment(123u, 3u).contains(C2Segment(124u, 2u)), "");
+ static_assert(!C2Segment(123u, 3u).contains(C2Segment(125u, 2u)), "");
+
+ // ==
+ static_assert(C2Segment(123u, 456u) == C2Segment(123u, 456u), "");
+ static_assert(!(C2Segment(123u, 456u) == C2Segment(123u, 457u)), "");
+ static_assert(!(C2Segment(123u, 456u) == C2Segment(123u, 455u)), "");
+ static_assert(!(C2Segment(123u, 456u) == C2Segment(122u, 456u)), "");
+ static_assert(!(C2Segment(123u, 456u) == C2Segment(124u, 456u)), "");
+ static_assert(!(C2Segment(123u, 0u) == C2Segment(124u, 0u)), "");
+ static_assert(C2Segment(123u, 0u) == C2Segment(123u, 0u), "");
+ static_assert(C2Segment(123u, 1 + ~123u) == C2Segment(124u, 1 + ~124u), "");
+
+ // !=
+ static_assert(!(C2Segment(123u, 456u) != C2Segment(123u, 456u)), "");
+ static_assert(C2Segment(123u, 456u) != C2Segment(123u, 457u), "");
+ static_assert(C2Segment(123u, 456u) != C2Segment(123u, 455u), "");
+ static_assert(C2Segment(123u, 456u) != C2Segment(122u, 456u), "");
+ static_assert(C2Segment(123u, 456u) != C2Segment(124u, 456u), "");
+ static_assert(C2Segment(123u, 0u) != C2Segment(124u, 0u), "");
+ static_assert(!(C2Segment(123u, 0u) != C2Segment(123u, 0u)), "");
+ static_assert(!(C2Segment(123u, 1 + ~123u) != C2Segment(124u, 1 + ~124u)), "");
+
+ // <=
+ static_assert(C2Segment(123u, 456u) <= C2Segment(123u, 456u), "");
+ static_assert(C2Segment(123u, 456u) <= C2Segment(123u, 457u), "");
+ static_assert(C2Segment(123u, 456u) <= C2Segment(122u, 457u), "");
+ static_assert(!(C2Segment(123u, 457u) <= C2Segment(123u, 456u)), "");
+ static_assert(!(C2Segment(122u, 457u) <= C2Segment(123u, 456u)), "");
+ static_assert(!(C2Segment(123u, 457u) <= C2Segment(124u, 457u)), "");
+ static_assert(!(C2Segment(122u, 457u) <= C2Segment(123u, 457u)), "");
+ static_assert(!(C2Segment(122u, 0u) <= C2Segment(123u, 0u)), "");
+ static_assert(C2Segment(123u, 0u) <= C2Segment(122u, 1u), "");
+ static_assert(C2Segment(122u, 0u) <= C2Segment(122u, 1u), "");
+ static_assert(!(C2Segment(122u, ~122u) <= C2Segment(122u, 1 + ~122u)), "");
+ static_assert(!(C2Segment(122u, 1 + ~122u) <= C2Segment(122u, ~122u)), "");
+ static_assert(!(C2Segment(122u, 1 + ~122u) <= C2Segment(122u, 1 + ~122u)), "");
+
+ // <
+ static_assert(!(C2Segment(123u, 456u) < C2Segment(123u, 456u)), "");
+ static_assert(C2Segment(123u, 456u) < C2Segment(123u, 457u), "");
+ static_assert(C2Segment(123u, 456u) < C2Segment(122u, 457u), "");
+ static_assert(!(C2Segment(123u, 457u) < C2Segment(123u, 456u)), "");
+ static_assert(!(C2Segment(122u, 457u) < C2Segment(123u, 456u)), "");
+ static_assert(!(C2Segment(123u, 457u) < C2Segment(124u, 457u)), "");
+ static_assert(!(C2Segment(122u, 457u) < C2Segment(123u, 457u)), "");
+ static_assert(!(C2Segment(122u, 0u) < C2Segment(123u, 0u)), "");
+ static_assert(C2Segment(123u, 0u) < C2Segment(122u, 1u), "");
+ static_assert(C2Segment(122u, 0u) < C2Segment(122u, 1u), "");
+ static_assert(!(C2Segment(122u, ~122u) < C2Segment(122u, 1 + ~122u)), "");
+ static_assert(!(C2Segment(122u, 1 + ~122u) < C2Segment(122u, ~122u)), "");
+ static_assert(!(C2Segment(122u, 1 + ~122u) < C2Segment(122u, 1 + ~122u)), "");
+
+ // <=
+ static_assert(C2Segment(123u, 456u) >= C2Segment(123u, 456u), "");
+ static_assert(C2Segment(123u, 457u) >= C2Segment(123u, 456u), "");
+ static_assert(C2Segment(122u, 457u) >= C2Segment(123u, 456u), "");
+ static_assert(!(C2Segment(123u, 456u) >= C2Segment(123u, 457u)), "");
+ static_assert(!(C2Segment(123u, 456u) >= C2Segment(122u, 457u)), "");
+ static_assert(!(C2Segment(124u, 457u) >= C2Segment(123u, 457u)), "");
+ static_assert(!(C2Segment(123u, 457u) >= C2Segment(122u, 457u)), "");
+ static_assert(!(C2Segment(123u, 0u) >= C2Segment(122u, 0u)), "");
+ static_assert(C2Segment(122u, 1u) >= C2Segment(123u, 0u), "");
+ static_assert(C2Segment(122u, 1u) >= C2Segment(122u, 0u), "");
+ static_assert(!(C2Segment(122u, 1 + ~122u) >= C2Segment(122u, ~122u)), "");
+ static_assert(!(C2Segment(122u, ~122u) >= C2Segment(122u, 1 + ~122u)), "");
+ static_assert(!(C2Segment(122u, 1 + ~122u) >= C2Segment(122u, 1 + ~122u)), "");
+
+ // <
+ static_assert(!(C2Segment(123u, 456u) > C2Segment(123u, 456u)), "");
+ static_assert(C2Segment(123u, 457u) > C2Segment(123u, 456u), "");
+ static_assert(C2Segment(122u, 457u) > C2Segment(123u, 456u), "");
+ static_assert(!(C2Segment(123u, 456u) > C2Segment(123u, 457u)), "");
+ static_assert(!(C2Segment(123u, 456u) > C2Segment(122u, 457u)), "");
+ static_assert(!(C2Segment(124u, 457u) > C2Segment(123u, 457u)), "");
+ static_assert(!(C2Segment(123u, 457u) > C2Segment(122u, 457u)), "");
+ static_assert(!(C2Segment(123u, 0u) > C2Segment(122u, 0u)), "");
+ static_assert(C2Segment(122u, 1u) > C2Segment(123u, 0u), "");
+ static_assert(C2Segment(122u, 1u) > C2Segment(122u, 0u), "");
+ static_assert(!(C2Segment(122u, 1 + ~122u) > C2Segment(122u, ~122u)), "");
+ static_assert(!(C2Segment(122u, ~122u) > C2Segment(122u, 1 + ~122u)), "");
+ static_assert(!(C2Segment(122u, 1 + ~122u) > C2Segment(122u, 1 + ~122u)), "");
+
+ // end
+ static_assert(C2Segment(123u, 456u).end() == 579u, "");
+ static_assert(C2Segment(123u, 0u).end() == 123u, "");
+ static_assert(C2Segment(123u, ~123u).end() == 0xffffffffu, "");
+ static_assert(C2Segment(123u, 1 + ~123u).end() == 0u, "");
+
+ // intersect
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 456u)) == C2Segment(123u, 456u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 460u)) == C2Segment(123u, 456u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(124u, 460u)) == C2Segment(124u, 455u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(579u, 460u)) == C2Segment(579u, 0u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(589u, 460u)) == C2Segment(589u, ~9u /* -10 */), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(123u, 455u)) == C2Segment(123u, 455u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(122u, 456u)) == C2Segment(123u, 455u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 123u)) == C2Segment(123u, 0u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 0u)) == C2Segment(123u, ~122u /* -123 */), "");
+
+ // normalize (change invalid segments to empty segments)
+ static_assert(C2Segment(123u, 456u).normalize() == C2Segment(123u, 456u), "");
+ static_assert(C2Segment(123u, ~123u).normalize() == C2Segment(123u, ~123u), "");
+ static_assert(C2Segment(123u, 1 + ~123u).normalize() == C2Segment(123u, 0u), "");
+
+ // note: normalize cannot be used to make this work
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, ~150u)).normalize() == C2Segment(150u, 429u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u)).normalize() != C2Segment(150u, 429u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u)).normalize() == C2Segment(150u, 0u), "");
+
+ // saturate (change invalid segments to full segments up to max)
+ static_assert(C2Segment(123u, 456u).saturate() == C2Segment(123u, 456u), "");
+ static_assert(C2Segment(123u, ~123u).saturate() == C2Segment(123u, ~123u), "");
+ static_assert(C2Segment(123u, 1 + ~123u).saturate() == C2Segment(123u, ~123u), "");
+
+ // note: saturate can be used to make this work but only partially
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(150u, 1 + ~150u).saturate()).normalize() == C2Segment(150u, 429u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(0u, 100u).saturate()).normalize() == C2Segment(123u, 0u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(1000u, 100u).saturate()).normalize() != C2Segment(579u, 0u), "");
+ static_assert(C2Segment(123u, 456u).intersect(C2Segment(1000u, 100u).saturate()).normalize() == C2Segment(1000u, 0u), "");
+
+ }
+
+ static void StaticLinearRangeAndCapacityTest() {
+ class TestCapacity : public _C2LinearCapacityAspect {
+ using _C2LinearCapacityAspect::_C2LinearCapacityAspect;
+ friend class C2BufferUtilsTest;
+ };
+
+ class TestRange : public _C2LinearRangeAspect {
+ using _C2LinearRangeAspect::_C2LinearRangeAspect;
+ friend class C2BufferUtilsTest;
+ };
+
+ // _C2LinearCapacityAspect
+ static_assert(TestCapacity(0u).capacity() == 0u, "");
+ constexpr TestCapacity cap(123u);
+ static_assert(TestCapacity(&cap).capacity() == 123u, "");
+ static_assert(TestCapacity(nullptr).capacity() == 0u, "");
+
+ // _C2LinearCapacityRange
+ static_assert(TestRange(&cap).capacity() == 123u, "");
+ static_assert(TestRange(&cap).offset() == 0u, "");
+ static_assert(TestRange(&cap).size() == 123u, "");
+ static_assert(TestRange(&cap).endOffset() == 123u, "");
+
+ constexpr TestRange range(&cap, 50u, 100u);
+
+ static_assert(range.capacity() == 123u, "");
+ static_assert(range.offset() == 50u, "");
+ static_assert(range.size() == 73u, "");
+ static_assert(range.endOffset() == 123u, "");
+
+ static_assert(TestRange(&cap, 20u, 30u).capacity() == 123u, "");
+ static_assert(TestRange(&cap, 20u, 30u).offset() == 20u, "");
+ static_assert(TestRange(&cap, 20u, 30u).size() == 30u, "");
+ static_assert(TestRange(&cap, 20u, 30u).endOffset() == 50u, "");
+
+ static_assert(TestRange(&cap, 200u, 30u).capacity() == 123u, "");
+ static_assert(TestRange(&cap, 200u, 30u).offset() == 123u, "");
+ static_assert(TestRange(&cap, 200u, 30u).size() == 0u, "");
+ static_assert(TestRange(&cap, 200u, 30u).endOffset() == 123u, "");
+
+ }
+
+};
+
+
class C2BufferTest : public ::testing::Test {
public:
C2BufferTest()
@@ -180,6 +383,14 @@
data[i] = i % 100u;
}
+ writeView.setOffset(kCapacity / 3);
+ data = writeView.data();
+ ASSERT_NE(nullptr, data);
+ for (size_t i = 0; i < writeView.size(); ++i) {
+ ASSERT_EQ((i + kCapacity / 3) % 100u, data[i]) << " at i = " << i
+ << "; data = " << static_cast<void *>(data);
+ }
+
C2Fence fence;
C2ConstLinearBlock constBlock = block->share(
kCapacity / 3, kCapacity / 3, fence);
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
index 155583d..b287ca8 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -25,6 +25,7 @@
#include <C2AllocatorGralloc.h>
#include <C2Buffer.h>
+#include <C2PlatformSupport.h>
namespace android {
@@ -185,7 +186,7 @@
C2Rect rect, C2MemoryUsage usage, int *fenceFd,
C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) override;
- virtual bool isValid() const override { return true; }
+ virtual C2Allocator::id_t getAllocatorId() const override { return mAllocatorId; }
virtual const C2Handle *handle() const override { return mLockedHandle ? : mHandle; }
virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
@@ -195,7 +196,8 @@
const BufferDescriptorInfo &info,
const sp<IMapper> &mapper,
hidl_handle &hidlHandle,
- const C2HandleGralloc *const handle);
+ const C2HandleGralloc *const handle,
+ C2Allocator::id_t allocatorId);
int dup() const;
c2_status_t status() const;
@@ -207,20 +209,24 @@
buffer_handle_t mBuffer;
const C2HandleGralloc *mLockedHandle;
bool mLocked;
+ C2Allocator::id_t mAllocatorId;
};
C2AllocationGralloc::C2AllocationGralloc(
const BufferDescriptorInfo &info,
const sp<IMapper> &mapper,
hidl_handle &hidlHandle,
- const C2HandleGralloc *const handle)
+ const C2HandleGralloc *const handle,
+ C2Allocator::id_t allocatorId)
: C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
mInfo(info),
mMapper(mapper),
mHidlHandle(std::move(hidlHandle)),
mHandle(handle),
mBuffer(nullptr),
- mLocked(false) {}
+ mLocked(false),
+ mAllocatorId(allocatorId) {
+}
C2AllocationGralloc::~C2AllocationGralloc() {
if (!mBuffer) {
@@ -422,11 +428,19 @@
/* ===================================== GRALLOC ALLOCATOR ==================================== */
class C2AllocatorGralloc::Impl {
public:
- Impl();
+ Impl(id_t id);
- id_t getId() const;
+ id_t getId() const {
+ return mTraits->id;
+ }
- C2String getName() const;
+ C2String getName() const {
+ return mTraits->name;
+ }
+
+ std::shared_ptr<const C2Allocator::Traits> getTraits() const {
+ return mTraits;
+ }
c2_status_t newGraphicAllocation(
uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
@@ -439,13 +453,19 @@
c2_status_t status() const { return mInit; }
private:
+ std::shared_ptr<C2Allocator::Traits> mTraits;
c2_status_t mInit;
sp<IAllocator> mAllocator;
sp<IMapper> mMapper;
};
-C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
- // TODO: share a global service
+C2AllocatorGralloc::Impl::Impl(id_t id) : mInit(C2_OK) {
+ // TODO: get this from allocator
+ C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
+ Traits traits = { "android.allocator.gralloc", id, C2Allocator::GRAPHIC, minUsage, maxUsage };
+ mTraits = std::make_shared<C2Allocator::Traits>(traits);
+
+ // gralloc allocator is a singleton, so all objects share a global service
mAllocator = IAllocator::getService();
mMapper = IMapper::getService();
if (mAllocator == nullptr || mMapper == nullptr) {
@@ -453,14 +473,6 @@
}
}
-C2Allocator::id_t C2AllocatorGralloc::Impl::getId() const {
- return 1; /// \todo implement ID
-}
-
-C2String C2AllocatorGralloc::Impl::getName() const {
- return "android.allocator.gralloc";
-}
-
c2_status_t C2AllocatorGralloc::Impl::newGraphicAllocation(
uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
std::shared_ptr<C2GraphicAllocation> *allocation) {
@@ -517,7 +529,8 @@
C2HandleGralloc::WrapNativeHandle(
buffer.getNativeHandle(),
info.mapperInfo.width, info.mapperInfo.height,
- (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride)));
+ (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride),
+ mTraits->id));
return C2_OK;
}
@@ -536,11 +549,11 @@
hidl_handle hidlHandle = C2HandleGralloc::UnwrapNativeHandle(grallocHandle);
- allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle));
+ allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle, mTraits->id));
return C2_OK;
}
-C2AllocatorGralloc::C2AllocatorGralloc(id_t) : mImpl(new Impl) {}
+C2AllocatorGralloc::C2AllocatorGralloc(id_t id) : mImpl(new Impl(id)) {}
C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
@@ -552,6 +565,10 @@
return mImpl->getName();
}
+std::shared_ptr<const C2Allocator::Traits> C2AllocatorGralloc::getTraits() const {
+ return mImpl->getTraits();
+}
+
c2_status_t C2AllocatorGralloc::newGraphicAllocation(
uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
std::shared_ptr<C2GraphicAllocation> *allocation) {
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index ff92679..0de8cde 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include <map>
+#include <mutex>
#include <C2BufferPriv.h>
#include <C2BlockInternal.h>
@@ -61,33 +62,33 @@
friend class ::android::C2LinearBlock;
};
-class C2DefaultGraphicView : public C2GraphicView {
+class GraphicViewBuddy : public C2GraphicView {
using C2GraphicView::C2GraphicView;
friend class ::android::C2ConstGraphicBlock;
friend class ::android::C2GraphicBlock;
};
-class C2AcquirableConstGraphicView : public C2Acquirable<const C2GraphicView> {
+class AcquirableConstGraphicViewBuddy : public C2Acquirable<const C2GraphicView> {
using C2Acquirable::C2Acquirable;
friend class ::android::C2ConstGraphicBlock;
};
-class C2AcquirableGraphicView : public C2Acquirable<C2GraphicView> {
+class AcquirableGraphicViewBuddy : public C2Acquirable<C2GraphicView> {
using C2Acquirable::C2Acquirable;
friend class ::android::C2GraphicBlock;
};
-class C2DefaultConstGraphicBlock : public C2ConstGraphicBlock {
+class ConstGraphicBlockBuddy : public C2ConstGraphicBlock {
using C2ConstGraphicBlock::C2ConstGraphicBlock;
friend class ::android::C2GraphicBlock;
};
-class C2DefaultGraphicBlock : public C2GraphicBlock {
+class GraphicBlockBuddy : public C2GraphicBlock {
using C2GraphicBlock::C2GraphicBlock;
friend class ::android::C2BasicGraphicBlockPool;
};
-class C2DefaultBufferData : public C2BufferData {
+class BufferDataBuddy : public C2BufferData {
using C2BufferData::C2BufferData;
friend class ::android::C2Buffer;
};
@@ -241,10 +242,11 @@
C2WriteView::C2WriteView(std::shared_ptr<Impl> impl)
// UGLY: _C2LinearRangeAspect requires a bona-fide object for capacity to prevent spoofing, so
// this is what we have to do.
- : _C2EditableLinearRange(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
+// TODO: use childRange
+ : _C2EditableLinearRangeAspect(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
C2WriteView::C2WriteView(c2_status_t error)
- : _C2EditableLinearRange(nullptr), mImpl(std::make_shared<Impl>(error)) {}
+ : _C2EditableLinearRangeAspect(nullptr), mImpl(std::make_shared<Impl>(error)) {}
uint8_t *C2WriteView::base() { return mImpl->data(); }
@@ -309,14 +311,6 @@
return ConstLinearBlockBuddy(mImpl, C2LinearRange(*this, offset_, size_), fence);
}
-std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
- const std::shared_ptr<C2LinearAllocation> &alloc,
- const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
- std::shared_ptr<C2Block1D::Impl> impl =
- std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
- return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
-}
-
C2BasicLinearBlockPool::C2BasicLinearBlockPool(
const std::shared_ptr<C2Allocator> &allocator)
: mAllocator(allocator) { }
@@ -338,215 +332,288 @@
return C2_OK;
}
+std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
+ const std::shared_ptr<C2LinearAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
+ std::shared_ptr<C2Block1D::Impl> impl =
+ std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
+ return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
+}
+
/* ========================================== 2D BLOCK ========================================= */
-class C2Block2D::Impl {
+/**
+ * Implementation that is shared between all 2D blocks and views.
+ *
+ * For blocks' Impl's crop is always the allotted crop, even if it is a sub block.
+ *
+ * For views' Impl's crop is the mapped portion - which for now is always the
+ * allotted crop.
+ */
+class C2_HIDE _C2Block2DImpl : public _C2PlanarSectionAspect {
public:
- const C2Handle *handle() const {
- return mAllocation->handle();
+ /**
+ * Impl's crop is always the or part of the allotted crop of the allocation.
+ */
+ _C2Block2DImpl(const std::shared_ptr<C2GraphicAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
+ const C2Rect &allottedCrop = C2Rect(~0u, ~0u))
+ : _C2PlanarSectionAspect(alloc.get(), allottedCrop),
+ mAllocation(alloc),
+ mPoolData(poolData) { }
+
+ /** returns const pool data */
+ std::shared_ptr<const _C2BlockPoolData> poolData() const {
+ return mPoolData;
}
- Impl(const std::shared_ptr<C2GraphicAllocation> &alloc)
- : mAllocation(alloc) {}
+ /** returns native handle */
+ const C2Handle *handle() const {
+ return mAllocation ? mAllocation->handle() : nullptr;
+ }
+
+ /** returns the allocator's ID */
+ C2Allocator::id_t getAllocatorId() const {
+ // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
+ return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
+ }
+
+ std::shared_ptr<C2GraphicAllocation> getAllocation() const {
+ return mAllocation;
+ }
private:
std::shared_ptr<C2GraphicAllocation> mAllocation;
+ std::shared_ptr<_C2BlockPoolData> mPoolData;
};
-C2Block2D::C2Block2D(const std::shared_ptr<C2GraphicAllocation> &alloc)
- : _C2PlanarSection(alloc.get()), mImpl(new Impl(alloc)) {}
+class C2_HIDE _C2MappingBlock2DImpl : public _C2Block2DImpl {
+public:
+ using _C2Block2DImpl::_C2Block2DImpl;
+
+ /**
+ * This class contains the mapped data pointer, and the potential error.
+ */
+ struct Mapped {
+ private:
+ friend class _C2MappingBlock2DImpl;
+
+ Mapped(const _C2Block2DImpl *impl, bool writable, C2Fence *fence __unused)
+ : mImpl(impl), mWritable(writable) {
+ memset(mData, 0, sizeof(mData));
+ const C2Rect crop = mImpl->crop();
+ // gralloc requires mapping the whole region of interest as we cannot
+ // map multiple regions
+ mError = mImpl->getAllocation()->map(
+ crop,
+ { C2MemoryUsage::CPU_READ, writable ? C2MemoryUsage::CPU_WRITE : 0 },
+ nullptr,
+ &mLayout,
+ mData);
+ if (mError != C2_OK) {
+ memset(&mLayout, 0, sizeof(mLayout));
+ memset(mData, 0, sizeof(mData));
+ } else {
+ // TODO: validate plane layout and
+ // adjust data pointers to the crop region's top left corner.
+ // fail if it is not on a subsampling boundary
+ for (size_t planeIx = 0; planeIx < mLayout.numPlanes; ++planeIx) {
+ const uint32_t colSampling = mLayout.planes[planeIx].colSampling;
+ const uint32_t rowSampling = mLayout.planes[planeIx].rowSampling;
+ if (crop.left % colSampling || crop.right() % colSampling
+ || crop.top % rowSampling || crop.bottom() % rowSampling) {
+ // cannot calculate data pointer
+ mImpl->getAllocation()->unmap(nullptr);
+ memset(&mLayout, 0, sizeof(mLayout));
+ memset(mData, 0, sizeof(mData));
+ mError = C2_BAD_VALUE;
+ return;
+ }
+ mData[planeIx] += (ssize_t)crop.left * mLayout.planes[planeIx].colInc
+ + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
+ }
+ }
+ }
+
+ explicit Mapped(c2_status_t error)
+ : mImpl(nullptr), mWritable(false), mError(error) {
+ // CHECK(error != C2_OK);
+ memset(&mLayout, 0, sizeof(mLayout));
+ memset(mData, 0, sizeof(mData));
+ }
+
+ public:
+ ~Mapped() {
+ if (mData[0] != nullptr) {
+ mImpl->getAllocation()->unmap(nullptr);
+ }
+ }
+
+ /** returns mapping status */
+ c2_status_t error() const { return mError; }
+
+ /** returns data pointer */
+ uint8_t *const *data() const { return mData; }
+
+ /** returns the plane layout */
+ C2PlanarLayout layout() const { return mLayout; }
+
+ /** returns whether the mapping is writable */
+ bool writable() const { return mWritable; }
+
+ private:
+ const _C2Block2DImpl *mImpl;
+ bool mWritable;
+ c2_status_t mError;
+ uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
+ C2PlanarLayout mLayout;
+ };
+
+ /**
+ * Maps the allotted region.
+ *
+ * If already mapped and it is currently in use, returns the existing mapping.
+ * If fence is provided, an acquire fence is stored there.
+ */
+ std::shared_ptr<Mapped> map(bool writable, C2Fence *fence) {
+ std::lock_guard<std::mutex> lock(mMappedLock);
+ std::shared_ptr<Mapped> existing = mMapped.lock();
+ if (!existing) {
+ existing = std::shared_ptr<Mapped>(new Mapped(this, writable, fence));
+ mMapped = existing;
+ } else {
+ // if we mapped the region read-only, we cannot remap it read-write
+ if (writable && !existing->writable()) {
+ existing = std::shared_ptr<Mapped>(new Mapped(C2_CANNOT_DO));
+ }
+ if (fence != nullptr) {
+ *fence = C2Fence();
+ }
+ }
+ return existing;
+ }
+
+private:
+ std::weak_ptr<Mapped> mMapped;
+ std::mutex mMappedLock;
+};
+
+class C2_HIDE _C2MappedBlock2DImpl : public _C2Block2DImpl {
+public:
+ _C2MappedBlock2DImpl(const _C2Block2DImpl &impl,
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping)
+ : _C2Block2DImpl(impl), mMapping(mapping) {
+ }
+
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping() const { return mMapping; }
+
+private:
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mMapping;
+};
+
+/**
+ * Block implementation.
+ */
+class C2Block2D::Impl : public _C2MappingBlock2DImpl {
+ using _C2MappingBlock2DImpl::_C2MappingBlock2DImpl;
+};
const C2Handle *C2Block2D::handle() const {
return mImpl->handle();
}
-class C2GraphicView::Impl {
-public:
- Impl(uint8_t *const *data, const C2PlanarLayout &layout)
- : mData(data), mLayout(layout), mError(C2_OK) {}
- explicit Impl(c2_status_t error) : mData(nullptr), mError(error) {}
+C2Allocator::id_t C2Block2D::getAllocatorId() const {
+ return mImpl->getAllocatorId();
+}
- uint8_t *const *data() const { return mData; }
- const C2PlanarLayout &layout() const { return mLayout; }
- c2_status_t error() const { return mError; }
+C2Block2D::C2Block2D(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
+ // always clamp subsection to parent (impl) crop for safety
+ : _C2PlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
+}
-private:
- uint8_t *const *mData;
- C2PlanarLayout mLayout;
- c2_status_t mError;
+/**
+ * Graphic view implementation.
+ *
+ * range of Impl is the mapped range of the underlying allocation. range of View is the current
+ * crop.
+ */
+class C2GraphicView::Impl : public _C2MappedBlock2DImpl {
+ using _C2MappedBlock2DImpl::_C2MappedBlock2DImpl;
};
-C2GraphicView::C2GraphicView(
- const _C2PlanarCapacityAspect *parent,
- uint8_t *const *data,
- const C2PlanarLayout& layout)
- : _C2PlanarSection(parent), mImpl(new Impl(data, layout)) {}
-
-C2GraphicView::C2GraphicView(c2_status_t error)
- : _C2PlanarSection(nullptr), mImpl(new Impl(error)) {}
+C2GraphicView::C2GraphicView(std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
+ : _C2EditablePlanarSectionAspect(impl.get(), section.crop()), mImpl(impl) {
+}
const uint8_t *const *C2GraphicView::data() const {
- return mImpl->data();
+ return mImpl->mapping()->data();
}
uint8_t *const *C2GraphicView::data() {
- return mImpl->data();
+ return mImpl->mapping()->data();
}
const C2PlanarLayout C2GraphicView::layout() const {
- return mImpl->layout();
+ return mImpl->mapping()->layout();
}
const C2GraphicView C2GraphicView::subView(const C2Rect &rect) const {
- C2GraphicView view(this, mImpl->data(), mImpl->layout());
- view.setCrop_be(rect);
- return view;
+ return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
}
C2GraphicView C2GraphicView::subView(const C2Rect &rect) {
- C2GraphicView view(this, mImpl->data(), mImpl->layout());
- view.setCrop_be(rect);
- return view;
+ return C2GraphicView(mImpl, C2PlanarSection(*mImpl, rect));
}
c2_status_t C2GraphicView::error() const {
- return mImpl->error();
+ return mImpl->mapping()->error();
}
-class C2ConstGraphicBlock::Impl {
-public:
- explicit Impl(const std::shared_ptr<C2GraphicAllocation> &alloc)
- : mAllocation(alloc), mData{ nullptr } {}
-
- ~Impl() {
- if (mData[0] != nullptr) {
- // TODO: fence
- mAllocation->unmap(nullptr);
- }
- }
-
- c2_status_t map(C2Rect rect) {
- if (mData[0] != nullptr) {
- // Already mapped.
- return C2_OK;
- }
- c2_status_t err = mAllocation->map(
- rect,
- { C2MemoryUsage::CPU_READ, 0 },
- nullptr,
- &mLayout,
- mData);
- if (err != C2_OK) {
- memset(mData, 0, sizeof(mData));
- }
- return err;
- }
-
- C2ConstGraphicBlock subBlock(const C2Rect &rect, C2Fence fence) const {
- C2ConstGraphicBlock block(mAllocation, fence);
- block.setCrop_be(rect);
- return block;
- }
-
- uint8_t *const *data() const {
- return mData[0] == nullptr ? nullptr : &mData[0];
- }
-
- const C2PlanarLayout &layout() const { return mLayout; }
-
-private:
- std::shared_ptr<C2GraphicAllocation> mAllocation;
- C2PlanarLayout mLayout;
- uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
-};
-
+/**
+ * Const graphic block implementation.
+ */
C2ConstGraphicBlock::C2ConstGraphicBlock(
- const std::shared_ptr<C2GraphicAllocation> &alloc, C2Fence fence)
- : C2Block2D(alloc), mImpl(new Impl(alloc)), mFence(fence) {}
+ std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion, C2Fence fence)
+ : C2Block2D(impl, section), mFence(fence) { }
C2Acquirable<const C2GraphicView> C2ConstGraphicBlock::map() const {
- c2_status_t err = mImpl->map(crop());
- if (err != C2_OK) {
- C2DefaultGraphicView view(err);
- return C2AcquirableConstGraphicView(err, mFence, view);
- }
- C2DefaultGraphicView view(this, mImpl->data(), mImpl->layout());
- return C2AcquirableConstGraphicView(err, mFence, view);
+ C2Fence fence;
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
+ mImpl->map(false /* writable */, &fence);
+ std::shared_ptr<GraphicViewBuddy::Impl> gvi =
+ std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
+ return AcquirableConstGraphicViewBuddy(
+ mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
}
C2ConstGraphicBlock C2ConstGraphicBlock::subBlock(const C2Rect &rect) const {
- return mImpl->subBlock(rect, mFence);
+ return C2ConstGraphicBlock(mImpl, C2PlanarSection(*mImpl, crop().intersect(rect)), mFence);
}
-class C2GraphicBlock::Impl {
-public:
- explicit Impl(const std::shared_ptr<C2GraphicAllocation> &alloc)
- : mAllocation(alloc), mData{ nullptr } {}
-
- ~Impl() {
- if (mData[0] != nullptr) {
- // TODO: fence
- mAllocation->unmap(nullptr);
- }
- }
-
- c2_status_t map(C2Rect rect) {
- if (mData[0] != nullptr) {
- // Already mapped.
- return C2_OK;
- }
- uint8_t *data[C2PlanarLayout::MAX_NUM_PLANES];
- c2_status_t err = mAllocation->map(
- rect,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- nullptr,
- &mLayout,
- data);
- if (err == C2_OK) {
- memcpy(mData, data, sizeof(mData));
- } else {
- memset(mData, 0, sizeof(mData));
- }
- return err;
- }
-
- C2ConstGraphicBlock share(const C2Rect &crop, C2Fence fence) const {
- C2DefaultConstGraphicBlock block(mAllocation, fence);
- block.setCrop_be(crop);
- return block;
- }
-
- uint8_t *const *data() const {
- return mData[0] == nullptr ? nullptr : mData;
- }
-
- const C2PlanarLayout &layout() const { return mLayout; }
-
-private:
- std::shared_ptr<C2GraphicAllocation> mAllocation;
- C2PlanarLayout mLayout;
- uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
-};
-
-C2GraphicBlock::C2GraphicBlock(const std::shared_ptr<C2GraphicAllocation> &alloc)
- : C2Block2D(alloc), mImpl(new Impl(alloc)) {}
+/**
+ * Graphic block implementation.
+ */
+C2GraphicBlock::C2GraphicBlock(
+ std::shared_ptr<Impl> impl, const _C2PlanarSectionAspect §ion)
+ : C2Block2D(impl, section) { }
C2Acquirable<C2GraphicView> C2GraphicBlock::map() {
- c2_status_t err = mImpl->map(crop());
- if (err != C2_OK) {
- C2DefaultGraphicView view(err);
- // TODO: fence
- return C2AcquirableGraphicView(err, C2Fence(), view);
- }
- C2DefaultGraphicView view(this, mImpl->data(), mImpl->layout());
- // TODO: fence
- return C2AcquirableGraphicView(err, C2Fence(), view);
+ C2Fence fence;
+ std::shared_ptr<_C2MappingBlock2DImpl::Mapped> mapping =
+ mImpl->map(true /* writable */, &fence);
+ std::shared_ptr<GraphicViewBuddy::Impl> gvi =
+ std::shared_ptr<GraphicViewBuddy::Impl>(new GraphicViewBuddy::Impl(*mImpl, mapping));
+ return AcquirableGraphicViewBuddy(
+ mapping->error(), fence, GraphicViewBuddy(gvi, C2PlanarSection(*mImpl, crop())));
}
C2ConstGraphicBlock C2GraphicBlock::share(const C2Rect &crop, C2Fence fence) {
- return mImpl->share(crop, fence);
+ return ConstGraphicBlockBuddy(mImpl, C2PlanarSection(*mImpl, crop), fence);
}
+/**
+ * Basic block pool implementations.
+ */
C2BasicGraphicBlockPool::C2BasicGraphicBlockPool(
const std::shared_ptr<C2Allocator> &allocator)
: mAllocator(allocator) {}
@@ -565,11 +632,19 @@
return err;
}
- block->reset(new C2DefaultGraphicBlock(alloc));
+ *block = _C2BlockFactory::CreateGraphicBlock(alloc);
return C2_OK;
}
+std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
+ const std::shared_ptr<C2GraphicAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &data, const C2Rect &allottedCrop) {
+ std::shared_ptr<C2Block2D::Impl> impl =
+ std::make_shared<C2Block2D::Impl>(alloc, data, allottedCrop);
+ return std::shared_ptr<C2GraphicBlock>(new C2GraphicBlock(impl, *impl));
+}
+
/* ========================================== BUFFER ========================================= */
class C2BufferData::Impl {
@@ -679,7 +754,7 @@
private:
C2Buffer * const mThis;
- C2DefaultBufferData mData;
+ BufferDataBuddy mData;
std::map<C2Param::Type, std::shared_ptr<C2Info>> mInfos;
std::list<std::pair<OnDestroyNotify, void *>> mNotify;
};
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
index 0e1a3ac..9dc7152 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -49,9 +49,7 @@
virtual C2String getName() const override;
- virtual std::shared_ptr<const Traits> getTraits() const override {
- return nullptr; // \todo
- }
+ virtual std::shared_ptr<const Traits> getTraits() const override;
virtual c2_status_t newGraphicAllocation(
uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
@@ -61,7 +59,7 @@
const C2Handle *handle,
std::shared_ptr<C2GraphicAllocation> *allocation) override;
- C2AllocatorGralloc(id_t id = 0);
+ C2AllocatorGralloc(id_t id);
c2_status_t status() const;
diff --git a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
index c84d1fb..9c68369 100644
--- a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
@@ -24,15 +24,44 @@
struct _C2BlockPoolData;
/**
- * Interface for creating blocks by block pool/buffer passing implementations.
+ * Internal only interface for creating blocks by block pool/buffer passing implementations.
+ *
+ * \todo this must be hidden
*/
-struct C2_HIDE _C2BlockFactory {
+struct _C2BlockFactory {
+ /**
+ * Create a linear block from an allocation for an allotted range.
+ *
+ * @param alloc parent allocation
+ * @param data blockpool data
+ * @param offset allotted range offset
+ * @param size allotted size
+ *
+ * @return shared pointer to the linear block. nullptr if there was not enough memory to
+ * create this block.
+ */
static
std::shared_ptr<C2LinearBlock> C2_HIDE CreateLinearBlock(
const std::shared_ptr<C2LinearAllocation> &alloc,
const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
size_t offset = 0,
size_t size = ~(size_t)0);
+
+ /**
+ * Create a graphic block from an allocation for an allotted section.
+ *
+ * @param alloc parent allocation
+ * @param data blockpool data
+ * @param crop allotted crop region
+ *
+ * @return shared pointer to the graphic block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(
+ const std::shared_ptr<C2GraphicAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
+ const C2Rect &allottedCrop = C2Rect(~0u, ~0u));
};
}