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