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 &section);
+
+    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 &section);
     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 &section, 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 &section);
 
-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 &section)
+    // 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 &section)
+    : _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 &section, 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 &section)
+    : 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));
 };
 
 }