1 /*
2 * Copyright 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 <android-base/logging.h>
20
21 #include <codec2/hidl/1.0/InputSurfaceConnection.h>
22 #include <codec2/hidl/1.0/InputSurfaceConnection.h>
23
24 #include <memory>
25 #include <list>
26 #include <mutex>
27 #include <atomic>
28
29 #include <hidl/HidlSupport.h>
30 #include <media/stagefright/bqhelper/ComponentWrapper.h>
31 #include <system/graphics.h>
32 #include <ui/GraphicBuffer.h>
33 #include <utils/Errors.h>
34
35 #include <C2.h>
36 #include <C2AllocatorGralloc.h>
37 #include <C2BlockInternal.h>
38 #include <C2Buffer.h>
39 #include <C2Component.h>
40 #include <C2Config.h>
41 #include <C2Debug.h>
42 #include <C2PlatformSupport.h>
43 #include <C2Work.h>
44
45 namespace android {
46 namespace hardware {
47 namespace media {
48 namespace c2 {
49 namespace V1_0 {
50 namespace utils {
51
52 constexpr int32_t kBufferCount = 16;
53
54 using namespace ::android;
55 using ::android::hardware::hidl_string;
56 using ::android::hardware::hidl_vec;
57 using ::android::hardware::Return;
58
59 namespace /* unnamed */ {
60
61 class Buffer2D : public C2Buffer {
62 public:
Buffer2D(C2ConstGraphicBlock block)63 explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {
64 }
65 };
66
67 } // unnamed namespace
68
69 // Derived class of ComponentWrapper for use with
70 // GraphicBufferSource::configure().
71 //
72 struct InputSurfaceConnection::Impl : public ComponentWrapper {
73
Implandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl74 Impl(const sp<GraphicBufferSource>& source,
75 const std::shared_ptr<C2Component>& localComp)
76 : mSource{source}, mLocalComp{localComp}, mSink{}, mFrameIndex{0} {
77 std::shared_ptr<C2ComponentInterface> intf = localComp->intf();
78 mSinkName = intf ? intf->getName() : "";
79 }
80
Implandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl81 Impl(const sp<GraphicBufferSource>& source,
82 const sp<IInputSink>& sink)
83 : mSource{source}, mLocalComp{}, mSink{sink}, mFrameIndex{0} {
84 Return<sp<IConfigurable>> transResult = sink->getConfigurable();
85 if (!transResult.isOk()) {
86 LOG(ERROR) << "Remote sink is dead.";
87 return;
88 }
89 mSinkConfigurable =
90 static_cast<sp<IConfigurable>>(transResult);
91 if (!mSinkConfigurable) {
92 LOG(ERROR) << "Remote sink is not configurable.";
93 mSinkName = "";
94 return;
95 }
96
97 hidl_string name;
98 Return<void> transStatus = mSinkConfigurable->getName(
__anonce38f9970202(const hidl_string& n) 99 [&name](const hidl_string& n) {
100 name = n;
101 });
102 if (!transStatus.isOk()) {
103 LOG(ERROR) << "Remote sink's configurable is dead.";
104 mSinkName = "";
105 return;
106 }
107 mSinkName = name.c_str();
108 }
109
~Implandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl110 virtual ~Impl() {
111 mSource->stop();
112 mSource->release();
113 }
114
initandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl115 bool init() {
116 if (mSource == nullptr) {
117 return false;
118 }
119 status_t err = mSource->initCheck();
120 if (err != OK) {
121 LOG(WARNING) << "Impl::init -- GraphicBufferSource init failed: "
122 << "status = " << err << ".";
123 return false;
124 }
125
126 // TODO: read settings properly from the interface
127 C2StreamPictureSizeInfo::input inputSize;
128 C2StreamUsageTuning::input usage;
129 c2_status_t c2Status = queryFromSink({ &inputSize, &usage },
130 {},
131 C2_MAY_BLOCK,
132 nullptr);
133 if (c2Status != C2_OK) {
134 LOG(WARNING) << "Impl::init -- cannot query information from "
135 "the component interface: "
136 << "status = " << asString(c2Status) << ".";
137 return false;
138 }
139
140 // TODO: proper color aspect & dataspace
141 android_dataspace dataSpace = HAL_DATASPACE_BT709;
142
143 // TODO: use the usage read from intf
144 // uint32_t grallocUsage =
145 // C2AndroidMemoryUsage(C2MemoryUsage(usage.value)).
146 // asGrallocUsage();
147
148 uint32_t grallocUsage =
149 mSinkName.compare(0, 11, "c2.android.") == 0 ?
150 GRALLOC_USAGE_SW_READ_OFTEN :
151 GRALLOC_USAGE_HW_VIDEO_ENCODER;
152
153 err = mSource->configure(
154 this, dataSpace, kBufferCount,
155 inputSize.width, inputSize.height,
156 grallocUsage);
157 if (err != OK) {
158 LOG(WARNING) << "Impl::init -- GBS configure failed: "
159 << "status = " << err << ".";
160 return false;
161 }
162 for (int32_t i = 0; i < kBufferCount; ++i) {
163 if (mSource->onInputBufferAdded(i) != OK) {
164 LOG(WARNING) << "Impl::init: failed to populate GBS slots.";
165 return false;
166 }
167 }
168 if (mSource->start() != OK) {
169 LOG(WARNING) << "Impl::init -- GBS failed to start.";
170 return false;
171 }
172 mAllocatorMutex.lock();
173 c2_status_t c2err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
174 C2AllocatorStore::PLATFORM_START + 1, // GRALLOC
175 &mAllocator);
176 mAllocatorMutex.unlock();
177 if (c2err != OK) {
178 LOG(WARNING) << "Impl::init -- failed to fetch gralloc allocator: "
179 << "status = " << asString(c2err) << ".";
180 return false;
181 }
182 return true;
183 }
184
185 // From ComponentWrapper
submitBufferandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl186 virtual status_t submitBuffer(
187 int32_t bufferId,
188 const sp<GraphicBuffer>& buffer,
189 int64_t timestamp,
190 int fenceFd) override {
191 LOG(VERBOSE) << "Impl::submitBuffer -- bufferId = " << bufferId << ".";
192 // TODO: Use fd to construct fence
193 (void)fenceFd;
194
195 std::shared_ptr<C2GraphicAllocation> alloc;
196 C2Handle* handle = WrapNativeCodec2GrallocHandle(
197 buffer->handle,
198 buffer->width, buffer->height,
199 buffer->format, buffer->usage, buffer->stride);
200 mAllocatorMutex.lock();
201 c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
202 mAllocatorMutex.unlock();
203 if (err != OK) {
204 native_handle_close(handle);
205 native_handle_delete(handle);
206 return UNKNOWN_ERROR;
207 }
208 std::shared_ptr<C2GraphicBlock> block =
209 _C2BlockFactory::CreateGraphicBlock(alloc);
210
211 std::unique_ptr<C2Work> work(new C2Work);
212 work->input.flags = (C2FrameData::flags_t)0;
213 work->input.ordinal.timestamp = timestamp;
214 work->input.ordinal.frameIndex = mFrameIndex.fetch_add(
215 1, std::memory_order_relaxed);
216 work->input.buffers.clear();
217 std::shared_ptr<C2Buffer> c2Buffer(
218 // TODO: fence
219 new Buffer2D(block->share(
220 C2Rect(block->width(), block->height()), ::C2Fence())),
221 [bufferId, source = mSource](C2Buffer* ptr) {
222 delete ptr;
223 if (source != nullptr) {
224 // TODO: fence
225 (void)source->onInputBufferEmptied(bufferId, -1);
226 }
227 });
228 work->input.buffers.push_back(c2Buffer);
229 work->worklets.clear();
230 work->worklets.emplace_back(new C2Worklet);
231 std::list<std::unique_ptr<C2Work>> items;
232 items.push_back(std::move(work));
233
234 err = queueToSink(&items);
235 return (err == C2_OK) ? OK : UNKNOWN_ERROR;
236 }
237
submitEosandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl238 virtual status_t submitEos(int32_t bufferId) override {
239 LOG(VERBOSE) << "Impl::submitEos -- bufferId = " << bufferId << ".";
240 (void)bufferId;
241
242 std::unique_ptr<C2Work> work(new C2Work);
243 work->input.flags = (C2FrameData::flags_t)0;
244 work->input.ordinal.frameIndex = mFrameIndex.fetch_add(
245 1, std::memory_order_relaxed);
246 work->input.buffers.clear();
247 work->worklets.clear();
248 work->worklets.emplace_back(new C2Worklet);
249 std::list<std::unique_ptr<C2Work>> items;
250 items.push_back(std::move(work));
251
252 c2_status_t err = queueToSink(&items);
253 return (err == C2_OK) ? OK : UNKNOWN_ERROR;
254 }
255
dispatchDataSpaceChangedandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl256 virtual void dispatchDataSpaceChanged(
257 int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
258 // TODO
259 (void)dataSpace;
260 (void)aspects;
261 (void)pixelFormat;
262 }
263
264 // Configurable interface for InputSurfaceConnection::Impl.
265 //
266 // This class is declared as an inner class so that it will have access to
267 // all Impl's members.
268 struct ConfigurableIntf : public ConfigurableC2Intf {
269 sp<Impl> mConnection;
ConfigurableIntfandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl::ConfigurableIntf270 ConfigurableIntf(const sp<Impl>& connection)
271 : ConfigurableC2Intf{"input-surface-connection", 0},
272 mConnection{connection} {}
273 virtual c2_status_t config(
274 const std::vector<C2Param*> ¶ms,
275 c2_blocking_t mayBlock,
276 std::vector<std::unique_ptr<C2SettingResult>> *const failures
277 ) override;
278 virtual c2_status_t query(
279 const std::vector<C2Param::Index> &indices,
280 c2_blocking_t mayBlock,
281 std::vector<std::unique_ptr<C2Param>> *const params) const override;
282 virtual c2_status_t querySupportedParams(
283 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
284 ) const override;
285 virtual c2_status_t querySupportedValues(
286 std::vector<C2FieldSupportedValuesQuery> &fields,
287 c2_blocking_t mayBlock) const override;
288 };
289
290 private:
queryFromSinkandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl291 c2_status_t queryFromSink(
292 const std::vector<C2Param*> &stackParams,
293 const std::vector<C2Param::Index> &heapParamIndices,
294 c2_blocking_t mayBlock,
295 std::vector<std::unique_ptr<C2Param>>* const heapParams) {
296 if (mLocalComp) {
297 std::shared_ptr<C2ComponentInterface> intf = mLocalComp->intf();
298 if (intf) {
299 return intf->query_vb(stackParams,
300 heapParamIndices,
301 mayBlock,
302 heapParams);
303 } else {
304 LOG(ERROR) << "queryFromSink -- "
305 << "component does not have an interface.";
306 return C2_BAD_STATE;
307 }
308 }
309
310 CHECK(mSink) << "-- queryFromSink "
311 << "-- connection has no sink.";
312 CHECK(mSinkConfigurable) << "-- queryFromSink "
313 << "-- sink has no configurable.";
314
315 hidl_vec<ParamIndex> indices(
316 stackParams.size() + heapParamIndices.size());
317 size_t numIndices = 0;
318 for (C2Param* const& stackParam : stackParams) {
319 if (!stackParam) {
320 LOG(DEBUG) << "queryFromSink -- null stack param encountered.";
321 continue;
322 }
323 indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
324 }
325 size_t numStackIndices = numIndices;
326 for (const C2Param::Index& index : heapParamIndices) {
327 indices[numIndices++] =
328 static_cast<ParamIndex>(static_cast<uint32_t>(index));
329 }
330 indices.resize(numIndices);
331 if (heapParams) {
332 heapParams->reserve(heapParams->size() + numIndices);
333 }
334 c2_status_t status;
335 Return<void> transStatus = mSinkConfigurable->query(
336 indices,
337 mayBlock == C2_MAY_BLOCK,
338 [&status, &numStackIndices, &stackParams, heapParams](
339 Status s, const Params& p) {
340 status = static_cast<c2_status_t>(s);
341 if (status != C2_OK && status != C2_BAD_INDEX) {
342 LOG(DEBUG) << "queryFromSink -- call failed: "
343 << "status = " << asString(status) << ".";
344 return;
345 }
346 std::vector<C2Param*> paramPointers;
347 if (!parseParamsBlob(¶mPointers, p)) {
348 LOG(DEBUG) << "queryFromSink -- error while "
349 << "parsing params.";
350 status = C2_CORRUPTED;
351 return;
352 }
353 size_t i = 0;
354 for (auto it = paramPointers.begin();
355 it != paramPointers.end(); ) {
356 C2Param* paramPointer = *it;
357 if (numStackIndices > 0) {
358 --numStackIndices;
359 if (!paramPointer) {
360 LOG(DEBUG) << "queryFromSink -- "
361 "null stack param.";
362 ++it;
363 continue;
364 }
365 for (; i < stackParams.size() &&
366 !stackParams[i]; ) {
367 ++i;
368 }
369 CHECK(i < stackParams.size());
370 if (stackParams[i]->index() !=
371 paramPointer->index()) {
372 LOG(DEBUG) << "queryFromSink -- "
373 "param skipped (index = "
374 << stackParams[i]->index() << ").";
375 stackParams[i++]->invalidate();
376 continue;
377 }
378 if (!stackParams[i++]->updateFrom(*paramPointer)) {
379 LOG(DEBUG) << "queryFromSink -- "
380 "param update failed (index = "
381 << paramPointer->index() << ").";
382 }
383 } else {
384 if (!paramPointer) {
385 LOG(DEBUG) << "queryFromSink -- "
386 "null heap param.";
387 ++it;
388 continue;
389 }
390 if (!heapParams) {
391 LOG(WARNING) << "queryFromSink -- "
392 "too many stack params.";
393 break;
394 }
395 heapParams->emplace_back(C2Param::Copy(*paramPointer));
396 }
397 ++it;
398 }
399 });
400 if (!transStatus.isOk()) {
401 LOG(ERROR) << "queryFromSink -- transaction failed.";
402 return C2_CORRUPTED;
403 }
404 return status;
405 }
406
queueToSinkandroid::hardware::media::c2::V1_0::utils::InputSurfaceConnection::Impl407 c2_status_t queueToSink(std::list<std::unique_ptr<C2Work>>* const items) {
408 if (mLocalComp) {
409 return mLocalComp->queue_nb(items);
410 }
411
412 CHECK(mSink) << "-- queueToSink "
413 << "-- connection has no sink.";
414
415 WorkBundle workBundle;
416 if (!objcpy(&workBundle, *items, nullptr)) {
417 LOG(ERROR) << "queueToSink -- bad input.";
418 return C2_CORRUPTED;
419 }
420 Return<Status> transStatus = mSink->queue(workBundle);
421 if (!transStatus.isOk()) {
422 LOG(ERROR) << "queueToSink -- transaction failed.";
423 return C2_CORRUPTED;
424 }
425 c2_status_t status =
426 static_cast<c2_status_t>(static_cast<Status>(transStatus));
427 if (status != C2_OK) {
428 LOG(DEBUG) << "queueToSink -- call failed: "
429 << asString(status);
430 }
431 return status;
432 }
433
434 sp<GraphicBufferSource> mSource;
435 std::shared_ptr<C2Component> mLocalComp;
436 sp<IInputSink> mSink;
437 sp<IConfigurable> mSinkConfigurable;
438 std::string mSinkName;
439
440 // Needed for ComponentWrapper implementation
441 std::mutex mAllocatorMutex;
442 std::shared_ptr<C2Allocator> mAllocator;
443 std::atomic_uint64_t mFrameIndex;
444
445 };
446
InputSurfaceConnection(const sp<GraphicBufferSource> & source,const std::shared_ptr<C2Component> & comp,const std::shared_ptr<ParameterCache> & cache)447 InputSurfaceConnection::InputSurfaceConnection(
448 const sp<GraphicBufferSource>& source,
449 const std::shared_ptr<C2Component>& comp,
450 const std::shared_ptr<ParameterCache>& cache)
451 : mImpl{new Impl(source, comp)},
452 mConfigurable{new CachedConfigurable(
453 std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
454 mConfigurable->init(cache);
455 }
456
InputSurfaceConnection(const sp<GraphicBufferSource> & source,const sp<IInputSink> & sink,const std::shared_ptr<ParameterCache> & cache)457 InputSurfaceConnection::InputSurfaceConnection(
458 const sp<GraphicBufferSource>& source,
459 const sp<IInputSink>& sink,
460 const std::shared_ptr<ParameterCache>& cache)
461 : mImpl{new Impl(source, sink)},
462 mConfigurable{new CachedConfigurable(
463 std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
464 mConfigurable->init(cache);
465 }
466
disconnect()467 Return<Status> InputSurfaceConnection::disconnect() {
468 std::lock_guard<std::mutex> lock(mImplMutex);
469 mImpl = nullptr;
470 return Status::OK;
471 }
472
~InputSurfaceConnection()473 InputSurfaceConnection::~InputSurfaceConnection() {
474 mImpl = nullptr;
475 }
476
init()477 bool InputSurfaceConnection::init() {
478 std::lock_guard<std::mutex> lock(mImplMutex);
479 return mImpl->init();
480 }
481
getConfigurable()482 Return<sp<IConfigurable>> InputSurfaceConnection::getConfigurable() {
483 return mConfigurable;
484 }
485
486 // Configurable interface for InputSurfaceConnection::Impl
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)487 c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::config(
488 const std::vector<C2Param*> ¶ms,
489 c2_blocking_t mayBlock,
490 std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
491 // TODO: implement
492 (void)params;
493 (void)mayBlock;
494 (void)failures;
495 return C2_OK;
496 }
497
query(const std::vector<C2Param::Index> & indices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const params) const498 c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::query(
499 const std::vector<C2Param::Index> &indices,
500 c2_blocking_t mayBlock,
501 std::vector<std::unique_ptr<C2Param>> *const params) const {
502 // TODO: implement
503 (void)indices;
504 (void)mayBlock;
505 (void)params;
506 return C2_OK;
507 }
508
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const509 c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedParams(
510 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
511 // TODO: implement
512 (void)params;
513 return C2_OK;
514 }
515
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const516 c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedValues(
517 std::vector<C2FieldSupportedValuesQuery> &fields,
518 c2_blocking_t mayBlock) const {
519 // TODO: implement
520 (void)fields;
521 (void)mayBlock;
522 return C2_OK;
523 }
524
525 } // namespace utils
526 } // namespace V1_0
527 } // namespace c2
528 } // namespace media
529 } // namespace hardware
530 } // namespace android
531
532