Loading media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ #include <gtest/gtest.h> #include <C2AllocatorIon.h> #include <C2AllocatorGralloc.h> #include <C2Buffer.h> #include <C2BufferPriv.h> #include <C2ParamDef.h> Loading media/libstagefright/codec2/vndk/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ cc_library_static { name: "libstagefright_codec2_vndk", srcs: [ "C2AllocatorIon.cpp", "C2AllocatorGralloc.cpp", "C2Buffer.cpp", "C2Config.cpp", ], Loading media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp 0 → 100644 +340 −0 Original line number Diff line number Diff line /* * 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 media/libstagefright/codec2/vndk/C2AllocatorIon.cpp 0 → 100644 +344 −0 Original line number Diff line number Diff line /* * 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 media/libstagefright/codec2/vndk/C2Buffer.cpp +2 −696 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ #include <gtest/gtest.h> #include <C2AllocatorIon.h> #include <C2AllocatorGralloc.h> #include <C2Buffer.h> #include <C2BufferPriv.h> #include <C2ParamDef.h> Loading
media/libstagefright/codec2/vndk/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ cc_library_static { name: "libstagefright_codec2_vndk", srcs: [ "C2AllocatorIon.cpp", "C2AllocatorGralloc.cpp", "C2Buffer.cpp", "C2Config.cpp", ], Loading
media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp 0 → 100644 +340 −0 Original line number Diff line number Diff line /* * 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
media/libstagefright/codec2/vndk/C2AllocatorIon.cpp 0 → 100644 +344 −0 Original line number Diff line number Diff line /* * 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
media/libstagefright/codec2/vndk/C2Buffer.cpp +2 −696 File changed.Preview size limit exceeded, changes collapsed. Show changes