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