Merge "Codec2: separate param/paramutils test from other Codec2 unit tests"
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index 18d0841..a185880 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -16,6 +16,8 @@
 
 #include <gtest/gtest.h>
 
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
 #include <C2ParamDef.h>
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
index 66f31cb..93bcb3a 100644
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -2,6 +2,8 @@
     name: "libstagefright_codec2_vndk",
 
     srcs: [
+        "C2AllocatorIon.cpp",
+        "C2AllocatorGralloc.cpp",
         "C2Buffer.cpp",
         "C2Config.cpp",
     ],
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
new file mode 100644
index 0000000..16b818b
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2AllocatorIon"
+#include <utils/Log.h>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <hardware/gralloc.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2Buffer.h>
+
+namespace android {
+
+using ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using ::android::hardware::graphics::mapper::V2_0::Error;
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_vec;
+
+/* ===================================== GRALLOC ALLOCATION ==================================== */
+static C2Error maperr2error(Error maperr) {
+    switch (maperr) {
+        case Error::NONE:           return C2_OK;
+        case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+        case Error::BAD_BUFFER:     return C2_BAD_VALUE;
+        case Error::BAD_VALUE:      return C2_BAD_VALUE;
+        case Error::NO_RESOURCES:   return C2_NO_MEMORY;
+        case Error::UNSUPPORTED:    return C2_UNSUPPORTED;
+    }
+    return C2_CORRUPTED;
+}
+
+class C2AllocationGralloc : public C2GraphicAllocation {
+public:
+    virtual ~C2AllocationGralloc();
+
+    virtual C2Error map(
+            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
+    virtual C2Error unmap(C2Fence *fenceFd /* nullable */) override;
+    virtual bool isValid() const override { return true; }
+    virtual const C2Handle *handle() const override { return mHandle; }
+    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
+
+    // internal methods
+    // |handle| will be moved.
+    C2AllocationGralloc(
+              const IMapper::BufferDescriptorInfo &info,
+              const sp<IMapper> &mapper,
+              hidl_handle &handle);
+    int dup() const;
+    C2Error status() const;
+
+private:
+    const IMapper::BufferDescriptorInfo mInfo;
+    const sp<IMapper> mMapper;
+    const hidl_handle mHandle;
+    buffer_handle_t mBuffer;
+    bool mLocked;
+};
+
+C2AllocationGralloc::C2AllocationGralloc(
+          const IMapper::BufferDescriptorInfo &info,
+          const sp<IMapper> &mapper,
+          hidl_handle &handle)
+    : C2GraphicAllocation(info.width, info.height),
+      mInfo(info),
+      mMapper(mapper),
+      mHandle(std::move(handle)),
+      mBuffer(nullptr),
+      mLocked(false) {}
+
+C2AllocationGralloc::~C2AllocationGralloc() {
+    if (!mBuffer) {
+        return;
+    }
+    if (mLocked) {
+        unmap(nullptr);
+    }
+    mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
+}
+
+C2Error C2AllocationGralloc::map(
+        C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+        C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
+    // TODO
+    (void) fenceFd;
+    (void) usage;
+
+    if (mBuffer && mLocked) {
+        return C2_DUPLICATE;
+    }
+    if (!layout || !addr) {
+        return C2_BAD_VALUE;
+    }
+
+    C2Error err = C2_OK;
+    if (!mBuffer) {
+        mMapper->importBuffer(
+                mHandle, [&err, this](const auto &maperr, const auto &buffer) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        mBuffer = static_cast<buffer_handle_t>(buffer);
+                    }
+                });
+        if (err != C2_OK) {
+            return err;
+        }
+    }
+
+    if (mInfo.format == PixelFormat::YCBCR_420_888 || mInfo.format == PixelFormat::YV12) {
+        YCbCrLayout ycbcrLayout;
+        mMapper->lockYCbCr(
+                const_cast<native_handle_t *>(mBuffer),
+                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
+                // TODO: fence
+                hidl_handle(),
+                [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        ycbcrLayout = mapLayout;
+                    }
+                });
+        if (err != C2_OK) {
+            return err;
+        }
+        addr[C2PlaneLayout::Y] = (uint8_t *)ycbcrLayout.y;
+        addr[C2PlaneLayout::U] = (uint8_t *)ycbcrLayout.cb;
+        addr[C2PlaneLayout::V] = (uint8_t *)ycbcrLayout.cr;
+        layout->mType = C2PlaneLayout::MEDIA_IMAGE_TYPE_YUV;
+        layout->mNumPlanes = 3;
+        layout->mPlanes[C2PlaneLayout::Y] = {
+            C2PlaneInfo::Y,                 // mChannel
+            1,                              // mColInc
+            (int32_t)ycbcrLayout.yStride,   // mRowInc
+            1,                              // mHorizSubsampling
+            1,                              // mVertSubsampling
+            8,                              // mBitDepth
+            8,                              // mAllocatedDepth
+        };
+        layout->mPlanes[C2PlaneLayout::U] = {
+            C2PlaneInfo::Cb,                  // mChannel
+            (int32_t)ycbcrLayout.chromaStep,  // mColInc
+            (int32_t)ycbcrLayout.cStride,     // mRowInc
+            2,                                // mHorizSubsampling
+            2,                                // mVertSubsampling
+            8,                                // mBitDepth
+            8,                                // mAllocatedDepth
+        };
+        layout->mPlanes[C2PlaneLayout::V] = {
+            C2PlaneInfo::Cr,                  // mChannel
+            (int32_t)ycbcrLayout.chromaStep,  // mColInc
+            (int32_t)ycbcrLayout.cStride,     // mRowInc
+            2,                                // mHorizSubsampling
+            2,                                // mVertSubsampling
+            8,                                // mBitDepth
+            8,                                // mAllocatedDepth
+        };
+    } else {
+        void *pointer = nullptr;
+        mMapper->lock(
+                const_cast<native_handle_t *>(mBuffer),
+                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
+                // TODO: fence
+                hidl_handle(),
+                [&err, &pointer](const auto &maperr, const auto &mapPointer) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        pointer = mapPointer;
+                    }
+                });
+        if (err != C2_OK) {
+            return err;
+        }
+        // TODO
+        return C2_UNSUPPORTED;
+    }
+    mLocked = true;
+
+    return C2_OK;
+}
+
+C2Error C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
+    // TODO: fence
+    C2Error err = C2_OK;
+    mMapper->unlock(
+            const_cast<native_handle_t *>(mBuffer),
+            [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
+                // TODO
+                (void) fenceFd;
+                (void) releaseFence;
+                err = maperr2error(maperr);
+                if (err == C2_OK) {
+                    // TODO: fence
+                }
+            });
+    if (err == C2_OK) {
+        mLocked = false;
+    }
+    return err;
+}
+
+bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
+    return other && other->handle() == handle();
+}
+
+/* ===================================== GRALLOC ALLOCATOR ==================================== */
+class C2AllocatorGralloc::Impl {
+public:
+    Impl();
+
+    C2Error allocateGraphicBuffer(
+            uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+            std::shared_ptr<C2GraphicAllocation> *allocation);
+
+    C2Error recreateGraphicBuffer(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *allocation);
+
+    C2Error status() const { return mInit; }
+
+private:
+    C2Error mInit;
+    sp<IAllocator> mAllocator;
+    sp<IMapper> mMapper;
+};
+
+C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
+    // TODO: share a global service
+    mAllocator = IAllocator::getService();
+    mMapper = IMapper::getService();
+    if (mAllocator == nullptr || mMapper == nullptr) {
+        mInit = C2_CORRUPTED;
+    }
+}
+
+C2Error C2AllocatorGralloc::Impl::allocateGraphicBuffer(
+        uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    // TODO: buffer usage should be determined according to |usage|
+    (void) usage;
+
+    IMapper::BufferDescriptorInfo info = {
+        width,
+        height,
+        1u,  // layerCount
+        (PixelFormat)format,
+        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+    };
+    C2Error err = C2_OK;
+    BufferDescriptor desc;
+    mMapper->createDescriptor(
+            info, [&err, &desc](const auto &maperr, const auto &descriptor) {
+                err = maperr2error(maperr);
+                if (err == C2_OK) {
+                    desc = descriptor;
+                }
+            });
+    if (err != C2_OK) {
+        return err;
+    }
+
+    // IAllocator shares IMapper error codes.
+    hidl_handle buffer;
+    mAllocator->allocate(
+            desc,
+            1u,
+            [&err, &buffer](const auto &maperr, const auto &stride, auto &buffers) {
+                (void) stride;
+                err = maperr2error(maperr);
+                if (err != C2_OK) {
+                    return;
+                }
+                if (buffers.size() != 1u) {
+                    err = C2_CORRUPTED;
+                    return;
+                }
+                buffer = std::move(buffers[0]);
+            });
+    if (err != C2_OK) {
+        return err;
+    }
+
+    allocation->reset(new C2AllocationGralloc(info, mMapper, buffer));
+    return C2_OK;
+}
+
+C2Error C2AllocatorGralloc::Impl::recreateGraphicBuffer(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    (void) handle;
+
+    // TODO: need to figure out BufferDescriptorInfo from the handle.
+    allocation->reset();
+    return C2_UNSUPPORTED;
+}
+
+C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
+
+C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
+
+C2Error C2AllocatorGralloc::allocateGraphicBuffer(
+        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    return mImpl->allocateGraphicBuffer(width, height, format, usage, allocation);
+}
+
+C2Error C2AllocatorGralloc::recreateGraphicBuffer(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *allocation) {
+    return mImpl->recreateGraphicBuffer(handle, allocation);
+}
+
+C2Error C2AllocatorGralloc::status() const {
+    return mImpl->status();
+}
+
+} // namespace android
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
new file mode 100644
index 0000000..7aa7769
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2AllocatorIon"
+#include <utils/Log.h>
+
+#include <ion/ion.h>
+#include <sys/mman.h>
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2ErrnoUtils.h>
+
+namespace android {
+
+/* ========================================= ION HANDLE ======================================== */
+struct C2HandleIon : public C2Handle {
+    C2HandleIon(int ionFd, ion_user_handle_t buffer) : C2Handle(cHeader),
+          mFds{ ionFd, buffer },
+          mInts{ kMagic } { }
+
+    static bool isValid(const C2Handle * const o);
+
+    int ionFd() const { return mFds.mIon; }
+    ion_user_handle_t buffer() const { return mFds.mBuffer; }
+
+    void setBuffer(ion_user_handle_t bufferFd) { mFds.mBuffer = bufferFd; }
+
+protected:
+    struct {
+        int mIon;
+        int mBuffer; // ion_user_handle_t
+    } mFds;
+    struct {
+        int mMagic;
+    } mInts;
+
+private:
+    typedef C2HandleIon _type;
+    enum {
+        kMagic = 'ion1',
+        numFds = sizeof(mFds) / sizeof(int),
+        numInts = sizeof(mInts) / sizeof(int),
+        version = sizeof(C2Handle) + sizeof(mFds) + sizeof(mInts)
+    };
+    //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
+    const static C2Handle cHeader;
+};
+
+const C2Handle C2HandleIon::cHeader = {
+    C2HandleIon::version,
+    C2HandleIon::numFds,
+    C2HandleIon::numInts,
+    {}
+};
+
+// static
+bool C2HandleIon::isValid(const C2Handle * const o) {
+    if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+        return false;
+    }
+    const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
+    return other->mInts.mMagic == kMagic;
+}
+
+// TODO: is the dup of an ion fd identical to ion_share?
+
+/* ======================================= ION ALLOCATION ====================================== */
+class C2AllocationIon : public C2LinearAllocation {
+public:
+    virtual C2Error map(
+        size_t offset, size_t size, C2MemoryUsage usage, int *fence,
+        void **addr /* nonnull */);
+    virtual C2Error unmap(void *addr, size_t size, int *fenceFd);
+    virtual bool isValid() const;
+    virtual ~C2AllocationIon();
+    virtual const C2Handle *handle() const;
+    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const;
+
+    // internal methods
+    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
+    C2AllocationIon(int ionFd, size_t size, int shareFd);
+    int dup() const;
+    C2Error status() const;
+
+protected:
+    class Impl;
+    Impl *mImpl;
+};
+
+class C2AllocationIon::Impl {
+public:
+    // NOTE: using constructor here instead of a factory method as we will need the
+    // error value and this simplifies the error handling by the wrapper.
+    Impl(int ionFd, size_t capacity, size_t align, unsigned heapMask, unsigned flags)
+        : mInit(C2_OK),
+          mHandle(ionFd, -1),
+          mMapFd(-1),
+          mCapacity(capacity) {
+        ion_user_handle_t buffer = -1;
+        int ret = ion_alloc(mHandle.ionFd(), mCapacity, align, heapMask, flags, &buffer);
+        if (ret == 0) {
+            mHandle.setBuffer(buffer);
+        } else {
+            mInit = c2_map_errno<ENOMEM, EACCES, EINVAL>(-ret);
+        }
+    }
+
+    Impl(int ionFd, size_t capacity, int shareFd)
+        : mHandle(ionFd, -1),
+          mMapFd(-1),
+          mCapacity(capacity) {
+        ion_user_handle_t buffer;
+        mInit = ion_import(mHandle.ionFd(), shareFd, &buffer);
+        if (mInit == 0) {
+            mHandle.setBuffer(buffer);
+        }
+        (void)mCapacity; // TODO
+    }
+
+    C2Error map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
+        (void)fenceFd; // TODO: wait for fence
+        *addr = nullptr;
+        int prot = PROT_NONE;
+        int flags = MAP_PRIVATE;
+        if (usage.mConsumer & GRALLOC_USAGE_SW_READ_MASK) {
+            prot |= PROT_READ;
+        }
+        if (usage.mProducer & GRALLOC_USAGE_SW_WRITE_MASK) {
+            prot |= PROT_WRITE;
+            flags = MAP_SHARED;
+        }
+
+        size_t alignmentBytes = offset % PAGE_SIZE;
+        size_t mapOffset = offset - alignmentBytes;
+        size_t mapSize = size + alignmentBytes;
+
+        C2Error err = C2_OK;
+        if (mMapFd == -1) {
+            int ret = ion_map(mHandle.ionFd(), mHandle.buffer(), mapSize, prot,
+                              flags, mapOffset, (unsigned char**)&mMapAddr, &mMapFd);
+            if (ret) {
+                mMapFd = -1;
+                *addr = nullptr;
+                err = c2_map_errno<EINVAL>(-ret);
+            } else {
+                *addr = (uint8_t *)mMapAddr + alignmentBytes;
+                mMapAlignmentBytes = alignmentBytes;
+                mMapSize = mapSize;
+            }
+        } else {
+            mMapAddr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
+            if (mMapAddr == MAP_FAILED) {
+                mMapAddr = *addr = nullptr;
+                err = c2_map_errno<EINVAL>(errno);
+            } else {
+                *addr = (uint8_t *)mMapAddr + alignmentBytes;
+                mMapAlignmentBytes = alignmentBytes;
+                mMapSize = mapSize;
+            }
+        }
+        return err;
+    }
+
+    C2Error unmap(void *addr, size_t size, int *fenceFd) {
+        if (addr != (uint8_t *)mMapAddr + mMapAlignmentBytes ||
+                size + mMapAlignmentBytes != mMapSize) {
+            return C2_BAD_VALUE;
+        }
+        int err = munmap(mMapAddr, mMapSize);
+        if (err != 0) {
+            return c2_map_errno<EINVAL>(errno);
+        }
+        if (fenceFd) {
+            *fenceFd = -1;
+        }
+        return C2_OK;
+    }
+
+    ~Impl() {
+        if (mMapFd != -1) {
+            close(mMapFd);
+            mMapFd = -1;
+        }
+
+        (void)ion_free(mHandle.ionFd(), mHandle.buffer());
+    }
+
+    C2Error status() const {
+        return mInit;
+    }
+
+    const C2Handle * handle() const {
+        return &mHandle;
+    }
+
+    int dup() const {
+        int fd = -1;
+        if (mInit != 0 || ion_share(mHandle.ionFd(), mHandle.buffer(), &fd) != 0) {
+            fd = -1;
+        }
+        return fd;
+    }
+
+private:
+    C2Error mInit;
+    C2HandleIon mHandle;
+    int mMapFd; // only one for now
+    void *mMapAddr;
+    size_t mMapAlignmentBytes;
+    size_t mMapSize;
+    size_t mCapacity;
+};
+
+C2Error C2AllocationIon::map(
+    size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
+    return mImpl->map(offset, size, usage, fenceFd, addr);
+}
+
+C2Error C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
+    return mImpl->unmap(addr, size, fenceFd);
+}
+
+bool C2AllocationIon::isValid() const {
+    return mImpl->status() == C2_OK;
+}
+
+C2Error C2AllocationIon::status() const {
+    return mImpl->status();
+}
+
+bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
+    return other != nullptr &&
+        other->handle(); // TODO
+}
+
+const C2Handle *C2AllocationIon::handle() const {
+    return mImpl->handle();
+}
+
+C2AllocationIon::~C2AllocationIon() {
+    delete mImpl;
+}
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
+    : C2LinearAllocation(size),
+      mImpl(new Impl(ionFd, size, align, heapMask, flags)) { }
+
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
+    : C2LinearAllocation(size),
+      mImpl(new Impl(ionFd, size, shareFd)) { }
+
+int C2AllocationIon::dup() const {
+    return mImpl->dup();
+}
+
+/* ======================================= ION ALLOCATOR ====================================== */
+C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
+    if (mIonFd < 0) {
+        switch (errno) {
+        case ENOENT:    mInit = C2_UNSUPPORTED; break;
+        default:        mInit = c2_map_errno<EACCES>(errno); break;
+        }
+    }
+}
+
+C2AllocatorIon::~C2AllocatorIon() {
+    if (mInit == C2_OK) {
+        ion_close(mIonFd);
+    }
+}
+
+C2Error C2AllocatorIon::allocateLinearBuffer(
+        uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
+    if (allocation == nullptr) {
+        return C2_BAD_VALUE;
+    }
+
+    allocation->reset();
+    if (mInit != C2_OK) {
+        return C2_UNSUPPORTED;
+    }
+
+    // get align, heapMask and flags
+    //size_t align = 1;
+    size_t align = 0;
+    unsigned heapMask = ~0;
+    unsigned flags = 0;
+    //TODO
+    (void) usage;
+#if 0
+    int err = mUsageMapper(usage, capacity, &align, &heapMask, &flags);
+    if (err < 0) {
+        return c2_map_errno<EINVAL, ENOMEM, EACCES>(-err);
+    }
+#endif
+
+    std::shared_ptr<C2AllocationIon> alloc
+        = std::make_shared<C2AllocationIon>(mIonFd, capacity, align, heapMask, flags);
+    C2Error ret = alloc->status();
+    if (ret == C2_OK) {
+        *allocation = alloc;
+    }
+    return ret;
+}
+
+C2Error C2AllocatorIon::recreateLinearBuffer(
+        const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
+    *allocation = nullptr;
+    if (mInit != C2_OK) {
+        return C2_UNSUPPORTED;
+    }
+
+    if (!C2HandleIon::isValid(handle)) {
+        return C2_BAD_VALUE;
+    }
+
+    // TODO: get capacity and validate it
+    const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
+    std::shared_ptr<C2AllocationIon> alloc
+        = std::make_shared<C2AllocationIon>(mIonFd, 0 /* capacity */, h->buffer());
+    C2Error ret = alloc->status();
+    if (ret == C2_OK) {
+        *allocation = alloc;
+    }
+    return ret;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 92ccfd1..1ffbf49 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -18,57 +18,12 @@
 #define LOG_TAG "C2Buffer"
 #include <utils/Log.h>
 
+#include <map>
+
 #include <C2BufferPriv.h>
 
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-
-#include <ion/ion.h>
-#include <hardware/gralloc.h>
-#include <sys/mman.h>
-
 namespace android {
 
-using ::android::hardware::graphics::allocator::V2_0::IAllocator;
-using ::android::hardware::graphics::common::V1_0::BufferUsage;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using ::android::hardware::graphics::mapper::V2_0::Error;
-using ::android::hardware::graphics::mapper::V2_0::IMapper;
-using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_vec;
-
-// standard ERRNO mappings
-template<int N> constexpr C2Error _c2_errno2error_impl();
-template<> constexpr C2Error _c2_errno2error_impl<0>()       { return C2_OK; }
-template<> constexpr C2Error _c2_errno2error_impl<EINVAL>()  { return C2_BAD_VALUE; }
-template<> constexpr C2Error _c2_errno2error_impl<EACCES>()  { return C2_NO_PERMISSION; }
-template<> constexpr C2Error _c2_errno2error_impl<EPERM>()   { return C2_NO_PERMISSION; }
-template<> constexpr C2Error _c2_errno2error_impl<ENOMEM>()  { return C2_NO_MEMORY; }
-
-// map standard errno-s to the equivalent C2Error
-template<int... N> struct _c2_map_errno_impl;
-template<int E, int ... N> struct _c2_map_errno_impl<E, N...> {
-    static C2Error map(int result) {
-        if (result == E) {
-            return _c2_errno2error_impl<E>();
-        } else {
-            return _c2_map_errno_impl<N...>::map(result);
-        }
-    }
-};
-template<> struct _c2_map_errno_impl<> {
-    static C2Error map(int result) {
-        return result == 0 ? C2_OK : C2_CORRUPTED;
-    }
-};
-
-template<int... N>
-C2Error c2_map_errno(int result) {
-    return _c2_map_errno_impl<N...>::map(result);
-}
-
 namespace {
 
 // Inherit from the parent, share with the friend.
@@ -142,357 +97,6 @@
 
 }  // namespace
 
-/* ======================================= ION ALLOCATION ====================================== */
-
-/**
- * ION handle
- */
-struct C2HandleIon : public C2Handle {
-    C2HandleIon(int ionFd, ion_user_handle_t buffer) : C2Handle(cHeader),
-          mFds{ ionFd, buffer },
-          mInts{ kMagic } { }
-
-    static bool isValid(const C2Handle * const o);
-
-    int ionFd() const { return mFds.mIon; }
-    ion_user_handle_t buffer() const { return mFds.mBuffer; }
-
-    void setBuffer(ion_user_handle_t bufferFd) { mFds.mBuffer = bufferFd; }
-
-protected:
-    struct {
-        int mIon;
-        int mBuffer; // ion_user_handle_t
-    } mFds;
-    struct {
-        int mMagic;
-    } mInts;
-
-private:
-    typedef C2HandleIon _type;
-    enum {
-        kMagic = 'ion1',
-        numFds = sizeof(mFds) / sizeof(int),
-        numInts = sizeof(mInts) / sizeof(int),
-        version = sizeof(C2Handle) + sizeof(mFds) + sizeof(mInts)
-    };
-    //constexpr static C2Handle cHeader = { version, numFds, numInts, {} };
-    const static C2Handle cHeader;
-};
-
-const C2Handle C2HandleIon::cHeader = {
-    C2HandleIon::version,
-    C2HandleIon::numFds,
-    C2HandleIon::numInts,
-    {}
-};
-
-// static
-bool C2HandleIon::isValid(const C2Handle * const o) {
-    if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
-        return false;
-    }
-    const C2HandleIon *other = static_cast<const C2HandleIon*>(o);
-    return other->mInts.mMagic == kMagic;
-}
-
-// TODO: is the dup of an ion fd identical to ion_share?
-
-class C2AllocationIon : public C2LinearAllocation {
-public:
-    virtual C2Error map(
-        size_t offset, size_t size, C2MemoryUsage usage, int *fence,
-        void **addr /* nonnull */);
-    virtual C2Error unmap(void *addr, size_t size, int *fenceFd);
-    virtual bool isValid() const;
-    virtual ~C2AllocationIon();
-    virtual const C2Handle *handle() const;
-    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const;
-
-    // internal methods
-    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
-    C2AllocationIon(int ionFd, size_t size, int shareFd);
-    int dup() const;
-    C2Error status() const;
-
-protected:
-    class Impl;
-    Impl *mImpl;
-};
-
-class C2AllocationIon::Impl {
-public:
-    // NOTE: using constructor here instead of a factory method as we will need the
-    // error value and this simplifies the error handling by the wrapper.
-    Impl(int ionFd, size_t capacity, size_t align, unsigned heapMask, unsigned flags)
-        : mInit(C2_OK),
-          mHandle(ionFd, -1),
-          mMapFd(-1),
-          mCapacity(capacity) {
-        ion_user_handle_t buffer = -1;
-        int ret = ion_alloc(mHandle.ionFd(), mCapacity, align, heapMask, flags, &buffer);
-        if (ret == 0) {
-            mHandle.setBuffer(buffer);
-        } else {
-            mInit = c2_map_errno<ENOMEM, EACCES, EINVAL>(-ret);
-        }
-    }
-
-    Impl(int ionFd, size_t capacity, int shareFd)
-        : mHandle(ionFd, -1),
-          mMapFd(-1),
-          mCapacity(capacity) {
-        ion_user_handle_t buffer;
-        mInit = ion_import(mHandle.ionFd(), shareFd, &buffer);
-        if (mInit == 0) {
-            mHandle.setBuffer(buffer);
-        }
-        (void)mCapacity; // TODO
-    }
-
-    C2Error map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
-        (void)fenceFd; // TODO: wait for fence
-        *addr = nullptr;
-        int prot = PROT_NONE;
-        int flags = MAP_PRIVATE;
-        if (usage.mConsumer & GRALLOC_USAGE_SW_READ_MASK) {
-            prot |= PROT_READ;
-        }
-        if (usage.mProducer & GRALLOC_USAGE_SW_WRITE_MASK) {
-            prot |= PROT_WRITE;
-            flags = MAP_SHARED;
-        }
-
-        size_t alignmentBytes = offset % PAGE_SIZE;
-        size_t mapOffset = offset - alignmentBytes;
-        size_t mapSize = size + alignmentBytes;
-
-        C2Error err = C2_OK;
-        if (mMapFd == -1) {
-            int ret = ion_map(mHandle.ionFd(), mHandle.buffer(), mapSize, prot,
-                              flags, mapOffset, (unsigned char**)&mMapAddr, &mMapFd);
-            if (ret) {
-                mMapFd = -1;
-                *addr = nullptr;
-                err = c2_map_errno<EINVAL>(-ret);
-            } else {
-                *addr = (uint8_t *)mMapAddr + alignmentBytes;
-                mMapAlignmentBytes = alignmentBytes;
-                mMapSize = mapSize;
-            }
-        } else {
-            mMapAddr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
-            if (mMapAddr == MAP_FAILED) {
-                mMapAddr = *addr = nullptr;
-                err = c2_map_errno<EINVAL>(errno);
-            } else {
-                *addr = (uint8_t *)mMapAddr + alignmentBytes;
-                mMapAlignmentBytes = alignmentBytes;
-                mMapSize = mapSize;
-            }
-        }
-        return err;
-    }
-
-    C2Error unmap(void *addr, size_t size, int *fenceFd) {
-        if (addr != (uint8_t *)mMapAddr + mMapAlignmentBytes ||
-                size + mMapAlignmentBytes != mMapSize) {
-            return C2_BAD_VALUE;
-        }
-        int err = munmap(mMapAddr, mMapSize);
-        if (err != 0) {
-            return c2_map_errno<EINVAL>(errno);
-        }
-        if (fenceFd) {
-            *fenceFd = -1;
-        }
-        return C2_OK;
-    }
-
-    ~Impl() {
-        if (mMapFd != -1) {
-            close(mMapFd);
-            mMapFd = -1;
-        }
-
-        (void)ion_free(mHandle.ionFd(), mHandle.buffer());
-    }
-
-    C2Error status() const {
-        return mInit;
-    }
-
-    const C2Handle * handle() const {
-        return &mHandle;
-    }
-
-    int dup() const {
-        int fd = -1;
-        if (mInit != 0 || ion_share(mHandle.ionFd(), mHandle.buffer(), &fd) != 0) {
-            fd = -1;
-        }
-        return fd;
-    }
-
-private:
-    C2Error mInit;
-    C2HandleIon mHandle;
-    int mMapFd; // only one for now
-    void *mMapAddr;
-    size_t mMapAlignmentBytes;
-    size_t mMapSize;
-    size_t mCapacity;
-};
-
-C2Error C2AllocationIon::map(
-    size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
-    return mImpl->map(offset, size, usage, fenceFd, addr);
-}
-
-C2Error C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
-    return mImpl->unmap(addr, size, fenceFd);
-}
-
-bool C2AllocationIon::isValid() const {
-    return mImpl->status() == C2_OK;
-}
-
-C2Error C2AllocationIon::status() const {
-    return mImpl->status();
-}
-
-bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
-    return other != nullptr &&
-        other->handle(); // TODO
-}
-
-const C2Handle *C2AllocationIon::handle() const {
-    return mImpl->handle();
-}
-
-C2AllocationIon::~C2AllocationIon() {
-    delete mImpl;
-}
-
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
-    : C2LinearAllocation(size),
-      mImpl(new Impl(ionFd, size, align, heapMask, flags)) { }
-
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
-    : C2LinearAllocation(size),
-      mImpl(new Impl(ionFd, size, shareFd)) { }
-
-int C2AllocationIon::dup() const {
-    return mImpl->dup();
-}
-
-/* ======================================= ION ALLOCATOR ====================================== */
-
-C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
-    if (mIonFd < 0) {
-        switch (errno) {
-        case ENOENT:    mInit = C2_UNSUPPORTED; break;
-        default:        mInit = c2_map_errno<EACCES>(errno); break;
-        }
-    }
-}
-
-C2AllocatorIon::~C2AllocatorIon() {
-    if (mInit == C2_OK) {
-        ion_close(mIonFd);
-    }
-}
-
-/**
- * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
- * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param capacity        the size of requested allocation (the allocation could be slightly
- *                      larger, e.g. to account for any system-required alignment)
- * \param usage           the memory usage info for the requested allocation. \note that the
- *                      returned allocation may be later used/mapped with different usage.
- *                      The allocator should layout the buffer to be optimized for this usage,
- *                      but must support any usage. One exception: protected buffers can
- *                      only be used in a protected scenario.
- * \param allocation      pointer to where the allocation shall be stored on success. nullptr
- *                      will be stored here on failure
- *
- * \retval C2_OK        the allocation was successful
- * \retval C2_NO_MEMORY not enough memory to complete the allocation
- * \retval C2_TIMED_OUT the allocation timed out
- * \retval C2_NO_PERMISSION     no permission to complete the allocation
- * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
- * \retval C2_UNSUPPORTED       this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
-C2Error C2AllocatorIon::allocateLinearBuffer(
-        uint32_t capacity, C2MemoryUsage usage, std::shared_ptr<C2LinearAllocation> *allocation) {
-    *allocation = nullptr;
-    if (mInit != C2_OK) {
-        return C2_UNSUPPORTED;
-    }
-
-    // get align, heapMask and flags
-    //size_t align = 1;
-    size_t align = 0;
-    unsigned heapMask = ~0;
-    unsigned flags = 0;
-    //TODO
-    (void) usage;
-#if 0
-    int err = mUsageMapper(usage, capacity, &align, &heapMask, &flags);
-    if (err < 0) {
-        return c2_map_errno<EINVAL, ENOMEM, EACCES>(-err);
-    }
-#endif
-
-    std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(mIonFd, capacity, align, heapMask, flags);
-    C2Error ret = alloc->status();
-    if (ret == C2_OK) {
-        *allocation = alloc;
-    }
-    return ret;
-}
-
-/**
- * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
- * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param handle      the handle for the existing allocation
- * \param allocation  pointer to where the allocation shall be stored on success. nullptr
- *                  will be stored here on failure
- *
- * \retval C2_OK        the allocation was recreated successfully
- * \retval C2_NO_MEMORY not enough memory to recreate the allocation
- * \retval C2_TIMED_OUT the recreation timed out (unexpected)
- * \retval C2_NO_PERMISSION     no permission to recreate the allocation
- * \retval C2_BAD_VALUE invalid handle (caller error)
- * \retval C2_UNSUPPORTED       this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
-C2Error C2AllocatorIon::recreateLinearBuffer(
-        const C2Handle *handle, std::shared_ptr<C2LinearAllocation> *allocation) {
-    *allocation = nullptr;
-    if (mInit != C2_OK) {
-        return C2_UNSUPPORTED;
-    }
-
-    if (!C2HandleIon::isValid(handle)) {
-        return C2_BAD_VALUE;
-    }
-
-    // TODO: get capacity and validate it
-    const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
-    std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(mIonFd, 0 /* capacity */, h->buffer());
-    C2Error ret = alloc->status();
-    if (ret == C2_OK) {
-        *allocation = alloc;
-    }
-    return ret;
-}
-
 /* ========================================== 1D BLOCK ========================================= */
 
 class C2Block1D::Impl {
@@ -762,304 +366,6 @@
     return C2_OK;
 }
 
-/* ===================================== GRALLOC ALLOCATION ==================================== */
-
-static C2Error maperr2error(Error maperr) {
-    switch (maperr) {
-        case Error::NONE:           return C2_OK;
-        case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE;
-        case Error::BAD_BUFFER:     return C2_BAD_VALUE;
-        case Error::BAD_VALUE:      return C2_BAD_VALUE;
-        case Error::NO_RESOURCES:   return C2_NO_MEMORY;
-        case Error::UNSUPPORTED:    return C2_UNSUPPORTED;
-    }
-    return C2_CORRUPTED;
-}
-
-class C2AllocationGralloc : public C2GraphicAllocation {
-public:
-    virtual ~C2AllocationGralloc();
-
-    virtual C2Error map(
-            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
-            C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
-    virtual C2Error unmap(C2Fence *fenceFd /* nullable */) override;
-    virtual bool isValid() const override { return true; }
-    virtual const C2Handle *handle() const override { return mHandle; }
-    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
-
-    // internal methods
-    // |handle| will be moved.
-    C2AllocationGralloc(
-              const IMapper::BufferDescriptorInfo &info,
-              const sp<IMapper> &mapper,
-              hidl_handle &handle);
-    int dup() const;
-    C2Error status() const;
-
-private:
-    const IMapper::BufferDescriptorInfo mInfo;
-    const sp<IMapper> mMapper;
-    const hidl_handle mHandle;
-    buffer_handle_t mBuffer;
-    bool mLocked;
-};
-
-C2AllocationGralloc::C2AllocationGralloc(
-          const IMapper::BufferDescriptorInfo &info,
-          const sp<IMapper> &mapper,
-          hidl_handle &handle)
-    : C2GraphicAllocation(info.width, info.height),
-      mInfo(info),
-      mMapper(mapper),
-      mHandle(std::move(handle)),
-      mBuffer(nullptr),
-      mLocked(false) {}
-
-C2AllocationGralloc::~C2AllocationGralloc() {
-    if (!mBuffer) {
-        return;
-    }
-    if (mLocked) {
-        unmap(nullptr);
-    }
-    mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
-}
-
-C2Error C2AllocationGralloc::map(
-        C2Rect rect, C2MemoryUsage usage, int *fenceFd,
-        C2PlaneLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
-    // TODO
-    (void) fenceFd;
-    (void) usage;
-
-    if (mBuffer && mLocked) {
-        return C2_DUPLICATE;
-    }
-    if (!layout || !addr) {
-        return C2_BAD_VALUE;
-    }
-
-    C2Error err = C2_OK;
-    if (!mBuffer) {
-        mMapper->importBuffer(
-                mHandle, [&err, this](const auto &maperr, const auto &buffer) {
-                    err = maperr2error(maperr);
-                    if (err == C2_OK) {
-                        mBuffer = static_cast<buffer_handle_t>(buffer);
-                    }
-                });
-        if (err != C2_OK) {
-            return err;
-        }
-    }
-
-    if (mInfo.format == PixelFormat::YCBCR_420_888 || mInfo.format == PixelFormat::YV12) {
-        YCbCrLayout ycbcrLayout;
-        mMapper->lockYCbCr(
-                const_cast<native_handle_t *>(mBuffer),
-                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
-                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
-                // TODO: fence
-                hidl_handle(),
-                [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
-                    err = maperr2error(maperr);
-                    if (err == C2_OK) {
-                        ycbcrLayout = mapLayout;
-                    }
-                });
-        if (err != C2_OK) {
-            return err;
-        }
-        addr[C2PlaneLayout::Y] = (uint8_t *)ycbcrLayout.y;
-        addr[C2PlaneLayout::U] = (uint8_t *)ycbcrLayout.cb;
-        addr[C2PlaneLayout::V] = (uint8_t *)ycbcrLayout.cr;
-        layout->mType = C2PlaneLayout::MEDIA_IMAGE_TYPE_YUV;
-        layout->mNumPlanes = 3;
-        layout->mPlanes[C2PlaneLayout::Y] = {
-            C2PlaneInfo::Y,                 // mChannel
-            1,                              // mColInc
-            (int32_t)ycbcrLayout.yStride,   // mRowInc
-            1,                              // mHorizSubsampling
-            1,                              // mVertSubsampling
-            8,                              // mBitDepth
-            8,                              // mAllocatedDepth
-        };
-        layout->mPlanes[C2PlaneLayout::U] = {
-            C2PlaneInfo::Cb,                  // mChannel
-            (int32_t)ycbcrLayout.chromaStep,  // mColInc
-            (int32_t)ycbcrLayout.cStride,     // mRowInc
-            2,                                // mHorizSubsampling
-            2,                                // mVertSubsampling
-            8,                                // mBitDepth
-            8,                                // mAllocatedDepth
-        };
-        layout->mPlanes[C2PlaneLayout::V] = {
-            C2PlaneInfo::Cr,                  // mChannel
-            (int32_t)ycbcrLayout.chromaStep,  // mColInc
-            (int32_t)ycbcrLayout.cStride,     // mRowInc
-            2,                                // mHorizSubsampling
-            2,                                // mVertSubsampling
-            8,                                // mBitDepth
-            8,                                // mAllocatedDepth
-        };
-    } else {
-        void *pointer = nullptr;
-        mMapper->lock(
-                const_cast<native_handle_t *>(mBuffer),
-                BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
-                { (int32_t)rect.mLeft, (int32_t)rect.mTop, (int32_t)rect.mWidth, (int32_t)rect.mHeight },
-                // TODO: fence
-                hidl_handle(),
-                [&err, &pointer](const auto &maperr, const auto &mapPointer) {
-                    err = maperr2error(maperr);
-                    if (err == C2_OK) {
-                        pointer = mapPointer;
-                    }
-                });
-        if (err != C2_OK) {
-            return err;
-        }
-        // TODO
-        return C2_UNSUPPORTED;
-    }
-    mLocked = true;
-
-    return C2_OK;
-}
-
-C2Error C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
-    // TODO: fence
-    C2Error err = C2_OK;
-    mMapper->unlock(
-            const_cast<native_handle_t *>(mBuffer),
-            [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
-                // TODO
-                (void) fenceFd;
-                (void) releaseFence;
-                err = maperr2error(maperr);
-                if (err == C2_OK) {
-                    // TODO: fence
-                }
-            });
-    if (err == C2_OK) {
-        mLocked = false;
-    }
-    return err;
-}
-
-bool C2AllocationGralloc::equals(const std::shared_ptr<const C2GraphicAllocation> &other) const {
-    return other && other->handle() == handle();
-}
-
-/* ===================================== GRALLOC ALLOCATOR ==================================== */
-
-class C2AllocatorGralloc::Impl {
-public:
-    Impl();
-
-    C2Error allocateGraphicBuffer(
-            uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
-            std::shared_ptr<C2GraphicAllocation> *allocation);
-
-    C2Error recreateGraphicBuffer(
-            const C2Handle *handle,
-            std::shared_ptr<C2GraphicAllocation> *allocation);
-
-    C2Error status() const { return mInit; }
-
-private:
-    C2Error mInit;
-    sp<IAllocator> mAllocator;
-    sp<IMapper> mMapper;
-};
-
-C2AllocatorGralloc::Impl::Impl() : mInit(C2_OK) {
-    mAllocator = IAllocator::getService();
-    mMapper = IMapper::getService();
-    if (mAllocator == nullptr || mMapper == nullptr) {
-        mInit = C2_CORRUPTED;
-    }
-}
-
-C2Error C2AllocatorGralloc::Impl::allocateGraphicBuffer(
-        uint32_t width, uint32_t height, uint32_t format, const C2MemoryUsage &usage,
-        std::shared_ptr<C2GraphicAllocation> *allocation) {
-    // TODO: buffer usage should be determined according to |usage|
-    (void) usage;
-
-    IMapper::BufferDescriptorInfo info = {
-        width,
-        height,
-        1u,  // layerCount
-        (PixelFormat)format,
-        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
-    };
-    C2Error err = C2_OK;
-    BufferDescriptor desc;
-    mMapper->createDescriptor(
-            info, [&err, &desc](const auto &maperr, const auto &descriptor) {
-                err = maperr2error(maperr);
-                if (err == C2_OK) {
-                    desc = descriptor;
-                }
-            });
-    if (err != C2_OK) {
-        return err;
-    }
-
-    // IAllocator shares IMapper error codes.
-    hidl_handle buffer;
-    mAllocator->allocate(
-            desc,
-            1u,
-            [&err, &buffer](const auto &maperr, const auto &stride, auto &buffers) {
-                (void) stride;
-                err = maperr2error(maperr);
-                if (err != C2_OK) {
-                    return;
-                }
-                if (buffers.size() != 1u) {
-                    err = C2_CORRUPTED;
-                    return;
-                }
-                buffer = std::move(buffers[0]);
-            });
-    if (err != C2_OK) {
-        return err;
-    }
-
-    allocation->reset(new C2AllocationGralloc(info, mMapper, buffer));
-    return C2_OK;
-}
-
-C2Error C2AllocatorGralloc::Impl::recreateGraphicBuffer(
-        const C2Handle *handle,
-        std::shared_ptr<C2GraphicAllocation> *allocation) {
-    (void) handle;
-
-    // TODO: need to figure out BufferDescriptorInfo from the handle.
-    allocation->reset();
-    return C2_UNSUPPORTED;
-}
-
-C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
-C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
-
-C2Error C2AllocatorGralloc::allocateGraphicBuffer(
-        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
-        std::shared_ptr<C2GraphicAllocation> *allocation) {
-    return mImpl->allocateGraphicBuffer(width, height, format, usage, allocation);
-}
-
-C2Error C2AllocatorGralloc::recreateGraphicBuffer(
-        const C2Handle *handle,
-        std::shared_ptr<C2GraphicAllocation> *allocation) {
-    return mImpl->recreateGraphicBuffer(handle, allocation);
-}
-
-C2Error C2AllocatorGralloc::status() const { return mImpl->status(); }
-
 /* ========================================== 2D BLOCK ========================================= */
 
 class C2Block2D::Impl {
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
new file mode 100644
index 0000000..94f74c8
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorGralloc : public C2Allocator {
+public:
+    // (usage, capacity) => (align, heapMask, flags)
+    typedef std::function<int (C2MemoryUsage, size_t,
+                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
+
+    virtual C2Error allocateGraphicBuffer(
+            uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+            std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+    virtual C2Error recreateGraphicBuffer(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *allocation) override;
+
+    C2AllocatorGralloc();
+
+    C2Error status() const;
+
+    virtual ~C2AllocatorGralloc();
+
+private:
+    class Impl;
+    Impl *mImpl;
+};
+
+#if 0
+class C2Allocation::Impl {
+public:
+    Impl() : mMapped(false), mBase(nullptr) { }
+    uint8_t* base() { return mMapped ? mBase : nullptr; }
+
+    // TODO: call map...
+
+private:
+    bool mMapped;
+    uint8_t *mBase;
+};
+#endif
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_GRALLOC_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
new file mode 100644
index 0000000..a453a7d
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+#define STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
+
+#include <functional>
+
+#include <C2Buffer.h>
+
+namespace android {
+
+class C2AllocatorIon : public C2Allocator {
+public:
+    // (usage, capacity) => (align, heapMask, flags)
+    typedef std::function<int (C2MemoryUsage, size_t,
+                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
+
+    virtual C2Error allocateLinearBuffer(
+            uint32_t capacity, C2MemoryUsage usage,
+            std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+    virtual C2Error recreateLinearBuffer(
+            const C2Handle *handle,
+            std::shared_ptr<C2LinearAllocation> *allocation) override;
+
+    C2AllocatorIon();
+
+    C2Error status() const { return mInit; }
+
+    virtual ~C2AllocatorIon();
+
+private:
+    C2Error mInit;
+    int mIonFd;
+    usage_mapper_fn mUsageMapper;
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ALLOCATOR_ION_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
index b7c752f..6a8f94e 100644
--- a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
+++ b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
@@ -23,32 +23,6 @@
 
 namespace android {
 
-class C2AllocatorIon : public C2Allocator {
-public:
-    // (usage, capacity) => (align, heapMask, flags)
-    typedef std::function<int (C2MemoryUsage, size_t,
-                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
-
-    virtual C2Error allocateLinearBuffer(
-            uint32_t capacity, C2MemoryUsage usage,
-            std::shared_ptr<C2LinearAllocation> *allocation) override;
-
-    virtual C2Error recreateLinearBuffer(
-            const C2Handle *handle,
-            std::shared_ptr<C2LinearAllocation> *allocation) override;
-
-    C2AllocatorIon();
-
-    C2Error status() const { return mInit; }
-
-    virtual ~C2AllocatorIon();
-
-private:
-    C2Error mInit;
-    int mIonFd;
-    usage_mapper_fn mUsageMapper;
-};
-
 class C2DefaultBlockAllocator : public C2BlockAllocator {
 public:
     explicit C2DefaultBlockAllocator(const std::shared_ptr<C2Allocator> &allocator);
@@ -65,31 +39,6 @@
     const std::shared_ptr<C2Allocator> mAllocator;
 };
 
-class C2AllocatorGralloc : public C2Allocator {
-public:
-    // (usage, capacity) => (align, heapMask, flags)
-    typedef std::function<int (C2MemoryUsage, size_t,
-                      /* => */ size_t*, unsigned*, unsigned*)> usage_mapper_fn;
-
-    virtual C2Error allocateGraphicBuffer(
-            uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
-            std::shared_ptr<C2GraphicAllocation> *allocation) override;
-
-    virtual C2Error recreateGraphicBuffer(
-            const C2Handle *handle,
-            std::shared_ptr<C2GraphicAllocation> *allocation) override;
-
-    C2AllocatorGralloc();
-
-    C2Error status() const;
-
-    virtual ~C2AllocatorGralloc();
-
-private:
-    class Impl;
-    Impl *mImpl;
-};
-
 class C2DefaultGraphicBlockAllocator : public C2BlockAllocator {
 public:
     explicit C2DefaultGraphicBlockAllocator(const std::shared_ptr<C2Allocator> &allocator);
diff --git a/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
new file mode 100644
index 0000000..f834cdb
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+#define STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
+#include <errno.h>
+#include <C2.h>
+
+namespace android {
+
+// standard ERRNO mappings
+template<int N> constexpr C2Error _c2_errno2error_impl();
+template<> constexpr C2Error _c2_errno2error_impl<0>()       { return C2_OK; }
+template<> constexpr C2Error _c2_errno2error_impl<EINVAL>()  { return C2_BAD_VALUE; }
+template<> constexpr C2Error _c2_errno2error_impl<EACCES>()  { return C2_NO_PERMISSION; }
+template<> constexpr C2Error _c2_errno2error_impl<EPERM>()   { return C2_NO_PERMISSION; }
+template<> constexpr C2Error _c2_errno2error_impl<ENOMEM>()  { return C2_NO_MEMORY; }
+
+// map standard errno-s to the equivalent C2Error
+template<int... N> struct _c2_map_errno_impl;
+template<int E, int ... N> struct _c2_map_errno_impl<E, N...> {
+    static C2Error map(int result) {
+        if (result == E) {
+            return _c2_errno2error_impl<E>();
+        } else {
+            return _c2_map_errno_impl<N...>::map(result);
+        }
+    }
+};
+template<> struct _c2_map_errno_impl<> {
+    static C2Error map(int result) {
+        return result == 0 ? C2_OK : C2_CORRUPTED;
+    }
+};
+
+template<int... N>
+C2Error c2_map_errno(int result) {
+    return _c2_map_errno_impl<N...>::map(result);
+}
+
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
+
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
index 4de14d2..c4cc6a6 100644
--- a/media/libstagefright/codecs/cmds/codec2.cpp
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -52,6 +52,8 @@
 #include <gui/SurfaceComposerClient.h>
 
 #include <util/C2ParamUtils.h>
+#include <C2AllocatorGralloc.h>
+#include <C2AllocatorIon.h>
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
 #include <C2Component.h>