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:
Buffer2D(C2ConstGraphicBlock block)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 {
Implhardware::google::media::c2::V1_0::utils::InputSurfaceConnection::Impl67     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 
inithardware::google::media::c2::V1_0::utils::InputSurfaceConnection::Impl75     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
submitBufferhardware::google::media::c2::V1_0::utils::InputSurfaceConnection::Impl156     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 
submitEoshardware::google::media::c2::V1_0::utils::InputSurfaceConnection::Impl213     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 
dispatchDataSpaceChangedhardware::google::media::c2::V1_0::utils::InputSurfaceConnection::Impl235     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 
InputSurfaceConnection(const sp<GraphicBufferSource> & source,const std::shared_ptr<C2Component> & comp)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 
~InputSurfaceConnection()260 InputSurfaceConnection::~InputSurfaceConnection() {
261     if (mSource) {
262         (void)mSource->stop();
263         (void)mSource->release();
264         mSource.clear();
265     }
266     mImpl.clear();
267 }
268 
init()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 
disconnect()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