Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "Codec2-InputSurfaceConnection"
     19 #include <log/log.h>
     20 
     21 #include <codec2/hidl/1.0/InputSurfaceConnection.h>
     22 
     23 #include <media/stagefright/bqhelper/ComponentWrapper.h>
     24 
     25 #include <C2BlockInternal.h>
     26 #include <C2PlatformSupport.h>
     27 #include <C2AllocatorGralloc.h>
     28 
     29 #include <C2Debug.h>
     30 #include <C2Config.h>
     31 #include <C2Component.h>
     32 #include <C2Work.h>
     33 #include <C2Buffer.h>
     34 #include <C2.h>
     35 
     36 #include <ui/GraphicBuffer.h>
     37 #include <system/graphics.h>
     38 #include <utils/Errors.h>
     39 
     40 #include <memory>
     41 #include <list>
     42 #include <mutex>
     43 #include <atomic>
     44 
     45 namespace /* unnamed */ {
     46 
     47 class Buffer2D : public C2Buffer {
     48 public:
     49     explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {
     50     }
     51 };
     52 
     53 constexpr int32_t kBufferCount = 16;
     54 
     55 } // unnamed namespace
     56 
     57 namespace hardware {
     58 namespace google {
     59 namespace media {
     60 namespace c2 {
     61 namespace V1_0 {
     62 namespace utils {
     63 
     64 using namespace ::android;
     65 
     66 struct InputSurfaceConnection::Impl : public ComponentWrapper {
     67     Impl(
     68             const sp<GraphicBufferSource>& source,
     69             const std::shared_ptr<C2Component>& comp) :
     70         mSource(source), mComp(comp), mFrameIndex(0) {
     71     }
     72 
     73     virtual ~Impl() = default;
     74 
     75     bool init() {
     76         sp<GraphicBufferSource> source = mSource.promote();
     77         if (source == nullptr) {
     78             return false;
     79         }
     80         status_t err = source->initCheck();
     81         if (err != OK) {
     82             ALOGE("Impl::init -- GBS init failed: %d", err);
     83             return false;
     84         }
     85 
     86         // Query necessary information for GraphicBufferSource::configure() from
     87         // the component interface.
     88         std::shared_ptr<C2Component> comp = mComp.lock();
     89         if (!comp) {
     90             ALOGE("Impl::init -- component died.");
     91             return false;
     92         }
     93         std::shared_ptr<C2ComponentInterface> intf = comp->intf();
     94         if (!intf) {
     95             ALOGE("Impl::init -- null component interface.");
     96             return false;
     97         }
     98 
     99         // TODO: read settings properly from the interface
    100         C2VideoSizeStreamTuning::input inputSize;
    101         C2StreamUsageTuning::input usage;
    102         c2_status_t c2Status = intf->query_vb(
    103                 { &inputSize, &usage },
    104                 {},
    105                 C2_MAY_BLOCK,
    106                 nullptr);
    107         if (c2Status != C2_OK) {
    108             ALOGD("Impl::init -- cannot query information from "
    109                     "the component interface: %s.", asString(c2Status));
    110             return false;
    111         }
    112 
    113         // TODO: proper color aspect & dataspace
    114         android_dataspace dataSpace = HAL_DATASPACE_BT709;
    115 
    116         // TODO: use the usage read from intf
    117         // uint32_t grallocUsage =
    118         //         C2AndroidMemoryUsage(C2MemoryUsage(usage.value)).
    119         //         asGrallocUsage();
    120         uint32_t grallocUsage =
    121                 strncmp(intf->getName().c_str(), "c2.android.", 11) == 0 ?
    122                 GRALLOC_USAGE_SW_READ_OFTEN :
    123                 GRALLOC_USAGE_HW_VIDEO_ENCODER;
    124 
    125         err = source->configure(
    126                 this, dataSpace, kBufferCount,
    127                 inputSize.width, inputSize.height,
    128                 grallocUsage);
    129         if (err != OK) {
    130             ALOGE("Impl::init -- GBS configure failed: %d", err);
    131             return false;
    132         }
    133         for (int32_t i = 0; i < kBufferCount; ++i) {
    134             if (!source->onInputBufferAdded(i).isOk()) {
    135                 ALOGE("Impl::init: populating GBS slots failed");
    136                 return false;
    137             }
    138         }
    139         if (!source->start().isOk()) {
    140             ALOGE("Impl::init -- GBS start failed");
    141             return false;
    142         }
    143         mAllocatorMutex.lock();
    144         c2_status_t c2err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
    145                 C2AllocatorStore::PLATFORM_START + 1,  // GRALLOC
    146                 &mAllocator);
    147         mAllocatorMutex.unlock();
    148         if (c2err != OK) {
    149             ALOGE("Impl::init -- failed to fetch gralloc allocator: %d", c2err);
    150             return false;
    151         }
    152         return true;
    153     }
    154 
    155     // From ComponentWrapper
    156     virtual status_t submitBuffer(
    157             int32_t bufferId,
    158             const sp<GraphicBuffer>& buffer,
    159             int64_t timestamp,
    160             int fenceFd) override {
    161         ALOGV("Impl::submitBuffer -- bufferId = %d", bufferId);
    162         // TODO: Use fd to construct fence
    163         (void)fenceFd;
    164 
    165         std::shared_ptr<C2Component> comp = mComp.lock();
    166         if (!comp) {
    167             ALOGW("Impl::submitBuffer -- component died.");
    168             return NO_INIT;
    169         }
    170 
    171         std::shared_ptr<C2GraphicAllocation> alloc;
    172         C2Handle* handle = WrapNativeCodec2GrallocHandle(
    173                 native_handle_clone(buffer->handle),
    174                 buffer->width, buffer->height,
    175                 buffer->format, buffer->usage, buffer->stride);
    176         mAllocatorMutex.lock();
    177         c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
    178         mAllocatorMutex.unlock();
    179         if (err != OK) {
    180             return UNKNOWN_ERROR;
    181         }
    182         std::shared_ptr<C2GraphicBlock> block =
    183                 _C2BlockFactory::CreateGraphicBlock(alloc);
    184 
    185         std::unique_ptr<C2Work> work(new C2Work);
    186         work->input.flags = (C2FrameData::flags_t)0;
    187         work->input.ordinal.timestamp = timestamp;
    188         work->input.ordinal.frameIndex = mFrameIndex.fetch_add(
    189                 1, std::memory_order_relaxed);
    190         work->input.buffers.clear();
    191         std::shared_ptr<C2Buffer> c2Buffer(
    192                 // TODO: fence
    193                 new Buffer2D(block->share(
    194                         C2Rect(block->width(), block->height()), ::C2Fence())),
    195                 [bufferId, src = mSource](C2Buffer* ptr) {
    196                     delete ptr;
    197                     sp<GraphicBufferSource> source = src.promote();
    198                     if (source != nullptr) {
    199                         // TODO: fence
    200                         (void)source->onInputBufferEmptied(bufferId, -1);
    201                     }
    202                 });
    203         work->input.buffers.push_back(c2Buffer);
    204         work->worklets.clear();
    205         work->worklets.emplace_back(new C2Worklet);
    206         std::list<std::unique_ptr<C2Work>> items;
    207         items.push_back(std::move(work));
    208 
    209         err = comp->queue_nb(&items);
    210         return (err == C2_OK) ? OK : UNKNOWN_ERROR;
    211     }
    212 
    213     virtual status_t submitEos(int32_t /* bufferId */) override {
    214         ALOGV("Impl::submitEos");
    215         std::shared_ptr<C2Component> comp = mComp.lock();
    216         if (!comp) {
    217             ALOGW("Impl::submitEos -- component died.");
    218             return NO_INIT;
    219         }
    220 
    221         std::unique_ptr<C2Work> work(new C2Work);
    222         work->input.flags = (C2FrameData::flags_t)0;
    223         work->input.ordinal.frameIndex = mFrameIndex.fetch_add(
    224                 1, std::memory_order_relaxed);
    225         work->input.buffers.clear();
    226         work->worklets.clear();
    227         work->worklets.emplace_back(new C2Worklet);
    228         std::list<std::unique_ptr<C2Work>> items;
    229         items.push_back(std::move(work));
    230 
    231         c2_status_t err = comp->queue_nb(&items);
    232         return (err == C2_OK) ? OK : UNKNOWN_ERROR;
    233     }
    234 
    235     void dispatchDataSpaceChanged(
    236             int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
    237         // TODO
    238         (void)dataSpace;
    239         (void)aspects;
    240         (void)pixelFormat;
    241     }
    242 
    243 private:
    244     wp<GraphicBufferSource> mSource;
    245     std::weak_ptr<C2Component> mComp;
    246 
    247     // Needed for ComponentWrapper implementation
    248     std::mutex mAllocatorMutex;
    249     std::shared_ptr<C2Allocator> mAllocator;
    250     std::atomic_uint64_t mFrameIndex;
    251 };
    252 
    253 InputSurfaceConnection::InputSurfaceConnection(
    254         const sp<GraphicBufferSource>& source,
    255         const std::shared_ptr<C2Component>& comp) :
    256     mSource(source),
    257     mImpl(new Impl(source, comp)) {
    258 }
    259 
    260 InputSurfaceConnection::~InputSurfaceConnection() {
    261     if (mSource) {
    262         (void)mSource->stop();
    263         (void)mSource->release();
    264         mSource.clear();
    265     }
    266     mImpl.clear();
    267 }
    268 
    269 bool InputSurfaceConnection::init() {
    270     std::lock_guard<std::mutex> lock(mMutex);
    271     if (!mImpl) {
    272         return false;
    273     }
    274     return mImpl->init();
    275 }
    276 
    277 Return<Status> InputSurfaceConnection::disconnect() {
    278     ALOGV("disconnect");
    279     mMutex.lock();
    280     if (mSource) {
    281         (void)mSource->stop();
    282         (void)mSource->release();
    283         mSource.clear();
    284     }
    285     mImpl.clear();
    286     mMutex.unlock();
    287     ALOGV("disconnected");
    288     return Status::OK;
    289 }
    290 
    291 }  // namespace utils
    292 }  // namespace V1_0
    293 }  // namespace c2
    294 }  // namespace media
    295 }  // namespace google
    296 }  // namespace hardware
    297 
    298