• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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*> &params,
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(&paramPointers, 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*> &params,
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