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