1 /*
2 * Copyright 2020 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_TAG "SampleFilterPlugin"
18 #include <android-base/logging.h>
19
20 #include <chrono>
21 #include <thread>
22
23 #include <codec2/hidl/plugin/FilterPlugin.h>
24
25 #include <C2AllocatorGralloc.h>
26 #include <C2Config.h>
27 #include <C2PlatformSupport.h>
28 #include <Codec2Mapper.h>
29 #include <util/C2InterfaceHelper.h>
30
31 #include <renderengine/RenderEngine.h>
32 #include <system/window.h>
33 #include <ui/GraphicBuffer.h>
34 #include <utils/RefBase.h>
35
36 typedef C2StreamParam<C2Info, C2ColorAspectsStruct,
37 kParamIndexColorAspects | C2Param::CoreIndex::IS_REQUEST_FLAG>
38 C2StreamColorAspectsRequestInfo;
39
40 // In practice the vendor parameters will be defined in a separate header file,
41 // but for the purpose of this sample, we just define it here.
42
43 // Vendor-specific type index for filters start from this value. 0x7000 is added to
44 // avoid conflict with existing vendor type indices.
45 constexpr uint32_t kTypeIndexFilterStart = C2Param::TYPE_INDEX_VENDOR_START + 0x7000;
46 // Answer to the Ultimate Question of Life, the Universe, and Everything
47 // (Reference to The Hitchhiker's Guide to the Galaxy by Douglas Adams)
48 constexpr uint32_t kParamIndexVendorUltimateAnswer = kTypeIndexFilterStart + 0;
49 typedef C2StreamParam<C2Info, C2Int32Value, kParamIndexVendorUltimateAnswer>
50 C2StreamVendorUltimateAnswerInfo;
51 constexpr char C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER[] = "ultimate-answer";
52
53 namespace android {
54
55 using namespace std::literals::chrono_literals;
56
57 class SampleToneMappingFilter
58 : public C2Component, public std::enable_shared_from_this<SampleToneMappingFilter> {
59 public:
60 class Interface : public C2ComponentInterface {
61 public:
62 static const std::string NAME;
63 static const FilterPlugin_V1::Descriptor DESCRIPTOR;
64
Interface(c2_node_id_t id,const std::shared_ptr<C2ReflectorHelper> & reflector)65 Interface(c2_node_id_t id, const std::shared_ptr<C2ReflectorHelper> &reflector)
66 : mId(id),
67 mHelper(reflector) {
68 }
69 ~Interface() override = default;
getName() const70 C2String getName() const override { return NAME; }
getId() const71 c2_node_id_t getId() const override { return mId; }
72
query_vb(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const73 c2_status_t query_vb(
74 const std::vector<C2Param*> &stackParams,
75 const std::vector<C2Param::Index> &heapParamIndices,
76 c2_blocking_t mayBlock,
77 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
78 return mHelper.query(stackParams, heapParamIndices, mayBlock, heapParams);
79 }
config_vb(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)80 c2_status_t config_vb(
81 const std::vector<C2Param*> ¶ms,
82 c2_blocking_t mayBlock,
83 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
84 return mHelper.config(params, mayBlock, failures);
85 }
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const86 c2_status_t querySupportedParams_nb(
87 std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {
88 return mHelper.querySupportedParams(params);
89 }
querySupportedValues_vb(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const90 c2_status_t querySupportedValues_vb(
91 std::vector<C2FieldSupportedValuesQuery> &fields,
92 c2_blocking_t mayBlock) const override {
93 return mHelper.querySupportedValues(fields, mayBlock);
94 }
createTunnel_sm(c2_node_id_t)95 c2_status_t createTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }
releaseTunnel_sm(c2_node_id_t)96 c2_status_t releaseTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }
97
getDataSpace()98 uint32_t getDataSpace() {
99 Helper::Lock lock = mHelper.lock();
100 uint32_t dataspace = HAL_DATASPACE_UNKNOWN;
101 C2Mapper::map(
102 mHelper.mInputColorAspectInfo->range,
103 mHelper.mInputColorAspectInfo->primaries,
104 mHelper.mInputColorAspectInfo->matrix,
105 mHelper.mInputColorAspectInfo->transfer,
106 &dataspace);
107 return dataspace;
108 }
getHdrStaticMetadata()109 std::shared_ptr<C2StreamHdrStaticInfo::input> getHdrStaticMetadata() {
110 Helper::Lock lock = mHelper.lock();
111 return mHelper.mInputHdrStaticInfo;
112 }
getPoolId()113 C2BlockPool::local_id_t getPoolId() {
114 Helper::Lock lock = mHelper.lock();
115 return mHelper.mOutputPoolIds->m.values[0];
116 }
117
IsFilteringEnabled(const std::shared_ptr<C2ComponentInterface> & intf)118 static bool IsFilteringEnabled(const std::shared_ptr<C2ComponentInterface> &intf) {
119 C2StreamColorAspectsRequestInfo::output info(0u);
120 std::vector<std::unique_ptr<C2Param>> heapParams;
121 c2_status_t err = intf->query_vb({&info}, {}, C2_MAY_BLOCK, &heapParams);
122 if (err != C2_OK && err != C2_BAD_INDEX) {
123 LOG(WARNING) << "SampleToneMappingFilter::Interface::IsFilteringEnabled: "
124 << "query failed for " << intf->getName();
125 return false;
126 }
127 return info && info.transfer == C2Color::TRANSFER_170M;
128 }
129
QueryParamsForPreviousComponent(const std::shared_ptr<C2ComponentInterface> & intf,std::vector<std::unique_ptr<C2Param>> * params)130 static c2_status_t QueryParamsForPreviousComponent(
131 [[maybe_unused]] const std::shared_ptr<C2ComponentInterface> &intf,
132 std::vector<std::unique_ptr<C2Param>> *params) {
133 params->emplace_back(new C2StreamUsageTuning::output(
134 0u, C2AndroidMemoryUsage::HW_TEXTURE_READ));
135 params->emplace_back(new C2StreamPixelFormatInfo::output(
136 0u, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED));
137 return C2_OK;
138 }
139 private:
140 const c2_node_id_t mId;
141 struct Helper : public C2InterfaceHelper {
Helperandroid::SampleToneMappingFilter::Interface::Helper142 explicit Helper(std::shared_ptr<C2ReflectorHelper> reflector)
143 : C2InterfaceHelper(reflector) {
144 setDerivedInstance(this);
145
146 addParameter(
147 DefineParam(mApiFeatures, C2_PARAMKEY_API_FEATURES)
148 .withConstValue(new C2ApiFeaturesSetting(C2Config::api_feature_t(
149 API_REFLECTION |
150 API_VALUES |
151 API_CURRENT_VALUES |
152 API_DEPENDENCY |
153 API_SAME_INPUT_BUFFER)))
154 .build());
155
156 mName = C2ComponentNameSetting::AllocShared(NAME.size() + 1);
157 strncpy(mName->m.value, NAME.c_str(), NAME.size() + 1);
158 addParameter(
159 DefineParam(mName, C2_PARAMKEY_COMPONENT_NAME)
160 .withConstValue(mName)
161 .build());
162
163 addParameter(
164 DefineParam(mKind, C2_PARAMKEY_COMPONENT_KIND)
165 .withConstValue(new C2ComponentKindSetting(C2Component::KIND_OTHER))
166 .build());
167
168 addParameter(
169 DefineParam(mDomain, C2_PARAMKEY_COMPONENT_DOMAIN)
170 .withConstValue(new C2ComponentDomainSetting(C2Component::DOMAIN_VIDEO))
171 .build());
172
173 addParameter(
174 DefineParam(mInputStreamCount, C2_PARAMKEY_INPUT_STREAM_COUNT)
175 .withConstValue(new C2PortStreamCountTuning::input(1))
176 .build());
177
178 addParameter(
179 DefineParam(mOutputStreamCount, C2_PARAMKEY_OUTPUT_STREAM_COUNT)
180 .withConstValue(new C2PortStreamCountTuning::output(1))
181 .build());
182
183 addParameter(
184 DefineParam(mInputFormat, C2_PARAMKEY_INPUT_STREAM_BUFFER_TYPE)
185 .withConstValue(new C2StreamBufferTypeSetting::input(
186 0u, C2BufferData::GRAPHIC))
187 .build());
188
189 static const std::string kRawMediaType = "video/raw";
190 mInputMediaType = C2PortMediaTypeSetting::input::AllocShared(
191 kRawMediaType.size() + 1);
192 strncpy(mInputMediaType->m.value, kRawMediaType.c_str(), kRawMediaType.size() + 1);
193 addParameter(
194 DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE)
195 .withConstValue(mInputMediaType)
196 .build());
197
198 addParameter(
199 DefineParam(mOutputFormat, C2_PARAMKEY_OUTPUT_STREAM_BUFFER_TYPE)
200 .withConstValue(new C2StreamBufferTypeSetting::output(
201 0u, C2BufferData::GRAPHIC))
202 .build());
203
204 mOutputMediaType = C2PortMediaTypeSetting::output::AllocShared(
205 kRawMediaType.size() + 1);
206 strncpy(mOutputMediaType->m.value, kRawMediaType.c_str(), kRawMediaType.size() + 1);
207 addParameter(
208 DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE)
209 .withConstValue(mOutputMediaType)
210 .build());
211
212 addParameter(
213 DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY)
214 .withConstValue(new C2PortActualDelayTuning::input(0u))
215 .build());
216
217 addParameter(
218 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
219 .withConstValue(new C2PortActualDelayTuning::output(0u))
220 .build());
221
222 addParameter(
223 DefineParam(mActualPipelineDelay, C2_PARAMKEY_PIPELINE_DELAY)
224 .withConstValue(new C2ActualPipelineDelayTuning(0u))
225 .build());
226
227 C2BlockPool::local_id_t outputPoolIds[1] = { C2BlockPool::BASIC_GRAPHIC };
228 addParameter(
229 DefineParam(mOutputPoolIds, C2_PARAMKEY_OUTPUT_BLOCK_POOLS)
230 .withDefault(C2PortBlockPoolsTuning::output::AllocShared(outputPoolIds))
231 .withFields({ C2F(mOutputPoolIds, m.values[0]).any(),
232 C2F(mOutputPoolIds, m.values).inRange(0, 1) })
233 .withSetter(OutputBlockPoolSetter)
234 .build());
235
236 addParameter(
237 DefineParam(mInputHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
238 .withDefault(new C2StreamHdrStaticInfo::input(0u))
239 .withFields({
240 C2F(mInputHdrStaticInfo, mastering.red.x).any(),
241 })
242 .withSetter(HdrStaticInfoSetter)
243 .build());
244
245 addParameter(
246 DefineParam(mOutputHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
247 .withConstValue(new C2StreamHdrStaticInfo::output(0u))
248 .build());
249
250 addParameter(
251 DefineParam(mInputColorAspectInfo, C2_PARAMKEY_COLOR_ASPECTS)
252 .withDefault(new C2StreamColorAspectsInfo::input(0u))
253 .withFields({
254 C2F(mInputColorAspectInfo, range).any(),
255 C2F(mInputColorAspectInfo, primaries).any(),
256 C2F(mInputColorAspectInfo, transfer).any(),
257 C2F(mInputColorAspectInfo, matrix).any(),
258 })
259 .withSetter(InputColorAspectsSetter)
260 .build());
261
262 addParameter(
263 DefineParam(
264 mColorAspectRequestInfo,
265 (std::string(C2_PARAMKEY_COLOR_ASPECTS) + ".request").c_str())
266 .withDefault(new C2StreamColorAspectsRequestInfo::output(0u))
267 .withFields({
268 C2F(mColorAspectRequestInfo, range).any(),
269 C2F(mColorAspectRequestInfo, primaries).any(),
270 C2F(mColorAspectRequestInfo, transfer).oneOf({
271 C2Color::TRANSFER_UNSPECIFIED,
272 C2Color::TRANSFER_170M,
273 }),
274 C2F(mColorAspectRequestInfo, matrix).any(),
275 })
276 .withSetter(ColorAspectsRequestSetter)
277 .build());
278
279 addParameter(
280 DefineParam(mVendorUltimateAnswerInfo, C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER)
281 .withDefault(new C2StreamVendorUltimateAnswerInfo::input(0u))
282 .withFields({
283 C2F(mVendorUltimateAnswerInfo, value).any(),
284 })
285 .withSetter(VendorUltimateAnswerSetter)
286 .build());
287
288 addParameter(
289 DefineParam(mOutputColorAspectInfo, C2_PARAMKEY_COLOR_ASPECTS)
290 .withDefault(new C2StreamColorAspectsInfo::output(0u))
291 .withFields({
292 C2F(mOutputColorAspectInfo, range).any(),
293 C2F(mOutputColorAspectInfo, primaries).any(),
294 C2F(mOutputColorAspectInfo, transfer).any(),
295 C2F(mOutputColorAspectInfo, matrix).any(),
296 })
297 .withSetter(OutputColorAspectsSetter,
298 mInputColorAspectInfo,
299 mColorAspectRequestInfo)
300 .build());
301 }
302
OutputBlockPoolSetterandroid::SampleToneMappingFilter::Interface::Helper303 static C2R OutputBlockPoolSetter(
304 bool mayBlock,
305 C2P<C2PortBlockPoolsTuning::output> &me) {
306 (void)mayBlock, (void)me;
307 return C2R::Ok();
308 }
309
HdrStaticInfoSetterandroid::SampleToneMappingFilter::Interface::Helper310 static C2R HdrStaticInfoSetter(
311 bool mayBlock,
312 C2P<C2StreamHdrStaticInfo::input> &me) {
313 (void)mayBlock, (void)me;
314 return C2R::Ok();
315 }
316
InputColorAspectsSetterandroid::SampleToneMappingFilter::Interface::Helper317 static C2R InputColorAspectsSetter(
318 bool mayBlock,
319 C2P<C2StreamColorAspectsInfo::input> &me) {
320 (void)mayBlock, (void)me;
321 return C2R::Ok();
322 }
323
OutputColorAspectsSetterandroid::SampleToneMappingFilter::Interface::Helper324 static C2R OutputColorAspectsSetter(
325 bool mayBlock,
326 C2P<C2StreamColorAspectsInfo::output> &me,
327 const C2P<C2StreamColorAspectsInfo::input> &inputColor,
328 const C2P<C2StreamColorAspectsRequestInfo::output> &request) {
329 (void)mayBlock;
330 me.set().range = inputColor.v.range;
331 me.set().primaries = inputColor.v.primaries;
332 me.set().transfer = inputColor.v.transfer;
333 if (request.v.transfer == C2Color::TRANSFER_170M) {
334 me.set().transfer = C2Color::TRANSFER_170M;
335 }
336 me.set().matrix = inputColor.v.matrix;
337 return C2R::Ok();
338 }
339
ColorAspectsRequestSetterandroid::SampleToneMappingFilter::Interface::Helper340 static C2R ColorAspectsRequestSetter(
341 bool mayBlock,
342 C2P<C2StreamColorAspectsRequestInfo::output> &me) {
343 (void)mayBlock;
344 if (me.v.range != C2Color::RANGE_UNSPECIFIED) {
345 me.set().range = C2Color::RANGE_UNSPECIFIED;
346 }
347 if (me.v.primaries != C2Color::PRIMARIES_UNSPECIFIED) {
348 me.set().primaries = C2Color::PRIMARIES_UNSPECIFIED;
349 }
350 if (me.v.transfer != C2Color::TRANSFER_170M) {
351 me.set().transfer = C2Color::TRANSFER_UNSPECIFIED;
352 }
353 if (me.v.matrix != C2Color::MATRIX_UNSPECIFIED) {
354 me.set().matrix = C2Color::MATRIX_UNSPECIFIED;
355 }
356 return C2R::Ok();
357 }
358
VendorUltimateAnswerSetterandroid::SampleToneMappingFilter::Interface::Helper359 static C2R VendorUltimateAnswerSetter(
360 bool mayBlock,
361 C2P<C2StreamVendorUltimateAnswerInfo::input> &me) {
362 (void)mayBlock;
363 ALOGI("Answer to the Ultimate Question of Life, the Universe, and Everything "
364 "set to %d", me.v.value);
365 return C2R::Ok();
366 }
367
368 std::shared_ptr<C2ApiFeaturesSetting> mApiFeatures;
369
370 std::shared_ptr<C2ComponentNameSetting> mName;
371 std::shared_ptr<C2ComponentAliasesSetting> mAliases;
372 std::shared_ptr<C2ComponentKindSetting> mKind;
373 std::shared_ptr<C2ComponentDomainSetting> mDomain;
374
375 std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType;
376 std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType;
377 std::shared_ptr<C2StreamBufferTypeSetting::input> mInputFormat;
378 std::shared_ptr<C2StreamBufferTypeSetting::output> mOutputFormat;
379
380 std::shared_ptr<C2PortActualDelayTuning::input> mActualInputDelay;
381 std::shared_ptr<C2PortActualDelayTuning::output> mActualOutputDelay;
382 std::shared_ptr<C2ActualPipelineDelayTuning> mActualPipelineDelay;
383
384 std::shared_ptr<C2PortStreamCountTuning::input> mInputStreamCount;
385 std::shared_ptr<C2PortStreamCountTuning::output> mOutputStreamCount;
386
387 std::shared_ptr<C2PortBlockPoolsTuning::output> mOutputPoolIds;
388
389 std::shared_ptr<C2StreamHdrStaticInfo::input> mInputHdrStaticInfo;
390 std::shared_ptr<C2StreamHdrStaticInfo::output> mOutputHdrStaticInfo;
391 std::shared_ptr<C2StreamColorAspectsInfo::input> mInputColorAspectInfo;
392 std::shared_ptr<C2StreamColorAspectsInfo::output> mOutputColorAspectInfo;
393 std::shared_ptr<C2StreamColorAspectsRequestInfo::output> mColorAspectRequestInfo;
394
395 std::shared_ptr<C2StreamVendorUltimateAnswerInfo::input> mVendorUltimateAnswerInfo;
396 } mHelper;
397 };
398
SampleToneMappingFilter(c2_node_id_t id,const std::shared_ptr<C2ReflectorHelper> & reflector)399 SampleToneMappingFilter(c2_node_id_t id, const std::shared_ptr<C2ReflectorHelper> &reflector)
400 : mIntf(std::make_shared<Interface>(id, reflector)) {
401 }
~SampleToneMappingFilter()402 ~SampleToneMappingFilter() override {
403 if (mProcessingThread.joinable()) {
404 mProcessingThread.join();
405 }
406 }
407
setListener_vb(const std::shared_ptr<Listener> & listener,c2_blocking_t mayBlock)408 c2_status_t setListener_vb(
409 const std::shared_ptr<Listener> &listener, c2_blocking_t mayBlock) override {
410 std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 5ms;
411 {
412 std::unique_lock lock(mStateMutex);
413 if (mState == RELEASED) {
414 return C2_BAD_STATE;
415 }
416 if (mState == RUNNING && listener) {
417 return C2_BAD_STATE;
418 }
419 if (mState != STOPPED) {
420 return C2_BAD_STATE;
421 }
422 }
423 std::unique_lock lock(mListenerMutex, std::try_to_lock);
424 if (lock) {
425 mListener = listener;
426 return C2_OK;
427 }
428 if (mayBlock == C2_DONT_BLOCK) {
429 return C2_BLOCKING;
430 }
431 lock.try_lock_until(deadline);
432 if (!lock) {
433 return C2_TIMED_OUT;
434 }
435 mListener = listener;
436 return C2_OK;
437 }
438
queue_nb(std::list<std::unique_ptr<C2Work>> * const items)439 c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override {
440 if (!items) {
441 return C2_BAD_VALUE;
442 }
443 {
444 std::unique_lock lock(mStateMutex);
445 if (mState != RUNNING) {
446 return C2_BAD_STATE;
447 }
448 }
449 std::unique_lock lock(mQueueMutex);
450 mQueue.splice(mQueue.end(), *items);
451 mQueueCondition.notify_all();
452 return C2_OK;
453 }
454
announce_nb(const std::vector<C2WorkOutline> &)455 c2_status_t announce_nb(const std::vector<C2WorkOutline> &) override { return C2_OMITTED; }
456
flush_sm(flush_mode_t mode,std::list<std::unique_ptr<C2Work>> * const flushedWork)457 c2_status_t flush_sm(
458 flush_mode_t mode,
459 std::list<std::unique_ptr<C2Work>>* const flushedWork) override {
460 if (!flushedWork) {
461 return C2_BAD_VALUE;
462 }
463 if (mode == FLUSH_CHAIN) {
464 return C2_BAD_VALUE;
465 }
466 {
467 std::unique_lock lock(mStateMutex);
468 if (mState != RUNNING) {
469 return C2_BAD_STATE;
470 }
471 }
472 {
473 std::unique_lock lock(mQueueMutex);
474 mQueue.swap(*flushedWork);
475 }
476 // NOTE: this component does not have internal state to flush.
477 return C2_OK;
478 }
479
drain_nb(drain_mode_t mode)480 c2_status_t drain_nb(drain_mode_t mode) override {
481 if (mode == DRAIN_CHAIN) {
482 return C2_BAD_VALUE;
483 }
484 {
485 std::unique_lock lock(mStateMutex);
486 if (mState != RUNNING) {
487 return C2_BAD_STATE;
488 }
489 }
490 // NOTE: this component does not wait for work items before processing.
491 return C2_OK;
492 }
493
start()494 c2_status_t start() override {
495 //std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 500ms;
496 {
497 std::unique_lock lock(mStateMutex);
498 if (mState == STARTING) {
499 return C2_DUPLICATE;
500 }
501 if (mState != STOPPED) {
502 return C2_BAD_STATE;
503 }
504 mState = STARTING;
505 }
506 {
507 std::unique_lock lock(mProcessingMutex);
508 if (!mProcessingThread.joinable()) {
509 mProcessingThread = std::thread([this]() {
510 processLoop(shared_from_this());
511 });
512 }
513 }
514 {
515 std::unique_lock lock(mStateMutex);
516 mState = RUNNING;
517 }
518 return C2_OK;
519 }
520
stop()521 c2_status_t stop() override {
522 //std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 500ms;
523 {
524 std::unique_lock lock(mStateMutex);
525 if (mState == STOPPING) {
526 return C2_DUPLICATE;
527 }
528 if (mState != RUNNING) {
529 return C2_BAD_STATE;
530 }
531 mState = STOPPING;
532 }
533 {
534 std::unique_lock lock(mQueueMutex);
535 mQueueCondition.notify_all();
536 }
537 {
538 std::unique_lock lock(mProcessingMutex);
539 if (mProcessingThread.joinable()) {
540 mProcessingThread.join();
541 }
542 }
543 {
544 std::unique_lock lock(mStateMutex);
545 mState = STOPPED;
546 }
547 return C2_OK;
548 }
549
reset()550 c2_status_t reset() override {
551 //std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 500ms;
552 {
553 std::unique_lock lock(mStateMutex);
554 if (mState == RESETTING) {
555 return C2_DUPLICATE;
556 }
557 if (mState == RELEASED) {
558 return C2_BAD_STATE;
559 }
560 mState = RESETTING;
561 }
562 {
563 std::unique_lock lock(mQueueMutex);
564 mQueueCondition.notify_all();
565 }
566 {
567 std::unique_lock lock(mProcessingMutex);
568 if (mProcessingThread.joinable()) {
569 mProcessingThread.join();
570 }
571 }
572 {
573 std::unique_lock lock(mStateMutex);
574 mState = STOPPED;
575 }
576 return C2_OK;
577 }
578
release()579 c2_status_t release() override {
580 //std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 500ms;
581 {
582 std::unique_lock lock(mStateMutex);
583 if (mState == RELEASED || mState == RELEASING) {
584 return C2_DUPLICATE;
585 }
586 // TODO: return C2_BAD_STATE if not stopped
587 mState = RELEASING;
588 }
589 {
590 std::unique_lock lock(mQueueMutex);
591 mQueueCondition.notify_all();
592 }
593 {
594 std::unique_lock lock(mProcessingMutex);
595 if (mProcessingThread.joinable()) {
596 mProcessingThread.join();
597 }
598 }
599 {
600 std::unique_lock lock(mStateMutex);
601 mState = RELEASED;
602 }
603 return C2_OK;
604 }
605
intf()606 std::shared_ptr<C2ComponentInterface> intf() override {
607 return mIntf;
608 }
609
610 private:
processLoop(std::shared_ptr<SampleToneMappingFilter> thiz)611 void processLoop(std::shared_ptr<SampleToneMappingFilter> thiz) {
612 constexpr float kDefaultMaxLumiance = 500.0;
613 constexpr float kDefaultMaxMasteringLuminance = 1000.0;
614 constexpr float kDefaultMaxContentLuminance = 1000.0;
615 constexpr uint32_t kDstUsage =
616 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
617 GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
618
619 int32_t workCount = 0;
620 std::unique_ptr<renderengine::RenderEngine> renderEngine = renderengine::RenderEngine::create(
621 renderengine::RenderEngineCreationArgs::Builder()
622 .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
623 .setImageCacheSize(2 /*maxFrameBufferAcquiredBuffers*/)
624 .setUseColorManagerment(true)
625 .setEnableProtectedContext(false)
626 .setPrecacheToneMapperShaderOnly(true)
627 .setContextPriority(renderengine::RenderEngine::ContextPriority::LOW)
628 .build());
629 if (!renderEngine) {
630 std::unique_lock lock(mListenerMutex);
631 mListener->onError_nb(thiz, C2_CORRUPTED);
632 return;
633 }
634 uint32_t textureName = 0;
635 renderEngine->genTextures(1, &textureName);
636
637 while (true) {
638 // Before doing anything, verify the state
639 {
640 std::unique_lock lock(mStateMutex);
641 if (mState != RUNNING) {
642 break;
643 }
644 }
645 // Extract one work item
646 std::unique_ptr<C2Work> work;
647 {
648 std::unique_lock lock(mQueueMutex);
649 if (mQueue.empty()) {
650 mQueueCondition.wait_for(lock, 1s);
651 }
652 if (mQueue.empty()) {
653 continue;
654 }
655 mQueue.front().swap(work);
656 mQueue.pop_front();
657 ++workCount;
658 }
659 LOG(VERBOSE) << "work #" << workCount << ": flags=" << work->input.flags
660 << " timestamp=" << work->input.ordinal.timestamp.peek();;
661
662 std::vector<C2Param *> configUpdate;
663 for (const std::unique_ptr<C2Param> ¶m : work->input.configUpdate) {
664 configUpdate.push_back(param.get());
665 }
666 std::vector<std::unique_ptr<C2SettingResult>> failures;
667 mIntf->config_vb(configUpdate, C2_MAY_BLOCK, &failures);
668
669 std::shared_ptr<C2StreamHdrStaticInfo::input> hdrStaticInfo =
670 mIntf->getHdrStaticMetadata();
671 uint32_t dataspace = mIntf->getDataSpace();
672
673 std::shared_ptr<C2Buffer> buffer;
674 if (!work->input.buffers.empty()) {
675 buffer = work->input.buffers.front();
676 }
677 std::shared_ptr<C2Buffer> outC2Buffer;
678 status_t err = OK;
679 if (buffer) {
680 if (buffer->hasInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE)) {
681 std::shared_ptr<const C2Info> info =
682 buffer->getInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE);
683 std::unique_ptr<C2Param> flipped = C2Param::CopyAsStream(
684 *info, false /* output */, info->stream());
685 hdrStaticInfo.reset(static_cast<C2StreamHdrStaticInfo::input *>(
686 flipped.release()));
687 }
688 const C2Handle *c2Handle =
689 buffer->data().graphicBlocks().front().handle();
690 uint32_t width, height, format, stride, igbp_slot, generation;
691 uint64_t usage, igbp_id;
692 _UnwrapNativeCodec2GrallocMetadata(
693 c2Handle, &width, &height, &format, &usage, &stride, &generation,
694 &igbp_id, &igbp_slot);
695 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
696 sp<GraphicBuffer> srcBuffer = new GraphicBuffer(
697 grallocHandle, GraphicBuffer::CLONE_HANDLE,
698 width, height, format, 1, usage, stride);
699
700 native_handle_delete(grallocHandle);
701 std::shared_ptr<C2GraphicBlock> dstBlock;
702 C2BlockPool::local_id_t poolId = mIntf->getPoolId();
703 std::shared_ptr<C2BlockPool> pool;
704 GetCodec2BlockPool(poolId, thiz, &pool);
705 pool->fetchGraphicBlock(
706 width, height, HAL_PIXEL_FORMAT_RGBA_8888, C2AndroidMemoryUsage::FromGrallocUsage(kDstUsage),
707 &dstBlock);
708 outC2Buffer = C2Buffer::CreateGraphicBuffer(
709 dstBlock->share(C2Rect(width, height), C2Fence()));
710 c2Handle = dstBlock->handle();
711 _UnwrapNativeCodec2GrallocMetadata(
712 c2Handle, &width, &height, &format, &usage, &stride, &generation,
713 &igbp_id, &igbp_slot);
714 grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
715 sp<GraphicBuffer> dstBuffer = new GraphicBuffer(
716 grallocHandle, GraphicBuffer::CLONE_HANDLE,
717 width, height, format, 1, usage, stride);
718
719 native_handle_delete(grallocHandle);
720 Rect sourceCrop(0, 0, width, height);
721
722 renderengine::DisplaySettings clientCompositionDisplay;
723 std::vector<const renderengine::LayerSettings*> clientCompositionLayers;
724
725 clientCompositionDisplay.physicalDisplay = sourceCrop;
726 clientCompositionDisplay.clip = sourceCrop;
727
728 clientCompositionDisplay.outputDataspace = ui::Dataspace::V0_SRGB;
729 clientCompositionDisplay.maxLuminance = kDefaultMaxLumiance;
730 clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
731 renderengine::LayerSettings layerSettings;
732 layerSettings.geometry.boundaries = sourceCrop.toFloatRect();
733 layerSettings.alpha = 1.0f;
734
735 layerSettings.sourceDataspace = static_cast<ui::Dataspace>(dataspace);
736
737 // from BufferLayer
738 layerSettings.source.buffer.buffer = srcBuffer;
739 layerSettings.source.buffer.isOpaque = true;
740 // TODO: fence
741 layerSettings.source.buffer.fence = Fence::NO_FENCE;
742 layerSettings.source.buffer.textureName = textureName;
743 layerSettings.source.buffer.usePremultipliedAlpha = false;
744 layerSettings.source.buffer.maxMasteringLuminance =
745 (hdrStaticInfo && *hdrStaticInfo &&
746 hdrStaticInfo->mastering.maxLuminance > 0 &&
747 hdrStaticInfo->mastering.minLuminance > 0)
748 ? hdrStaticInfo->mastering.maxLuminance : kDefaultMaxMasteringLuminance;
749 layerSettings.source.buffer.maxContentLuminance =
750 (hdrStaticInfo && *hdrStaticInfo && hdrStaticInfo->maxCll > 0)
751 ? hdrStaticInfo->maxCll : kDefaultMaxContentLuminance;
752
753 // Set filtering to false since the capture itself doesn't involve
754 // any scaling, metadata retriever JNI is scaling the bitmap if
755 // display size is different from decoded size. If that scaling
756 // needs to be handled by server side, consider enable this based
757 // display size vs decoded size.
758 layerSettings.source.buffer.useTextureFiltering = false;
759 layerSettings.source.buffer.textureTransform = mat4();
760 clientCompositionLayers.push_back(&layerSettings);
761
762 // Use an empty fence for the buffer fence, since we just created the buffer so
763 // there is no need for synchronization with the GPU.
764 base::unique_fd bufferFence;
765 base::unique_fd drawFence;
766 renderEngine->useProtectedContext(false);
767 err = renderEngine->drawLayers(
768 clientCompositionDisplay, clientCompositionLayers, dstBuffer.get(),
769 /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
770
771 sp<Fence> fence = new Fence(std::move(drawFence));
772
773 // We can move waiting for fence & sending it back on a separate thread to improve
774 // efficiency, but leaving it here for simplicity.
775 if (err != OK) {
776 LOG(ERROR) << "drawLayers returned err " << err;
777 } else {
778 err = fence->wait(500);
779 if (err != OK) {
780 LOG(WARNING) << "wait for fence returned err " << err;
781 }
782 }
783 renderEngine->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL);
784 }
785
786 work->worklets.front()->output.ordinal = work->input.ordinal;
787 work->worklets.front()->output.flags = work->input.flags;
788 if (err == OK) {
789 work->workletsProcessed = 1;
790 if (outC2Buffer) {
791 work->worklets.front()->output.buffers.push_back(outC2Buffer);
792 }
793 work->result = C2_OK;
794 } else {
795 work->result = C2_CORRUPTED;
796 }
797 std::list<std::unique_ptr<C2Work>> items;
798 items.push_back(std::move(work));
799
800 std::unique_lock lock(mListenerMutex);
801 mListener->onWorkDone_nb(thiz, std::move(items));
802 LOG(VERBOSE) << "sent work #" << workCount;
803 }
804 }
805
806 mutable std::timed_mutex mListenerMutex;
807 std::shared_ptr<Listener> mListener;
808
809 mutable std::mutex mQueueMutex;
810 mutable std::condition_variable mQueueCondition;
811 std::list<std::unique_ptr<C2Work>> mQueue;
812
813 const std::shared_ptr<Interface> mIntf;
814
815 mutable std::mutex mStateMutex;
816 enum State {
817 STOPPED,
818 RUNNING,
819 RELEASED,
820 STARTING, // STOPPED -> RUNNING
821 STOPPING, // RUNNING -> STOPPED
822 RESETTING, // <<ANY>> -> STOPPED
823 RELEASING, // STOPPED -> RELEASED
824 } mState;
825
826 mutable std::mutex mProcessingMutex;
827 std::thread mProcessingThread;
828
829 };
830
831 // static
832 const std::string SampleToneMappingFilter::Interface::NAME = "c2.sample.tone-mapper";
833 // static
834 const FilterPlugin_V1::Descriptor SampleToneMappingFilter::Interface::DESCRIPTOR = {
835 // controlParams
836 {
837 C2StreamColorAspectsRequestInfo::output::PARAM_TYPE,
838 C2StreamVendorUltimateAnswerInfo::input::PARAM_TYPE,
839 },
840 // affectedParams
841 {
842 C2StreamHdrStaticInfo::output::PARAM_TYPE,
843 C2StreamColorAspectsInfo::output::PARAM_TYPE,
844 },
845 };
846
847 class SampleC2ComponentStore : public C2ComponentStore {
848 public:
SampleC2ComponentStore()849 SampleC2ComponentStore()
850 : mReflector(std::make_shared<C2ReflectorHelper>()),
851 mIntf(mReflector),
852 mFactories(CreateFactories(mReflector)) {
853 }
854 ~SampleC2ComponentStore() = default;
855
getName() const856 C2String getName() const override { return "android.sample.filter-plugin-store"; }
createComponent(C2String name,std::shared_ptr<C2Component> * const component)857 c2_status_t createComponent(
858 C2String name, std::shared_ptr<C2Component>* const component) override {
859 if (mFactories.count(name) == 0) {
860 return C2_BAD_VALUE;
861 }
862 return mFactories.at(name)->createComponent(++mNodeId, component);
863 }
createInterface(C2String name,std::shared_ptr<C2ComponentInterface> * const interface)864 c2_status_t createInterface(
865 C2String name, std::shared_ptr<C2ComponentInterface>* const interface) override {
866 if (mFactories.count(name) == 0) {
867 return C2_BAD_VALUE;
868 }
869 return mFactories.at(name)->createInterface(++mNodeId, interface);
870 }
listComponents()871 std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override {
872 std::vector<std::shared_ptr<const C2Component::Traits>> ret;
873 for (const auto &[name, factory] : mFactories) {
874 ret.push_back(factory->getTraits());
875 }
876 return ret;
877 }
copyBuffer(std::shared_ptr<C2GraphicBuffer>,std::shared_ptr<C2GraphicBuffer>)878 c2_status_t copyBuffer(
879 std::shared_ptr<C2GraphicBuffer>, std::shared_ptr<C2GraphicBuffer>) override {
880 return C2_OMITTED;
881 }
query_sm(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const882 c2_status_t query_sm(
883 const std::vector<C2Param*> &stackParams,
884 const std::vector<C2Param::Index> &heapParamIndices,
885 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
886 return mIntf.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
887 }
config_sm(const std::vector<C2Param * > & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)888 c2_status_t config_sm(
889 const std::vector<C2Param*> ¶ms,
890 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
891 return mIntf.config(params, C2_MAY_BLOCK, failures);
892 }
getParamReflector() const893 std::shared_ptr<C2ParamReflector> getParamReflector() const override {
894 return mReflector;
895 }
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const896 c2_status_t querySupportedParams_nb(
897 std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {
898 return mIntf.querySupportedParams(params);
899 }
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const900 c2_status_t querySupportedValues_sm(
901 std::vector<C2FieldSupportedValuesQuery> &fields) const override {
902 return mIntf.querySupportedValues(fields, C2_MAY_BLOCK);
903 }
904
905 private:
906 class ComponentFactory {
907 public:
908 virtual ~ComponentFactory() = default;
909
getTraits()910 const std::shared_ptr<const C2Component::Traits> &getTraits() { return mTraits; }
911
912 virtual c2_status_t createComponent(
913 c2_node_id_t id,
914 std::shared_ptr<C2Component>* const component) const = 0;
915 virtual c2_status_t createInterface(
916 c2_node_id_t id,
917 std::shared_ptr<C2ComponentInterface>* const interface) const = 0;
918 protected:
ComponentFactory(const std::shared_ptr<const C2Component::Traits> & traits)919 ComponentFactory(const std::shared_ptr<const C2Component::Traits> &traits)
920 : mTraits(traits) {
921 }
922 private:
923 const std::shared_ptr<const C2Component::Traits> mTraits;
924 };
925
926 template <class T>
927 struct ComponentFactoryImpl : public ComponentFactory {
928 public:
ComponentFactoryImplandroid::SampleC2ComponentStore::ComponentFactoryImpl929 ComponentFactoryImpl(
930 const std::shared_ptr<const C2Component::Traits> &traits,
931 const std::shared_ptr<C2ReflectorHelper> &reflector)
932 : ComponentFactory(traits),
933 mReflector(reflector) {
934 }
935 ~ComponentFactoryImpl() override = default;
createComponentandroid::SampleC2ComponentStore::ComponentFactoryImpl936 c2_status_t createComponent(
937 c2_node_id_t id,
938 std::shared_ptr<C2Component>* const component) const override {
939 *component = std::make_shared<T>(id, mReflector);
940 return C2_OK;
941 }
createInterfaceandroid::SampleC2ComponentStore::ComponentFactoryImpl942 c2_status_t createInterface(
943 c2_node_id_t id,
944 std::shared_ptr<C2ComponentInterface>* const interface) const override {
945 *interface = std::make_shared<typename T::Interface>(id, mReflector);
946 return C2_OK;
947 }
948 private:
949 std::shared_ptr<C2ReflectorHelper> mReflector;
950 };
951
952 template <class T>
AddFactory(std::map<C2String,std::unique_ptr<ComponentFactory>> * factories,const std::shared_ptr<C2ReflectorHelper> & reflector)953 static void AddFactory(
954 std::map<C2String, std::unique_ptr<ComponentFactory>> *factories,
955 const std::shared_ptr<C2ReflectorHelper> &reflector) {
956 std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0, reflector)};
957 std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
958 CHECK(C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf))
959 << "Failed to fill traits from interface";
960 factories->emplace(
961 traits->name,
962 new ComponentFactoryImpl<T>(traits, reflector));
963 }
964
CreateFactories(const std::shared_ptr<C2ReflectorHelper> & reflector)965 static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories(
966 const std::shared_ptr<C2ReflectorHelper> &reflector) {
967 std::map<C2String, std::unique_ptr<ComponentFactory>> factories;
968 AddFactory<SampleToneMappingFilter>(&factories, reflector);
969 return factories;
970 }
971
972
973 std::shared_ptr<C2ReflectorHelper> mReflector;
974 struct Interface : public C2InterfaceHelper {
Interfaceandroid::SampleC2ComponentStore::Interface975 explicit Interface(std::shared_ptr<C2ReflectorHelper> reflector)
976 : C2InterfaceHelper(reflector) {
977 }
978 } mIntf;
979
980 const std::map<C2String, std::unique_ptr<ComponentFactory>> mFactories;
981
982 std::atomic_int32_t mNodeId{0};
983 };
984
985 class SampleFilterPlugin : public FilterPlugin_V1 {
986 public:
SampleFilterPlugin()987 SampleFilterPlugin() : mStore(new SampleC2ComponentStore) {}
988 ~SampleFilterPlugin() override = default;
989
getComponentStore()990 std::shared_ptr<C2ComponentStore> getComponentStore() override {
991 return mStore;
992 }
993
describe(C2String name,Descriptor * desc)994 bool describe(C2String name, Descriptor *desc) override {
995 if (name == SampleToneMappingFilter::Interface::NAME) {
996 *desc = SampleToneMappingFilter::Interface::DESCRIPTOR;
997 return true;
998 }
999 return false;
1000 }
1001
isFilteringEnabled(const std::shared_ptr<C2ComponentInterface> & intf)1002 bool isFilteringEnabled(const std::shared_ptr<C2ComponentInterface> &intf) override {
1003 if (intf->getName() == SampleToneMappingFilter::Interface::NAME) {
1004 return SampleToneMappingFilter::Interface::IsFilteringEnabled(intf);
1005 }
1006 return false;
1007 }
1008
queryParamsForPreviousComponent(const std::shared_ptr<C2ComponentInterface> & intf,std::vector<std::unique_ptr<C2Param>> * params)1009 c2_status_t queryParamsForPreviousComponent(
1010 const std::shared_ptr<C2ComponentInterface> &intf,
1011 std::vector<std::unique_ptr<C2Param>> *params) override {
1012 if (intf->getName() == SampleToneMappingFilter::Interface::NAME) {
1013 return SampleToneMappingFilter::Interface::QueryParamsForPreviousComponent(
1014 intf, params);
1015 }
1016 return C2_BAD_VALUE;
1017 }
1018
1019 private:
1020 std::shared_ptr<C2ComponentStore> mStore;
1021 };
1022
1023 } // namespace android
1024
1025 extern "C" {
1026
GetFilterPluginVersion()1027 int32_t GetFilterPluginVersion() {
1028 return ::android::SampleFilterPlugin::VERSION;
1029 }
1030
CreateFilterPlugin()1031 void *CreateFilterPlugin() {
1032 return new ::android::SampleFilterPlugin;
1033 }
1034
DestroyFilterPlugin(void * plugin)1035 void DestroyFilterPlugin(void *plugin) {
1036 delete (::android::SampleFilterPlugin *)plugin;
1037 }
1038
1039 } // extern "C"
1040