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 "Codec2Client"
19 #include <android-base/logging.h>
20
21 #include <codec2/hidl/client.h>
22 #include <C2Debug.h>
23 #include <C2BufferPriv.h>
24 #include <C2Config.h> // for C2StreamUsageTuning
25 #include <C2PlatformSupport.h>
26
27 #include <android/hardware/media/bufferpool/2.0/IClientManager.h>
28 #include <android/hardware/media/c2/1.0/IComponent.h>
29 #include <android/hardware/media/c2/1.0/IComponentInterface.h>
30 #include <android/hardware/media/c2/1.0/IComponentListener.h>
31 #include <android/hardware/media/c2/1.0/IComponentStore.h>
32 #include <android/hardware/media/c2/1.0/IConfigurable.h>
33 #include <android/hidl/manager/1.2/IServiceManager.h>
34
35 #include <android-base/properties.h>
36 #include <bufferpool/ClientManager.h>
37 #include <codec2/hidl/1.0/types.h>
38 #include <codec2/hidl/1.1/types.h>
39 #include <codec2/hidl/1.2/types.h>
40 #include <codec2/hidl/output.h>
41
42 #include <cutils/native_handle.h>
43 #include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
44 #include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
45 #include <hardware/gralloc.h> // for GRALLOC_USAGE_*
46 #include <hidl/HidlSupport.h>
47 #include <system/window.h> // for NATIVE_WINDOW_QUERY_*
48 #include <media/stagefright/foundation/ADebug.h> // for asString(status_t)
49
50
51 #include <deque>
52 #include <iterator>
53 #include <limits>
54 #include <map>
55 #include <mutex>
56 #include <sstream>
57 #include <thread>
58 #include <type_traits>
59 #include <vector>
60
61 namespace android {
62
63 using ::android::hardware::hidl_vec;
64 using ::android::hardware::hidl_string;
65 using ::android::hardware::Return;
66 using ::android::hardware::Void;
67
68 using namespace ::android::hardware::media::c2::V1_1;
69 using namespace ::android::hardware::media::c2::V1_1::utils;
70 using namespace ::android::hardware::media::bufferpool::V2_0;
71 using namespace ::android::hardware::media::bufferpool::V2_0::implementation;
72
73 using HGraphicBufferProducer1 = ::android::hardware::graphics::bufferqueue::
74 V1_0::IGraphicBufferProducer;
75 using HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
76 V2_0::IGraphicBufferProducer;
77 using B2HGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
78 V2_0::utils::B2HGraphicBufferProducer;
79 using H2BGraphicBufferProducer2 = ::android::hardware::graphics::bufferqueue::
80 V2_0::utils::H2BGraphicBufferProducer;
81 using ::android::hardware::media::c2::V1_2::SurfaceSyncObj;
82
83 namespace /* unnamed */ {
84
85 // c2_status_t value that corresponds to hwbinder transaction failure.
86 constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
87
88 // By default prepare buffer to be displayed on any of the common surfaces
89 constexpr uint64_t kDefaultConsumerUsage =
90 (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER);
91
92 // Searches for a name in GetServiceNames() and returns the index found. If the
93 // name is not found, the returned index will be equal to
94 // GetServiceNames().size().
getServiceIndex(char const * name)95 size_t getServiceIndex(char const* name) {
96 std::vector<std::string> const& names = Codec2Client::GetServiceNames();
97 size_t i = 0;
98 for (; i < names.size(); ++i) {
99 if (name == names[i]) {
100 break;
101 }
102 }
103 return i;
104 }
105
106 class Client2Store : public C2ComponentStore {
107 std::shared_ptr<Codec2Client> mClient;
108
109 public:
Client2Store(std::shared_ptr<Codec2Client> const & client)110 Client2Store(std::shared_ptr<Codec2Client> const& client)
111 : mClient(client) { }
112
113 virtual ~Client2Store() = default;
114
config_sm(std::vector<C2Param * > const & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)115 virtual c2_status_t config_sm(
116 std::vector<C2Param*> const ¶ms,
117 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
118 return mClient->config(params, C2_MAY_BLOCK, failures);
119 };
120
copyBuffer(std::shared_ptr<C2GraphicBuffer>,std::shared_ptr<C2GraphicBuffer>)121 virtual c2_status_t copyBuffer(
122 std::shared_ptr<C2GraphicBuffer>,
123 std::shared_ptr<C2GraphicBuffer>) {
124 return C2_OMITTED;
125 }
126
createComponent(C2String,std::shared_ptr<C2Component> * const component)127 virtual c2_status_t createComponent(
128 C2String, std::shared_ptr<C2Component>* const component) {
129 component->reset();
130 return C2_OMITTED;
131 }
132
createInterface(C2String,std::shared_ptr<C2ComponentInterface> * const interface)133 virtual c2_status_t createInterface(
134 C2String, std::shared_ptr<C2ComponentInterface>* const interface) {
135 interface->reset();
136 return C2_OMITTED;
137 }
138
query_sm(std::vector<C2Param * > const & stackParams,std::vector<C2Param::Index> const & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const139 virtual c2_status_t query_sm(
140 std::vector<C2Param*> const& stackParams,
141 std::vector<C2Param::Index> const& heapParamIndices,
142 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
143 return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
144 }
145
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const146 virtual c2_status_t querySupportedParams_nb(
147 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
148 return mClient->querySupportedParams(params);
149 }
150
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const151 virtual c2_status_t querySupportedValues_sm(
152 std::vector<C2FieldSupportedValuesQuery>& fields) const {
153 return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
154 }
155
getName() const156 virtual C2String getName() const {
157 return mClient->getName();
158 }
159
getParamReflector() const160 virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
161 return mClient->getParamReflector();
162 }
163
listComponents()164 virtual std::vector<std::shared_ptr<C2Component::Traits const>> listComponents() {
165 return std::vector<std::shared_ptr<C2Component::Traits const>>();
166 }
167 };
168
169 } // unnamed namespace
170
171 // This class caches a Codec2Client object and its component traits. The client
172 // will be created the first time it is needed, and it can be refreshed if the
173 // service dies (by calling invalidate()). The first time listComponents() is
174 // called from the client, the result will be cached.
175 class Codec2Client::Cache {
176 // Cached client
177 std::shared_ptr<Codec2Client> mClient;
178 mutable std::mutex mClientMutex;
179
180 // Cached component traits
181 std::vector<C2Component::Traits> mTraits;
182 std::once_flag mTraitsInitializationFlag;
183
184 // The index of the service. This is based on GetServiceNames().
185 size_t mIndex;
186 // Called by s() exactly once to initialize the cache. The index must be a
187 // valid index into the vector returned by GetServiceNames(). Calling
188 // init(index) will associate the cache to the service with name
189 // GetServiceNames()[index].
init(size_t index)190 void init(size_t index) {
191 mIndex = index;
192 }
193
194 public:
195 Cache() = default;
196
197 // Initializes mClient if needed, then returns mClient.
198 // If the service is unavailable but listed in the manifest, this function
199 // will block indefinitely.
getClient()200 std::shared_ptr<Codec2Client> getClient() {
201 std::scoped_lock lock{mClientMutex};
202 if (!mClient) {
203 mClient = Codec2Client::_CreateFromIndex(mIndex);
204 }
205 CHECK(mClient) << "Failed to create Codec2Client to service \""
206 << GetServiceNames()[mIndex] << "\". (Index = "
207 << mIndex << ").";
208 return mClient;
209 }
210
211 // Causes a subsequent call to getClient() to create a new client. This
212 // function should be called after the service dies.
213 //
214 // Note: This function is called only by ForAllServices().
invalidate()215 void invalidate() {
216 std::scoped_lock lock{mClientMutex};
217 mClient = nullptr;
218 }
219
220 // Returns a list of traits for components supported by the service. This
221 // list is cached.
getTraits()222 std::vector<C2Component::Traits> const& getTraits() {
223 std::call_once(mTraitsInitializationFlag, [this]() {
224 bool success{false};
225 // Spin until _listComponents() is successful.
226 while (true) {
227 std::shared_ptr<Codec2Client> client = getClient();
228 mTraits = client->_listComponents(&success);
229 if (success) {
230 break;
231 }
232 invalidate();
233 using namespace std::chrono_literals;
234 static constexpr auto kServiceRetryPeriod = 5s;
235 LOG(INFO) << "Failed to retrieve component traits from service "
236 "\"" << GetServiceNames()[mIndex] << "\". "
237 "Retrying...";
238 std::this_thread::sleep_for(kServiceRetryPeriod);
239 }
240 });
241 return mTraits;
242 }
243
244 // List() returns the list of all caches.
List()245 static std::vector<Cache>& List() {
246 static std::vector<Cache> sCaches{[]() {
247 size_t numServices = GetServiceNames().size();
248 std::vector<Cache> caches(numServices);
249 for (size_t i = 0; i < numServices; ++i) {
250 caches[i].init(i);
251 }
252 return caches;
253 }()};
254 return sCaches;
255 }
256 };
257
258 // Codec2ConfigurableClient
259
getName() const260 const C2String& Codec2ConfigurableClient::getName() const {
261 return mName;
262 }
263
Codec2ConfigurableClient(const sp<IConfigurable> & base)264 Codec2ConfigurableClient::Codec2ConfigurableClient(
265 const sp<IConfigurable>& base)
266 : mBase{base},
__anon8dea2f180402() 267 mName{[base]() -> C2String {
268 C2String outName;
269 Return<void> transStatus = base->getName(
270 [&outName](const hidl_string& name) {
271 outName = name.c_str();
272 });
273 return transStatus.isOk() ? outName : "";
274 }()} {
275 }
276
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const277 c2_status_t Codec2ConfigurableClient::query(
278 const std::vector<C2Param*> &stackParams,
279 const std::vector<C2Param::Index> &heapParamIndices,
280 c2_blocking_t mayBlock,
281 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
282 hidl_vec<ParamIndex> indices(
283 stackParams.size() + heapParamIndices.size());
284 size_t numIndices = 0;
285 for (C2Param* const& stackParam : stackParams) {
286 if (!stackParam) {
287 LOG(WARNING) << "query -- null stack param encountered.";
288 continue;
289 }
290 indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
291 }
292 size_t numStackIndices = numIndices;
293 for (const C2Param::Index& index : heapParamIndices) {
294 indices[numIndices++] =
295 static_cast<ParamIndex>(static_cast<uint32_t>(index));
296 }
297 indices.resize(numIndices);
298 if (heapParams) {
299 heapParams->reserve(heapParams->size() + numIndices);
300 }
301 c2_status_t status;
302 Return<void> transStatus = mBase->query(
303 indices,
304 mayBlock == C2_MAY_BLOCK,
305 [&status, &numStackIndices, &stackParams, heapParams](
306 Status s, const Params& p) {
307 status = static_cast<c2_status_t>(s);
308 if (status != C2_OK && status != C2_BAD_INDEX) {
309 LOG(DEBUG) << "query -- call failed: "
310 << status << ".";
311 return;
312 }
313 std::vector<C2Param*> paramPointers;
314 if (!parseParamsBlob(¶mPointers, p)) {
315 LOG(ERROR) << "query -- error while parsing params.";
316 status = C2_CORRUPTED;
317 return;
318 }
319 size_t i = 0;
320 for (auto it = paramPointers.begin();
321 it != paramPointers.end(); ) {
322 C2Param* paramPointer = *it;
323 if (numStackIndices > 0) {
324 --numStackIndices;
325 if (!paramPointer) {
326 LOG(WARNING) << "query -- null stack param.";
327 ++it;
328 continue;
329 }
330 for (; i < stackParams.size() && !stackParams[i]; ) {
331 ++i;
332 }
333 if (i >= stackParams.size()) {
334 LOG(ERROR) << "query -- unexpected error.";
335 status = C2_CORRUPTED;
336 return;
337 }
338 if (stackParams[i]->index() != paramPointer->index()) {
339 LOG(WARNING) << "query -- param skipped: "
340 "index = "
341 << stackParams[i]->index() << ".";
342 stackParams[i++]->invalidate();
343 continue;
344 }
345 if (!stackParams[i++]->updateFrom(*paramPointer)) {
346 LOG(WARNING) << "query -- param update failed: "
347 "index = "
348 << paramPointer->index() << ".";
349 }
350 } else {
351 if (!paramPointer) {
352 LOG(WARNING) << "query -- null heap param.";
353 ++it;
354 continue;
355 }
356 if (!heapParams) {
357 LOG(WARNING) << "query -- "
358 "unexpected extra stack param.";
359 } else {
360 heapParams->emplace_back(
361 C2Param::Copy(*paramPointer));
362 }
363 }
364 ++it;
365 }
366 });
367 if (!transStatus.isOk()) {
368 LOG(ERROR) << "query -- transaction failed.";
369 return C2_TRANSACTION_FAILED;
370 }
371 return status;
372 }
373
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)374 c2_status_t Codec2ConfigurableClient::config(
375 const std::vector<C2Param*> ¶ms,
376 c2_blocking_t mayBlock,
377 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
378 Params hidlParams;
379 if (!createParamsBlob(&hidlParams, params)) {
380 LOG(ERROR) << "config -- bad input.";
381 return C2_TRANSACTION_FAILED;
382 }
383 c2_status_t status;
384 Return<void> transStatus = mBase->config(
385 hidlParams,
386 mayBlock == C2_MAY_BLOCK,
387 [&status, ¶ms, failures](
388 Status s,
389 const hidl_vec<SettingResult> f,
390 const Params& o) {
391 status = static_cast<c2_status_t>(s);
392 if (status != C2_OK && status != C2_BAD_INDEX) {
393 LOG(DEBUG) << "config -- call failed: "
394 << status << ".";
395 }
396 size_t i = failures->size();
397 failures->resize(i + f.size());
398 for (const SettingResult& sf : f) {
399 if (!objcpy(&(*failures)[i++], sf)) {
400 LOG(ERROR) << "config -- "
401 << "invalid SettingResult returned.";
402 return;
403 }
404 }
405 if (!updateParamsFromBlob(params, o)) {
406 LOG(ERROR) << "config -- "
407 << "failed to parse returned params.";
408 status = C2_CORRUPTED;
409 }
410 });
411 if (!transStatus.isOk()) {
412 LOG(ERROR) << "config -- transaction failed.";
413 return C2_TRANSACTION_FAILED;
414 }
415 return status;
416 }
417
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const418 c2_status_t Codec2ConfigurableClient::querySupportedParams(
419 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
420 // TODO: Cache and query properly!
421 c2_status_t status;
422 Return<void> transStatus = mBase->querySupportedParams(
423 std::numeric_limits<uint32_t>::min(),
424 std::numeric_limits<uint32_t>::max(),
425 [&status, params](
426 Status s,
427 const hidl_vec<ParamDescriptor>& p) {
428 status = static_cast<c2_status_t>(s);
429 if (status != C2_OK) {
430 LOG(DEBUG) << "querySupportedParams -- call failed: "
431 << status << ".";
432 return;
433 }
434 size_t i = params->size();
435 params->resize(i + p.size());
436 for (const ParamDescriptor& sp : p) {
437 if (!objcpy(&(*params)[i++], sp)) {
438 LOG(ERROR) << "querySupportedParams -- "
439 << "invalid returned ParamDescriptor.";
440 return;
441 }
442 }
443 });
444 if (!transStatus.isOk()) {
445 LOG(ERROR) << "querySupportedParams -- transaction failed.";
446 return C2_TRANSACTION_FAILED;
447 }
448 return status;
449 }
450
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const451 c2_status_t Codec2ConfigurableClient::querySupportedValues(
452 std::vector<C2FieldSupportedValuesQuery>& fields,
453 c2_blocking_t mayBlock) const {
454 hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
455 for (size_t i = 0; i < fields.size(); ++i) {
456 if (!objcpy(&inFields[i], fields[i])) {
457 LOG(ERROR) << "querySupportedValues -- bad input";
458 return C2_TRANSACTION_FAILED;
459 }
460 }
461
462 c2_status_t status;
463 Return<void> transStatus = mBase->querySupportedValues(
464 inFields,
465 mayBlock == C2_MAY_BLOCK,
466 [&status, &inFields, &fields](
467 Status s,
468 const hidl_vec<FieldSupportedValuesQueryResult>& r) {
469 status = static_cast<c2_status_t>(s);
470 if (status != C2_OK) {
471 LOG(DEBUG) << "querySupportedValues -- call failed: "
472 << status << ".";
473 return;
474 }
475 if (r.size() != fields.size()) {
476 LOG(ERROR) << "querySupportedValues -- "
477 "input and output lists "
478 "have different sizes.";
479 status = C2_CORRUPTED;
480 return;
481 }
482 for (size_t i = 0; i < fields.size(); ++i) {
483 if (!objcpy(&fields[i], inFields[i], r[i])) {
484 LOG(ERROR) << "querySupportedValues -- "
485 "invalid returned value.";
486 status = C2_CORRUPTED;
487 return;
488 }
489 }
490 });
491 if (!transStatus.isOk()) {
492 LOG(ERROR) << "querySupportedValues -- transaction failed.";
493 return C2_TRANSACTION_FAILED;
494 }
495 return status;
496 }
497
498 // Codec2Client::Component::HidlListener
499 struct Codec2Client::Component::HidlListener : public IComponentListener {
500 std::weak_ptr<Component> component;
501 std::weak_ptr<Listener> base;
502
onWorkDoneandroid::Codec2Client::Component::HidlListener503 virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
504 std::list<std::unique_ptr<C2Work>> workItems;
505 if (!objcpy(&workItems, workBundle)) {
506 LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
507 return Void();
508 }
509 // release input buffers potentially held by the component from queue
510 std::shared_ptr<Codec2Client::Component> strongComponent =
511 component.lock();
512 if (strongComponent) {
513 strongComponent->handleOnWorkDone(workItems);
514 }
515 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
516 listener->onWorkDone(component, workItems);
517 } else {
518 LOG(DEBUG) << "onWorkDone -- listener died.";
519 }
520 return Void();
521 }
522
onTrippedandroid::Codec2Client::Component::HidlListener523 virtual Return<void> onTripped(
524 const hidl_vec<SettingResult>& settingResults) override {
525 std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
526 settingResults.size());
527 for (size_t i = 0; i < settingResults.size(); ++i) {
528 std::unique_ptr<C2SettingResult> c2SettingResult;
529 if (!objcpy(&c2SettingResult, settingResults[i])) {
530 LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
531 return Void();
532 }
533 c2SettingResults[i] = std::move(c2SettingResult);
534 }
535 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
536 listener->onTripped(component, c2SettingResults);
537 } else {
538 LOG(DEBUG) << "onTripped -- listener died.";
539 }
540 return Void();
541 }
542
onErrorandroid::Codec2Client::Component::HidlListener543 virtual Return<void> onError(Status s, uint32_t errorCode) override {
544 LOG(DEBUG) << "onError --"
545 << " status = " << s
546 << ", errorCode = " << errorCode
547 << ".";
548 if (std::shared_ptr<Listener> listener = base.lock()) {
549 listener->onError(component, s == Status::OK ?
550 errorCode : static_cast<c2_status_t>(s));
551 } else {
552 LOG(DEBUG) << "onError -- listener died.";
553 }
554 return Void();
555 }
556
onFramesRenderedandroid::Codec2Client::Component::HidlListener557 virtual Return<void> onFramesRendered(
558 const hidl_vec<RenderedFrame>& renderedFrames) override {
559 std::shared_ptr<Listener> listener = base.lock();
560 if (!listener) {
561 LOG(DEBUG) << "onFramesRendered -- listener died.";
562 return Void();
563 }
564 for (const RenderedFrame& renderedFrame : renderedFrames) {
565 listener->onFrameRendered(
566 renderedFrame.bufferQueueId,
567 renderedFrame.slotId,
568 renderedFrame.timestampNs);
569 }
570 return Void();
571 }
572
onInputBuffersReleasedandroid::Codec2Client::Component::HidlListener573 virtual Return<void> onInputBuffersReleased(
574 const hidl_vec<InputBuffer>& inputBuffers) override {
575 std::shared_ptr<Listener> listener = base.lock();
576 if (!listener) {
577 LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
578 return Void();
579 }
580 for (const InputBuffer& inputBuffer : inputBuffers) {
581 LOG(VERBOSE) << "onInputBuffersReleased --"
582 " received death notification of"
583 " input buffer:"
584 " frameIndex = " << inputBuffer.frameIndex
585 << ", bufferIndex = " << inputBuffer.arrayIndex
586 << ".";
587 listener->onInputBufferDone(
588 inputBuffer.frameIndex, inputBuffer.arrayIndex);
589 }
590 return Void();
591 }
592
593 };
594
595 // Codec2Client::Component::BufferPoolSender
596 struct Codec2Client::Component::BufferPoolSender :
597 hardware::media::c2::V1_1::utils::DefaultBufferPoolSender {
BufferPoolSenderandroid::Codec2Client::Component::BufferPoolSender598 BufferPoolSender()
599 : hardware::media::c2::V1_1::utils::DefaultBufferPoolSender() {
600 }
601 };
602
603 // Codec2Client::Component::OutputBufferQueue
604 struct Codec2Client::Component::OutputBufferQueue :
605 hardware::media::c2::OutputBufferQueue {
OutputBufferQueueandroid::Codec2Client::Component::OutputBufferQueue606 OutputBufferQueue()
607 : hardware::media::c2::OutputBufferQueue() {
608 }
609 };
610
611 // Codec2Client
Codec2Client(sp<Base> const & base,size_t serviceIndex)612 Codec2Client::Codec2Client(sp<Base> const& base,
613 size_t serviceIndex)
614 : Configurable{
615 [base]() -> sp<IConfigurable> {
616 Return<sp<IConfigurable>> transResult =
617 base->getConfigurable();
618 return transResult.isOk() ?
619 static_cast<sp<IConfigurable>>(transResult) :
620 nullptr;
621 }()
622 },
623 mBase1_0{base},
624 mBase1_1{Base1_1::castFrom(base)},
625 mBase1_2{Base1_2::castFrom(base)},
626 mServiceIndex{serviceIndex} {
627 Return<sp<IClientManager>> transResult = base->getPoolClientManager();
628 if (!transResult.isOk()) {
629 LOG(ERROR) << "getPoolClientManager -- transaction failed.";
630 } else {
631 mHostPoolManager = static_cast<sp<IClientManager>>(transResult);
632 }
633 }
634
getBase() const635 sp<Codec2Client::Base> const& Codec2Client::getBase() const {
636 return mBase1_0;
637 }
638
getBase1_0() const639 sp<Codec2Client::Base1_0> const& Codec2Client::getBase1_0() const {
640 return mBase1_0;
641 }
642
getBase1_1() const643 sp<Codec2Client::Base1_1> const& Codec2Client::getBase1_1() const {
644 return mBase1_1;
645 }
646
getBase1_2() const647 sp<Codec2Client::Base1_2> const& Codec2Client::getBase1_2() const {
648 return mBase1_2;
649 }
650
getServiceName() const651 std::string const& Codec2Client::getServiceName() const {
652 return GetServiceNames()[mServiceIndex];
653 }
654
createComponent(const C2String & name,const std::shared_ptr<Codec2Client::Listener> & listener,std::shared_ptr<Codec2Client::Component> * const component)655 c2_status_t Codec2Client::createComponent(
656 const C2String& name,
657 const std::shared_ptr<Codec2Client::Listener>& listener,
658 std::shared_ptr<Codec2Client::Component>* const component) {
659
660 c2_status_t status;
661 sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
662 hidlListener->base = listener;
663 Return<void> transStatus;
664 if (mBase1_2) {
665 transStatus = mBase1_2->createComponent_1_2(
666 name,
667 hidlListener,
668 ClientManager::getInstance(),
669 [&status, component, hidlListener](
670 Status s,
671 const sp<IComponent>& c) {
672 status = static_cast<c2_status_t>(s);
673 if (status != C2_OK) {
674 return;
675 }
676 *component = std::make_shared<Codec2Client::Component>(c);
677 hidlListener->component = *component;
678 });
679 }
680 else if (mBase1_1) {
681 transStatus = mBase1_1->createComponent_1_1(
682 name,
683 hidlListener,
684 ClientManager::getInstance(),
685 [&status, component, hidlListener](
686 Status s,
687 const sp<IComponent>& c) {
688 status = static_cast<c2_status_t>(s);
689 if (status != C2_OK) {
690 return;
691 }
692 *component = std::make_shared<Codec2Client::Component>(c);
693 hidlListener->component = *component;
694 });
695 } else if (mBase1_0) { // ver1_0
696 transStatus = mBase1_0->createComponent(
697 name,
698 hidlListener,
699 ClientManager::getInstance(),
700 [&status, component, hidlListener](
701 Status s,
702 const sp<hardware::media::c2::V1_0::IComponent>& c) {
703 status = static_cast<c2_status_t>(s);
704 if (status != C2_OK) {
705 return;
706 }
707 *component = std::make_shared<Codec2Client::Component>(c);
708 hidlListener->component = *component;
709 });
710 } else {
711 status = C2_CORRUPTED;
712 }
713 if (!transStatus.isOk()) {
714 LOG(ERROR) << "createComponent(" << name.c_str()
715 << ") -- transaction failed.";
716 return C2_TRANSACTION_FAILED;
717 } else if (status != C2_OK) {
718 if (status == C2_NOT_FOUND) {
719 LOG(VERBOSE) << "createComponent(" << name.c_str()
720 << ") -- component not found.";
721 } else {
722 LOG(ERROR) << "createComponent(" << name.c_str()
723 << ") -- call failed: " << status << ".";
724 }
725 return status;
726 } else if (!*component) {
727 LOG(ERROR) << "createComponent(" << name.c_str()
728 << ") -- null component.";
729 return C2_CORRUPTED;
730 }
731
732 status = (*component)->setDeathListener(*component, listener);
733 if (status != C2_OK) {
734 LOG(ERROR) << "createComponent(" << name.c_str()
735 << ") -- failed to set up death listener: "
736 << status << ".";
737 }
738
739 (*component)->mBufferPoolSender->setReceiver(mHostPoolManager);
740 return status;
741 }
742
createInterface(const C2String & name,std::shared_ptr<Codec2Client::Interface> * const interface)743 c2_status_t Codec2Client::createInterface(
744 const C2String& name,
745 std::shared_ptr<Codec2Client::Interface>* const interface) {
746 c2_status_t status;
747 Return<void> transStatus = mBase1_0->createInterface(
748 name,
749 [&status, interface](
750 Status s,
751 const sp<IComponentInterface>& i) {
752 status = static_cast<c2_status_t>(s);
753 if (status != C2_OK) {
754 return;
755 }
756 *interface = std::make_shared<Interface>(i);
757 });
758 if (!transStatus.isOk()) {
759 LOG(ERROR) << "createInterface(" << name.c_str()
760 << ") -- transaction failed.";
761 return C2_TRANSACTION_FAILED;
762 } else if (status != C2_OK) {
763 if (status == C2_NOT_FOUND) {
764 LOG(VERBOSE) << "createInterface(" << name.c_str()
765 << ") -- component not found.";
766 } else {
767 LOG(ERROR) << "createInterface(" << name.c_str()
768 << ") -- call failed: " << status << ".";
769 }
770 return status;
771 }
772
773 return status;
774 }
775
createInputSurface(std::shared_ptr<InputSurface> * const inputSurface)776 c2_status_t Codec2Client::createInputSurface(
777 std::shared_ptr<InputSurface>* const inputSurface) {
778 c2_status_t status;
779 Return<void> transStatus = mBase1_0->createInputSurface(
780 [&status, inputSurface](
781 Status s,
782 const sp<IInputSurface>& i) {
783 status = static_cast<c2_status_t>(s);
784 if (status != C2_OK) {
785 return;
786 }
787 *inputSurface = std::make_shared<InputSurface>(i);
788 });
789 if (!transStatus.isOk()) {
790 LOG(ERROR) << "createInputSurface -- transaction failed.";
791 return C2_TRANSACTION_FAILED;
792 } else if (status != C2_OK) {
793 LOG(DEBUG) << "createInputSurface -- call failed: "
794 << status << ".";
795 }
796 return status;
797 }
798
listComponents() const799 std::vector<C2Component::Traits> const& Codec2Client::listComponents() const {
800 return Cache::List()[mServiceIndex].getTraits();
801 }
802
_listComponents(bool * success) const803 std::vector<C2Component::Traits> Codec2Client::_listComponents(
804 bool* success) const {
805 std::vector<C2Component::Traits> traits;
806 std::string const& serviceName = getServiceName();
807 Return<void> transStatus = mBase1_0->listComponents(
808 [&traits, &serviceName](Status s,
809 const hidl_vec<IComponentStore::ComponentTraits>& t) {
810 if (s != Status::OK) {
811 LOG(DEBUG) << "_listComponents -- call failed: "
812 << static_cast<c2_status_t>(s) << ".";
813 return;
814 }
815 traits.resize(t.size());
816 for (size_t i = 0; i < t.size(); ++i) {
817 if (!objcpy(&traits[i], t[i])) {
818 LOG(ERROR) << "_listComponents -- corrupted output.";
819 return;
820 }
821 traits[i].owner = serviceName;
822 }
823 });
824 if (!transStatus.isOk()) {
825 LOG(ERROR) << "_listComponents -- transaction failed.";
826 *success = false;
827 } else {
828 *success = true;
829 }
830 return traits;
831 }
832
copyBuffer(const std::shared_ptr<C2Buffer> & src,const std::shared_ptr<C2Buffer> & dst)833 c2_status_t Codec2Client::copyBuffer(
834 const std::shared_ptr<C2Buffer>& src,
835 const std::shared_ptr<C2Buffer>& dst) {
836 // TODO: Implement?
837 (void)src;
838 (void)dst;
839 LOG(ERROR) << "copyBuffer not implemented";
840 return C2_OMITTED;
841 }
842
843 std::shared_ptr<C2ParamReflector>
getParamReflector()844 Codec2Client::getParamReflector() {
845 // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it
846 // should reflect the HAL API.
847 struct SimpleParamReflector : public C2ParamReflector {
848 virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const {
849 hidl_vec<ParamIndex> indices(1);
850 indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
851 std::unique_ptr<C2StructDescriptor> descriptor;
852 Return<void> transStatus = mBase->getStructDescriptors(
853 indices,
854 [&descriptor](
855 Status s,
856 const hidl_vec<StructDescriptor>& sd) {
857 c2_status_t status = static_cast<c2_status_t>(s);
858 if (status != C2_OK) {
859 LOG(DEBUG) << "SimpleParamReflector -- "
860 "getStructDescriptors() failed: "
861 << status << ".";
862 descriptor.reset();
863 return;
864 }
865 if (sd.size() != 1) {
866 LOG(DEBUG) << "SimpleParamReflector -- "
867 "getStructDescriptors() "
868 "returned vector of size "
869 << sd.size() << ". "
870 "It should be 1.";
871 descriptor.reset();
872 return;
873 }
874 if (!objcpy(&descriptor, sd[0])) {
875 LOG(DEBUG) << "SimpleParamReflector -- "
876 "getStructDescriptors() returned "
877 "corrupted data.";
878 descriptor.reset();
879 return;
880 }
881 });
882 if (!transStatus.isOk()) {
883 LOG(DEBUG) << "SimpleParamReflector -- transaction failed: "
884 << transStatus.description();
885 descriptor.reset();
886 }
887 return descriptor;
888 }
889
890 SimpleParamReflector(sp<Base> base)
891 : mBase(base) { }
892
893 sp<Base> mBase;
894 };
895
896 return std::make_shared<SimpleParamReflector>(mBase1_0);
897 };
898
GetServiceNames()899 std::vector<std::string> const& Codec2Client::GetServiceNames() {
900 static std::vector<std::string> sServiceNames{[]() {
901 using ::android::hardware::media::c2::V1_0::IComponentStore;
902 using ::android::hidl::manager::V1_2::IServiceManager;
903
904 while (true) {
905 sp<IServiceManager> serviceManager = IServiceManager::getService();
906 CHECK(serviceManager) << "Hardware service manager is not running.";
907
908 // There are three categories of services based on names.
909 std::vector<std::string> defaultNames; // Prefixed with "default"
910 std::vector<std::string> vendorNames; // Prefixed with "vendor"
911 std::vector<std::string> otherNames; // Others
912 Return<void> transResult;
913 transResult = serviceManager->listManifestByInterface(
914 IComponentStore::descriptor,
915 [&defaultNames, &vendorNames, &otherNames](
916 hidl_vec<hidl_string> const& instanceNames) {
917 for (hidl_string const& instanceName : instanceNames) {
918 char const* name = instanceName.c_str();
919 if (strncmp(name, "default", 7) == 0) {
920 defaultNames.emplace_back(name);
921 } else if (strncmp(name, "vendor", 6) == 0) {
922 vendorNames.emplace_back(name);
923 } else {
924 otherNames.emplace_back(name);
925 }
926 }
927 });
928 if (transResult.isOk()) {
929 // Sort service names in each category.
930 std::sort(defaultNames.begin(), defaultNames.end());
931 std::sort(vendorNames.begin(), vendorNames.end());
932 std::sort(otherNames.begin(), otherNames.end());
933
934 // Concatenate the three lists in this order: default, vendor,
935 // other.
936 std::vector<std::string>& names = defaultNames;
937 names.reserve(names.size() + vendorNames.size() + otherNames.size());
938 names.insert(names.end(),
939 std::make_move_iterator(vendorNames.begin()),
940 std::make_move_iterator(vendorNames.end()));
941 names.insert(names.end(),
942 std::make_move_iterator(otherNames.begin()),
943 std::make_move_iterator(otherNames.end()));
944
945 // Summarize to logcat.
946 if (names.empty()) {
947 LOG(INFO) << "No Codec2 services declared in the manifest.";
948 } else {
949 std::stringstream stringOutput;
950 stringOutput << "Available Codec2 services:";
951 for (std::string const& name : names) {
952 stringOutput << " \"" << name << "\"";
953 }
954 LOG(INFO) << stringOutput.str();
955 }
956
957 return names;
958 }
959 LOG(ERROR) << "Could not retrieve the list of service instances of "
960 << IComponentStore::descriptor
961 << ". Retrying...";
962 }
963 }()};
964 return sServiceNames;
965 }
966
CreateFromService(const char * name,bool setAsPreferredCodec2ComponentStore)967 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
968 const char* name,
969 bool setAsPreferredCodec2ComponentStore) {
970 size_t index = getServiceIndex(name);
971 if (index == GetServiceNames().size()) {
972 if (setAsPreferredCodec2ComponentStore) {
973 LOG(WARNING) << "CreateFromService(" << name
974 << ") -- preferred C2ComponentStore not set.";
975 }
976 return nullptr;
977 }
978 std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);
979 if (setAsPreferredCodec2ComponentStore) {
980 SetPreferredCodec2ComponentStore(
981 std::make_shared<Client2Store>(client));
982 LOG(INFO) << "CreateFromService(" << name
983 << ") -- service set as preferred C2ComponentStore.";
984 }
985 return client;
986 }
987
988 std::vector<std::shared_ptr<Codec2Client>> Codec2Client::
CreateFromAllServices()989 CreateFromAllServices() {
990 std::vector<std::shared_ptr<Codec2Client>> clients(
991 GetServiceNames().size());
992 for (size_t i = GetServiceNames().size(); i > 0; ) {
993 --i;
994 clients[i] = _CreateFromIndex(i);
995 }
996 return clients;
997 }
998
_CreateFromIndex(size_t index)999 std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
1000 std::string const& name = GetServiceNames()[index];
1001 LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
1002 sp<Base> baseStore = Base::getService(name);
1003 CHECK(baseStore) << "Codec2 service \"" << name << "\""
1004 " inaccessible for unknown reasons.";
1005 LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
1006 return std::make_shared<Codec2Client>(baseStore, index);
1007 }
1008
ForAllServices(const std::string & key,size_t numberOfAttempts,std::function<c2_status_t (const std::shared_ptr<Codec2Client> &)> predicate)1009 c2_status_t Codec2Client::ForAllServices(
1010 const std::string &key,
1011 size_t numberOfAttempts,
1012 std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>
1013 predicate) {
1014 c2_status_t status = C2_NO_INIT; // no IComponentStores present
1015
1016 // Cache the mapping key -> index of Codec2Client in Cache::List().
1017 static std::mutex key2IndexMutex;
1018 static std::map<std::string, size_t> key2Index;
1019
1020 // By default try all stores. However, try the last known client first. If
1021 // the last known client fails, retry once. We do this by pushing the last
1022 // known client in front of the list of all clients.
1023 std::deque<size_t> indices;
1024 for (size_t index = Cache::List().size(); index > 0; ) {
1025 indices.push_front(--index);
1026 }
1027
1028 bool wasMapped = false;
1029 {
1030 std::scoped_lock lock{key2IndexMutex};
1031 auto it = key2Index.find(key);
1032 if (it != key2Index.end()) {
1033 indices.push_front(it->second);
1034 wasMapped = true;
1035 }
1036 }
1037
1038 for (size_t index : indices) {
1039 Cache& cache = Cache::List()[index];
1040 for (size_t tries = numberOfAttempts; tries > 0; --tries) {
1041 std::shared_ptr<Codec2Client> client{cache.getClient()};
1042 status = predicate(client);
1043 if (status == C2_OK) {
1044 std::scoped_lock lock{key2IndexMutex};
1045 key2Index[key] = index; // update last known client index
1046 return C2_OK;
1047 } else if (status == C2_NO_MEMORY) {
1048 return C2_NO_MEMORY;
1049 } else if (status == C2_TRANSACTION_FAILED) {
1050 LOG(WARNING) << "\"" << key << "\" failed for service \""
1051 << client->getName()
1052 << "\" due to transaction failure. "
1053 << "(Service may have crashed.)"
1054 << (tries > 1 ? " Retrying..." : "");
1055 cache.invalidate();
1056 continue;
1057 }
1058 if (wasMapped) {
1059 LOG(INFO) << "\"" << key << "\" became invalid in service \""
1060 << client->getName() << "\". Retrying...";
1061 wasMapped = false;
1062 }
1063 break;
1064 }
1065 }
1066 return status; // return the last status from a valid client
1067 }
1068
CreateComponentByName(const char * componentName,const std::shared_ptr<Listener> & listener,std::shared_ptr<Component> * component,std::shared_ptr<Codec2Client> * owner,size_t numberOfAttempts)1069 c2_status_t Codec2Client::CreateComponentByName(
1070 const char* componentName,
1071 const std::shared_ptr<Listener>& listener,
1072 std::shared_ptr<Component>* component,
1073 std::shared_ptr<Codec2Client>* owner,
1074 size_t numberOfAttempts) {
1075 std::string key{"create:"};
1076 key.append(componentName);
1077 c2_status_t status = ForAllServices(
1078 key,
1079 numberOfAttempts,
1080 [owner, component, componentName, &listener](
1081 const std::shared_ptr<Codec2Client> &client)
1082 -> c2_status_t {
1083 c2_status_t status = client->createComponent(componentName,
1084 listener,
1085 component);
1086 if (status == C2_OK) {
1087 if (owner) {
1088 *owner = client;
1089 }
1090 } else if (status != C2_NOT_FOUND) {
1091 LOG(DEBUG) << "IComponentStore("
1092 << client->getServiceName()
1093 << ")::createComponent(\"" << componentName
1094 << "\") returned status = "
1095 << status << ".";
1096 }
1097 return status;
1098 });
1099 if (status != C2_OK) {
1100 LOG(DEBUG) << "Failed to create component \"" << componentName
1101 << "\" from all known services. "
1102 "Last returned status = " << status << ".";
1103 }
1104 return status;
1105 }
1106
1107 std::shared_ptr<Codec2Client::Interface>
CreateInterfaceByName(const char * interfaceName,std::shared_ptr<Codec2Client> * owner,size_t numberOfAttempts)1108 Codec2Client::CreateInterfaceByName(
1109 const char* interfaceName,
1110 std::shared_ptr<Codec2Client>* owner,
1111 size_t numberOfAttempts) {
1112 std::string key{"create:"};
1113 key.append(interfaceName);
1114 std::shared_ptr<Interface> interface;
1115 c2_status_t status = ForAllServices(
1116 key,
1117 numberOfAttempts,
1118 [owner, &interface, interfaceName](
1119 const std::shared_ptr<Codec2Client> &client)
1120 -> c2_status_t {
1121 c2_status_t status = client->createInterface(interfaceName,
1122 &interface);
1123 if (status == C2_OK) {
1124 if (owner) {
1125 *owner = client;
1126 }
1127 } else if (status != C2_NOT_FOUND) {
1128 LOG(DEBUG) << "IComponentStore("
1129 << client->getServiceName()
1130 << ")::createInterface(\"" << interfaceName
1131 << "\") returned status = "
1132 << status << ".";
1133 }
1134 return status;
1135 });
1136 if (status != C2_OK) {
1137 LOG(DEBUG) << "Failed to create interface \"" << interfaceName
1138 << "\" from all known services. "
1139 "Last returned status = " << status << ".";
1140 }
1141 return interface;
1142 }
1143
ListComponents()1144 std::vector<C2Component::Traits> const& Codec2Client::ListComponents() {
1145 static std::vector<C2Component::Traits> sList{[]() {
1146 std::vector<C2Component::Traits> list;
1147 for (Cache& cache : Cache::List()) {
1148 std::vector<C2Component::Traits> const& traits = cache.getTraits();
1149 list.insert(list.end(), traits.begin(), traits.end());
1150 }
1151 return list;
1152 }()};
1153 return sList;
1154 }
1155
CreateInputSurface(char const * serviceName)1156 std::shared_ptr<Codec2Client::InputSurface> Codec2Client::CreateInputSurface(
1157 char const* serviceName) {
1158 int32_t inputSurfaceSetting = ::android::base::GetIntProperty(
1159 "debug.stagefright.c2inputsurface", int32_t(0));
1160 if (inputSurfaceSetting <= 0) {
1161 return nullptr;
1162 }
1163 size_t index = GetServiceNames().size();
1164 if (serviceName) {
1165 index = getServiceIndex(serviceName);
1166 if (index == GetServiceNames().size()) {
1167 LOG(DEBUG) << "CreateInputSurface -- invalid service name: \""
1168 << serviceName << "\"";
1169 }
1170 }
1171
1172 std::shared_ptr<Codec2Client::InputSurface> inputSurface;
1173 if (index != GetServiceNames().size()) {
1174 std::shared_ptr<Codec2Client> client = Cache::List()[index].getClient();
1175 if (client->createInputSurface(&inputSurface) == C2_OK) {
1176 return inputSurface;
1177 }
1178 }
1179 LOG(INFO) << "CreateInputSurface -- attempting to create an input surface "
1180 "from all services...";
1181 for (Cache& cache : Cache::List()) {
1182 std::shared_ptr<Codec2Client> client = cache.getClient();
1183 if (client->createInputSurface(&inputSurface) == C2_OK) {
1184 LOG(INFO) << "CreateInputSurface -- input surface obtained from "
1185 "service \"" << client->getServiceName() << "\"";
1186 return inputSurface;
1187 }
1188 }
1189 LOG(WARNING) << "CreateInputSurface -- failed to create an input surface "
1190 "from all services";
1191 return nullptr;
1192 }
1193
1194 // Codec2Client::Listener
1195
~Listener()1196 Codec2Client::Listener::~Listener() {
1197 }
1198
1199 // Codec2Client::Interface
Interface(const sp<Base> & base)1200 Codec2Client::Interface::Interface(const sp<Base>& base)
1201 : Configurable{
1202 [base]() -> sp<IConfigurable> {
1203 Return<sp<IConfigurable>> transResult =
1204 base->getConfigurable();
1205 return transResult.isOk() ?
1206 static_cast<sp<IConfigurable>>(transResult) :
1207 nullptr;
1208 }()
1209 },
1210 mBase{base} {
1211 }
1212
1213 // Codec2Client::Component
Component(const sp<Base> & base)1214 Codec2Client::Component::Component(const sp<Base>& base)
1215 : Configurable{
1216 [base]() -> sp<IConfigurable> {
1217 Return<sp<IComponentInterface>> transResult1 =
1218 base->getInterface();
1219 if (!transResult1.isOk()) {
1220 return nullptr;
1221 }
1222 Return<sp<IConfigurable>> transResult2 =
1223 static_cast<sp<IComponentInterface>>(transResult1)->
1224 getConfigurable();
1225 return transResult2.isOk() ?
1226 static_cast<sp<IConfigurable>>(transResult2) :
1227 nullptr;
1228 }()
1229 },
1230 mBase1_0{base},
1231 mBase1_1{Base1_1::castFrom(base)},
1232 mBase1_2{Base1_2::castFrom(base)},
1233 mBufferPoolSender{std::make_unique<BufferPoolSender>()},
1234 mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
1235 }
1236
Component(const sp<Base1_1> & base)1237 Codec2Client::Component::Component(const sp<Base1_1>& base)
1238 : Configurable{
1239 [base]() -> sp<IConfigurable> {
1240 Return<sp<IComponentInterface>> transResult1 =
1241 base->getInterface();
1242 if (!transResult1.isOk()) {
1243 return nullptr;
1244 }
1245 Return<sp<IConfigurable>> transResult2 =
1246 static_cast<sp<IComponentInterface>>(transResult1)->
1247 getConfigurable();
1248 return transResult2.isOk() ?
1249 static_cast<sp<IConfigurable>>(transResult2) :
1250 nullptr;
1251 }()
1252 },
1253 mBase1_0{base},
1254 mBase1_1{base},
1255 mBase1_2{Base1_2::castFrom(base)},
1256 mBufferPoolSender{std::make_unique<BufferPoolSender>()},
1257 mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
1258 }
1259
Component(const sp<Base1_2> & base)1260 Codec2Client::Component::Component(const sp<Base1_2>& base)
1261 : Configurable{
1262 [base]() -> sp<IConfigurable> {
1263 Return<sp<IComponentInterface>> transResult1 =
1264 base->getInterface();
1265 if (!transResult1.isOk()) {
1266 return nullptr;
1267 }
1268 Return<sp<IConfigurable>> transResult2 =
1269 static_cast<sp<IComponentInterface>>(transResult1)->
1270 getConfigurable();
1271 return transResult2.isOk() ?
1272 static_cast<sp<IConfigurable>>(transResult2) :
1273 nullptr;
1274 }()
1275 },
1276 mBase1_0{base},
1277 mBase1_1{base},
1278 mBase1_2{base},
1279 mBufferPoolSender{std::make_unique<BufferPoolSender>()},
1280 mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
1281 }
1282
~Component()1283 Codec2Client::Component::~Component() {
1284 }
1285
createBlockPool(C2Allocator::id_t id,C2BlockPool::local_id_t * blockPoolId,std::shared_ptr<Codec2Client::Configurable> * configurable)1286 c2_status_t Codec2Client::Component::createBlockPool(
1287 C2Allocator::id_t id,
1288 C2BlockPool::local_id_t* blockPoolId,
1289 std::shared_ptr<Codec2Client::Configurable>* configurable) {
1290 c2_status_t status;
1291 Return<void> transStatus = mBase1_0->createBlockPool(
1292 static_cast<uint32_t>(id),
1293 [&status, blockPoolId, configurable](
1294 Status s,
1295 uint64_t pId,
1296 const sp<IConfigurable>& c) {
1297 status = static_cast<c2_status_t>(s);
1298 configurable->reset();
1299 if (status != C2_OK) {
1300 LOG(DEBUG) << "createBlockPool -- call failed: "
1301 << status << ".";
1302 return;
1303 }
1304 *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
1305 *configurable = std::make_shared<Configurable>(c);
1306 });
1307 if (!transStatus.isOk()) {
1308 LOG(ERROR) << "createBlockPool -- transaction failed.";
1309 return C2_TRANSACTION_FAILED;
1310 }
1311 return status;
1312 }
1313
destroyBlockPool(C2BlockPool::local_id_t localId)1314 c2_status_t Codec2Client::Component::destroyBlockPool(
1315 C2BlockPool::local_id_t localId) {
1316 Return<Status> transResult = mBase1_0->destroyBlockPool(
1317 static_cast<uint64_t>(localId));
1318 if (!transResult.isOk()) {
1319 LOG(ERROR) << "destroyBlockPool -- transaction failed.";
1320 return C2_TRANSACTION_FAILED;
1321 }
1322 return static_cast<c2_status_t>(static_cast<Status>(transResult));
1323 }
1324
handleOnWorkDone(const std::list<std::unique_ptr<C2Work>> & workItems)1325 void Codec2Client::Component::handleOnWorkDone(
1326 const std::list<std::unique_ptr<C2Work>> &workItems) {
1327 // Output bufferqueue-based blocks' lifetime management
1328 mOutputBufferQueue->holdBufferQueueBlocks(workItems);
1329 }
1330
queue(std::list<std::unique_ptr<C2Work>> * const items)1331 c2_status_t Codec2Client::Component::queue(
1332 std::list<std::unique_ptr<C2Work>>* const items) {
1333 WorkBundle workBundle;
1334 if (!objcpy(&workBundle, *items, mBufferPoolSender.get())) {
1335 LOG(ERROR) << "queue -- bad input.";
1336 return C2_TRANSACTION_FAILED;
1337 }
1338 Return<Status> transStatus = mBase1_0->queue(workBundle);
1339 if (!transStatus.isOk()) {
1340 LOG(ERROR) << "queue -- transaction failed.";
1341 return C2_TRANSACTION_FAILED;
1342 }
1343 c2_status_t status =
1344 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1345 if (status != C2_OK) {
1346 LOG(DEBUG) << "queue -- call failed: " << status << ".";
1347 }
1348 return status;
1349 }
1350
flush(C2Component::flush_mode_t mode,std::list<std::unique_ptr<C2Work>> * const flushedWork)1351 c2_status_t Codec2Client::Component::flush(
1352 C2Component::flush_mode_t mode,
1353 std::list<std::unique_ptr<C2Work>>* const flushedWork) {
1354 (void)mode; // Flush mode isn't supported in HIDL yet.
1355 c2_status_t status;
1356 Return<void> transStatus = mBase1_0->flush(
1357 [&status, flushedWork](
1358 Status s, const WorkBundle& wb) {
1359 status = static_cast<c2_status_t>(s);
1360 if (status != C2_OK) {
1361 LOG(DEBUG) << "flush -- call failed: " << status << ".";
1362 return;
1363 }
1364 if (!objcpy(flushedWork, wb)) {
1365 status = C2_CORRUPTED;
1366 } else {
1367 status = C2_OK;
1368 }
1369 });
1370 if (!transStatus.isOk()) {
1371 LOG(ERROR) << "flush -- transaction failed.";
1372 return C2_TRANSACTION_FAILED;
1373 }
1374
1375 // Indices of flushed work items.
1376 std::vector<uint64_t> flushedIndices;
1377 for (const std::unique_ptr<C2Work> &work : *flushedWork) {
1378 if (work) {
1379 if (work->worklets.empty()
1380 || !work->worklets.back()
1381 || (work->worklets.back()->output.flags &
1382 C2FrameData::FLAG_INCOMPLETE) == 0) {
1383 // input is complete
1384 flushedIndices.emplace_back(
1385 work->input.ordinal.frameIndex.peeku());
1386 }
1387 }
1388 }
1389
1390 // Output bufferqueue-based blocks' lifetime management
1391 mOutputBufferQueue->holdBufferQueueBlocks(*flushedWork);
1392
1393 return status;
1394 }
1395
drain(C2Component::drain_mode_t mode)1396 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
1397 Return<Status> transStatus = mBase1_0->drain(
1398 mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
1399 if (!transStatus.isOk()) {
1400 LOG(ERROR) << "drain -- transaction failed.";
1401 return C2_TRANSACTION_FAILED;
1402 }
1403 c2_status_t status =
1404 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1405 if (status != C2_OK) {
1406 LOG(DEBUG) << "drain -- call failed: " << status << ".";
1407 }
1408 return status;
1409 }
1410
start()1411 c2_status_t Codec2Client::Component::start() {
1412 Return<Status> transStatus = mBase1_0->start();
1413 if (!transStatus.isOk()) {
1414 LOG(ERROR) << "start -- transaction failed.";
1415 return C2_TRANSACTION_FAILED;
1416 }
1417 c2_status_t status =
1418 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1419 if (status != C2_OK) {
1420 LOG(DEBUG) << "start -- call failed: " << status << ".";
1421 }
1422 return status;
1423 }
1424
stop()1425 c2_status_t Codec2Client::Component::stop() {
1426 Return<Status> transStatus = mBase1_0->stop();
1427 if (!transStatus.isOk()) {
1428 LOG(ERROR) << "stop -- transaction failed.";
1429 return C2_TRANSACTION_FAILED;
1430 }
1431 c2_status_t status =
1432 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1433 if (status != C2_OK) {
1434 LOG(DEBUG) << "stop -- call failed: " << status << ".";
1435 }
1436 return status;
1437 }
1438
reset()1439 c2_status_t Codec2Client::Component::reset() {
1440 Return<Status> transStatus = mBase1_0->reset();
1441 if (!transStatus.isOk()) {
1442 LOG(ERROR) << "reset -- transaction failed.";
1443 return C2_TRANSACTION_FAILED;
1444 }
1445 c2_status_t status =
1446 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1447 if (status != C2_OK) {
1448 LOG(DEBUG) << "reset -- call failed: " << status << ".";
1449 }
1450 return status;
1451 }
1452
release()1453 c2_status_t Codec2Client::Component::release() {
1454 Return<Status> transStatus = mBase1_0->release();
1455 if (!transStatus.isOk()) {
1456 LOG(ERROR) << "release -- transaction failed.";
1457 return C2_TRANSACTION_FAILED;
1458 }
1459 c2_status_t status =
1460 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1461 if (status != C2_OK) {
1462 LOG(DEBUG) << "release -- call failed: " << status << ".";
1463 }
1464 return status;
1465 }
1466
configureVideoTunnel(uint32_t avSyncHwId,native_handle_t ** sidebandHandle)1467 c2_status_t Codec2Client::Component::configureVideoTunnel(
1468 uint32_t avSyncHwId,
1469 native_handle_t** sidebandHandle) {
1470 *sidebandHandle = nullptr;
1471 if (!mBase1_1) {
1472 return C2_OMITTED;
1473 }
1474 c2_status_t status{};
1475 Return<void> transStatus = mBase1_1->configureVideoTunnel(avSyncHwId,
1476 [&status, sidebandHandle](
1477 Status s, hardware::hidl_handle const& h) {
1478 status = static_cast<c2_status_t>(s);
1479 if (h.getNativeHandle()) {
1480 *sidebandHandle = native_handle_clone(h.getNativeHandle());
1481 }
1482 });
1483 if (!transStatus.isOk()) {
1484 LOG(ERROR) << "configureVideoTunnel -- transaction failed.";
1485 return C2_TRANSACTION_FAILED;
1486 }
1487 return status;
1488 }
1489
setOutputSurface(C2BlockPool::local_id_t blockPoolId,const sp<IGraphicBufferProducer> & surface,uint32_t generation,int maxDequeueCount)1490 c2_status_t Codec2Client::Component::setOutputSurface(
1491 C2BlockPool::local_id_t blockPoolId,
1492 const sp<IGraphicBufferProducer>& surface,
1493 uint32_t generation,
1494 int maxDequeueCount) {
1495 uint64_t bqId = 0;
1496 sp<IGraphicBufferProducer> nullIgbp;
1497 sp<HGraphicBufferProducer2> nullHgbp;
1498
1499 sp<HGraphicBufferProducer2> igbp = surface ?
1500 surface->getHalInterface<HGraphicBufferProducer2>() : nullHgbp;
1501 if (surface && !igbp) {
1502 igbp = new B2HGraphicBufferProducer2(surface);
1503 }
1504
1505 std::shared_ptr<SurfaceSyncObj> syncObj;
1506
1507 if (!surface) {
1508 mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
1509 } else if (surface->getUniqueId(&bqId) != OK) {
1510 LOG(ERROR) << "setOutputSurface -- "
1511 "cannot obtain bufferqueue id.";
1512 bqId = 0;
1513 mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
1514 } else {
1515 mOutputBufferQueue->configure(surface, generation, bqId, maxDequeueCount, mBase1_2 ?
1516 &syncObj : nullptr);
1517 }
1518
1519 // set consumer bits
1520 // TODO: should this get incorporated into setOutputSurface method so that consumer bits
1521 // can be set atomically?
1522 uint64_t consumerUsage = kDefaultConsumerUsage;
1523 {
1524 if (surface) {
1525 int usage = 0;
1526 status_t err = surface->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage);
1527 if (err != NO_ERROR) {
1528 ALOGD("setOutputSurface -- failed to get consumer usage bits (%d/%s). ignoring",
1529 err, asString(err));
1530 } else {
1531 // Note: we are adding the default usage because components must support
1532 // producing output frames that can be displayed an all output surfaces.
1533
1534 // TODO: do not set usage for tunneled scenario. It is unclear if consumer usage
1535 // is meaningful in a tunneled scenario; on one hand output buffers exist, but
1536 // they do not exist inside of C2 scope. Any buffer usage shall be communicated
1537 // through the sideband channel.
1538
1539 // do an unsigned conversion as bit-31 may be 1
1540 consumerUsage = (uint32_t)usage | kDefaultConsumerUsage;
1541 }
1542 }
1543
1544 C2StreamUsageTuning::output outputUsage{
1545 0u, C2AndroidMemoryUsage::FromGrallocUsage(consumerUsage).expected};
1546 std::vector<std::unique_ptr<C2SettingResult>> failures;
1547 c2_status_t err = config({&outputUsage}, C2_MAY_BLOCK, &failures);
1548 if (err != C2_OK) {
1549 ALOGD("setOutputSurface -- failed to set consumer usage (%d/%s)",
1550 err, asString(err));
1551 }
1552 }
1553 ALOGD("setOutputSurface -- generation=%u consumer usage=%#llx%s",
1554 generation, (long long)consumerUsage, syncObj ? " sync" : "");
1555
1556 Return<Status> transStatus = syncObj ?
1557 mBase1_2->setOutputSurfaceWithSyncObj(
1558 static_cast<uint64_t>(blockPoolId),
1559 bqId == 0 ? nullHgbp : igbp, *syncObj) :
1560 mBase1_0->setOutputSurface(
1561 static_cast<uint64_t>(blockPoolId),
1562 bqId == 0 ? nullHgbp : igbp);
1563
1564 if (!transStatus.isOk()) {
1565 LOG(ERROR) << "setOutputSurface -- transaction failed.";
1566 return C2_TRANSACTION_FAILED;
1567 }
1568 c2_status_t status =
1569 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1570 if (status != C2_OK) {
1571 LOG(DEBUG) << "setOutputSurface -- call failed: " << status << ".";
1572 }
1573 ALOGD("Surface configure completed");
1574 return status;
1575 }
1576
queueToOutputSurface(const C2ConstGraphicBlock & block,const QueueBufferInput & input,QueueBufferOutput * output)1577 status_t Codec2Client::Component::queueToOutputSurface(
1578 const C2ConstGraphicBlock& block,
1579 const QueueBufferInput& input,
1580 QueueBufferOutput* output) {
1581 return mOutputBufferQueue->outputBuffer(block, input, output);
1582 }
1583
setOutputSurfaceMaxDequeueCount(int maxDequeueCount)1584 void Codec2Client::Component::setOutputSurfaceMaxDequeueCount(
1585 int maxDequeueCount) {
1586 mOutputBufferQueue->updateMaxDequeueBufferCount(maxDequeueCount);
1587 }
1588
connectToInputSurface(const std::shared_ptr<InputSurface> & inputSurface,std::shared_ptr<InputSurfaceConnection> * connection)1589 c2_status_t Codec2Client::Component::connectToInputSurface(
1590 const std::shared_ptr<InputSurface>& inputSurface,
1591 std::shared_ptr<InputSurfaceConnection>* connection) {
1592 c2_status_t status;
1593 Return<void> transStatus = mBase1_0->connectToInputSurface(
1594 inputSurface->mBase,
1595 [&status, connection](
1596 Status s, const sp<IInputSurfaceConnection>& c) {
1597 status = static_cast<c2_status_t>(s);
1598 if (status != C2_OK) {
1599 LOG(DEBUG) << "connectToInputSurface -- call failed: "
1600 << status << ".";
1601 return;
1602 }
1603 *connection = std::make_shared<InputSurfaceConnection>(c);
1604 });
1605 if (!transStatus.isOk()) {
1606 LOG(ERROR) << "connectToInputSurface -- transaction failed";
1607 return C2_TRANSACTION_FAILED;
1608 }
1609 return status;
1610 }
1611
connectToOmxInputSurface(const sp<HGraphicBufferProducer1> & producer,const sp<HGraphicBufferSource> & source,std::shared_ptr<InputSurfaceConnection> * connection)1612 c2_status_t Codec2Client::Component::connectToOmxInputSurface(
1613 const sp<HGraphicBufferProducer1>& producer,
1614 const sp<HGraphicBufferSource>& source,
1615 std::shared_ptr<InputSurfaceConnection>* connection) {
1616 c2_status_t status;
1617 Return<void> transStatus = mBase1_0->connectToOmxInputSurface(
1618 producer, source,
1619 [&status, connection](
1620 Status s, const sp<IInputSurfaceConnection>& c) {
1621 status = static_cast<c2_status_t>(s);
1622 if (status != C2_OK) {
1623 LOG(DEBUG) << "connectToOmxInputSurface -- call failed: "
1624 << status << ".";
1625 return;
1626 }
1627 *connection = std::make_shared<InputSurfaceConnection>(c);
1628 });
1629 if (!transStatus.isOk()) {
1630 LOG(ERROR) << "connectToOmxInputSurface -- transaction failed.";
1631 return C2_TRANSACTION_FAILED;
1632 }
1633 return status;
1634 }
1635
disconnectFromInputSurface()1636 c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
1637 Return<Status> transStatus = mBase1_0->disconnectFromInputSurface();
1638 if (!transStatus.isOk()) {
1639 LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
1640 return C2_TRANSACTION_FAILED;
1641 }
1642 c2_status_t status =
1643 static_cast<c2_status_t>(static_cast<Status>(transStatus));
1644 if (status != C2_OK) {
1645 LOG(DEBUG) << "disconnectFromInputSurface -- call failed: "
1646 << status << ".";
1647 }
1648 return status;
1649 }
1650
setDeathListener(const std::shared_ptr<Component> & component,const std::shared_ptr<Listener> & listener)1651 c2_status_t Codec2Client::Component::setDeathListener(
1652 const std::shared_ptr<Component>& component,
1653 const std::shared_ptr<Listener>& listener) {
1654
1655 struct HidlDeathRecipient : public hardware::hidl_death_recipient {
1656 std::weak_ptr<Component> component;
1657 std::weak_ptr<Listener> base;
1658
1659 virtual void serviceDied(
1660 uint64_t /* cookie */,
1661 const wp<::android::hidl::base::V1_0::IBase>& /* who */
1662 ) override {
1663 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
1664 listener->onDeath(component);
1665 } else {
1666 LOG(DEBUG) << "onDeath -- listener died.";
1667 }
1668 }
1669 };
1670
1671 sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient();
1672 deathRecipient->base = listener;
1673 deathRecipient->component = component;
1674
1675 component->mDeathRecipient = deathRecipient;
1676 Return<bool> transResult = component->mBase1_0->linkToDeath(
1677 component->mDeathRecipient, 0);
1678 if (!transResult.isOk()) {
1679 LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
1680 return C2_TRANSACTION_FAILED;
1681 }
1682 if (!static_cast<bool>(transResult)) {
1683 LOG(DEBUG) << "setDeathListener -- linkToDeath() call failed.";
1684 return C2_CORRUPTED;
1685 }
1686 return C2_OK;
1687 }
1688
1689 // Codec2Client::InputSurface
InputSurface(const sp<IInputSurface> & base)1690 Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base)
1691 : Configurable{
1692 [base]() -> sp<IConfigurable> {
1693 Return<sp<IConfigurable>> transResult =
1694 base->getConfigurable();
1695 return transResult.isOk() ?
1696 static_cast<sp<IConfigurable>>(transResult) :
1697 nullptr;
1698 }()
1699 },
1700 mBase{base},
1701 mGraphicBufferProducer{new
__anon8dea2f182102() 1702 H2BGraphicBufferProducer2([base]() -> sp<HGraphicBufferProducer2> {
1703 Return<sp<HGraphicBufferProducer2>> transResult =
1704 base->getGraphicBufferProducer();
1705 return transResult.isOk() ?
1706 static_cast<sp<HGraphicBufferProducer2>>(transResult) :
1707 nullptr;
1708 }())} {
1709 }
1710
1711 sp<IGraphicBufferProducer>
getGraphicBufferProducer() const1712 Codec2Client::InputSurface::getGraphicBufferProducer() const {
1713 return mGraphicBufferProducer;
1714 }
1715
getHalInterface() const1716 sp<IInputSurface> Codec2Client::InputSurface::getHalInterface() const {
1717 return mBase;
1718 }
1719
1720 // Codec2Client::InputSurfaceConnection
InputSurfaceConnection(const sp<IInputSurfaceConnection> & base)1721 Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
1722 const sp<IInputSurfaceConnection>& base)
1723 : Configurable{
1724 [base]() -> sp<IConfigurable> {
1725 Return<sp<IConfigurable>> transResult =
1726 base->getConfigurable();
1727 return transResult.isOk() ?
1728 static_cast<sp<IConfigurable>>(transResult) :
1729 nullptr;
1730 }()
1731 },
1732 mBase{base} {
1733 }
1734
disconnect()1735 c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
1736 Return<Status> transResult = mBase->disconnect();
1737 return static_cast<c2_status_t>(static_cast<Status>(transResult));
1738 }
1739
1740 } // namespace android
1741